Adding intrinsic with variable argument list HOWTO.

Hi, I've been hitting my head to wall two days now. This is practically my first contact with InstrInfo.td files. Is there any tutorial how to make this kind of stuff? Or should I just keep on studying Sparc and other backends?

So I added new intrinsic to llvm/include/llvm/TCEInstrinsics.td:

def int_tce_customop : Intrinsic<[llvm_void_ty, llvm_ptr_ty, llvm_vararg_ty], , "llvm.tce.customop">;

I made opt pass that converts __custom_op() functions to calls to llvm.tce.customop calls.

grep llvm.tce.customop hello2.ll

        tail call void (i8*, ...)* @llvm.tce.customop( i8* getelementptr ([7 x i8]* @.str, i32 0, i32 0), i32 %tmp78 )
        tail call void (i8*, ...)* @llvm.tce.customop( i8* getelementptr ([7 x i8]* @.str, i32 0, i32 0), i32 10 )
        tail call void (i8*, ...)* @llvm.tce.customop( i8* getelementptr ([7 x i8]* @.str, i32 0, i32 0), i32 %tmp12 )
declare void @llvm.tce.customop(i8*, ...)

No I need to add code to llvm/lib/Target/TCE/TCEInstrInfo.td, for recognizing that variable argument intrinsic and I have no idea how it's done. Right now I'm trying following:

def CustomOpParams : SDTypeProfile<0,2,>;

def customop : SDNode<"ISD::INTRINSIC_VOID", CustomOpParams>;

def : Pat<(customop tglobaladdr:$dst,iPTR:$vararg),
          (int_tce_customop tglobaladdr:$dst, iAny:$vararg)>;

def : Pat<(call texternalsym:$dst,iAny:$vararg),
          (int_tce_customop texternalsym:$dst, iAny:$vararg)>;

but compilation gives following error:

isVoid:void anonymous.52: (intrinsic_void:void 197:iPTR, (tglobaladdr:iPTR):$dst, isVoid:void)
/home/elhigu/llvm-install/llvm/Release/bin/tblgen: In anonymous.52: Type inference contradiction found in node!

Mikael Lepistö

Hi, I've been hitting my head to wall two days now. This is practically
my first contact with InstrInfo.td files. Is there any tutorial how to
make this kind of stuff? Or should I just keep on studying Sparc and
other backends?

Unfortunately studying other targets (and trial and error) is the best way. This is not well documented.

So I added new intrinsic to llvm/include/llvm/TCEInstrinsics.td:

def int_tce_customop :
    Intrinsic<[llvm_void_ty, llvm_ptr_ty, llvm_vararg_ty], ,
"llvm.tce.customop">;

I made opt pass that converts __custom_op() functions to calls to
llvm.tce.customop calls.

> grep llvm.tce.customop hello2.ll
        tail call void (i8*, ...)* @llvm.tce.customop( i8* getelementptr
([7 x i8]* @.str, i32 0, i32 0), i32 %tmp78 )
        tail call void (i8*, ...)* @llvm.tce.customop( i8* getelementptr
([7 x i8]* @.str, i32 0, i32 0), i32 10 )
        tail call void (i8*, ...)* @llvm.tce.customop( i8* getelementptr
([7 x i8]* @.str, i32 0, i32 0), i32 %tmp12 )
declare void @llvm.tce.customop(i8*, ...)

No I need to add code to llvm/lib/Target/TCE/TCEInstrInfo.td, for
recognizing that variable argument intrinsic and I have no idea how it's
done. Right now I'm trying following:

def CustomOpParams : SDTypeProfile<0,2,>;

def customop : SDNode<"ISD::INTRINSIC_VOID", CustomOpParams>;

def : Pat<(customop tglobaladdr:$dst,iPTR:$vararg),
          (int_tce_customop tglobaladdr:$dst, iAny:$vararg)>;

def : Pat<(call texternalsym:$dst,iAny:$vararg),
          (int_tce_customop texternalsym:$dst, iAny:$vararg)>;

You want to match an intrinsic pattern to a particular target instruction. Try something like

def customop_i8 : I<(outs), (ins r8:$dst, variable_ops), "customop $dst",
                                     [(int_tce_customop tglobaladdr:$dst)]>;

variable_ops means the instruction has variable number of operands.

You can also use the def : Pat syntax. But you still need the instruction definition. Then
def : Pat<(int_tce_customop tglobaladdr:$dst), (customop tglobaladdr:$dst)>

Note variable_ops isn't needed on the def : Pat rule, just on the instruction.

Hope this helps.

Evan