Hi All,
I'm working on a back end for an architecture that makes use of multi-typed register classes.
def MR: RegisterClass<"namespace", [type1, type2, ... ], ... >
When running some preliminary tests I found that the instruction selector refused to select certain ops (specifically stores) for some instructions when the operand type wasn't the first type for the register class. After some digging around I seem to have solved the problem by creating bitconvert patterns between the types in the register class like the following:
def : Pat<(type1 (bitconvert (type2 MR:$src))), (type1 MR:$src)>;
def : Pat<(type2 (bitconvert (type1 MR:$src))), (type2 MR:$src)>;
...
Adding these patterns appeared to allow the instruction selector to select/legalize the store operations. So I have two questions:
1) Is relying on these patterns for instruction selection/legalization the correct way to implement multi-typed RegisterClasses? I like having TableGen do the pattern work for me rather than writing custom selection code...
2) I'd think that when a multi-typed RegisterClass is declared that these bitconvert patterns between types in that class automatically become legal. Is there a reason that TableGen shouldn't automatically generate these patterns when a multi-typed register class is created?
Thanks
selector refused to select certain ops (specifically stores) for some
instructions when the operand type wasn't the first type for the
register class. After some digging around I seem to have solved the
problem by creating bitconvert patterns between the types in the
register class like the following:
def : Pat<(type1 (bitconvert (type2 MR:$src))), (type1 MR:$src)>;
def : Pat<(type2 (bitconvert (type1 MR:$src))), (type2 MR:$src)>;
...
Adding these patterns appeared to allow the instruction selector to
select/legalize the store operations. So I have two questions:
1) Is relying on these patterns for instruction selection/
legalization the correct way to implement multi-typed
RegisterClasses? I like having TableGen do the pattern work for me
rather than writing custom selection code...
2) I'd think that when a multi-typed RegisterClass is declared that
these bitconvert patterns between types in that class automatically
become legal. Is there a reason that TableGen shouldn't automatically
generate these patterns when a multi-typed register class is created?
X86 backend has the VR64 and VR128 register classes which are exactly like this. Rather than adding a whole bunch of instruction selection rules to match all the possibilities. We've decided to ask the legalizer to normalize the target-independent nodes to one particular type. See X86ISelLowering.cpp:
// Promote v16i8, v8i16, v4i32 load, select, and, or, xor to v2i64.
for (unsigned VT = (unsigned)MVT::v16i8; VT != (unsigned)MVT::v2i64; VT++) {
setOperationAction(ISD::AND, (MVT::ValueType)VT, Promote);
AddPromotedToType (ISD::AND, (MVT::ValueType)VT, MVT::v2i64);
...
Evan
Thanks Evan,
I had tried something like this, but ran into some problems.
llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp:1478: failed assertion `MVT::isVector(VT) && "Cannot promote this load!"'
and
llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp:1766: failed assertion `MVT::isVector(VT) && "Unknown legal promote case!"'
it appears that for load/store only vector types of equivalent bit-widths can be promoted in this way, but one cannot promote an f32 to an i32.
Also, I was incorrect in thinking that the bitconvert patterns I mentioned in the original post had solved my problems. I ended up having to explicitly add patterns for the f32 types to the InstrInfo.td. And then, it only seems to work if I add a pseudo instruction with the following selection pattern (store (f32 Regs:$src), ADDRri:$addr), rather than adding a pattern such as the following:
def : Pat<(store (f32 Regs:$src), ADDRri:$addr), (ST32 Regs:$src, ADDRri:$addr)>;
The above pattern produced the following error because the TargetOperandInfo for the 1 operand of the store had a NULL register class.
llvm/lib/CodeGen/SelectionDAG/ScheduleDAG.cpp:304: failed assertion `RC && "Don't have operand info for this instruction!"'
Why the pseudo-op doesn't have this problem, I'm not clear.
Thanks
Thanks Evan,
I had tried something like this, but ran into some problems.
llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp:1478: failed assertion
`MVT::isVector(VT) && "Cannot promote this load!"'
and
llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp:1766: failed assertion
`MVT::isVector(VT) && "Unknown legal promote case!"'
it appears that for load/store only vector types of equivalent bit-
widths can be promoted in this way, but one cannot promote an f32 to
an i32.
Right. I am afraid will have to add separate patterns for f32 cases.
Also, I was incorrect in thinking that the bitconvert patterns I
mentioned in the original post had solved my problems. I ended up
having to explicitly add patterns for the f32 types to the
InstrInfo.td. And then, it only seems to work if I add a pseudo
instruction with the following selection pattern (store (f32 Regs:
$src), ADDRri:$addr), rather than adding a pattern such as the
following:
def : Pat<(store (f32 Regs:$src), ADDRri:$addr), (ST32 Regs:$src,
ADDRri:$addr)>;
The above pattern produced the following error because the
TargetOperandInfo for the 1 operand of the store had a NULL register
class.
llvm/lib/CodeGen/SelectionDAG/ScheduleDAG.cpp:304: failed assertion
`RC && "Don't have operand info for this instruction!"'
Why the pseudo-op doesn't have this problem, I'm not clear.
I can't tell from the information you have provided. How is ST32 defined?
Evan
def ST32 : F0<opcode,
(ops MEMri:$addr, Regs:$src),
"st32 [$addr], $src",
[(store Regs:$src, ADDRri:$addr)]>;
Seems to me the pattern should be:
def : Pat<(store (f32 Regs:$src), ADDRri:$addr), (ST32 ADDRi:$addr, Regs:$src)>;
You have the order of operands reversed?
Evan