summaryrefslogtreecommitdiff
path: root/utils
diff options
context:
space:
mode:
authorDaniel Sanders <daniel_l_sanders@apple.com>2017-12-04 20:39:32 +0000
committerDaniel Sanders <daniel_l_sanders@apple.com>2017-12-04 20:39:32 +0000
commite35711676bd03eb1caf7a9cb41179d82121c0457 (patch)
tree7f503474d78f64753f5e7b7775e0a3753748a0f6 /utils
parent07f4dc367b2fe397d356114da57ed58556ad231c (diff)
[globalisel][tablegen] Split atomic load/store into separate opcode and enable for AArch64.
This patch splits atomics out of the generic G_LOAD/G_STORE and into their own G_ATOMIC_LOAD/G_ATOMIC_STORE. This is a pragmatic decision rather than a necessary one. Atomic load/store has little in implementation in common with non-atomic load/store. They tend to be handled very differently throughout the backend. It also has the nice side-effect of slightly improving the common-case performance at ISel since there's no longer a need for an atomicity check in the matcher table. All targets have been updated to remove the atomic load/store check from the G_LOAD/G_STORE path. AArch64 has also been updated to mark G_ATOMIC_LOAD/G_ATOMIC_STORE legal. There is one issue with this patch though which also affects the extending loads and truncating stores. The rules only match when an appropriate G_ANYEXT is present in the MIR. For example, (G_ATOMIC_STORE (G_TRUNC:s16 (G_ANYEXT:s32 (G_ATOMIC_LOAD:s16 X)))) will match but: (G_ATOMIC_STORE (G_ATOMIC_LOAD:s16 X)) will not. This shouldn't be a problem at the moment, but as we get better at eliminating extends/truncates we'll likely start failing to match in some cases. The current plan is to fix this in a patch that changes the representation of extending-load/truncating-store to allow the MMO to describe a different type to the operation. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@319691 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'utils')
-rw-r--r--utils/TableGen/GlobalISelEmitter.cpp131
1 files changed, 88 insertions, 43 deletions
diff --git a/utils/TableGen/GlobalISelEmitter.cpp b/utils/TableGen/GlobalISelEmitter.cpp
index 062fe59d820..288f78b5d0c 100644
--- a/utils/TableGen/GlobalISelEmitter.cpp
+++ b/utils/TableGen/GlobalISelEmitter.cpp
@@ -2378,8 +2378,9 @@ private:
CodeGenRegBank CGRegs;
/// Keep track of the equivalence between SDNodes and Instruction by mapping
- /// SDNodes to the GINodeEquiv mapping. We need to map to the GINodeEquiv to
- /// check for attributes on the relation such as CheckMMOIsNonAtomic.
+ /// SDNodes to the GINodeEquiv mapping. We map to the GINodeEquiv in case we
+ /// need to check for attributes on the relation such as (the now removed)
+ /// CheckMMOIsNonAtomic.
/// This is defined using 'GINodeEquiv' in the target description.
DenseMap<Record *, Record *> NodeEquivs;
@@ -2398,6 +2399,8 @@ private:
Record *findNodeEquiv(Record *N) const;
Error importRulePredicates(RuleMatcher &M, ArrayRef<Predicate> Predicates);
+ Error importInstructionPredicates(InstructionMatcher &InsnMatcher,
+ const TreePatternNode *Src) const;
Expected<InstructionMatcher &> createAndImportSelDAGMatcher(
RuleMatcher &Rule, InstructionMatcher &InsnMatcher,
const TreePatternNode *Src, unsigned &TempOpIdx) const;
@@ -2483,45 +2486,8 @@ GlobalISelEmitter::importRulePredicates(RuleMatcher &M,
return Error::success();
}
-Expected<InstructionMatcher &> GlobalISelEmitter::createAndImportSelDAGMatcher(
- RuleMatcher &Rule, InstructionMatcher &InsnMatcher,
- const TreePatternNode *Src, unsigned &TempOpIdx) const {
- Record *SrcGIEquivOrNull = nullptr;
- const CodeGenInstruction *SrcGIOrNull = nullptr;
-
- // Start with the defined operands (i.e., the results of the root operator).
- if (Src->getExtTypes().size() > 1)
- return failedImport("Src pattern has multiple results");
-
- if (Src->isLeaf()) {
- Init *SrcInit = Src->getLeafValue();
- if (isa<IntInit>(SrcInit)) {
- InsnMatcher.addPredicate<InstructionOpcodeMatcher>(
- &Target.getInstruction(RK.getDef("G_CONSTANT")));
- } else
- return failedImport(
- "Unable to deduce gMIR opcode to handle Src (which is a leaf)");
- } else {
- SrcGIEquivOrNull = findNodeEquiv(Src->getOperator());
- if (!SrcGIEquivOrNull)
- return failedImport("Pattern operator lacks an equivalent Instruction" +
- explainOperator(Src->getOperator()));
- SrcGIOrNull = &Target.getInstruction(SrcGIEquivOrNull->getValueAsDef("I"));
-
- // The operators look good: match the opcode
- InsnMatcher.addPredicate<InstructionOpcodeMatcher>(SrcGIOrNull);
- }
-
- unsigned OpIdx = 0;
- for (const TypeSetByHwMode &VTy : Src->getExtTypes()) {
- // Results don't have a name unless they are the root node. The caller will
- // set the name if appropriate.
- OperandMatcher &OM = InsnMatcher.addOperand(OpIdx++, "", TempOpIdx);
- if (auto Error = OM.addTypeCheckPredicate(VTy, false /* OperandIsAPointer */))
- return failedImport(toString(std::move(Error)) +
- " for result of Src pattern operator");
- }
-
+Error GlobalISelEmitter::importInstructionPredicates(
+ InstructionMatcher &InsnMatcher, const TreePatternNode *Src) const {
for (const auto &Predicate : Src->getPredicateFns()) {
if (Predicate.isAlwaysTrue())
continue;
@@ -2610,9 +2576,50 @@ Expected<InstructionMatcher &> GlobalISelEmitter::createAndImportSelDAGMatcher(
return failedImport("Src pattern child has predicate (" +
explainPredicates(Src) + ")");
}
- if (SrcGIEquivOrNull && SrcGIEquivOrNull->getValueAsBit("CheckMMOIsNonAtomic"))
- InsnMatcher.addPredicate<AtomicOrderingMMOPredicateMatcher>("NotAtomic");
+ return Error::success();
+}
+
+Expected<InstructionMatcher &> GlobalISelEmitter::createAndImportSelDAGMatcher(
+ RuleMatcher &Rule, InstructionMatcher &InsnMatcher,
+ const TreePatternNode *Src, unsigned &TempOpIdx) const {
+ Record *SrcGIEquivOrNull = nullptr;
+ const CodeGenInstruction *SrcGIOrNull = nullptr;
+
+ // Start with the defined operands (i.e., the results of the root operator).
+ if (Src->getExtTypes().size() > 1)
+ return failedImport("Src pattern has multiple results");
+
+ if (Src->isLeaf()) {
+ Init *SrcInit = Src->getLeafValue();
+ if (isa<IntInit>(SrcInit)) {
+ InsnMatcher.addPredicate<InstructionOpcodeMatcher>(
+ &Target.getInstruction(RK.getDef("G_CONSTANT")));
+ } else
+ return failedImport(
+ "Unable to deduce gMIR opcode to handle Src (which is a leaf)");
+ } else {
+ SrcGIEquivOrNull = findNodeEquiv(Src->getOperator());
+ if (!SrcGIEquivOrNull)
+ return failedImport("Pattern operator lacks an equivalent Instruction" +
+ explainOperator(Src->getOperator()));
+ SrcGIOrNull = &Target.getInstruction(SrcGIEquivOrNull->getValueAsDef("I"));
+
+ // The operators look good: match the opcode
+ InsnMatcher.addPredicate<InstructionOpcodeMatcher>(SrcGIOrNull);
+ }
+
+ unsigned OpIdx = 0;
+ for (const TypeSetByHwMode &VTy : Src->getExtTypes()) {
+ // Results don't have a name unless they are the root node. The caller will
+ // set the name if appropriate.
+ OperandMatcher &OM = InsnMatcher.addOperand(OpIdx++, "", TempOpIdx);
+ if (auto Error = OM.addTypeCheckPredicate(VTy, false /* OperandIsAPointer */))
+ return failedImport(toString(std::move(Error)) +
+ " for result of Src pattern operator");
+ }
+
+
if (Src->isLeaf()) {
Init *SrcInit = Src->getLeafValue();
if (IntInit *SrcIntInit = dyn_cast<IntInit>(SrcInit)) {
@@ -2631,6 +2638,8 @@ Expected<InstructionMatcher &> GlobalISelEmitter::createAndImportSelDAGMatcher(
// here since we don't support ImmLeaf predicates yet. However, we still
// need to note the hidden operand to get GIM_CheckNumOperands correct.
InsnMatcher.addOperand(OpIdx++, "", TempOpIdx);
+ if (auto Error = importInstructionPredicates(InsnMatcher, Src))
+ return std::move(Error);
return InsnMatcher;
}
@@ -2665,6 +2674,8 @@ Expected<InstructionMatcher &> GlobalISelEmitter::createAndImportSelDAGMatcher(
}
}
+ if (auto Error = importInstructionPredicates(InsnMatcher, Src))
+ return std::move(Error);
return InsnMatcher;
}
@@ -3698,6 +3709,40 @@ TreePatternNode *GlobalISelEmitter::fixupPatternNode(TreePatternNode *N) {
return Ext;
}
}
+
+ if (N->getOperator()->getName() == "atomic_load") {
+ // If it's a atomic-load we need to adapt the pattern slightly. We need
+ // to split the node into (anyext (atomic_load ...)), and then apply the
+ // <<atomic_load_TY>> predicate by updating the result type of the load.
+ //
+ // For example:
+ // (atomic_load:[i32] [iPTR])<<atomic_load_i16>>
+ // must be transformed into:
+ // (anyext:[i32] (atomic_load:[i16] [iPTR]))
+
+ std::vector<TreePredicateFn> Predicates;
+ Record *MemVT = nullptr;
+ for (const auto &P : N->getPredicateFns()) {
+ if (P.isAtomic() && P.getMemoryVT()) {
+ MemVT = P.getMemoryVT();
+ continue;
+ }
+ Predicates.push_back(P);
+ }
+
+ if (MemVT) {
+ TypeSetByHwMode ValueTy = getValueType(MemVT);
+ if (ValueTy != N->getType(0)) {
+ TreePatternNode *Ext =
+ new TreePatternNode(RK.getDef("anyext"), {N}, 1);
+ Ext->setType(0, N->getType(0));
+ N->clearPredicateFns();
+ N->setPredicateFns(Predicates);
+ N->setType(0, ValueTy);
+ return Ext;
+ }
+ }
+ }
}
return N;