From e35711676bd03eb1caf7a9cb41179d82121c0457 Mon Sep 17 00:00:00 2001 From: Daniel Sanders Date: Mon, 4 Dec 2017 20:39:32 +0000 Subject: [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 --- utils/TableGen/GlobalISelEmitter.cpp | 131 +++++++++++++++++++++++------------ 1 file changed, 88 insertions(+), 43 deletions(-) (limited to 'utils') 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 NodeEquivs; @@ -2398,6 +2399,8 @@ private: Record *findNodeEquiv(Record *N) const; Error importRulePredicates(RuleMatcher &M, ArrayRef Predicates); + Error importInstructionPredicates(InstructionMatcher &InsnMatcher, + const TreePatternNode *Src) const; Expected createAndImportSelDAGMatcher( RuleMatcher &Rule, InstructionMatcher &InsnMatcher, const TreePatternNode *Src, unsigned &TempOpIdx) const; @@ -2483,45 +2486,8 @@ GlobalISelEmitter::importRulePredicates(RuleMatcher &M, return Error::success(); } -Expected 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(SrcInit)) { - InsnMatcher.addPredicate( - &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(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 GlobalISelEmitter::createAndImportSelDAGMatcher( return failedImport("Src pattern child has predicate (" + explainPredicates(Src) + ")"); } - if (SrcGIEquivOrNull && SrcGIEquivOrNull->getValueAsBit("CheckMMOIsNonAtomic")) - InsnMatcher.addPredicate("NotAtomic"); + return Error::success(); +} + +Expected 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(SrcInit)) { + InsnMatcher.addPredicate( + &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(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(SrcInit)) { @@ -2631,6 +2638,8 @@ Expected 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 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 + // <> predicate by updating the result type of the load. + // + // For example: + // (atomic_load:[i32] [iPTR])<> + // must be transformed into: + // (anyext:[i32] (atomic_load:[i16] [iPTR])) + + std::vector 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; -- cgit v1.2.3