[llvm] ee3feef - TableGen/GlobalISel: Allow output instructions with multiple defs
Matt Arsenault via llvm-commits
llvm-commits at lists.llvm.org
Mon Jul 27 15:31:20 PDT 2020
Author: Matt Arsenault
Date: 2020-07-27T18:31:13-04:00
New Revision: ee3feef5aaaa3c385fbe08bdb2d48829ad440b56
URL: https://github.com/llvm/llvm-project/commit/ee3feef5aaaa3c385fbe08bdb2d48829ad440b56
DIFF: https://github.com/llvm/llvm-project/commit/ee3feef5aaaa3c385fbe08bdb2d48829ad440b56.diff
LOG: TableGen/GlobalISel: Allow output instructions with multiple defs
The DAG behavior allows matchching input patterns with a single result
to the first result of an output instruction that defines multiple
results. The remaining defs are implicitly dead.
This starts to fix using manual selection for AMDGPU add/sub (although
it's still needed, mostly because it's also still needed for
G_PTR_ADD).
Added:
llvm/test/TableGen/GlobalISelEmitter-output-discard.td
Modified:
llvm/test/CodeGen/AMDGPU/GlobalISel/inst-select-add.mir
llvm/test/TableGen/Common/GlobalISelEmitterCommon.td
llvm/utils/TableGen/GlobalISelEmitter.cpp
Removed:
################################################################################
diff --git a/llvm/test/CodeGen/AMDGPU/GlobalISel/inst-select-add.mir b/llvm/test/CodeGen/AMDGPU/GlobalISel/inst-select-add.mir
index baed490c0758..47b4a5c400d3 100644
--- a/llvm/test/CodeGen/AMDGPU/GlobalISel/inst-select-add.mir
+++ b/llvm/test/CodeGen/AMDGPU/GlobalISel/inst-select-add.mir
@@ -94,8 +94,7 @@ body: |
; GFX6-LABEL: name: add_neg_inline_const_64_to_sub_s32_v
; GFX6: liveins: $vgpr0
; GFX6: [[COPY:%[0-9]+]]:vgpr_32 = COPY $vgpr0
- ; GFX6: [[V_MOV_B32_e32_:%[0-9]+]]:vgpr_32 = V_MOV_B32_e32 -64, implicit $exec
- ; GFX6: %2:vgpr_32, dead %3:sreg_64_xexec = V_ADD_CO_U32_e64 [[COPY]], [[V_MOV_B32_e32_]], 0, implicit $exec
+ ; GFX6: %2:vgpr_32, dead %3:sreg_64 = V_SUB_CO_U32_e64 [[COPY]], 64, 0, implicit $exec
; GFX6: S_ENDPGM 0, implicit %2
; GFX9-LABEL: name: add_neg_inline_const_64_to_sub_s32_v
; GFX9: liveins: $vgpr0
diff --git a/llvm/test/TableGen/Common/GlobalISelEmitterCommon.td b/llvm/test/TableGen/Common/GlobalISelEmitterCommon.td
index 2fe84fb95296..9ae6c8be7dc2 100644
--- a/llvm/test/TableGen/Common/GlobalISelEmitterCommon.td
+++ b/llvm/test/TableGen/Common/GlobalISelEmitterCommon.td
@@ -12,6 +12,9 @@ def GPR32Op : RegisterOperand<GPR32>;
def F0 : Register<"f0"> { let Namespace = "MyTarget"; }
def FPR32 : RegisterClass<"MyTarget", [f32], 32, (add F0)>;
def FPR32Op : RegisterOperand<FPR32>;
+def B0 : Register<"b0"> { let Namespace = "MyTarget"; }
+def GPR8 : RegisterClass<"MyTarget", [i8], 8, (add B0)>;
+
def p0 : PtrValueType <i32, 0>;
class I<dag OOps, dag IOps, list<dag> Pat>
diff --git a/llvm/test/TableGen/GlobalISelEmitter-output-discard.td b/llvm/test/TableGen/GlobalISelEmitter-output-discard.td
new file mode 100644
index 000000000000..c755d8377e61
--- /dev/null
+++ b/llvm/test/TableGen/GlobalISelEmitter-output-discard.td
@@ -0,0 +1,27 @@
+// RUN: llvm-tblgen -gen-global-isel -warn-on-skipped-patterns -I %p/../../include -I %p/Common %s -o - < %s | FileCheck -check-prefix=GISEL %s
+
+include "llvm/Target/Target.td"
+include "GlobalISelEmitterCommon.td"
+
+// Test that extra explicit results are treated as dead defs.
+def ADD_CO : I<(outs GPR32:$dst, GPR8:$flag),
+ (ins GPR32Op:$src0, GPR32Op:$src1), []>;
+
+// GISEL: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_ADD,
+// GISEL-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32,
+// GISEL-NEXT: GIM_CheckType, /*MI*/0, /*Op*/1, /*Type*/GILLT_s32,
+// GISEL-NEXT: GIM_CheckType, /*MI*/0, /*Op*/2, /*Type*/GILLT_s32,
+// GISEL-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID,
+// GISEL-NEXT: // (add:{ *:[i32] } i32:{ *:[i32] }:$src0, i32:{ *:[i32] }:$src1) => (ADD_CO:{ *:[i32] }:{ *:[i8] } GPR32:{ *:[i32] }:$src0, GPR32:{ *:[i32] }:$src1)
+// GISEL-NEXT: GIR_MakeTempReg, /*TempRegID*/0, /*TypeID*/GILLT_s8,
+// GISEL-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::ADD_CO,
+// GISEL-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
+// GISEL-NEXT: GIR_AddTempRegister, /*InsnID*/0, /*TempRegID*/0, /*TempRegFlags*/RegState::Define|RegState::Dead,
+// GISEL-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/1, // src0
+// GISEL-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/2, // src1
+// GISEL-NEXT: GIR_EraseFromParent, /*InsnID*/0,
+// GISEL-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
+def : Pat <
+ (add i32:$src0, i32:$src1),
+ (ADD_CO GPR32:$src0, GPR32:$src1)
+>;
diff --git a/llvm/utils/TableGen/GlobalISelEmitter.cpp b/llvm/utils/TableGen/GlobalISelEmitter.cpp
index 4e8dcc52fc20..a9ebf8f1beaf 100644
--- a/llvm/utils/TableGen/GlobalISelEmitter.cpp
+++ b/llvm/utils/TableGen/GlobalISelEmitter.cpp
@@ -2628,12 +2628,14 @@ class TempRegRenderer : public OperandRenderer {
unsigned TempRegID;
const CodeGenSubRegIndex *SubRegIdx;
bool IsDef;
+ bool IsDead;
public:
TempRegRenderer(unsigned InsnID, unsigned TempRegID, bool IsDef = false,
- const CodeGenSubRegIndex *SubReg = nullptr)
+ const CodeGenSubRegIndex *SubReg = nullptr,
+ bool IsDead = false)
: OperandRenderer(OR_Register), InsnID(InsnID), TempRegID(TempRegID),
- SubRegIdx(SubReg), IsDef(IsDef) {}
+ SubRegIdx(SubReg), IsDef(IsDef), IsDead(IsDead) {}
static bool classof(const OperandRenderer *R) {
return R->getKind() == OR_TempRegister;
@@ -2650,9 +2652,13 @@ class TempRegRenderer : public OperandRenderer {
<< MatchTable::Comment("TempRegID") << MatchTable::IntValue(TempRegID)
<< MatchTable::Comment("TempRegFlags");
- if (IsDef)
- Table << MatchTable::NamedValue("RegState::Define");
- else
+ if (IsDef) {
+ SmallString<32> RegFlags;
+ RegFlags += "RegState::Define";
+ if (IsDead)
+ RegFlags += "|RegState::Dead";
+ Table << MatchTable::NamedValue(RegFlags);
+ } else
Table << MatchTable::IntValue(0);
if (SubRegIdx)
@@ -3394,7 +3400,11 @@ class GlobalISelEmitter {
Expected<action_iterator>
createInstructionRenderer(action_iterator InsertPt, RuleMatcher &M,
const TreePatternNode *Dst);
- void importExplicitDefRenderers(BuildMIAction &DstMIBuilder);
+
+ Expected<action_iterator>
+ importExplicitDefRenderers(action_iterator InsertPt, RuleMatcher &M,
+ BuildMIAction &DstMIBuilder,
+ const TreePatternNode *Dst);
Expected<action_iterator>
importExplicitUseRenderers(action_iterator InsertPt, RuleMatcher &M,
@@ -4220,7 +4230,9 @@ Expected<BuildMIAction &> GlobalISelEmitter::createAndImportInstructionRenderer(
CopyToPhysRegMIBuilder.addRenderer<CopyPhysRegRenderer>(PhysInput.first);
}
- importExplicitDefRenderers(DstMIBuilder);
+ if (auto Error = importExplicitDefRenderers(InsertPt, M, DstMIBuilder, Dst)
+ .takeError())
+ return std::move(Error);
if (auto Error = importExplicitUseRenderers(InsertPt, M, DstMIBuilder, Dst)
.takeError())
@@ -4372,13 +4384,34 @@ Expected<action_iterator> GlobalISelEmitter::createInstructionRenderer(
DstI);
}
-void GlobalISelEmitter::importExplicitDefRenderers(
- BuildMIAction &DstMIBuilder) {
+Expected<action_iterator> GlobalISelEmitter::importExplicitDefRenderers(
+ action_iterator InsertPt, RuleMatcher &M, BuildMIAction &DstMIBuilder,
+ const TreePatternNode *Dst) {
const CodeGenInstruction *DstI = DstMIBuilder.getCGI();
- for (unsigned I = 0; I < DstI->Operands.NumDefs; ++I) {
- const CGIOperandList::OperandInfo &DstIOperand = DstI->Operands[I];
- DstMIBuilder.addRenderer<CopyRenderer>(DstIOperand.Name);
+ const unsigned NumDefs = DstI->Operands.NumDefs;
+ if (NumDefs == 0)
+ return InsertPt;
+
+ DstMIBuilder.addRenderer<CopyRenderer>(DstI->Operands[0].Name);
+
+ // Patterns only handle a single result, so any result after the first is an
+ // implicitly dead def.
+ for (unsigned I = 1; I < NumDefs; ++I) {
+ const TypeSetByHwMode &ExtTy = Dst->getExtType(I);
+ if (!ExtTy.isMachineValueType())
+ return failedImport("unsupported typeset");
+
+ auto OpTy = MVTToLLT(ExtTy.getMachineValueType().SimpleTy);
+ if (!OpTy)
+ return failedImport("unsupported type");
+
+ unsigned TempRegID = M.allocateTempRegID();
+ InsertPt =
+ M.insertAction<MakeTempRegisterAction>(InsertPt, *OpTy, TempRegID);
+ DstMIBuilder.addRenderer<TempRegRenderer>(TempRegID, true, nullptr, true);
}
+
+ return InsertPt;
}
Expected<action_iterator> GlobalISelEmitter::importExplicitUseRenderers(
@@ -4814,8 +4847,8 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
auto &DstI = Target.getInstruction(DstOp);
StringRef DstIName = DstI.TheDef->getName();
- if (DstI.Operands.NumDefs != Src->getExtTypes().size())
- return failedImport("Src pattern results and dst MI defs are
diff erent (" +
+ if (DstI.Operands.NumDefs < Src->getExtTypes().size())
+ return failedImport("Src pattern result has more defs than dst MI (" +
to_string(Src->getExtTypes().size()) + " def(s) vs " +
to_string(DstI.Operands.NumDefs) + " def(s))");
More information about the llvm-commits
mailing list