Tablegen to match a literal in an instruction

I am trying to make some modifications to our code generator that will produce better code, but require adding new patterns.

What I am trying to do is take a register/register pattern and change it to a register/immediate.

So for example, I have this pattern:

class ILFormat<ILOpCode op, dag outs, dag ins, string asmstr, list pattern>

: Instruction {

let Namespace = “AMDIL”;

dag OutOperandList = outs;

dag InOperandList = ins;

ILOpCode operation = op;

let Pattern = pattern;

let AsmString = !strconcat(asmstr, “\n”);

bit hasIEEEFlag = 0;

bit hasZeroOpFlag = 0;

}

class BinaryOp<ILOpCode op, SDNode OpNode, RegisterClass dReg,

RegisterClass sReg0, RegisterClass sReg1>

: ILFormat<op, (outs dReg:$dst), (ins sReg0:$src0, sReg1:$src1),

!strconcat(op.Text, " $dst, $src0, $src1"),

[(set dReg:$dst, (OpNode sReg0:$src0, sReg1:$src1))]>;

multiclass BinaryOpMCInt<ILOpCode OpCode, SDNode OpNode> {

def _i8 : BinaryOp<OpCode, OpNode, GPRI8, GPRI8, GPRI8>;

def _i16 : BinaryOp<OpCode, OpNode, GPRI16, GPRI16, GPRI16>;

def _i32 : BinaryOp<OpCode, OpNode, GPRI32, GPRI32, GPRI32>;

def _i64 : BinaryOp<OpCode, OpNode, GPRI64, GPRI64, GPRI64>;

}

defm AND : BinaryOpMCInt<IL_OP_AND, and>;

I want to turn this into a register/immediate pattern by changing it to:

class ILFormat<dag outs, dag ins, string asmstr, list pattern>

: Instruction {

let Namespace = “AMDIL”;

dag OutOperandList = outs;

dag InOperandList = ins;

let Pattern = pattern;

let AsmString = !strconcat(asmstr, “\n”);

}

multiclass BinaryOp<SDNode OpNode, RegisterClass dReg,

RegisterClass sReg0, RegisterClass sReg1, Operand lit>

{

def _rr: ILFormat<op, (outs dReg:$dst), (ins sReg0:$src0, sReg1:$src1),

!strconcat(op.Text, " $dst, $src0, $src1"),

[(set dReg:$dst, (OpNode sReg0:$src0, sReg1:$src1))]>;

def _ri : ILFormat<op, (outs dReg:$dst), (ins sReg0:$src0, lit:$src1),

“and $dst, $src0, $src1”),

[(set dReg:$dst, (OpNode sReg0:$src0, imm:$src1))]>;

}

multiclass BinaryOpMCInt {

defm _i32 : BinaryOp<OpNode, GPRI32, GPRI32, GPRI32, i32imm>;

}

defm AND : BinaryOpMCInt;

When I run on a simple program which just ands a value and writes to memory, I get this error:

LLVM ERROR: Cannot select: 0x99555d0: i32 = Constant<2> [ORD=7] [ID=8]

Where 0x99555d0 is only used as the second operand of the ‘and’ node.

So, how can I figure out what I’m doing wrong? Does anyone see anything majorly wrong here?

Thanks,

Micah

Micah,

I don't see anything wrong with this offhand. Have you tried getting the debug output from llc -debug, and matching it up with the state machine in your DAGISel.inc to see at what step the auto-generated matcher is failing to match your and-with-immediate?

-Owen

I’m not at the machine that has the changes, but it was failing at index 0.

Micah

Also, another point to note.

If I create an instruction that just does (set GPRI32, imm) as the pattern, then it matches. The problem is that I get a lot of moves in the code, instead of getting the immediate inlined into the instruction itself.

Micah

Right, it's failing when it tries to materialize a move of a constant into a register. But it's only trying to do that because it previously failed to fold the constant into the AND. What you need to do is step through the path it takes when matching the AND node, and try to figure out why it ends up selecting the register-register version rather than the register-immediate version. Fortunately, the debug output from llc will contain a complete trace of what happened, so you just need to line it up with GenDAGISel.inc and determine which step did the wrong thing.

At a guess, I'd say you probably have a type declared wrong somewhere.

--Owen

Thanks for the tip, didn’t think to look at the AND node as a culprit because we have a similar pattern on a different internal backend and its matching fine.

Micah