Changeset View
Standalone View
utils/TableGen/GlobalISelEmitter.cpp
Show First 20 Lines • Show All 176 Lines • ▼ Show 20 Lines | |||||
/// Helper function to let the emitter report skip reason error messages. | /// Helper function to let the emitter report skip reason error messages. | ||||
static Error failedImport(const Twine &Reason) { | static Error failedImport(const Twine &Reason) { | ||||
return make_error<StringError>(Reason, inconvertibleErrorCode()); | return make_error<StringError>(Reason, inconvertibleErrorCode()); | ||||
} | } | ||||
static Error isTrivialOperatorNode(const TreePatternNode *N) { | static Error isTrivialOperatorNode(const TreePatternNode *N) { | ||||
std::string Explanation = ""; | std::string Explanation = ""; | ||||
std::string Separator = ""; | std::string Separator = ""; | ||||
if (N->isLeaf()) { | |||||
if (isa<IntInit>(N->getLeafValue())) | |||||
return Error::success(); | |||||
Explanation = "Is a leaf"; | |||||
Separator = ", "; | |||||
} | |||||
if (N->hasAnyPredicate()) { | if (N->hasAnyPredicate()) { | ||||
Explanation = Separator + "Has a predicate (" + explainPredicates(N) + ")"; | Explanation = Separator + "Has a predicate (" + explainPredicates(N) + ")"; | ||||
Separator = ", "; | Separator = ", "; | ||||
} | } | ||||
if (N->getTransformFn()) { | if (N->getTransformFn()) { | ||||
Explanation += Separator + "Has a transform function"; | Explanation += Separator + "Has a transform function"; | ||||
Separator = ", "; | Separator = ", "; | ||||
} | } | ||||
if (!N->isLeaf() && !N->hasAnyPredicate() && !N->getTransformFn()) | if (!N->hasAnyPredicate() && !N->getTransformFn()) | ||||
return Error::success(); | return Error::success(); | ||||
return failedImport(Explanation); | return failedImport(Explanation); | ||||
} | } | ||||
static Record *getInitValueAsRegClass(Init *V) { | static Record *getInitValueAsRegClass(Init *V) { | ||||
if (DefInit *VDefInit = dyn_cast<DefInit>(V)) { | if (DefInit *VDefInit = dyn_cast<DefInit>(V)) { | ||||
if (VDefInit->getDef()->isSubClassOf("RegisterOperand")) | if (VDefInit->getDef()->isSubClassOf("RegisterOperand")) | ||||
▲ Show 20 Lines • Show All 2,035 Lines • ▼ Show 20 Lines | Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) { | ||||
// If the root of either pattern isn't a simple operator, ignore it. | // If the root of either pattern isn't a simple operator, ignore it. | ||||
if (auto Err = isTrivialOperatorNode(Dst)) | if (auto Err = isTrivialOperatorNode(Dst)) | ||||
return failedImport("Dst pattern root isn't a trivial operator (" + | return failedImport("Dst pattern root isn't a trivial operator (" + | ||||
toString(std::move(Err)) + ")"); | toString(std::move(Err)) + ")"); | ||||
if (auto Err = isTrivialOperatorNode(Src)) | if (auto Err = isTrivialOperatorNode(Src)) | ||||
return failedImport("Src pattern root isn't a trivial operator (" + | return failedImport("Src pattern root isn't a trivial operator (" + | ||||
toString(std::move(Err)) + ")"); | toString(std::move(Err)) + ")"); | ||||
if (Dst->isLeaf()) | InstructionMatcher &InsnMatcherTemp = M.addInstructionMatcher(Src->getName()); | ||||
unsigned TempOpIdx = 0; | |||||
auto InsnMatcherOrError = | |||||
createAndImportSelDAGMatcher(InsnMatcherTemp, Src, TempOpIdx); | |||||
if (auto Error = InsnMatcherOrError.takeError()) | |||||
return std::move(Error); | |||||
InstructionMatcher &InsnMatcher = InsnMatcherOrError.get(); | |||||
if (Dst->isLeaf()) { | |||||
Record *RCDef = getInitValueAsRegClass(Dst->getLeafValue()); | |||||
const CodeGenRegisterClass &RC = Target.getRegisterClass(RCDef); | |||||
if (RCDef) { | |||||
// We need to replace the def and all it's uses with the specified | |||||
rovka: Typo: its | |||||
// operand. However, we must also insert COPY's wherever needed. | |||||
// For now, emit a copy and let the register allocator clean up. | |||||
auto &DstI = Target.getInstruction(RK.getDef("COPY")); | |||||
const auto &DstIOperand = DstI.Operands[0]; | |||||
OperandMatcher &OM0 = InsnMatcher.getOperand(0); | |||||
OM0.setSymbolicName(DstIOperand.Name); | |||||
OM0.addPredicate<RegisterBankOperandMatcher>(RC); | |||||
auto &DstMIBuilder = M.addAction<BuildMIAction>(0, &DstI, InsnMatcher); | |||||
DstMIBuilder.addRenderer<CopyRenderer>(0, InsnMatcher, DstIOperand.Name); | |||||
DstMIBuilder.addRenderer<CopyRenderer>(0, InsnMatcher, Dst->getName()); | |||||
M.addAction<ConstrainOperandToRegClassAction>(0, 0, RC); | |||||
// We're done with this pattern! It's eligible for GISel emission; return | |||||
// it. | |||||
++NumPatternImported; | |||||
return std::move(M); | |||||
} | |||||
return failedImport("Dst pattern root isn't a known leaf"); | return failedImport("Dst pattern root isn't a known leaf"); | ||||
} | |||||
// Start with the defined operands (i.e., the results of the root operator). | // Start with the defined operands (i.e., the results of the root operator). | ||||
Record *DstOp = Dst->getOperator(); | Record *DstOp = Dst->getOperator(); | ||||
if (!DstOp->isSubClassOf("Instruction")) | if (!DstOp->isSubClassOf("Instruction")) | ||||
return failedImport("Pattern operator isn't an instruction"); | return failedImport("Pattern operator isn't an instruction"); | ||||
auto &DstI = Target.getInstruction(DstOp); | auto &DstI = Target.getInstruction(DstOp); | ||||
if (DstI.Operands.NumDefs != Src->getExtTypes().size()) | if (DstI.Operands.NumDefs != Src->getExtTypes().size()) | ||||
return failedImport("Src pattern results and dst MI defs are different (" + | return failedImport("Src pattern results and dst MI defs are different (" + | ||||
to_string(Src->getExtTypes().size()) + " def(s) vs " + | to_string(Src->getExtTypes().size()) + " def(s) vs " + | ||||
to_string(DstI.Operands.NumDefs) + " def(s))"); | to_string(DstI.Operands.NumDefs) + " def(s))"); | ||||
Not Done ReplyInline ActionsWould it make sense to move these 2 checks higher up, as a quick exit? (So we don't createAndImport the Src only to discover that Dst wasn't an instruction in the first place). rovka: Would it make sense to move these 2 checks higher up, as a quick exit? (So we don't… | |||||
Not Done ReplyInline ActionsWe could do that. The only reason it comes after the matcher is to keep a boundary between the code that handles the matcher and the code that handles the renderer. The two were tangled together in the early versions of GlobalISelEmitter.cpp. dsanders: We could do that. The only reason it comes after the matcher is to keep a boundary between the… | |||||
Not Done ReplyInline ActionsI just went to do this and I don't think it can be moved up without significant changes. The Dst->getOperator() on line 2285 requires that Dst->isLeaf() is false so it must either come after the if-statement on line 2255 or be wrapped in a if (!Dst->isLeaf()) {}. If we choose to move the if-statement on line 2255 up as well then we're creating the renderer before the matcher which will break getOperand(StringRef) because the variables (defineInsnVar()) wont be defined at that point. If we chose to wrap it in an if (!Dst->isLeaf()) and move it past line 2255's if-statement then we have a use-beyond-scope issue to fix and fixing that requires allowing DstOp to be null and rewriting DstI to be a (possibly-null) pointer which will impact the createAndImportInstructionRenderer() function and those it calls. dsanders: I just went to do this and I don't think it can be moved up without significant changes. The… | |||||
Not Done ReplyInline ActionsOk, it's fine as it is then. rovka: Ok, it's fine as it is then. | |||||
InstructionMatcher &InsnMatcherTemp = M.addInstructionMatcher(Src->getName()); | |||||
unsigned TempOpIdx = 0; | |||||
auto InsnMatcherOrError = | |||||
createAndImportSelDAGMatcher(InsnMatcherTemp, Src, TempOpIdx); | |||||
if (auto Error = InsnMatcherOrError.takeError()) | |||||
return std::move(Error); | |||||
InstructionMatcher &InsnMatcher = InsnMatcherOrError.get(); | |||||
// The root of the match also has constraints on the register bank so that it | // The root of the match also has constraints on the register bank so that it | ||||
// matches the result instruction. | // matches the result instruction. | ||||
unsigned OpIdx = 0; | unsigned OpIdx = 0; | ||||
for (const EEVT::TypeSet &Ty : Src->getExtTypes()) { | for (const EEVT::TypeSet &Ty : Src->getExtTypes()) { | ||||
(void)Ty; | (void)Ty; | ||||
const auto &DstIOperand = DstI.Operands[OpIdx]; | const auto &DstIOperand = DstI.Operands[OpIdx]; | ||||
Record *DstIOpRec = DstIOperand.Rec; | Record *DstIOpRec = DstIOperand.Rec; | ||||
▲ Show 20 Lines • Show All 212 Lines • ▼ Show 20 Lines | SubtargetFeatureInfo::emitComputeAvailableFeatures( | ||||
Target.getName(), "InstructionSelector", | Target.getName(), "InstructionSelector", | ||||
"computeAvailableFunctionFeatures", FunctionFeatures, OS, | "computeAvailableFunctionFeatures", FunctionFeatures, OS, | ||||
"const MachineFunction *MF"); | "const MachineFunction *MF"); | ||||
// Emit a table containing the LLT objects needed by the matcher and an enum | // Emit a table containing the LLT objects needed by the matcher and an enum | ||||
// for the matcher to reference them with. | // for the matcher to reference them with. | ||||
std::vector<LLTCodeGen> TypeObjects = { | std::vector<LLTCodeGen> TypeObjects = { | ||||
LLT::scalar(8), LLT::scalar(16), LLT::scalar(32), | LLT::scalar(8), LLT::scalar(16), LLT::scalar(32), | ||||
LLT::scalar(64), LLT::scalar(80), LLT::vector(8, 1), | LLT::scalar(64), LLT::scalar(80), LLT::scalar(128), | ||||
LLT::vector(16, 1), LLT::vector(32, 1), LLT::vector(64, 1), | LLT::vector(8, 1), LLT::vector(16, 1), LLT::vector(32, 1), | ||||
LLT::vector(8, 8), LLT::vector(16, 8), LLT::vector(32, 8), | LLT::vector(64, 1), LLT::vector(8, 8), LLT::vector(16, 8), | ||||
LLT::vector(64, 8), LLT::vector(4, 16), LLT::vector(8, 16), | LLT::vector(32, 8), LLT::vector(64, 8), LLT::vector(4, 16), | ||||
LLT::vector(16, 16), LLT::vector(32, 16), LLT::vector(2, 32), | LLT::vector(8, 16), LLT::vector(16, 16), LLT::vector(32, 16), | ||||
LLT::vector(4, 32), LLT::vector(8, 32), LLT::vector(16, 32), | LLT::vector(2, 32), LLT::vector(4, 32), LLT::vector(8, 32), | ||||
LLT::vector(2, 64), LLT::vector(4, 64), LLT::vector(8, 64), | LLT::vector(16, 32), LLT::vector(2, 64), LLT::vector(4, 64), | ||||
LLT::vector(8, 64), | |||||
}; | }; | ||||
std::sort(TypeObjects.begin(), TypeObjects.end()); | std::sort(TypeObjects.begin(), TypeObjects.end()); | ||||
OS << "enum {\n"; | OS << "enum {\n"; | ||||
for (const auto &TypeObject : TypeObjects) { | for (const auto &TypeObject : TypeObjects) { | ||||
OS << " "; | OS << " "; | ||||
TypeObject.emitCxxEnumValue(OS); | TypeObject.emitCxxEnumValue(OS); | ||||
OS << ",\n"; | OS << ",\n"; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 129 Lines • Show Last 20 Lines |
Typo: its