summaryrefslogtreecommitdiffstats
path: root/llvm/utils/TableGen/GlobalISelEmitter.cpp
diff options
context:
space:
mode:
authorDaniel Sanders <daniel_l_sanders@apple.com>2018-05-05 20:53:24 +0000
committerDaniel Sanders <daniel_l_sanders@apple.com>2018-05-05 20:53:24 +0000
commitf84bc3793e9d1ba170a35b1909dd1057b63c2f15 (patch)
tree2aa1ef2b1c80f09f5774668e8e3bba8102aac24d /llvm/utils/TableGen/GlobalISelEmitter.cpp
parentc86da6bcfe16e9334e492c6fa774e028e3f1123a (diff)
downloadbcm5719-llvm-f84bc3793e9d1ba170a35b1909dd1057b63c2f15.tar.gz
bcm5719-llvm-f84bc3793e9d1ba170a35b1909dd1057b63c2f15.zip
[globalisel] Update GlobalISel emitter to match new representation of extending loads
Summary: Previously, a extending load was represented at (G_*EXT (G_LOAD x)). This had a few drawbacks: * G_LOAD had to be legal for all sizes you could extend from, even if registers didn't naturally hold those sizes. * All sizes you could extend from had to be allocatable just in case the extend went missing (e.g. by optimization). * At minimum, G_*EXT and G_TRUNC had to be legal for these sizes. As we improve optimization of extends and truncates, this legality requirement would spread without considerable care w.r.t when certain combines were permitted. * The SelectionDAG importer required some ugly and fragile pattern rewriting to translate patterns into this style. This patch changes the representation to: * (G_[SZ]EXTLOAD x) * (G_LOAD x) any-extends when MMO.getSize() * 8 < ResultTy.getSizeInBits() which resolves these issues by allowing targets to work entirely in their native register sizes, and by having a more direct translation from SelectionDAG patterns. Each extending load can be lowered by the legalizer into separate extends and loads, however a target that supports s1 will need the any-extending load to extend to at least s8 since LLVM does not represent memory accesses smaller than 8 bit. The legalizer can widenScalar G_LOAD into an any-extending load but sign/zero-extending loads need help from something else like a combiner pass. A follow-up patch that adds combiner helpers for for this will follow. The new representation requires that the MMO correctly reflect the memory access so this has been corrected in a couple tests. I've also moved the extending loads to their own tests since they are (mostly) separate opcodes now. Additionally, the re-write appears to have invalidated two tests from select-with-no-legality-check.mir since the matcher table no longer contains loads that result in s1's and they aren't legal in AArch64 anymore. Depends on D45540 Reviewers: ab, aditya_nandakumar, bogner, rtereshin, volkan, rovka, javed.absar Reviewed By: rtereshin Subscribers: javed.absar, llvm-commits, kristof.beyls Differential Revision: https://reviews.llvm.org/D45541 llvm-svn: 331601
Diffstat (limited to 'llvm/utils/TableGen/GlobalISelEmitter.cpp')
-rw-r--r--llvm/utils/TableGen/GlobalISelEmitter.cpp224
1 files changed, 133 insertions, 91 deletions
diff --git a/llvm/utils/TableGen/GlobalISelEmitter.cpp b/llvm/utils/TableGen/GlobalISelEmitter.cpp
index 3ecacd24cf0..40c8fa94f44 100644
--- a/llvm/utils/TableGen/GlobalISelEmitter.cpp
+++ b/llvm/utils/TableGen/GlobalISelEmitter.cpp
@@ -176,6 +176,9 @@ public:
bool operator==(const LLTCodeGen &B) const { return Ty == B.Ty; }
};
+// Track all types that are used so we can emit the corresponding enum.
+std::set<LLTCodeGen> KnownTypes;
+
class InstructionMatcher;
/// Convert an MVT to an equivalent LLT if possible, or the invalid LLT() for
/// MVTs that don't map cleanly to an LLT (e.g., iPTR, *any, ...).
@@ -285,12 +288,16 @@ static Error isTrivialOperatorNode(const TreePatternNode *N) {
if (Predicate.isImmediatePattern())
continue;
- if (Predicate.isNonExtLoad())
+ if (Predicate.isNonExtLoad() || Predicate.isAnyExtLoad() ||
+ Predicate.isSignExtLoad() || Predicate.isZeroExtLoad())
continue;
if (Predicate.isNonTruncStore())
continue;
+ if (Predicate.isLoad() && Predicate.getMemoryVT())
+ continue;
+
if (Predicate.isLoad() || Predicate.isStore()) {
if (Predicate.isUnindexed())
continue;
@@ -863,6 +870,8 @@ public:
IPM_Opcode,
IPM_ImmPredicate,
IPM_AtomicOrderingMMO,
+ IPM_MemoryLLTSize,
+ IPM_MemoryVsLLTSize,
OPM_SameOperand,
OPM_ComplexPattern,
OPM_IntrinsicID,
@@ -964,8 +973,6 @@ protected:
LLTCodeGen Ty;
public:
- static std::set<LLTCodeGen> KnownTypes;
-
LLTOperandMatcher(unsigned InsnVarID, unsigned OpIdx, const LLTCodeGen &Ty)
: OperandPredicateMatcher(OPM_LLT, InsnVarID, OpIdx), Ty(Ty) {
KnownTypes.insert(Ty);
@@ -989,8 +996,6 @@ public:
}
};
-std::set<LLTCodeGen> LLTOperandMatcher::KnownTypes;
-
/// Generates code to check that an operand is a pointer to any address space.
///
/// In SelectionDAG, the types did not describe pointers or address spaces. As a
@@ -1518,6 +1523,82 @@ public:
}
};
+/// Generates code to check that the size of an MMO is exactly N bytes.
+class MemorySizePredicateMatcher : public InstructionPredicateMatcher {
+protected:
+ unsigned MMOIdx;
+ uint64_t Size;
+
+public:
+ MemorySizePredicateMatcher(unsigned InsnVarID, unsigned MMOIdx, unsigned Size)
+ : InstructionPredicateMatcher(IPM_MemoryLLTSize, InsnVarID),
+ MMOIdx(MMOIdx), Size(Size) {}
+
+ static bool classof(const PredicateMatcher *P) {
+ return P->getKind() == IPM_MemoryLLTSize;
+ }
+ bool isIdentical(const PredicateMatcher &B) const override {
+ return InstructionPredicateMatcher::isIdentical(B) &&
+ MMOIdx == cast<MemorySizePredicateMatcher>(&B)->MMOIdx &&
+ Size == cast<MemorySizePredicateMatcher>(&B)->Size;
+ }
+
+ void emitPredicateOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const override {
+ Table << MatchTable::Opcode("GIM_CheckMemorySizeEqualTo")
+ << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
+ << MatchTable::Comment("MMO") << MatchTable::IntValue(MMOIdx)
+ << MatchTable::Comment("Size") << MatchTable::IntValue(Size)
+ << MatchTable::LineBreak;
+ }
+};
+
+/// Generates code to check that the size of an MMO is less-than, equal-to, or
+/// greater than a given LLT.
+class MemoryVsLLTSizePredicateMatcher : public InstructionPredicateMatcher {
+public:
+ enum RelationKind {
+ GreaterThan,
+ EqualTo,
+ LessThan,
+ };
+
+protected:
+ unsigned MMOIdx;
+ RelationKind Relation;
+ unsigned OpIdx;
+
+public:
+ MemoryVsLLTSizePredicateMatcher(unsigned InsnVarID, unsigned MMOIdx,
+ enum RelationKind Relation,
+ unsigned OpIdx)
+ : InstructionPredicateMatcher(IPM_MemoryVsLLTSize, InsnVarID),
+ MMOIdx(MMOIdx), Relation(Relation), OpIdx(OpIdx) {}
+
+ static bool classof(const PredicateMatcher *P) {
+ return P->getKind() == IPM_MemoryVsLLTSize;
+ }
+ bool isIdentical(const PredicateMatcher &B) const override {
+ return InstructionPredicateMatcher::isIdentical(B) &&
+ MMOIdx == cast<MemoryVsLLTSizePredicateMatcher>(&B)->MMOIdx &&
+ Relation == cast<MemoryVsLLTSizePredicateMatcher>(&B)->Relation &&
+ OpIdx == cast<MemoryVsLLTSizePredicateMatcher>(&B)->OpIdx;
+ }
+
+ void emitPredicateOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const override {
+ Table << MatchTable::Opcode(Relation == EqualTo
+ ? "GIM_CheckMemorySizeEqualToLLT"
+ : Relation == GreaterThan
+ ? "GIM_CheckMemorySizeGreaterThanLLT"
+ : "GIM_CheckMemorySizeLessThanLLT")
+ << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
+ << MatchTable::Comment("MMO") << MatchTable::IntValue(MMOIdx)
+ << MatchTable::Comment("OpIdx") << MatchTable::IntValue(OpIdx)
+ << MatchTable::LineBreak;
+ }
+};
+
/// Generates code to check that a set of predicates and operands match for a
/// particular instruction.
///
@@ -2621,6 +2702,8 @@ private:
void gatherNodeEquivs();
Record *findNodeEquiv(Record *N) const;
+ const CodeGenInstruction *getEquivNode(Record &Equiv,
+ const TreePatternNode *N) const;
Error importRulePredicates(RuleMatcher &M, ArrayRef<Predicate> Predicates);
Expected<InstructionMatcher &> createAndImportSelDAGMatcher(
@@ -2667,9 +2750,6 @@ private:
void declareSubtargetFeature(Record *Predicate);
- TreePatternNode *fixupPatternNode(TreePatternNode *N);
- void fixupPatternTrees(TreePattern *P);
-
/// Takes a sequence of \p Rules and group them based on the predicates
/// they share. \p StorageGroupMatcher is used as a memory container
/// for the group that are created as part of this process.
@@ -2734,9 +2814,22 @@ Record *GlobalISelEmitter::findNodeEquiv(Record *N) const {
return NodeEquivs.lookup(N);
}
+const CodeGenInstruction *
+GlobalISelEmitter::getEquivNode(Record &Equiv, const TreePatternNode *N) const {
+ for (const auto &Predicate : N->getPredicateFns()) {
+ if (!Equiv.isValueUnset("IfSignExtend") && Predicate.isLoad() &&
+ Predicate.isSignExtLoad())
+ return &Target.getInstruction(Equiv.getValueAsDef("IfSignExtend"));
+ if (!Equiv.isValueUnset("IfZeroExtend") && Predicate.isLoad() &&
+ Predicate.isZeroExtLoad())
+ return &Target.getInstruction(Equiv.getValueAsDef("IfZeroExtend"));
+ }
+ return &Target.getInstruction(Equiv.getValueAsDef("I"));
+}
+
GlobalISelEmitter::GlobalISelEmitter(RecordKeeper &RK)
- : RK(RK), CGP(RK, [&](TreePattern *P) { fixupPatternTrees(P); }),
- Target(CGP.getTargetInfo()), CGRegs(RK, Target.getHwModes()) {}
+ : RK(RK), CGP(RK), Target(CGP.getTargetInfo()),
+ CGRegs(RK, Target.getHwModes()) {}
//===- Emitter ------------------------------------------------------------===//
@@ -2776,7 +2869,7 @@ Expected<InstructionMatcher &> GlobalISelEmitter::createAndImportSelDAGMatcher(
if (!SrcGIEquivOrNull)
return failedImport("Pattern operator lacks an equivalent Instruction" +
explainOperator(Src->getOperator()));
- SrcGIOrNull = &Target.getInstruction(SrcGIEquivOrNull->getValueAsDef("I"));
+ SrcGIOrNull = getEquivNode(*SrcGIEquivOrNull, Src);
// The operators look good: match the opcode
InsnMatcher.addPredicate<InstructionOpcodeMatcher>(SrcGIOrNull);
@@ -2801,8 +2894,26 @@ Expected<InstructionMatcher &> GlobalISelEmitter::createAndImportSelDAGMatcher(
continue;
}
- // No check required. G_LOAD by itself is a non-extending load.
- if (Predicate.isNonExtLoad())
+ // G_LOAD is used for both non-extending and any-extending loads.
+ if (Predicate.isLoad() && Predicate.isNonExtLoad()) {
+ InsnMatcher.addPredicate<MemoryVsLLTSizePredicateMatcher>(
+ 0, MemoryVsLLTSizePredicateMatcher::EqualTo, 0);
+ continue;
+ }
+ if (Predicate.isLoad() && Predicate.isAnyExtLoad()) {
+ InsnMatcher.addPredicate<MemoryVsLLTSizePredicateMatcher>(
+ 0, MemoryVsLLTSizePredicateMatcher::LessThan, 0);
+ continue;
+ }
+
+ // No check required. We already did it by swapping the opcode.
+ if (!SrcGIEquivOrNull->isValueUnset("IfSignExtend") &&
+ Predicate.isSignExtLoad())
+ continue;
+
+ // No check required. We already did it by swapping the opcode.
+ if (!SrcGIEquivOrNull->isValueUnset("IfZeroExtend") &&
+ Predicate.isZeroExtLoad())
continue;
// No check required. G_STORE by itself is a non-extending store.
@@ -2817,8 +2928,13 @@ Expected<InstructionMatcher &> GlobalISelEmitter::createAndImportSelDAGMatcher(
if (!MemTyOrNone)
return failedImport("MemVT could not be converted to LLT");
- OperandMatcher &OM = InsnMatcher.getOperand(0);
- OM.addPredicate<LLTOperandMatcher>(MemTyOrNone.getValue());
+ // MMO's work in bytes so we must take care of unusual types like i1
+ // don't round down.
+ unsigned MemSizeInBits =
+ llvm::alignTo(MemTyOrNone->get().getSizeInBits(), 8);
+
+ InsnMatcher.addPredicate<MemorySizePredicateMatcher>(
+ 0, MemSizeInBits / 8);
continue;
}
}
@@ -3406,6 +3522,7 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
M.addAction<DebugCommentAction>(llvm::to_string(*P.getSrcPattern()) +
" => " +
llvm::to_string(*P.getDstPattern()));
+ M.addAction<DebugCommentAction>("Rule ID " + llvm::to_string(M.getRuleID()));
if (auto Error = importRulePredicates(M, P.getPredicates()))
return std::move(Error);
@@ -3846,7 +3963,7 @@ void GlobalISelEmitter::run(raw_ostream &OS) {
// Emit a table containing the LLT objects needed by the matcher and an enum
// for the matcher to reference them with.
std::vector<LLTCodeGen> TypeObjects;
- for (const auto &Ty : LLTOperandMatcher::KnownTypes)
+ for (const auto &Ty : KnownTypes)
TypeObjects.push_back(Ty);
llvm::sort(TypeObjects.begin(), TypeObjects.end());
OS << "// LLT Objects.\n"
@@ -4035,81 +4152,6 @@ void GlobalISelEmitter::declareSubtargetFeature(Record *Predicate) {
Predicate, SubtargetFeatureInfo(Predicate, SubtargetFeatures.size()));
}
-TreePatternNode *GlobalISelEmitter::fixupPatternNode(TreePatternNode *N) {
- if (!N->isLeaf()) {
- for (unsigned I = 0, E = N->getNumChildren(); I < E; ++I) {
- TreePatternNode *OrigChild = N->getChild(I);
- TreePatternNode *NewChild = fixupPatternNode(OrigChild);
- if (OrigChild != NewChild)
- N->setChild(I, NewChild);
- }
-
- if (N->getOperator()->getName() == "ld") {
- // If it's a signext-load we need to adapt the pattern slightly. We need
- // to split the node into (sext (ld ...)), remove the <<signext>> predicate,
- // and then apply the <<signextTY>> predicate by updating the result type
- // of the load.
- //
- // For example:
- // (ld:[i32] [iPTR])<<unindexed>><<signext>><<signexti16>>
- // must be transformed into:
- // (sext:[i32] (ld:[i16] [iPTR])<<unindexed>>)
- //
- // Likewise for zeroext-load and anyext-load.
-
- std::vector<TreePredicateFn> Predicates;
- bool IsSignExtLoad = false;
- bool IsZeroExtLoad = false;
- bool IsAnyExtLoad = false;
- Record *MemVT = nullptr;
- for (const auto &P : N->getPredicateFns()) {
- if (P.isLoad() && P.isSignExtLoad()) {
- IsSignExtLoad = true;
- continue;
- }
- if (P.isLoad() && P.isZeroExtLoad()) {
- IsZeroExtLoad = true;
- continue;
- }
- if (P.isLoad() && P.isAnyExtLoad()) {
- IsAnyExtLoad = true;
- continue;
- }
- if (P.isLoad() && P.getMemoryVT()) {
- MemVT = P.getMemoryVT();
- continue;
- }
- Predicates.push_back(P);
- }
-
- if ((IsSignExtLoad || IsZeroExtLoad || IsAnyExtLoad) && MemVT) {
- assert((IsSignExtLoad + IsZeroExtLoad + IsAnyExtLoad) == 1 &&
- "IsSignExtLoad, IsZeroExtLoad, IsAnyExtLoad are mutually exclusive");
- TreePatternNode *Ext = new TreePatternNode(
- RK.getDef(IsSignExtLoad ? "sext"
- : IsZeroExtLoad ? "zext" : "anyext"),
- {N}, 1);
- Ext->setType(0, N->getType(0));
- N->clearPredicateFns();
- N->setPredicateFns(Predicates);
- N->setType(0, getValueType(MemVT));
- return Ext;
- }
- }
- }
-
- return N;
-}
-
-void GlobalISelEmitter::fixupPatternTrees(TreePattern *P) {
- for (unsigned I = 0, E = P->getNumTrees(); I < E; ++I) {
- TreePatternNode *OrigTree = P->getTree(I);
- TreePatternNode *NewTree = fixupPatternNode(OrigTree);
- if (OrigTree != NewTree)
- P->setTree(I, NewTree);
- }
-}
-
std::unique_ptr<PredicateMatcher> RuleMatcher::forgetFirstCondition() {
assert(!insnmatchers_empty() &&
"Trying to forget something that does not exist");
OpenPOWER on IntegriCloud