-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[TableGen][GISel] Extract common function for determining MI's regclass #120135
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -459,6 +459,10 @@ class GlobalISelEmitter final : public GlobalISelMatchTableExecutorEmitter { | |
const CodeGenRegisterClass * | ||
inferRegClassFromPattern(const TreePatternNode &N); | ||
|
||
const CodeGenRegisterClass * | ||
inferRegClassFromInstructionPattern(const TreePatternNode &N, | ||
unsigned ResIdx); | ||
|
||
Error constrainOperands(action_iterator InsertPt, RuleMatcher &M, | ||
unsigned InsnID, const TreePatternNode &Dst); | ||
|
||
|
@@ -1856,46 +1860,85 @@ GlobalISelEmitter::inferRegClassFromPattern(const TreePatternNode &N) { | |
|
||
// Don't want to try and infer things when there could potentially be more | ||
// than one candidate register class. | ||
auto &Inst = Target.getInstruction(OpRec); | ||
return inferRegClassFromInstructionPattern(N, /*ResIdx=*/0); | ||
} | ||
|
||
const CodeGenRegisterClass * | ||
GlobalISelEmitter::inferRegClassFromInstructionPattern(const TreePatternNode &N, | ||
unsigned ResIdx) { | ||
const CodeGenInstruction &Inst = Target.getInstruction(N.getOperator()); | ||
assert(ResIdx < Inst.Operands.NumDefs && | ||
"Can only infer register class for explicit defs"); | ||
|
||
// Handle any special-case instructions which we can safely infer register | ||
// classes from. | ||
StringRef InstName = Inst.TheDef->getName(); | ||
bool IsRegSequence = InstName == "REG_SEQUENCE"; | ||
if (IsRegSequence || InstName == "COPY_TO_REGCLASS") { | ||
// If we have a COPY_TO_REGCLASS, then we need to handle it specially. It | ||
// has the desired register class as the first child. | ||
const TreePatternNode &RCChild = N.getChild(IsRegSequence ? 0 : 1); | ||
if (InstName == "REG_SEQUENCE") { | ||
// (outs $super_dst), (ins $dst_regclass, variable_ops) | ||
// Destination register class is explicitly specified by the first operand. | ||
const TreePatternNode &RCChild = N.getChild(0); | ||
if (!RCChild.isLeaf()) | ||
return nullptr; | ||
return getRegClassFromLeaf(RCChild); | ||
} | ||
|
||
if (InstName == "COPY_TO_REGCLASS") { | ||
// (outs $dst), (ins $src, $dst_regclass) | ||
// Destination register class is explicitly specified by the second operand. | ||
const TreePatternNode &RCChild = N.getChild(1); | ||
if (!RCChild.isLeaf()) | ||
return nullptr; | ||
return getRegClassFromLeaf(RCChild); | ||
} | ||
|
||
if (InstName == "INSERT_SUBREG") { | ||
// (outs $super_dst), (ins $super_src, $sub_src, $sub_idx); | ||
// If we can infer the register class for the first operand, use that. | ||
// Otherwise, find a register class that supports both the specified | ||
// sub-register index and the type of the instruction's result. | ||
const TreePatternNode &Child0 = N.getChild(0); | ||
assert(Child0.getNumTypes() == 1 && "Unexpected number of types!"); | ||
const TypeSetByHwMode &VTy = Child0.getExtType(0); | ||
return inferSuperRegisterClassForNode(VTy, Child0, N.getChild(2)); | ||
return inferSuperRegisterClassForNode(N.getExtType(0), Child0, | ||
N.getChild(2)); | ||
} | ||
|
||
if (InstName == "EXTRACT_SUBREG") { | ||
assert(N.getNumTypes() == 1 && "Unexpected number of types!"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was actually bugged, but wasn't covered by tests. |
||
const TypeSetByHwMode &VTy = N.getExtType(0); | ||
return inferSuperRegisterClass(VTy, N.getChild(1)); | ||
// (outs $sub_dst), (ins $super_src, $sub_idx) | ||
// Find a register class that can be used for a sub-register copy from | ||
// the specified source at the specified sub-register index. | ||
const CodeGenRegisterClass *SuperRC = | ||
inferRegClassFromPattern(N.getChild(0)); | ||
if (!SuperRC) | ||
return nullptr; | ||
|
||
const CodeGenSubRegIndex *SubIdx = inferSubRegIndexForNode(N.getChild(1)); | ||
if (!SubIdx) | ||
return nullptr; | ||
|
||
const auto SubRCAndSubRegRC = | ||
SuperRC->getMatchingSubClassWithSubRegs(CGRegs, SubIdx); | ||
if (!SubRCAndSubRegRC) | ||
return nullptr; | ||
|
||
return SubRCAndSubRegRC->second; | ||
} | ||
|
||
if (InstName == "SUBREG_TO_REG") { | ||
// (outs $super_dst), (ins $super_src, $sub_src, $sub_idx) | ||
// Find a register class that supports both the specified sub-register | ||
// index and the type of the instruction's result. | ||
return inferSuperRegisterClass(N.getExtType(0), N.getChild(2)); | ||
} | ||
|
||
// Handle destination record types that we can safely infer a register class | ||
// from. | ||
const auto &DstIOperand = Inst.Operands[0]; | ||
const auto &DstIOperand = Inst.Operands[ResIdx]; | ||
const Record *DstIOpRec = DstIOperand.Rec; | ||
if (DstIOpRec->isSubClassOf("RegisterOperand")) { | ||
DstIOpRec = DstIOpRec->getValueAsDef("RegClass"); | ||
const CodeGenRegisterClass &RC = Target.getRegisterClass(DstIOpRec); | ||
return &RC; | ||
} | ||
if (DstIOpRec->isSubClassOf("RegisterOperand")) | ||
return &Target.getRegisterClass(DstIOpRec->getValueAsDef("RegClass")); | ||
|
||
if (DstIOpRec->isSubClassOf("RegisterClass")) { | ||
const CodeGenRegisterClass &RC = Target.getRegisterClass(DstIOpRec); | ||
return &RC; | ||
} | ||
if (DstIOpRec->isSubClassOf("RegisterClass")) | ||
return &Target.getRegisterClass(DstIOpRec); | ||
|
||
return nullptr; | ||
} | ||
|
@@ -2043,8 +2086,7 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) { | |
if (!DstOp->isSubClassOf("Instruction")) | ||
return failedImport("Pattern operator isn't an instruction"); | ||
|
||
auto &DstI = Target.getInstruction(DstOp); | ||
StringRef DstIName = DstI.TheDef->getName(); | ||
const CodeGenInstruction &DstI = Target.getInstruction(DstOp); | ||
|
||
// Count both implicit and explicit defs in the dst instruction. | ||
// This avoids errors importing patterns that have inherent implicit defs. | ||
|
@@ -2070,68 +2112,24 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) { | |
|
||
// The root of the match also has constraints on the register bank so that it | ||
// matches the result instruction. | ||
unsigned OpIdx = 0; | ||
unsigned N = std::min(DstExpDefs, SrcNumDefs); | ||
for (unsigned I = 0; I < N; ++I) { | ||
const TypeSetByHwMode &VTy = Src.getExtType(I); | ||
const auto &DstIOperand = DstI.Operands[I]; | ||
|
||
const auto &DstIOperand = DstI.Operands[OpIdx]; | ||
PointerUnion<const Record *, const CodeGenRegisterClass *> MatchedRC = | ||
DstIOperand.Rec; | ||
if (DstIName == "COPY_TO_REGCLASS") { | ||
MatchedRC = getInitValueAsRegClass(Dst.getChild(1).getLeafValue()); | ||
|
||
if (MatchedRC.isNull()) | ||
return failedImport( | ||
"COPY_TO_REGCLASS operand #1 isn't a register class"); | ||
} else if (DstIName == "REG_SEQUENCE") { | ||
MatchedRC = getInitValueAsRegClass(Dst.getChild(0).getLeafValue()); | ||
if (MatchedRC.isNull()) | ||
return failedImport("REG_SEQUENCE operand #0 isn't a register class"); | ||
} else if (DstIName == "EXTRACT_SUBREG") { | ||
const CodeGenRegisterClass *InferredClass = | ||
inferRegClassFromPattern(Dst.getChild(0)); | ||
if (!InferredClass) | ||
return failedImport( | ||
"Could not infer class for EXTRACT_SUBREG operand #0"); | ||
|
||
// We can assume that a subregister is in the same bank as it's super | ||
// register. | ||
MatchedRC = InferredClass->getDef(); | ||
Comment on lines
-2098
to
-2100
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here is the difference in behavior: previously we were satisfied with the class of the operand, now we actually try to infer the class of the result. This is a bit slower, but it looks like we would have tried to infer it later anyway (and bailed out if we couldn't). |
||
} else if (DstIName == "INSERT_SUBREG") { | ||
const CodeGenRegisterClass *MaybeSuperClass = | ||
inferSuperRegisterClassForNode(VTy, Dst.getChild(0), Dst.getChild(2)); | ||
if (!MaybeSuperClass) | ||
return failedImport( | ||
"Cannot infer register class for INSERT_SUBREG operand #0"); | ||
// Move to the next pattern here, because the register class we found | ||
// doesn't necessarily have a record associated with it. So, we can't | ||
// set DstIOpRec using this. | ||
MatchedRC = MaybeSuperClass; | ||
} else if (DstIName == "SUBREG_TO_REG") { | ||
const CodeGenRegisterClass *MaybeRegClass = | ||
inferSuperRegisterClass(VTy, Dst.getChild(2)); | ||
if (!MaybeRegClass) | ||
return failedImport( | ||
"Cannot infer register class for SUBREG_TO_REG operand #0"); | ||
MatchedRC = MaybeRegClass; | ||
} else if (cast<const Record *>(MatchedRC)->isSubClassOf("RegisterOperand")) | ||
MatchedRC = cast<const Record *>(MatchedRC)->getValueAsDef("RegClass"); | ||
else if (!cast<const Record *>(MatchedRC)->isSubClassOf("RegisterClass")) | ||
return failedImport("Dst MI def isn't a register class" + to_string(Dst)); | ||
|
||
OperandMatcher &OM = InsnMatcher.getOperand(OpIdx); | ||
OperandMatcher &OM = InsnMatcher.getOperand(I); | ||
// The operand names declared in the DstI instruction are unrelated to | ||
// those used in pattern's source and destination DAGs, so mangle the | ||
// former to prevent implicitly adding unexpected | ||
// GIM_CheckIsSameOperand predicates by the defineOperand method. | ||
OM.setSymbolicName(getMangledRootDefName(DstIOperand.Name)); | ||
M.defineOperand(OM.getSymbolicName(), OM); | ||
if (auto *R = dyn_cast<const Record *>(MatchedRC)) | ||
MatchedRC = &Target.getRegisterClass(R); | ||
OM.addPredicate<RegisterBankOperandMatcher>( | ||
*cast<const CodeGenRegisterClass *>(MatchedRC)); | ||
++OpIdx; | ||
|
||
const CodeGenRegisterClass *RC = | ||
inferRegClassFromInstructionPattern(Dst, I); | ||
if (!RC) | ||
return failedImport("Could not infer register class for result #" + | ||
Twine(I) + " from pattern " + to_string(Dst)); | ||
OM.addPredicate<RegisterBankOperandMatcher>(*RC); | ||
} | ||
|
||
auto DstMIBuilderOrError = | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure why this is encoded as a class and not the bank directly
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess because TableGen cannot infer regbank itself.
There was an attempt to do this at tablegen level, but AFAIK it doesn't cover all cases and targets still need to override
getRegBankFromRegClass
in some cases.