[llvm] r317117 - [globalisel][tablegen] Add support for multi-insn emission
Daniel Sanders via llvm-commits
llvm-commits at lists.llvm.org
Wed Nov 1 12:57:58 PDT 2017
Author: dsanders
Date: Wed Nov 1 12:57:57 2017
New Revision: 317117
URL: http://llvm.org/viewvc/llvm-project?rev=317117&view=rev
Log:
[globalisel][tablegen] Add support for multi-insn emission
The importer will now accept nested instructions in the result pattern such as
(ADDWrr $a, (SUBWrr $b, $c)). This is only valid when the nested instruction
def's a single vreg and the parent instruction consumes a single vreg where a
nested instruction is specified. The importer will automatically create a vreg
to connect the two using the type information from the pattern. This vreg will
be constrained to the register classes given in the instruction definitions*.
* REG_SEQUENCE is explicitly rejected because of this. The definition doesn't
constrain to a register class and it therefore needs special handling.
Added:
llvm/trunk/test/CodeGen/AArch64/GlobalISel/select-bitcast-bigendian.mir
llvm/trunk/test/CodeGen/AArch64/GlobalISel/select-intrinsic-crypto-aesmc.mir
Modified:
llvm/trunk/include/llvm/CodeGen/GlobalISel/InstructionSelector.h
llvm/trunk/include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h
llvm/trunk/test/TableGen/GlobalISelEmitter.td
llvm/trunk/utils/TableGen/GlobalISelEmitter.cpp
Modified: llvm/trunk/include/llvm/CodeGen/GlobalISel/InstructionSelector.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/GlobalISel/InstructionSelector.h?rev=317117&r1=317116&r2=317117&view=diff
==============================================================================
--- llvm/trunk/include/llvm/CodeGen/GlobalISel/InstructionSelector.h (original)
+++ llvm/trunk/include/llvm/CodeGen/GlobalISel/InstructionSelector.h Wed Nov 1 12:57:57 2017
@@ -16,6 +16,7 @@
#ifndef LLVM_CODEGEN_GLOBALISEL_INSTRUCTIONSELECTOR_H
#define LLVM_CODEGEN_GLOBALISEL_INSTRUCTIONSELECTOR_H
+#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Optional.h"
#include <bitset>
@@ -212,6 +213,10 @@ enum {
/// - InsnID - Instruction ID to modify
/// - RegNum - The register to add
GIR_AddRegister,
+ /// Add a a temporary register to the specified instruction
+ /// - InsnID - Instruction ID to modify
+ /// - TempRegID - The temporary register ID to add
+ GIR_AddTempRegister,
/// Add an immediate to the specified instruction
/// - InsnID - Instruction ID to modify
/// - Imm - The immediate to add
@@ -250,6 +255,10 @@ enum {
/// Erase from parent.
/// - InsnID - Instruction ID to erase
GIR_EraseFromParent,
+ /// Create a new temporary register that's not constrained.
+ /// - TempRegID - The temporary register ID to initialize.
+ /// - Expected type
+ GIR_MakeTempReg,
/// A successful emission
GIR_Done,
@@ -291,6 +300,7 @@ protected:
struct MatcherState {
std::vector<ComplexRendererFns::value_type> Renderers;
RecordedMIVector MIs;
+ DenseMap<unsigned, unsigned> TempRegisters;
MatcherState(unsigned MaxRenderers);
};
Modified: llvm/trunk/include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h?rev=317117&r1=317116&r2=317117&view=diff
==============================================================================
--- llvm/trunk/include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h (original)
+++ llvm/trunk/include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h Wed Nov 1 12:57:57 2017
@@ -434,12 +434,13 @@ bool InstructionSelector::executeMatchTa
case GIR_MutateOpcode: {
int64_t OldInsnID = MatchTable[CurrentIdx++];
- int64_t NewInsnID = MatchTable[CurrentIdx++];
+ uint64_t NewInsnID = MatchTable[CurrentIdx++];
int64_t NewOpcode = MatchTable[CurrentIdx++];
- assert((size_t)NewInsnID == OutMIs.size() &&
- "Expected to store MIs in order");
- OutMIs.push_back(MachineInstrBuilder(*State.MIs[OldInsnID]->getMF(),
- State.MIs[OldInsnID]));
+ if (NewInsnID >= OutMIs.size())
+ OutMIs.resize(NewInsnID + 1);
+
+ OutMIs[NewInsnID] = MachineInstrBuilder(*State.MIs[OldInsnID]->getMF(),
+ State.MIs[OldInsnID]);
OutMIs[NewInsnID]->setDesc(TII.get(NewOpcode));
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
dbgs() << CurrentIdx << ": GIR_MutateOpcode(OutMIs["
@@ -449,16 +450,16 @@ bool InstructionSelector::executeMatchTa
}
case GIR_BuildMI: {
- int64_t InsnID = MatchTable[CurrentIdx++];
+ uint64_t NewInsnID = MatchTable[CurrentIdx++];
int64_t Opcode = MatchTable[CurrentIdx++];
- assert((size_t)InsnID == OutMIs.size() &&
- "Expected to store MIs in order");
- (void)InsnID;
- OutMIs.push_back(BuildMI(*State.MIs[0]->getParent(), State.MIs[0],
- State.MIs[0]->getDebugLoc(), TII.get(Opcode)));
+ if (NewInsnID >= OutMIs.size())
+ OutMIs.resize(NewInsnID + 1);
+
+ OutMIs[NewInsnID] = BuildMI(*State.MIs[0]->getParent(), State.MIs[0],
+ State.MIs[0]->getDebugLoc(), TII.get(Opcode));
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
- dbgs() << CurrentIdx << ": GIR_BuildMI(OutMIs[" << InsnID
- << "], " << Opcode << ")\n");
+ dbgs() << CurrentIdx << ": GIR_BuildMI(OutMIs["
+ << NewInsnID << "], " << Opcode << ")\n");
break;
}
@@ -541,6 +542,19 @@ bool InstructionSelector::executeMatchTa
break;
}
+ case GIR_AddTempRegister: {
+ int64_t InsnID = MatchTable[CurrentIdx++];
+ int64_t TempRegID = MatchTable[CurrentIdx++];
+ uint64_t TempRegFlags = MatchTable[CurrentIdx++];
+ assert(OutMIs[InsnID] && "Attempted to add to undefined instruction");
+ OutMIs[InsnID].addReg(State.TempRegisters[TempRegID], TempRegFlags);
+ DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
+ dbgs() << CurrentIdx << ": GIR_AddTempRegister(OutMIs["
+ << InsnID << "], TempRegisters[" << TempRegID
+ << "], " << TempRegFlags << ")\n");
+ break;
+ }
+
case GIR_AddImm: {
int64_t InsnID = MatchTable[CurrentIdx++];
int64_t Imm = MatchTable[CurrentIdx++];
@@ -651,6 +665,18 @@ bool InstructionSelector::executeMatchTa
break;
}
+ case GIR_MakeTempReg: {
+ int64_t TempRegID = MatchTable[CurrentIdx++];
+ int64_t TypeID = MatchTable[CurrentIdx++];
+
+ State.TempRegisters[TempRegID] =
+ MRI.createGenericVirtualRegister(MatcherInfo.TypeObjects[TypeID]);
+ DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
+ dbgs() << CurrentIdx << ": TempRegs[" << TempRegID
+ << "] = GIR_MakeTempReg(" << TypeID << ")\n");
+ break;
+ }
+
case GIR_Done:
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
dbgs() << CurrentIdx << ": GIR_Done");
Added: llvm/trunk/test/CodeGen/AArch64/GlobalISel/select-bitcast-bigendian.mir
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/AArch64/GlobalISel/select-bitcast-bigendian.mir?rev=317117&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/AArch64/GlobalISel/select-bitcast-bigendian.mir (added)
+++ llvm/trunk/test/CodeGen/AArch64/GlobalISel/select-bitcast-bigendian.mir Wed Nov 1 12:57:57 2017
@@ -0,0 +1,19 @@
+# RUN: llc -O0 -mtriple=arm64eb-- -run-pass=instruction-select -verify-machineinstrs -global-isel %s -o - | FileCheck %s
+---
+name: bitcast_v2f32_to_s64
+legalized: true
+regBankSelected: true
+
+body: |
+ bb.0:
+ liveins: %x0
+
+ ; CHECK-LABEL: name: bitcast_v2f32_to_s64
+ ; CHECK: [[COPY:%[0-9]+]]:fpr64 = COPY %x0
+ ; CHECK: [[COPY1:%[0-9]+]]:fpr64 = COPY [[COPY]]
+ ; CHECK: [[REV:%[0-9]+]]:fpr64 = REV64v2i32 [[COPY1]]
+ ; CHECK: %x0 = COPY [[REV]]
+ %0:fpr(<2 x s32>) = COPY %x0
+ %1:fpr(s64) = G_BITCAST %0
+ %x0 = COPY %1(s64)
+...
Added: llvm/trunk/test/CodeGen/AArch64/GlobalISel/select-intrinsic-crypto-aesmc.mir
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/AArch64/GlobalISel/select-intrinsic-crypto-aesmc.mir?rev=317117&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/AArch64/GlobalISel/select-intrinsic-crypto-aesmc.mir (added)
+++ llvm/trunk/test/CodeGen/AArch64/GlobalISel/select-intrinsic-crypto-aesmc.mir Wed Nov 1 12:57:57 2017
@@ -0,0 +1,26 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
+# RUN: llc -mtriple=aarch64-- -mattr=+fuse-aes -run-pass=instruction-select -verify-machineinstrs -global-isel %s -o - | FileCheck %s
+
+---
+# Check that we select the aarch64_crypto_aesmc and aarch64_crypto_aese
+# intrinsics into an ARSMCrrTied and AESErr instruction sequence.
+name: aesmc_aese
+legalized: true
+regBankSelected: true
+
+body: |
+ bb.0:
+ liveins: %q0, %q1
+
+ ; CHECK-LABEL: name: aesmc_aese
+ ; CHECK: [[COPY:%[0-9]+]]:fpr128 = COPY %q0
+ ; CHECK: [[COPY1:%[0-9]+]]:fpr128 = COPY %q1
+ ; CHECK: [[T0:%[0-9]+]]:fpr128 = AESErr [[COPY]], [[COPY1]]
+ ; CHECK: [[T1:%[0-9]+]]:fpr128 = AESMCrrTied [[T0]]
+ ; CHECK: %q0 = COPY [[T1]]
+ %0:fpr(<16 x s8>) = COPY %q0
+ %1:fpr(<16 x s8>) = COPY %q1
+ %2:fpr(<16 x s8>) = G_INTRINSIC intrinsic(@llvm.aarch64.crypto.aese), %0, %1
+ %3:fpr(<16 x s8>) = G_INTRINSIC intrinsic(@llvm.aarch64.crypto.aesmc), %2
+ %q0 = COPY %3(<16 x s8>)
+...
Modified: llvm/trunk/test/TableGen/GlobalISelEmitter.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/TableGen/GlobalISelEmitter.td?rev=317117&r1=317116&r2=317117&view=diff
==============================================================================
--- llvm/trunk/test/TableGen/GlobalISelEmitter.td (original)
+++ llvm/trunk/test/TableGen/GlobalISelEmitter.td Wed Nov 1 12:57:57 2017
@@ -192,13 +192,16 @@ def HasC : Predicate<"Subtarget->hasC()"
// CHECK-NEXT: // Label 0: @[[LABEL]]
def INSN3 : I<(outs GPR32:$dst),
- (ins GPR32Op:$src1, GPR32:$src2a, GPR32:$src2b, GPR32:$src3, complex:$src4, i32imm:$src5a, i32imm:$src5b), []>;
+ (ins GPR32Op:$src1, GPR32:$src2a, GPR32:$src2b, GPR32:$scr), []>;
+def INSN4 : I<(outs GPR32:$scr),
+ (ins GPR32:$src3, complex:$src4, i32imm:$src5a, i32imm:$src5b), []>;
def : Pat<(select GPR32:$src1, (complex_rr GPR32:$src2a, GPR32:$src2b),
(select GPR32:$src3,
complex:$src4,
(complex i32imm:$src5a, i32imm:$src5b))),
- (INSN3 GPR32:$src1, GPR32:$src2b, GPR32:$src2a, GPR32:$src3,
- complex:$src4, i32imm:$src5a, i32imm:$src5b)>;
+ (INSN3 GPR32:$src1, GPR32:$src2b, GPR32:$src2a,
+ (INSN4 GPR32:$src3, complex:$src4, i32imm:$src5a,
+ i32imm:$src5b))>;
//===- Test a pattern with multiple ComplexPattern operands. --------------===//
//
@@ -232,16 +235,20 @@ def : Pat<(select GPR32:$src1, (complex_
// CHECK-NEXT: GIM_CheckType, /*MI*/1, /*Op*/3, /*Type*/GILLT_s32,
// CHECK-NEXT: GIM_CheckComplexPattern, /*MI*/1, /*Op*/3, /*Renderer*/2, GICP_gi_complex,
// CHECK-NEXT: GIM_CheckIsSafeToFold, /*InsnID*/1,
-// CHECK-NEXT: // (select:{ *:[i32] } GPR32:{ *:[i32] }:$src1, (complex_rr:{ *:[i32] } GPR32:{ *:[i32] }:$src2a, GPR32:{ *:[i32] }:$src2b), (select:{ *:[i32] } GPR32:{ *:[i32] }:$src3, complex:{ *:[i32] }:$src4, (complex:{ *:[i32] } i32imm:{ *:[i32] }:$src5a, i32imm:{ *:[i32] }:$src5b))) => (INSN3:{ *:[i32] } GPR32:{ *:[i32] }:$src1, GPR32:{ *:[i32] }:$src2b, GPR32:{ *:[i32] }:$src2a, GPR32:{ *:[i32] }:$src3, complex:{ *:[i32] }:$src4, i32imm:{ *:[i32] }:$src5a, i32imm:{ *:[i32] }:$src5b)
+// CHECK-NEXT: // (select:{ *:[i32] } GPR32:{ *:[i32] }:$src1, (complex_rr:{ *:[i32] } GPR32:{ *:[i32] }:$src2a, GPR32:{ *:[i32] }:$src2b), (select:{ *:[i32] } GPR32:{ *:[i32] }:$src3, complex:{ *:[i32] }:$src4, (complex:{ *:[i32] } i32imm:{ *:[i32] }:$src5a, i32imm:{ *:[i32] }:$src5b))) => (INSN3:{ *:[i32] } GPR32:{ *:[i32] }:$src1, GPR32:{ *:[i32] }:$src2b, GPR32:{ *:[i32] }:$src2a, (INSN4:{ *:[i32] } GPR32:{ *:[i32] }:$src3, complex:{ *:[i32] }:$src4, i32imm:{ *:[i32] }:$src5a, i32imm:{ *:[i32] }:$src5b))
+// CHECK-NEXT: GIR_MakeTempReg, /*TempRegID*/0, /*TypeID*/GILLT_s32,
+// CHECK-NEXT: GIR_BuildMI, /*InsnID*/1, /*Opcode*/MyTarget::INSN4,
+// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/1, /*TempRegID*/0, /*TempRegFlags*/RegState::Define,
+// CHECK-NEXT: GIR_Copy, /*NewInsnID*/1, /*OldInsnID*/1, /*OpIdx*/1, // src3
+// CHECK-NEXT: GIR_ComplexRenderer, /*InsnID*/1, /*RendererID*/1,
+// CHECK-NEXT: GIR_ComplexSubOperandRenderer, /*InsnID*/1, /*RendererID*/2, /*SubOperand*/0, // src5a
+// CHECK-NEXT: GIR_ComplexSubOperandRenderer, /*InsnID*/1, /*RendererID*/2, /*SubOperand*/1, // src5b
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::INSN3,
// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/1, // src1
// CHECK-NEXT: GIR_ComplexSubOperandRenderer, /*InsnID*/0, /*RendererID*/0, /*SubOperand*/1, // src2b
// CHECK-NEXT: GIR_ComplexSubOperandRenderer, /*InsnID*/0, /*RendererID*/0, /*SubOperand*/0, // src2a
-// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/1, /*OpIdx*/1, // src3
-// CHECK-NEXT: GIR_ComplexRenderer, /*InsnID*/0, /*RendererID*/1,
-// CHECK-NEXT: GIR_ComplexSubOperandRenderer, /*InsnID*/0, /*RendererID*/2, /*SubOperand*/0, // src5a
-// CHECK-NEXT: GIR_ComplexSubOperandRenderer, /*InsnID*/0, /*RendererID*/2, /*SubOperand*/1, // src5b
+// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/0, /*TempRegID*/0, /*TempRegFlags*/0,
// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
// CHECK-NEXT: GIR_Done,
Modified: llvm/trunk/utils/TableGen/GlobalISelEmitter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/GlobalISelEmitter.cpp?rev=317117&r1=317116&r2=317117&view=diff
==============================================================================
--- llvm/trunk/utils/TableGen/GlobalISelEmitter.cpp (original)
+++ llvm/trunk/utils/TableGen/GlobalISelEmitter.cpp Wed Nov 1 12:57:57 2017
@@ -555,6 +555,9 @@ protected:
/// ID for the next output instruction allocated with allocateOutputInsnID()
unsigned NextOutputInsnID;
+ /// ID for the next temporary register ID allocated with allocateTempRegID()
+ unsigned NextTempRegID;
+
std::vector<Record *> RequiredFeatures;
ArrayRef<SMLoc> SrcLoc;
@@ -570,7 +573,7 @@ public:
RuleMatcher(ArrayRef<SMLoc> SrcLoc)
: Matchers(), Actions(), InsnVariableIDs(), MutatableInsns(),
DefinedOperands(), NextInsnVarID(0), NextOutputInsnID(0),
- SrcLoc(SrcLoc), ComplexSubOperands() {}
+ NextTempRegID(0), SrcLoc(SrcLoc), ComplexSubOperands() {}
RuleMatcher(RuleMatcher &&Other) = default;
RuleMatcher &operator=(RuleMatcher &&Other) = default;
@@ -658,6 +661,7 @@ public:
InstructionMatcher &insnmatcher_front() const { return *Matchers.front(); }
unsigned allocateOutputInsnID() { return NextOutputInsnID++; }
+ unsigned allocateTempRegID() { return NextTempRegID++; }
};
using action_iterator = RuleMatcher::action_iterator;
@@ -1476,6 +1480,7 @@ public:
OR_CopyFConstantAsFPImm,
OR_Imm,
OR_Register,
+ OR_TempRegister,
OR_ComplexPattern
};
@@ -1692,6 +1697,37 @@ public:
}
};
+/// Adds a specific temporary virtual register to the instruction being built.
+/// This is used to chain instructions together when emitting multiple
+/// instructions.
+class TempRegRenderer : public OperandRenderer {
+protected:
+ unsigned InsnID;
+ unsigned TempRegID;
+ bool IsDef;
+
+public:
+ TempRegRenderer(unsigned InsnID, unsigned TempRegID, bool IsDef = false)
+ : OperandRenderer(OR_Register), InsnID(InsnID), TempRegID(TempRegID),
+ IsDef(IsDef) {}
+
+ static bool classof(const OperandRenderer *R) {
+ return R->getKind() == OR_TempRegister;
+ }
+
+ void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override {
+ Table << MatchTable::Opcode("GIR_AddTempRegister")
+ << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID)
+ << MatchTable::Comment("TempRegID") << MatchTable::IntValue(TempRegID)
+ << MatchTable::Comment("TempRegFlags");
+ if (IsDef)
+ Table << MatchTable::NamedValue("RegState::Define");
+ else
+ Table << MatchTable::IntValue(0);
+ Table << MatchTable::LineBreak;
+ }
+};
+
/// Adds a specific immediate to the instruction being built.
class ImmRenderer : public OperandRenderer {
protected:
@@ -1906,9 +1942,13 @@ public:
<< MatchTable::LineBreak;
}
- Table << MatchTable::Opcode("GIR_EraseFromParent")
- << MatchTable::Comment("InsnID") << MatchTable::IntValue(0)
- << MatchTable::LineBreak;
+ // FIXME: This is a hack but it's sufficient for ISel. We'll need to do
+ // better for combines. Particularly when there are multiple match
+ // roots.
+ if (InsnID == 0)
+ Table << MatchTable::Opcode("GIR_EraseFromParent")
+ << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID)
+ << MatchTable::LineBreak;
}
};
@@ -1948,6 +1988,26 @@ public:
}
};
+/// Generates code to create a temporary register which can be used to chain
+/// instructions together.
+class MakeTempRegisterAction : public MatchAction {
+private:
+ LLTCodeGen Ty;
+ unsigned TempRegID;
+
+public:
+ MakeTempRegisterAction(const LLTCodeGen &Ty, unsigned TempRegID)
+ : Ty(Ty), TempRegID(TempRegID) {}
+
+ void emitActionOpcodes(MatchTable &Table, RuleMatcher &Rule) const override {
+ Table << MatchTable::Opcode("GIR_MakeTempReg")
+ << MatchTable::Comment("TempRegID") << MatchTable::IntValue(TempRegID)
+ << MatchTable::Comment("TypeID")
+ << MatchTable::NamedValue(Ty.getCxxEnumValue())
+ << MatchTable::LineBreak;
+ }
+};
+
InstructionMatcher &RuleMatcher::addInstructionMatcher(StringRef SymbolicName) {
Matchers.emplace_back(new InstructionMatcher(*this, SymbolicName));
MutatableInsns.insert(Matchers.back().get());
@@ -1974,6 +2034,7 @@ Kind &RuleMatcher::addAction(Args &&...
Actions.emplace_back(llvm::make_unique<Kind>(std::forward<Args>(args)...));
return *static_cast<Kind *>(Actions.back().get());
}
+
// Emplaces an action of the specified Kind before the given insertion point.
//
// Returns an iterator pointing at the newly created instruction.
@@ -1984,7 +2045,8 @@ Kind &RuleMatcher::addAction(Args &&...
template <class Kind, class... Args>
action_iterator RuleMatcher::insertAction(action_iterator InsertPt,
Args &&... args) {
- return Actions.insert(InsertPt, llvm::make_unique<Kind>(std::forward<Args>(args)...));
+ return Actions.emplace(InsertPt,
+ llvm::make_unique<Kind>(std::forward<Args>(args)...));
}
unsigned
@@ -2264,6 +2326,9 @@ private:
Expected<BuildMIAction &>
createAndImportInstructionRenderer(RuleMatcher &M,
const TreePatternNode *Dst);
+ Expected<action_iterator> createAndImportSubInstructionRenderer(
+ action_iterator InsertPt, RuleMatcher &M, const TreePatternNode *Dst,
+ unsigned TempReg);
Expected<action_iterator>
createInstructionRenderer(action_iterator InsertPt, RuleMatcher &M,
const TreePatternNode *Dst);
@@ -2275,7 +2340,7 @@ private:
Expected<action_iterator>
importExplicitUseRenderer(action_iterator InsertPt, RuleMatcher &Rule,
BuildMIAction &DstMIBuilder,
- TreePatternNode *DstChild) const;
+ TreePatternNode *DstChild);
Error importDefaultOperandRenderers(BuildMIAction &DstMIBuilder,
DagInit *DefaultOps) const;
Error
@@ -2607,7 +2672,7 @@ Error GlobalISelEmitter::importChildMatc
Expected<action_iterator> GlobalISelEmitter::importExplicitUseRenderer(
action_iterator InsertPt, RuleMatcher &Rule, BuildMIAction &DstMIBuilder,
- TreePatternNode *DstChild) const {
+ TreePatternNode *DstChild) {
if (DstChild->getTransformFn() != nullptr) {
return failedImport("Dst pattern child has transform fn " +
DstChild->getTransformFn()->getName());
@@ -2645,6 +2710,30 @@ Expected<action_iterator> GlobalISelEmit
return InsertPt;
}
+ if (DstChild->getOperator()->isSubClassOf("Instruction")) {
+ ArrayRef<TypeSetByHwMode> ChildTypes = DstChild->getExtTypes();
+ if (ChildTypes.size() != 1)
+ return failedImport("Dst pattern child has multiple results");
+
+ Optional<LLTCodeGen> OpTyOrNone = None;
+ if (ChildTypes.front().isMachineValueType())
+ OpTyOrNone =
+ MVTToLLT(ChildTypes.front().getMachineValueType().SimpleTy);
+ if (!OpTyOrNone)
+ return failedImport("Dst operand has an unsupported type");
+
+ unsigned TempRegID = Rule.allocateTempRegID();
+ InsertPt = Rule.insertAction<MakeTempRegisterAction>(
+ InsertPt, OpTyOrNone.getValue(), TempRegID);
+ DstMIBuilder.addRenderer<TempRegRenderer>(TempRegID);
+
+ auto InsertPtOrError = createAndImportSubInstructionRenderer(
+ ++InsertPt, Rule, DstChild, TempRegID);
+ if (auto Error = InsertPtOrError.takeError())
+ return std::move(Error);
+ return InsertPtOrError.get();
+ }
+
return failedImport("Dst pattern child isn't a leaf node or an MBB" + llvm::to_string(*DstChild));
}
@@ -2723,6 +2812,31 @@ Expected<BuildMIAction &> GlobalISelEmit
return DstMIBuilder;
}
+Expected<action_iterator>
+GlobalISelEmitter::createAndImportSubInstructionRenderer(
+ action_iterator InsertPt, RuleMatcher &M, const TreePatternNode *Dst,
+ unsigned TempRegID) {
+ auto InsertPtOrError = createInstructionRenderer(InsertPt, M, Dst);
+
+ // TODO: Assert there's exactly one result.
+
+ if (auto Error = InsertPtOrError.takeError())
+ return std::move(Error);
+ InsertPt = InsertPtOrError.get();
+
+ BuildMIAction &DstMIBuilder =
+ *static_cast<BuildMIAction *>(InsertPtOrError.get()->get());
+
+ // Assign the result to TempReg.
+ DstMIBuilder.addRenderer<TempRegRenderer>(TempRegID, true);
+
+ InsertPtOrError = importExplicitUseRenderers(InsertPt, M, DstMIBuilder, Dst);
+ if (auto Error = InsertPtOrError.takeError())
+ return std::move(Error);
+
+ return InsertPtOrError.get();
+}
+
Expected<action_iterator> GlobalISelEmitter::createInstructionRenderer(
action_iterator InsertPt, RuleMatcher &M, const TreePatternNode *Dst) {
Record *DstOp = Dst->getOperator();
@@ -2740,6 +2854,8 @@ Expected<action_iterator> GlobalISelEmit
DstI = &Target.getInstruction(RK.getDef("COPY"));
else if (DstI->TheDef->getName() == "EXTRACT_SUBREG")
DstI = &Target.getInstruction(RK.getDef("COPY"));
+ else if (DstI->TheDef->getName() == "REG_SEQUENCE")
+ return failedImport("Unable to emit REG_SEQUENCE");
return M.insertAction<BuildMIAction>(InsertPt, M.allocateOutputInsnID(),
DstI);
@@ -2767,8 +2883,12 @@ Expected<action_iterator> GlobalISelEmit
if (DefInit *SubRegInit =
dyn_cast<DefInit>(Dst->getChild(1)->getLeafValue())) {
- CodeGenRegisterClass *RC = CGRegs.getRegClass(
- getInitValueAsRegClass(Dst->getChild(0)->getLeafValue()));
+ Record *RCDef = getInitValueAsRegClass(Dst->getChild(0)->getLeafValue());
+ if (!RCDef)
+ return failedImport("EXTRACT_SUBREG child #0 could not "
+ "be coerced to a register class");
+
+ CodeGenRegisterClass *RC = CGRegs.getRegClass(RCDef);
CodeGenSubRegIndex *SubIdx = CGRegs.getSubRegIdx(SubRegInit->getDef());
const auto &SrcRCDstRCPair =
More information about the llvm-commits
mailing list