Lowering intrinsic that return an int1

Hi all,

I’m playing with intrinsics and I was wondering how to lower an intrinsic that should return, for example, an int1? More precisely, how to return the value when working with MachineInst?

First, I have defined an instrinsic in “Intrinsics.td”:

def int_antivm : Intrinsic<[llvm_i1_ty], [], [], “llvm.antivm”>;

Then I want to lower it in the X86 backend, so I defined a pseudo instruction in “X86InstrCompiler.td”:

let usesCustomInserter = 1, Defs = [EFLAGS] in {
def ANTIVM : PseudoI<(outs), (ins), [(int_antivm)]>;
}

I wrote my custom inserter:

MachineBasicBlock *
X86TargetLowering::EmitANTIVMWithCustomInserter(
MachineInstr *MI,
MachineBasicBlock *MBB) const {

// Some stuff,

MI->eraseFromParent(); // The pseudo is gone now.
return BB;
}

Should I put the return value to EAX (like for a standard function) ?

Thank you for your help.

Hi all,

I’m playing with intrinsics and I was wondering how to lower an intrinsic that should return, for example, an int1? More precisely, how to return the value when working with MachineInst?

First, I have defined an instrinsic in “Intrinsics.td”:

def int_antivm : Intrinsic<[llvm_i1_ty], [], [], “llvm.antivm”>;

Then I want to lower it in the X86 backend, so I defined a pseudo instruction in “X86InstrCompiler.td”:

let usesCustomInserter = 1, Defs = [EFLAGS] in {

I think pseudo-instructions should also define isPseudo = 1

def ANTIVM : PseudoI<(outs), (ins), [(int_antivm)]>;
}

I wrote my custom inserter:

MachineBasicBlock *
X86TargetLowering::EmitANTIVMWithCustomInserter(
MachineInstr *MI,
MachineBasicBlock *MBB) const {

// Some stuff,

MI->eraseFromParent(); // The pseudo is gone now.
return BB;
}

Should I put the return value to EAX (like for a standard function) ?

I expect that before your custom inserter, the value produced by your pseudo instruction was in a vreg. You just have to reuse this vreg to put the result of your “stuff”.
If you run llc with —print-before-all, you should be able to see the actual sequence.

I think pseudo-instructions should also define isPseudo = 1

Ah yes, thank you.

I expect that before your custom inserter, the value produced by your pseudo instruction was in a vreg. You just have to reuse this vreg to put the result of your “stuff”.
If you run llc with —print-before-all, you should be able to see the actual sequence.

That’s exactly my problem. How to know before my custom inserter where the produced value will be? I found some documentation about the x86 target saying that the operand 0 is always the destination value, is it right? Also, sometimes I saw getOperand(0).getReg(), but how can I be sure that the destination will be in a vreg? Should I specify it explicitly in the TableGen definition?

I admit being a bit lost inside the backend…

Thank you for your help

Yes the first operands are the destinations (MI can produce multiple values).

The instruction selector will always use a vreg to select your instruction, you don’t have anything to do.
The custom inserter is executed before register allocation, and it is the role of the RA to turn the vreg into a physical one,

The physical registers that you can see at this point are mainly here to implement the ABI AFAIK.

—Mehdi

I should also add that I don’t know what you’re trying to achieve, but keep in mind that some scheduling and optimizations will run after this point.Depending on the end result you are seeking, you might need to your expansion later.

Thank’s a lot, it nearly works !

My intrinsics now:

def int_antivm2 : Intrinsic<[llvm_i8_ty], [llvm_ptr_ty], [], “llvm.antivm2”>;

My “backend” intrinsics:

let usesCustomInserter = 1, isPseudo = 1, Defs = [EFLAGS, EAX, ECX, EDX, EBX] in {
def ANTIVM : PseudoI<(outs GR8:$dst), (ins i32mem:$src), [(set GR8:$dst, (int_antivm2 addr:$src))]>;
}

As I understand ANTIVM:

  • It returns an int8 into a one byte register (GR8)

  • It receives a pointer stored on memory (i32mem)

  • [(set GR8:$dst, (int_antivm2 addr:$src))] match two DAGNode that corresponds to int_antivm2 translation into SelectionDAG node

Am I right? I constructed both by try-and-error based on example I found here and there.

Seems to work well when returning a llvm_i8_ty but I got a “PromotionInteger error” with llvm_i1_ty. I tried to also change “GR8” to “VK1” (seems to be a register of one bit) in the second one, but without success. Any idea?