diff options
author | Daniel Sanders <daniel_l_sanders@apple.com> | 2017-06-27 10:11:39 +0000 |
---|---|---|
committer | Daniel Sanders <daniel_l_sanders@apple.com> | 2017-06-27 10:11:39 +0000 |
commit | cc36dbf55d9f32a955301d5ea454fb5e0bb4a6c9 (patch) | |
tree | 8f09bb7255dc0f63967aafe0969ca36782613f15 /llvm/utils/TableGen/GlobalISelEmitter.cpp | |
parent | 3e0d39e40390b63f649d86cff05e54495bd9d513 (diff) | |
download | bcm5719-llvm-cc36dbf55d9f32a955301d5ea454fb5e0bb4a6c9.tar.gz bcm5719-llvm-cc36dbf55d9f32a955301d5ea454fb5e0bb4a6c9.zip |
[globalisel][tablegen] Add support for EXTRACT_SUBREG.
Summary:
After this patch, we finally have test cases that require multiple
instruction emission.
Depends on D33590
Reviewers: ab, qcolombet, t.p.northover, rovka, kristof.beyls
Subscribers: javed.absar, llvm-commits, igorb
Differential Revision: https://reviews.llvm.org/D33596
llvm-svn: 306388
Diffstat (limited to 'llvm/utils/TableGen/GlobalISelEmitter.cpp')
-rw-r--r-- | llvm/utils/TableGen/GlobalISelEmitter.cpp | 151 |
1 files changed, 142 insertions, 9 deletions
diff --git a/llvm/utils/TableGen/GlobalISelEmitter.cpp b/llvm/utils/TableGen/GlobalISelEmitter.cpp index 03d231a153d..50da9085c21 100644 --- a/llvm/utils/TableGen/GlobalISelEmitter.cpp +++ b/llvm/utils/TableGen/GlobalISelEmitter.cpp @@ -832,7 +832,13 @@ public: //===- Actions ------------------------------------------------------------===// class OperandRenderer { public: - enum RendererKind { OR_Copy, OR_Imm, OR_Register, OR_ComplexPattern }; + enum RendererKind { + OR_Copy, + OR_CopySubReg, + OR_Imm, + OR_Register, + OR_ComplexPattern + }; protected: RendererKind Kind; @@ -877,6 +883,42 @@ public: } }; +/// A CopySubRegRenderer emits code to copy a single register operand from an +/// existing instruction to the one being built and indicate that only a +/// subregister should be copied. +class CopySubRegRenderer : public OperandRenderer { +protected: + /// The matcher for the instruction that this operand is copied from. + /// This provides the facility for looking up an a operand by it's name so + /// that it can be used as a source for the instruction being built. + const InstructionMatcher &Matched; + /// The name of the operand. + const StringRef SymbolicName; + /// The subregister to extract. + const CodeGenSubRegIndex *SubReg; + +public: + CopySubRegRenderer(const InstructionMatcher &Matched, StringRef SymbolicName, + const CodeGenSubRegIndex *SubReg) + : OperandRenderer(OR_CopySubReg), Matched(Matched), + SymbolicName(SymbolicName), SubReg(SubReg) {} + + static bool classof(const OperandRenderer *R) { + return R->getKind() == OR_CopySubReg; + } + + const StringRef getSymbolicName() const { return SymbolicName; } + + void emitCxxRenderStmts(raw_ostream &OS, RuleMatcher &Rule) const override { + const OperandMatcher &Operand = Matched.getOperand(SymbolicName); + StringRef InsnVarName = + Rule.getInsnVarName(Operand.getInstructionMatcher()); + std::string OperandExpr = Operand.getOperandExpr(InsnVarName); + OS << " MIB.addReg(" << OperandExpr << ".getReg() /*" << SymbolicName + << "*/, 0, " << SubReg->EnumValue << ");\n"; + } +}; + /// Adds a specific physical register to the instruction being built. /// This is typically useful for WZR/XZR on AArch64. class AddRegisterRenderer : public OperandRenderer { @@ -1292,6 +1334,7 @@ private: const RecordKeeper &RK; const CodeGenDAGPatterns CGP; const CodeGenTarget &Target; + CodeGenRegBank CGRegs; /// Keep track of the equivalence between SDNodes and Instruction. /// This is defined using 'GINodeEquiv' in the target description. @@ -1315,9 +1358,9 @@ private: Error importChildMatcher(InstructionMatcher &InsnMatcher, const TreePatternNode *SrcChild, unsigned OpIdx, unsigned &TempOpIdx) const; - Expected<BuildMIAction &> createAndImportInstructionRenderer( - RuleMatcher &M, const TreePatternNode *Dst, - const InstructionMatcher &InsnMatcher) const; + Expected<BuildMIAction &> + createAndImportInstructionRenderer(RuleMatcher &M, const TreePatternNode *Dst, + const InstructionMatcher &InsnMatcher); Error importExplicitUseRenderer(BuildMIAction &DstMIBuilder, TreePatternNode *DstChild, const InstructionMatcher &InsnMatcher) const; @@ -1354,7 +1397,7 @@ const CodeGenInstruction *GlobalISelEmitter::findNodeEquiv(Record *N) const { } GlobalISelEmitter::GlobalISelEmitter(RecordKeeper &RK) - : RK(RK), CGP(RK), Target(CGP.getTargetInfo()) {} + : RK(RK), CGP(RK), Target(CGP.getTargetInfo()), CGRegs(RK) {} //===- Emitter ------------------------------------------------------------===// @@ -1585,7 +1628,7 @@ Error GlobalISelEmitter::importExplicitUseRenderer( Expected<BuildMIAction &> GlobalISelEmitter::createAndImportInstructionRenderer( RuleMatcher &M, const TreePatternNode *Dst, - const InstructionMatcher &InsnMatcher) const { + const InstructionMatcher &InsnMatcher) { Record *DstOp = Dst->getOperator(); if (!DstOp->isSubClassOf("Instruction")) { if (DstOp->isSubClassOf("ValueType")) @@ -1597,13 +1640,17 @@ Expected<BuildMIAction &> GlobalISelEmitter::createAndImportInstructionRenderer( unsigned DstINumUses = DstI->Operands.size() - DstI->Operands.NumDefs; unsigned ExpectedDstINumUses = Dst->getNumChildren(); + bool IsExtractSubReg = false; // COPY_TO_REGCLASS is just a copy with a ConstrainOperandToRegClassAction - // attached. + // attached. Similarly for EXTRACT_SUBREG except that's a subregister copy. if (DstI->TheDef->getName() == "COPY_TO_REGCLASS") { DstI = &Target.getInstruction(RK.getDef("COPY")); DstINumUses--; // Ignore the class constraint. ExpectedDstINumUses--; + } else if (DstI->TheDef->getName() == "EXTRACT_SUBREG") { + DstI = &Target.getInstruction(RK.getDef("COPY")); + IsExtractSubReg = true; } auto &DstMIBuilder = M.addAction<BuildMIAction>("NewI", DstI, InsnMatcher); @@ -1614,6 +1661,32 @@ Expected<BuildMIAction &> GlobalISelEmitter::createAndImportInstructionRenderer( DstMIBuilder.addRenderer<CopyRenderer>(InsnMatcher, DstIOperand.Name); } + // EXTRACT_SUBREG needs to use a subregister COPY. + if (IsExtractSubReg) { + if (!Dst->getChild(0)->isLeaf()) + return failedImport("EXTRACT_SUBREG child #1 is not a leaf"); + + if (DefInit *SubRegInit = dyn_cast<DefInit>(Dst->getChild(1)->getLeafValue())) { + CodeGenRegisterClass *RC = CGRegs.getRegClass( + getInitValueAsRegClass(Dst->getChild(0)->getLeafValue())); + CodeGenSubRegIndex *SubIdx = CGRegs.getSubRegIdx(SubRegInit->getDef()); + + const auto &SrcRCDstRCPair = + RC->getMatchingSubClassWithSubRegs(CGRegs, SubIdx); + if (SrcRCDstRCPair.hasValue()) { + assert(SrcRCDstRCPair->second && "Couldn't find a matching subclass"); + if (SrcRCDstRCPair->first != RC) + return failedImport("EXTRACT_SUBREG requires an additional COPY"); + } + + DstMIBuilder.addRenderer<CopySubRegRenderer>( + InsnMatcher, Dst->getChild(0)->getName(), SubIdx); + return DstMIBuilder; + } + + return failedImport("EXTRACT_SUBREG child #1 is not a subreg index"); + } + // Render the explicit uses. unsigned Child = 0; unsigned NumDefaultOps = 0; @@ -1740,6 +1813,16 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) { if (DstIOpRec == nullptr) return failedImport( "COPY_TO_REGCLASS operand #1 isn't a register class"); + } else if (DstI.TheDef->getName() == "EXTRACT_SUBREG") { + if (!Dst->getChild(0)->isLeaf()) + return failedImport("EXTRACT_SUBREG operand #0 isn't a leaf"); + + // We can assume that a subregister is in the same bank as it's super register. + DstIOpRec = getInitValueAsRegClass(Dst->getChild(0)->getLeafValue()); + + if (DstIOpRec == nullptr) + return failedImport( + "EXTRACT_SUBREG operand #0 isn't a register class"); } else if (DstIOpRec->isSubClassOf("RegisterOperand")) DstIOpRec = DstIOpRec->getValueAsDef("RegClass"); else if (!DstIOpRec->isSubClassOf("RegisterClass")) @@ -1776,8 +1859,58 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) { M.addAction<ConstrainOperandToRegClassAction>( "NewI", 0, Target.getRegisterClass(DstIOpRec)); - } else - M.addAction<ConstrainOperandsToDefinitionAction>("NewI"); + + // We're done with this pattern! It's eligible for GISel emission; return + // it. + ++NumPatternImported; + return std::move(M); + } + + if (DstI.TheDef->getName() == "EXTRACT_SUBREG") { + // EXTRACT_SUBREG selects into a subregister COPY but unlike most + // instructions, the result register class is controlled by the + // subregisters of the operand. As a result, we must constrain the result + // class rather than check that it's already the right one. + if (!Dst->getChild(0)->isLeaf()) + return failedImport("EXTRACT_SUBREG child #1 is not a leaf"); + + if (DefInit *SubRegInit = + dyn_cast<DefInit>(Dst->getChild(1)->getLeafValue())) { + // Constrain the result to the same register bank as the operand. + Record *DstIOpRec = + getInitValueAsRegClass(Dst->getChild(0)->getLeafValue()); + + if (DstIOpRec == nullptr) + return failedImport("EXTRACT_SUBREG operand #1 isn't a register class"); + + CodeGenSubRegIndex *SubIdx = CGRegs.getSubRegIdx(SubRegInit->getDef()); + CodeGenRegisterClass *SrcRC = CGRegs.getRegClass( + getInitValueAsRegClass(Dst->getChild(0)->getLeafValue())); + + // It would be nice to leave this constraint implicit but we're required + // to pick a register class so constrain the result to a register class + // that can hold the correct MVT. + // + // FIXME: This may introduce an extra copy if the chosen class doesn't + // actually contain the subregisters. + assert(Src->getExtTypes().size() == 1); + + const auto &SrcRCDstRCPair = + SrcRC->getMatchingSubClassWithSubRegs(CGRegs, SubIdx); + assert(SrcRCDstRCPair->second && "Couldn't find a matching subclass"); + M.addAction<ConstrainOperandToRegClassAction>("NewI", 0, *SrcRCDstRCPair->second); + M.addAction<ConstrainOperandToRegClassAction>("NewI", 1, *SrcRCDstRCPair->first); + + // We're done with this pattern! It's eligible for GISel emission; return + // it. + ++NumPatternImported; + return std::move(M); + } + + return failedImport("EXTRACT_SUBREG child #1 is not a subreg index"); + } + + M.addAction<ConstrainOperandsToDefinitionAction>("NewI"); // We're done with this pattern! It's eligible for GISel emission; return it. ++NumPatternImported; |