Pattern matching question

Our target has a load.idx opcode with the following semantics:

load.idx r1,r2,r3, SIZE : r1 ← mem[r2 + (r3 << sizeof(operand))]

(where sizeof(operand) is in the range 0…3

Here’s a snippet of the DAG I want to match so that a load.idx instruction is selected:

0x30d29c0: i64 = Constant<3>

0x30d2e00: i64 = shl 0x30d2be0, 0x30d29c0 [ORD=3]

0x30d2f10: i64 = add 0x30d2cf0, 0x30d2e00 [ORD=3]

0x30d28b0:
0x30d3020: i64,ch = load 0x30a3ec0, 0x30d2f10, 0x30d28b0<LD8%arrayidx16(addrspace=4)> [ORD=4]

Here’s what I’m trying in TargetInstrInfo.td:

class Addr< int numArgs, string funcName, dag opInfo >
: Operand,
ComplexPattern< i64, numArgs, funcName, [], [SDNPWantParent] > {
let MIOperandInfo = opInfo;
}

let PrintMethod = “printMemOperand” in {
def ADDR_RR : Addr< 2, “SelectAddrRegReg”,
(ops GPRC:$base, GPRC:$offsetreg) >;
def ADDR_RI : Addr< 2, “SelectAddrRegImm”,
(ops GPRC:$base, i64imm:$offsetimm) >;
}
def ADDR_I : Addr< 1, “SelectAddrImmLocal”, (ops i64imm:$imm) >;
def ADDR_SHLI : Addr< 2, “SelectAddrShlImm”,
(ops GPRC:$base, ( shl GPRC:$offsetreg, (i64 3))) >;

multiclass LoadOp< bits<7> op,
string instr_asm,
OperandInfo info,
InstrItinClass itin=II_LOAD1_RR > {
let opsize = info.sizeCode in {

//
// store: mem[r2 + r3] = r1
//
def _RR : FR3< op,
(outs),
(ins ADDR_RR:$addr, info.regClass:$r1),
instr_asm # “\t\t$r1, $addr, " # info.sizeStr,
[(store info.regClass:$r1, ADDR_RR:$addr)],
itin > {
let regcount = 5; // ISA change
}
//
// load: r1 = mem[r2 + (r3 << sizeof(operand) ]
//
def _SHLI : FR3< op,
(outs info.regClass:$r1),
(ins ADDR_SHLI:$addr),
//instr_asm#”\t$r1, $r2, $r3, "#info.sizeStr,
instr_asm # "\t\t$r1, $addr, " # info.sizeStr,
[(set info.regClass:$r1, (load ADDR_SHLI:$addr))],
itin > {
}

}

defm LOADI64_SHL : LoadOp< 0b1001100, “load.idx”, OpInfo_I64 >;

//end

(Note: ADDR_RR, ADDR_RI, ADDR_I definitions already existed, I’m trying to add ADDR_SHLI).

When I try to run llvm-tblgen with -gen-instr-info I get:
llvm-tblgen: /home/phil/eqware/tg/tg/xe-llvm/include/llvm/Support/Casting.h:237: typename llvm::cast_retty<X, Y*>::ret_type llvm::cast(Y*) [with X = llvm::DefInit; Y = llvm::Init; typename llvm::cast_retty<X, Y*>::ret_type = llvm::DefInit*]: Assertion `isa(Val) && “cast() argument of incompatible type!”’ failed.

The problem seems to be the (ins ADDR_SHLI:$addr in def _SHLI above. If I change it to: (ins ADDR_RR:$addr) it runs ok, but then it’s not going to match what I’m trying to match.

Am I going about this the right way or is there be a different approach?

Phil