summaryrefslogtreecommitdiff
path: root/llvm/utils/TableGen/GlobalISelEmitter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/utils/TableGen/GlobalISelEmitter.cpp')
-rw-r--r--llvm/utils/TableGen/GlobalISelEmitter.cpp184
1 files changed, 144 insertions, 40 deletions
diff --git a/llvm/utils/TableGen/GlobalISelEmitter.cpp b/llvm/utils/TableGen/GlobalISelEmitter.cpp
index d8d4c9f4f55cf..c14294951cc11 100644
--- a/llvm/utils/TableGen/GlobalISelEmitter.cpp
+++ b/llvm/utils/TableGen/GlobalISelEmitter.cpp
@@ -609,7 +609,7 @@ MatchTableRecord MatchTable::LineBreak = {
void MatchTableRecord::emit(raw_ostream &OS, bool LineBreakIsNextAfterThis,
const MatchTable &Table) const {
bool UseLineComment =
- LineBreakIsNextAfterThis | (Flags & MTRF_LineBreakFollows);
+ LineBreakIsNextAfterThis || (Flags & MTRF_LineBreakFollows);
if (Flags & (MTRF_JumpTarget | MTRF_CommaFollows))
UseLineComment = false;
@@ -620,7 +620,7 @@ void MatchTableRecord::emit(raw_ostream &OS, bool LineBreakIsNextAfterThis,
if (Flags & MTRF_Label)
OS << ": @" << Table.getLabelIndex(LabelID);
- if (Flags & MTRF_Comment && !UseLineComment)
+ if ((Flags & MTRF_Comment) && !UseLineComment)
OS << "*/";
if (Flags & MTRF_JumpTarget) {
@@ -1181,7 +1181,7 @@ public:
TypeIDValues.clear();
unsigned ID = 0;
- for (const LLTCodeGen LLTy : KnownTypes)
+ for (const LLTCodeGen &LLTy : KnownTypes)
TypeIDValues[LLTy] = ID++;
}
@@ -1707,7 +1707,7 @@ public:
}
StringRef getOpcode() const { return I->TheDef->getName(); }
- unsigned getNumOperands() const { return I->Operands.size(); }
+ bool isVariadicNumOperands() const { return I->Operands.isVariadic; }
StringRef getOperandType(unsigned OpIdx) const {
return I->Operands[OpIdx].OperandType;
@@ -2153,7 +2153,7 @@ public:
return false;
}
- for (const auto &Operand : zip(Operands, B.Operands)) {
+ for (auto Operand : zip(Operands, B.Operands)) {
if (std::get<0>(Operand)->isHigherPriorityThan(*std::get<1>(Operand)))
return true;
if (std::get<1>(Operand)->isHigherPriorityThan(*std::get<0>(Operand)))
@@ -2273,7 +2273,7 @@ void InstructionMatcher::optimize() {
Stash.push_back(predicates_pop_front());
if (Stash.back().get() == &OpcMatcher) {
- if (NumOperandsCheck && OpcMatcher.getNumOperands() < getNumOperands())
+ if (NumOperandsCheck && OpcMatcher.isVariadicNumOperands())
Stash.emplace_back(
new InstructionNumOperandsMatcher(InsnVarID, getNumOperands()));
NumOperandsCheck = false;
@@ -2318,7 +2318,8 @@ public:
OR_Register,
OR_TempRegister,
OR_ComplexPattern,
- OR_Custom
+ OR_Custom,
+ OR_CustomOperand
};
protected:
@@ -2726,6 +2727,38 @@ public:
}
};
+class CustomOperandRenderer : public OperandRenderer {
+protected:
+ unsigned InsnID;
+ const Record &Renderer;
+ /// The name of the operand.
+ const std::string SymbolicName;
+
+public:
+ CustomOperandRenderer(unsigned InsnID, const Record &Renderer,
+ StringRef SymbolicName)
+ : OperandRenderer(OR_CustomOperand), InsnID(InsnID), Renderer(Renderer),
+ SymbolicName(SymbolicName) {}
+
+ static bool classof(const OperandRenderer *R) {
+ return R->getKind() == OR_CustomOperand;
+ }
+
+ void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override {
+ const OperandMatcher &OpdMatcher = Rule.getOperandMatcher(SymbolicName);
+ Table << MatchTable::Opcode("GIR_CustomOperandRenderer")
+ << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID)
+ << MatchTable::Comment("OldInsnID")
+ << MatchTable::IntValue(OpdMatcher.getInsnVarID())
+ << MatchTable::Comment("OpIdx")
+ << MatchTable::IntValue(OpdMatcher.getOpIdx())
+ << MatchTable::Comment("OperandRenderer")
+ << MatchTable::NamedValue(
+ "GICR_" + Renderer.getValueAsString("RendererFn").str())
+ << MatchTable::Comment(SymbolicName) << MatchTable::LineBreak;
+ }
+};
+
/// An action taken when all Matcher predicates succeeded for a parent rule.
///
/// Typical actions include:
@@ -3159,7 +3192,7 @@ bool RuleMatcher::isHigherPriorityThan(const RuleMatcher &B) const {
if (Matchers.size() < B.Matchers.size())
return false;
- for (const auto &Matcher : zip(Matchers, B.Matchers)) {
+ for (auto Matcher : zip(Matchers, B.Matchers)) {
if (std::get<0>(Matcher)->isHigherPriorityThan(*std::get<1>(Matcher)))
return true;
if (std::get<1>(Matcher)->isHigherPriorityThan(*std::get<0>(Matcher)))
@@ -3281,8 +3314,8 @@ private:
unsigned &TempOpIdx) const;
Error importChildMatcher(RuleMatcher &Rule, InstructionMatcher &InsnMatcher,
const TreePatternNode *SrcChild,
- bool OperandIsAPointer, unsigned OpIdx,
- unsigned &TempOpIdx);
+ bool OperandIsAPointer, bool OperandIsImmArg,
+ unsigned OpIdx, unsigned &TempOpIdx);
Expected<BuildMIAction &> createAndImportInstructionRenderer(
RuleMatcher &M, InstructionMatcher &InsnMatcher,
@@ -3722,9 +3755,19 @@ Expected<InstructionMatcher &> GlobalISelEmitter::createAndImportSelDAGMatcher(
for (unsigned i = 0; i != NumChildren; ++i) {
TreePatternNode *SrcChild = Src->getChild(i);
+ // We need to determine the meaning of a literal integer based on the
+ // context. If this is a field required to be an immediate (such as an
+ // immarg intrinsic argument), the required predicates are different than
+ // a constant which may be materialized in a register. If we have an
+ // argument that is required to be an immediate, we should not emit an LLT
+ // type check, and should not be looking for a G_CONSTANT defined
+ // register.
+ bool OperandIsImmArg = SrcGIOrNull->isOperandImmArg(i);
+
// SelectionDAG allows pointers to be represented with iN since it doesn't
// distinguish between pointers and integers but they are different types in GlobalISel.
// Coerce integers to pointers to address space 0 if the context indicates a pointer.
+ //
bool OperandIsAPointer = SrcGIOrNull->isOperandAPointer(i);
if (IsIntrinsic) {
@@ -3737,16 +3780,17 @@ Expected<InstructionMatcher &> GlobalISelEmitter::createAndImportSelDAGMatcher(
continue;
}
- // We have to check intrinsics for llvm_anyptr_ty parameters.
+ // We have to check intrinsics for llvm_anyptr_ty and immarg parameters.
//
// Note that we have to look at the i-1th parameter, because we don't
// have the intrinsic ID in the intrinsic's parameter list.
OperandIsAPointer |= II->isParamAPointer(i - 1);
+ OperandIsImmArg |= II->isParamImmArg(i - 1);
}
if (auto Error =
importChildMatcher(Rule, InsnMatcher, SrcChild, OperandIsAPointer,
- OpIdx++, TempOpIdx))
+ OperandIsImmArg, OpIdx++, TempOpIdx))
return std::move(Error);
}
}
@@ -3784,12 +3828,10 @@ static StringRef getSrcChildName(const TreePatternNode *SrcChild,
return SrcChildName;
}
-Error GlobalISelEmitter::importChildMatcher(RuleMatcher &Rule,
- InstructionMatcher &InsnMatcher,
- const TreePatternNode *SrcChild,
- bool OperandIsAPointer,
- unsigned OpIdx,
- unsigned &TempOpIdx) {
+Error GlobalISelEmitter::importChildMatcher(
+ RuleMatcher &Rule, InstructionMatcher &InsnMatcher,
+ const TreePatternNode *SrcChild, bool OperandIsAPointer,
+ bool OperandIsImmArg, unsigned OpIdx, unsigned &TempOpIdx) {
Record *PhysReg = nullptr;
StringRef SrcChildName = getSrcChildName(SrcChild, PhysReg);
@@ -3819,10 +3861,14 @@ Error GlobalISelEmitter::importChildMatcher(RuleMatcher &Rule,
}
}
- if (auto Error =
- OM.addTypeCheckPredicate(ChildTypes.front(), OperandIsAPointer))
- return failedImport(toString(std::move(Error)) + " for Src operand (" +
- to_string(*SrcChild) + ")");
+ // Immediate arguments have no meaningful type to check as they don't have
+ // registers.
+ if (!OperandIsImmArg) {
+ if (auto Error =
+ OM.addTypeCheckPredicate(ChildTypes.front(), OperandIsAPointer))
+ return failedImport(toString(std::move(Error)) + " for Src operand (" +
+ to_string(*SrcChild) + ")");
+ }
// Check for nested instructions.
if (!SrcChild->isLeaf()) {
@@ -3873,7 +3919,13 @@ Error GlobalISelEmitter::importChildMatcher(RuleMatcher &Rule,
// Check for constant immediates.
if (auto *ChildInt = dyn_cast<IntInit>(SrcChild->getLeafValue())) {
- OM.addPredicate<ConstantIntOperandMatcher>(ChildInt->getValue());
+ if (OperandIsImmArg) {
+ // Checks for argument directly in operand list
+ OM.addPredicate<LiteralIntOperandMatcher>(ChildInt->getValue());
+ } else {
+ // Checks for materialized constant
+ OM.addPredicate<ConstantIntOperandMatcher>(ChildInt->getValue());
+ }
return Error::success();
}
@@ -3939,12 +3991,22 @@ Expected<action_iterator> GlobalISelEmitter::importExplicitUseRenderer(
}
if (!DstChild->isLeaf()) {
-
if (DstChild->getOperator()->isSubClassOf("SDNodeXForm")) {
auto Child = DstChild->getChild(0);
auto I = SDNodeXFormEquivs.find(DstChild->getOperator());
if (I != SDNodeXFormEquivs.end()) {
- DstMIBuilder.addRenderer<CustomRenderer>(*I->second, Child->getName());
+ Record *XFormOpc = DstChild->getOperator()->getValueAsDef("Opcode");
+ if (XFormOpc->getName() == "timm") {
+ // If this is a TargetConstant, there won't be a corresponding
+ // instruction to transform. Instead, this will refer directly to an
+ // operand in an instruction's operand list.
+ DstMIBuilder.addRenderer<CustomOperandRenderer>(*I->second,
+ Child->getName());
+ } else {
+ DstMIBuilder.addRenderer<CustomRenderer>(*I->second,
+ Child->getName());
+ }
+
return InsertPt;
}
return failedImport("SDNodeXForm " + Child->getName() +
@@ -4309,18 +4371,48 @@ Expected<action_iterator> GlobalISelEmitter::importExplicitUseRenderers(
ExpectedDstINumUses--;
}
+ // NumResults - This is the number of results produced by the instruction in
+ // the "outs" list.
+ unsigned NumResults = OrigDstI->Operands.NumDefs;
+
+ // Number of operands we know the output instruction must have. If it is
+ // variadic, we could have more operands.
+ unsigned NumFixedOperands = DstI->Operands.size();
+
+ // Loop over all of the fixed operands of the instruction pattern, emitting
+ // code to fill them all in. The node 'N' usually has number children equal to
+ // the number of input operands of the instruction. However, in cases where
+ // there are predicate operands for an instruction, we need to fill in the
+ // 'execute always' values. Match up the node operands to the instruction
+ // operands to do this.
unsigned Child = 0;
+
+ // Similarly to the code in TreePatternNode::ApplyTypeConstraints, count the
+ // number of operands at the end of the list which have default values.
+ // Those can come from the pattern if it provides enough arguments, or be
+ // filled in with the default if the pattern hasn't provided them. But any
+ // operand with a default value _before_ the last mandatory one will be
+ // filled in with their defaults unconditionally.
+ unsigned NonOverridableOperands = NumFixedOperands;
+ while (NonOverridableOperands > NumResults &&
+ CGP.operandHasDefault(DstI->Operands[NonOverridableOperands - 1].Rec))
+ --NonOverridableOperands;
+
unsigned NumDefaultOps = 0;
for (unsigned I = 0; I != DstINumUses; ++I) {
- const CGIOperandList::OperandInfo &DstIOperand =
- DstI->Operands[DstI->Operands.NumDefs + I];
+ unsigned InstOpNo = DstI->Operands.NumDefs + I;
+
+ // Determine what to emit for this operand.
+ Record *OperandNode = DstI->Operands[InstOpNo].Rec;
// If the operand has default values, introduce them now.
- // FIXME: Until we have a decent test case that dictates we should do
- // otherwise, we're going to assume that operands with default values cannot
- // be specified in the patterns. Therefore, adding them will not cause us to
- // end up with too many rendered operands.
- if (DstIOperand.Rec->isSubClassOf("OperandWithDefaultOps")) {
+ if (CGP.operandHasDefault(OperandNode) &&
+ (InstOpNo < NonOverridableOperands || Child >= Dst->getNumChildren())) {
+ // This is a predicate or optional def operand which the pattern has not
+ // overridden, or which we aren't letting it override; emit the 'default
+ // ops' operands.
+
+ const CGIOperandList::OperandInfo &DstIOperand = DstI->Operands[InstOpNo];
DagInit *DefaultOps = DstIOperand.Rec->getValueAsDag("DefaultOps");
if (auto Error = importDefaultOperandRenderers(
InsertPt, M, DstMIBuilder, DefaultOps))
@@ -5082,7 +5174,7 @@ void GlobalISelEmitter::run(raw_ostream &OS) {
<< " typedef void(" << Target.getName()
<< "InstructionSelector::*CustomRendererFn)(MachineInstrBuilder &, const "
- "MachineInstr&) "
+ "MachineInstr&, int) "
"const;\n"
<< " const ISelInfoTy<PredicateBitset, ComplexMatcherMemFn, "
"CustomRendererFn> "
@@ -5127,8 +5219,23 @@ void GlobalISelEmitter::run(raw_ostream &OS) {
});
SubtargetFeatureInfo::emitComputeAvailableFeatures(
- Target.getName(), "InstructionSelector", "computeAvailableModuleFeatures",
+ Target.getName(), "InstructionSelector", "computeAvailableModuleFeatures",
ModuleFeatures, OS);
+
+
+ OS << "void " << Target.getName() << "InstructionSelector"
+ "::setupGeneratedPerFunctionState(MachineFunction &MF) {\n"
+ " AvailableFunctionFeatures = computeAvailableFunctionFeatures("
+ "(const " << Target.getName() << "Subtarget*)&MF.getSubtarget(), &MF);\n"
+ "}\n";
+
+ if (Target.getName() == "X86" || Target.getName() == "AArch64") {
+ // TODO: Implement PGSO.
+ OS << "static bool shouldOptForSize(const MachineFunction *MF) {\n";
+ OS << " return MF->getFunction().hasOptSize();\n";
+ OS << "}\n\n";
+ }
+
SubtargetFeatureInfo::emitComputeAvailableFeatures(
Target.getName(), "InstructionSelector",
"computeAvailableFunctionFeatures", FunctionFeatures, OS,
@@ -5168,7 +5275,7 @@ void GlobalISelEmitter::run(raw_ostream &OS) {
return true;
if (A.size() > B.size())
return false;
- for (const auto &Pair : zip(A, B)) {
+ for (auto Pair : zip(A, B)) {
if (std::get<0>(Pair)->getName() < std::get<1>(Pair)->getName())
return true;
if (std::get<0>(Pair)->getName() > std::get<1>(Pair)->getName())
@@ -5245,7 +5352,7 @@ void GlobalISelEmitter::run(raw_ostream &OS) {
OS << Target.getName() << "InstructionSelector::CustomRendererFn\n"
<< Target.getName() << "InstructionSelector::CustomRenderers[] = {\n"
- << " nullptr, // GICP_Invalid\n";
+ << " nullptr, // GICR_Invalid\n";
for (const auto &Record : CustomRendererFns)
OS << " &" << Target.getName()
<< "InstructionSelector::" << Record->getValueAsString("RendererFn")
@@ -5273,10 +5380,6 @@ void GlobalISelEmitter::run(raw_ostream &OS) {
"&CoverageInfo) const {\n"
<< " MachineFunction &MF = *I.getParent()->getParent();\n"
<< " MachineRegisterInfo &MRI = MF.getRegInfo();\n"
- << " // FIXME: This should be computed on a per-function basis rather "
- "than per-insn.\n"
- << " AvailableFunctionFeatures = computeAvailableFunctionFeatures(&STI, "
- "&MF);\n"
<< " const PredicateBitset AvailableFeatures = getAvailableFeatures();\n"
<< " NewMIVector OutMIs;\n"
<< " State.MIs.clear();\n"
@@ -5312,6 +5415,7 @@ void GlobalISelEmitter::run(raw_ostream &OS) {
<< "computeAvailableFunctionFeatures(const " << Target.getName()
<< "Subtarget *Subtarget,\n"
<< " const MachineFunction *MF) const;\n"
+ << "void setupGeneratedPerFunctionState(MachineFunction &MF) override;\n"
<< "#endif // ifdef GET_GLOBALISEL_PREDICATES_DECL\n";
OS << "#ifdef GET_GLOBALISEL_PREDICATES_INIT\n"