summaryrefslogtreecommitdiffstats
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.cpp151
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;
OpenPOWER on IntegriCloud