Adding an architecture specific intrinsic and an annotation
There are three things I write about here. Two work (Adding a calling convention and Using an intrinsic to implement an new target instruction). One I still don't understand how to do (access the SP in the IR).
I started with llvm basic doc on adding intrinsic. All paths are relative to $LLVMBASE.
Reading the sp
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., add
int_x86_read_sp
to IntrinsicsX86.tdlet 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., add psuedoI to X86InstrULI.td
let Uses = [RSP] in def READSP64 : PseudoI<(outs GR64:$dst), (ins), [(set GR64:$dst, RSP)]>, Requires<[In64BitMode]>;
-
And, to make testing more easily, I added to the following builtin to the front-end in BuiltinsX86.def
// read the SP 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,
Adding instrinsics which can be mapped to new instructions.
- created intrinsics in IntrinsicsX86.td, e.g.,
etc. (Must have thedef int_x86_uli_send0 : GCCBuiltin<"__builtin_uli_send0">, Intrinsic<[], [llvm_i32_ty, llvm_i32_ty, llvm_ptr_ty], []>;
GCCBuiltin
part so you don't have to do any work on the front-end. - If you want the user to be able to add these, then you have to creat matching definitions for front end in BuiltinsX86.def, e.g.,
BUILTIN(__builtin_uli_send0, "viiv*", "")
- can now create .ll code using:
../build/bin/clang -S -emit-llvm srcfile.c
- Now get
LLVM ERROR: Cannot select: intrinsic %llvm.x86.uli.send0
- since the
send0
would require psuedoI to combine the proc and int number, I created a__builtin_uli_send0c
which requires the user to combine dest proc and int number. This should simplify code generation. - added rest of intrinsics, built-ins, and instructions to appropriate files. New instructions in
llvm/lib/Target/X86/
. Need to get appropriate format for instruction.MRMSrcReg
works for 2 arg instructions, e.g., ulisend.- MRM2r works for 1 in, 1 out when they are contrainted via
let Constraints = "$src = $dest"
, e.g.,ULIFROMIREG
- example def:
Thedef ULISEND0 : I <0x3e, MRMSrcReg, (outs), (ins GR64:$src0, GR64:$src1), "ulisend\t{$src0, $src1}", [(int_x86_uli_send0c GR64:$src0, GR64:$src1)], IIC_ALU_NONMEM>, TB, Requires<[In64BitMode]>;
TB
is for a prefix code which allows us to add our new instruction.
Adding calling convention
I wanted to be able to change the calling convention for a function, so I added an annotation that can do that. This is an architecture specific annotation.
more to write here