Adding an intrinsic to read the stack pointer, e.g., RSP in x86

I need to use the stack pointer, e.g., RSP on X86, to get some
information off the stack. I am not sure what the best way to do this is.

My plan was to create an intrinsic, e.g.,

let TargetPrefix = “x86” in {
def int_x86_read_sp : GCCBuiltin<"__builtin_read_sp">,
Intrinsic<[llvm_i64_ty], [], [IntrNoMem]>;
}

I thought I would define a PseudoI, e.g.,

let Uses = [RSP] in
def READSP64 : PseudoI<(outs GR64:$dst), (ins),
[(set GR64:$dst, RSP)]>,
Requires<[In64BitMode]>;

But, actually I am not sure how this would come into play. (Do I need this? If so, how do I use it?)

To test it out I added a Builtin to BuiltinsX86.def, e.g.,

BUILTIN(__builtin_read_sp, “ULLi”, “”)

When I try and compile, I get a proper .ll file from clang with the instruction

%0 = call i64 @llvm.x86.read.sp()

However, it fails, with

llc: ./llvm/lib/CodeGen/SelectionDAG/InstrEmitter.cpp:303: unsigned int llvm::InstrEmitter::getVR(llvm::SDValue, llvm::DenseMap<llvm::SDValue, unsigned int>&): Assertion `I != VRBaseMap.end() && “Node emitted out of order - late”’ failed.

I am not sure how to introduce the IR to read the RSP so I can create
code to do a calculation on the RSP to retrieve a value buried in the
stack. I figure I need to lower the call i64 @llvm.x86.read.sp in
X86TargetLowering::LowerOperation. I am not sure if this would be
ISD::INTRINSIC_WO_CHAIN or ISD::INTRINSIC_W_CHAIN (and I don’t
actually understand what would go in the intrinsic definition to make
it one or the other. Any pointers would be appreciated. Thanks,

seth

I believe clang does support getting the stack-pointer via the “gcc register variable extension”. The syntax and behaviour would follow this:
https://gcc.gnu.org/onlinedocs/gcc/Global-Register-Variables.html#Global-Register-Variables

however, it is restricted specifically to the stack-pointer.

#include <stdio.h>

register size_t stack asm(“rsp”);

int main()
{
printf("%zx\n", stack);
}

It compiles to this LLVM IR:
define i32 @main() #0 {
entry:
%0 = call i64 @llvm.read_register.i64(metadata !0)
%call = call i32 (i8*, …) @printf(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i32 0, i32 0), i64 %0)
ret i32 0
}

Is there a reason that you cannot insert some inline assembly code to read the stack pointer? The only downside to it (as far as I can tell) is that you would need to have different assembly code for each platform on which you want to do this. Regards, John Criswell

The issue is that I need to insert this code as part of a transformation. Is there a way to insert assembly code in a pass?

-seth

Yes. You can create an inline assembly code “value” by creating an InlineAsm object. You then make that “value” an argument to an LLVM CallInst object. For more information, look at the InlineAsm and CallInst classes in the LLVM Doxygen documentation. Regards, John Criswell