1. example code in C
extern "C" void f() { short a = 5; }
2. Corresponding LLVM IR code
define void @f() {
entry:
%a = alloca i16, align 2
store i16 5, i16* %a, align 2
ret void}
3. Corresponding Legalized DAG
Legalized selection DAG: %bb.0 'f:entry'
SelectionDAG has 6 nodes:
t0: ch = EntryToken
t5: ch = store<(store 2 into %ir.a)> t0, Constant:i16<5>, FrameIndex:i16<0>, undef:i16
t6: ch = M88kISD::RET_FLAG t5
4. Instruction Target Description for Instruction Selection Pattern Matching
def ToL6 : SDNodeXForm<imm, [{
int64_t Value = N->getSExtValue();
return CurDAG->getTargetConstant(Value, SDLoc(N), MVT::i16);}]>;
class ImmediateAsmOperand<string name> : AsmOperandClass {
let Name = name;
let RenderMethod = "addImmOperands";}
def S6Imm : ImmediateAsmOperand<"S6Imm">;
// immediate operand
class ImmediateOp<ValueType vt, string asmop> : Operand<vt> {
let PrintMethod = "print"#asmop#"Operand";
// static DecodeStatus #DecoderMethod(MCInst &Inst, int64_t Imm,
// uint64_t Address, const void *Decoder)
let DecoderMethod = "decode"#asmop#"Operand";
let ParserMatchClass = !cast<AsmOperandClass>(asmop);
let OperandType = "OPERAND_IMMEDIATE";
}
class ImmOpWithPattern<ValueType vt, string asmop, code pred, SDNodeXForm xform,
SDNode ImmNode = imm> :
ImmediateOp<vt, asmop>, PatLeaf<(vt ImmNode), pred, xform>;
multiclass Immediate<ValueType vt, code pred, SDNodeXForm xform, string asmop> {
// for llvm ir constant
def "" : ImmOpWithPattern<vt, asmop, pred, xform>;
// for target constant
def _timm : ImmOpWithPattern<vt, asmop, pred, xform, timm>;
}
defm imm16InL6 : Immediate<i16, [{
int64_t Value = N->getSExtValue();
return (-32 <= Value && Value <= 31);
}], ToL6, "S6Imm">;
def M88kMemAsmOperand : AsmOperandClass {
let Name = "Mem";
// OperandMatchResultTy XXXMCTargetAsmParser::parseMemOperand(OperandVector &);
let ParserMethod = "parseMemOperand";
//void XXXMCParsedAsmOperand::addMemOperand(MCInst &Inst, unsigned N) const
let RenderMethod = "addMemOperand";
}
// Address operand MachineInstruction/MCInst Operand
def frameSlot : Operand<iPTR> {
// void XXXInstPrinter::#PrintMethod(const MCInst *MI, unsigned opNo,
// const MCSubtargetInfo &STI,
// raw_ostream &O);
let PrintMethod = "printMemOperand";
// unsigned XXXMCCodeEmitter::#EncoderMethod(const MCInst &MI, unsigned OpNo,
// SmallVectorImpl<MCFixup> &Fixups,
// const MCSubtargetInfo &STI) const
let EncoderMethod = "getMemEncoding";
let MIOperandInfo = (ops GPROpnd, imm16InL6);
let ParserMatchClass = M88kMemAsmOperand;}
def frameObject :
ComplexPattern<iPTR, 2, "SelectFrameObject", [frameindex], [SDNPWantParent]>;
def STm: F_LSR<0b0111,
(outs), (ins GPROpnd:$r, frameSlot:$obj),
!strconcat("str", " $r, $obj"),
[(store GPROpnd:$r, frameObject:$obj)]>;
def MVI: F_MVI<(outs GPROpnd:$dr),
(ins imm16InL6:$imm6),
!strconcat("mvi", " $dr, $imm6"),[]>;
// patterns for constants
def : Pat<(i16 imm16InL6:$imm6),(MVI imm16InL6:$imm6)>;
That is quite a lot for comprehension. Let us demystify the whole process by reading that .td code snippet from bottom up.
First of all, t5: ch = store<(store 2 into %ir.a)> t0, Constant:i16<5>, FrameIndex:i16<0>, undef:i16 is what going to be matched by pattern.
There are three parts in that operation or IR instruction (more formal words).
- the
store<(store 2 into %ir.a)> t0
operator. - the
Constant:i16<5>
operand. - the
FrameIndex:i16<0>
operand. - the
undef:i16
part, which is corresponding thealign 2
in LLVM IR, can be ignored for Instruction Selection.
Our pattern for store
is (store GPROpnd:$r, frameObject:$obj)
which means store a register to a frame object, which is not the same as IR store in Legalized DAG.
1. Match the Constant:i16<5> to get a register holding that constant.
We need to match the Constant:i16<5>
via def:Pat<(i16 imm16InL6:$imm6),(MVI imm16InL6:$imm6)>
to give us a register holding the constant. imm16InL6 is an Operand as well as PatLeaf to match a constant (immediate) with predicate in code part for checking if the constant is fit in 6 bits. That bit width is restricted by the target ISA mvi
instruction. The output of matched instruction is GPROpnd:$r
, which shows in outs
of
def MVI: F_MVI<(outs GPROpnd:$dr),
(ins imm16InL6:$imm6),
!strconcat("mvi", " $dr, $imm6"),
[]>;
that matches the first operand of the pattern (store GPROpnd:$r, frameObject:$obj)
for our target store instruction. Now for the second operand.
2. Match the FrameIndex:i16<0> operand.
FrameIndex is a reference to an object in stack frame. Here we use complex pattern def frameObject:ComplexPattern<iPTR, 2, "SelectFrameObject", [frameindex], [SDNPWantParent]>;
to match it, which means use SelectFrameObject
method of XXXDAGToDAGISel
class to match a DAG with frameindex
as its root. iPTR
means the type of match result is a pointer to memory. 2
means the matched result has 2
operands. SDNPWantParent
means that method needs the parent node of frameindex
, which in this case should be store
. Therefore, we get the following method.
bool XXXDAGToDAGISel::SelectFrameObject(SDNode *Parent, SDValue frameIndex,
SDValue &Base, SDValue &Offset)
when this method return true, that means the DAG rooted with frameindex processed successfully, and the result would be 2 SDValue
, Base
and Offset
. Then turn into frameSlot
operand, defined as
def frameSlot : Operand<iPTR> {
// void XXXInstPrinter::#PrintMethod(const MCInst *MI, unsigned opNo,
// const MCSubtargetInfo &STI,
// raw_ostream &O);
let PrintMethod = "printMemOperand";
// unsigned XXXMCCodeEmitter::#EncoderMethod(const MCInst &MI, unsigned OpNo,
// SmallVectorImpl<MCFixup> &Fixups,
// const MCSubtargetInfo &STI) const
let EncoderMethod = "getMemEncoding";
let MIOperandInfo = (ops GPROpnd, imm16InL6);
let ParserMatchClass = M88kMemAsmOperand;}
See the type iPTR
and MIOperandInfo
which match the complex pattern result, its type and value. The Operand in .td file represents an operand of MachineInstruction
or MCInst
. By the way, PrintMethod
, EncoderMethod
, DecoderMethod
is used for that operand to output as asm text, binary and be decoded as binary respectively, and the ParserMatchClass
is for parsing asm text back to MCInst
Operand, as show in following image.
Now we satisfy the (store GPROpnd:$r, frameObject:$obj)
pattern, then STm
will be selected accordingly.