[llvm] [GlobalISel] Add `GITypeOf` special type (PR #66079)
Pierre van Houtryve via llvm-commits
llvm-commits at lists.llvm.org
Tue Sep 12 06:17:59 PDT 2023
https://github.com/Pierre-vh updated https://github.com/llvm/llvm-project/pull/66079:
>From 7cc3795ae0389fe0087f0bd05b8ac48402a4dfde Mon Sep 17 00:00:00 2001
From: pvanhout <pierre.vanhoutryve at amd.com>
Date: Mon, 11 Sep 2023 14:43:47 +0200
Subject: [PATCH 1/3] [RFC][GlobalISel] Use Builders in MatchTable
The MatchTableExecutor did not use the MachineIRBuilder nor Observers to build instructions.
This meant that it only had a very superficial view of what's going on when rules are being applied. Custom code could create insts that the executor didn't know about.
Using a builder & an observer allows it to collect any instruction that's created as long as the same builder is used by the supporting C++ code. For instance, flags are propagated more thoroughly now.
Another benefit that may come later is that I'm trying to improve how constants are created in apply MIR patterns.
`MachineIRBuilder::buildConstant` automatically handles splats for us,
this means that we may change `addCImm` to use that and handle vector cases automatically.
---
.../CodeGen/GlobalISel/GIMatchTableExecutor.h | 39 +++++---
.../GlobalISel/GIMatchTableExecutorImpl.h | 66 ++++++++-----
.../CodeGen/GlobalISel/MachineIRBuilder.h | 10 ++
.../GlobalISel/GIMatchTableExecutor.cpp | 4 +
.../AArch64/GlobalISel/combine-sdiv.mir | 28 +++---
...galizercombiner-ashr-shl-to-sext-inreg.mir | 4 +-
.../combine-fma-add-mul-pre-legalize.mir | 96 +++++++++----------
.../GlobalISel/combine-fma-unmerge-values.mir | 20 ++--
.../combine-fold-binop-into-select.mir | 20 ++--
.../AMDGPU/GlobalISel/combine-fsub-fneg.mir | 28 +++---
.../GlobalISelCombinerEmitter/match-table.td | 6 +-
llvm/test/TableGen/GlobalISelEmitter.td | 6 +-
.../TableGen/GlobalISelCombinerEmitter.cpp | 8 +-
llvm/utils/TableGen/GlobalISelEmitter.cpp | 7 +-
.../GlobalISelMatchTableExecutorEmitter.cpp | 2 +-
15 files changed, 195 insertions(+), 149 deletions(-)
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutor.h b/llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutor.h
index 2b0733cf9353e6c..8c1a067af3a6912 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutor.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutor.h
@@ -18,6 +18,7 @@
#include "llvm/ADT/Bitset.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h"
#include "llvm/CodeGen/GlobalISel/Utils.h"
#include "llvm/CodeGen/LowLevelType.h"
#include "llvm/CodeGen/MachineFunction.h"
@@ -40,6 +41,7 @@ class APInt;
class APFloat;
class GISelKnownBits;
class MachineInstr;
+class MachineIRBuilder;
class MachineInstrBuilder;
class MachineFunction;
class MachineOperand;
@@ -501,10 +503,25 @@ class GIMatchTableExecutor {
}
protected:
+ /// Observer used by \ref executeMatchTable to record all instructions created
+ /// by the rule.
+ class GIMatchTableObserver : public GISelChangeObserver {
+ public:
+ virtual ~GIMatchTableObserver();
+
+ void erasingInstr(MachineInstr &MI) override { CreatedInsts.erase(&MI); }
+ void createdInstr(MachineInstr &MI) override { CreatedInsts.insert(&MI); }
+ void changingInstr(MachineInstr &MI) override {}
+ void changedInstr(MachineInstr &MI) override {}
+
+ // Keeps track of all instructions that have been created when applying a
+ // rule.
+ SmallDenseSet<MachineInstr *, 4> CreatedInsts;
+ };
+
using ComplexRendererFns =
std::optional<SmallVector<std::function<void(MachineInstrBuilder &)>, 4>>;
using RecordedMIVector = SmallVector<MachineInstr *, 4>;
- using NewMIVector = SmallVector<MachineInstrBuilder, 4>;
struct MatcherState {
std::vector<ComplexRendererFns::value_type> Renderers;
@@ -555,15 +572,15 @@ class GIMatchTableExecutor {
/// and false otherwise.
template <class TgtExecutor, class PredicateBitset, class ComplexMatcherMemFn,
class CustomRendererFn>
- bool executeMatchTable(
- TgtExecutor &Exec, NewMIVector &OutMIs, MatcherState &State,
- const ExecInfoTy<PredicateBitset, ComplexMatcherMemFn, CustomRendererFn>
- &ISelInfo,
- const int64_t *MatchTable, const TargetInstrInfo &TII,
- MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI,
- const RegisterBankInfo &RBI, const PredicateBitset &AvailableFeatures,
- CodeGenCoverage *CoverageInfo,
- GISelChangeObserver *Observer = nullptr) const;
+ bool executeMatchTable(TgtExecutor &Exec, MatcherState &State,
+ const ExecInfoTy<PredicateBitset, ComplexMatcherMemFn,
+ CustomRendererFn> &ExecInfo,
+ MachineIRBuilder &Builder, const int64_t *MatchTable,
+ const TargetInstrInfo &TII, MachineRegisterInfo &MRI,
+ const TargetRegisterInfo &TRI,
+ const RegisterBankInfo &RBI,
+ const PredicateBitset &AvailableFeatures,
+ CodeGenCoverage *CoverageInfo) const;
virtual const int64_t *getMatchTable() const {
llvm_unreachable("Should have been overridden by tablegen if used");
@@ -592,7 +609,7 @@ class GIMatchTableExecutor {
}
virtual void runCustomAction(unsigned, const MatcherState &State,
- NewMIVector &OutMIs) const {
+ ArrayRef<MachineInstrBuilder> OutMIs) const {
llvm_unreachable("Subclass does not implement runCustomAction!");
}
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h b/llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h
index 883c1ca0fe350b0..3b2718e11864a1a 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h
@@ -18,6 +18,7 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/CodeGen/GlobalISel/GIMatchTableExecutor.h"
#include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h"
+#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
#include "llvm/CodeGen/GlobalISel/Utils.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineOperand.h"
@@ -42,17 +43,33 @@ namespace llvm {
template <class TgtExecutor, class PredicateBitset, class ComplexMatcherMemFn,
class CustomRendererFn>
bool GIMatchTableExecutor::executeMatchTable(
- TgtExecutor &Exec, NewMIVector &OutMIs, MatcherState &State,
+ TgtExecutor &Exec, MatcherState &State,
const ExecInfoTy<PredicateBitset, ComplexMatcherMemFn, CustomRendererFn>
&ExecInfo,
- const int64_t *MatchTable, const TargetInstrInfo &TII,
- MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI,
- const RegisterBankInfo &RBI, const PredicateBitset &AvailableFeatures,
- CodeGenCoverage *CoverageInfo, GISelChangeObserver *Observer) const {
+ MachineIRBuilder &Builder, const int64_t *MatchTable,
+ const TargetInstrInfo &TII, MachineRegisterInfo &MRI,
+ const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI,
+ const PredicateBitset &AvailableFeatures,
+ CodeGenCoverage *CoverageInfo) const {
+
+ // Setup observer
+ GIMatchTableObserver MTObserver;
+ GISelObserverWrapper Observer(&MTObserver);
+ if (auto *CurObs = Builder.getChangeObserver())
+ Observer.addObserver(CurObs);
+
+ // TODO: Set MF delegate?
+
+ // Setup builder.
+ auto RestoreOldObserver = Builder.setTemporaryChangeObserver(Observer);
uint64_t CurrentIdx = 0;
SmallVector<uint64_t, 4> OnFailResumeAt;
+ // We also record MachineInstrs manually in this vector so opcodes can address
+ // them.
+ SmallVector<MachineInstrBuilder, 4> OutMIs;
+
// Bypass the flag check on the instruction, and only look at the MCInstrDesc.
bool NoFPException = !State.MIs[0]->getDesc().mayRaiseFPException();
@@ -71,14 +88,16 @@ bool GIMatchTableExecutor::executeMatchTable(
return RejectAndResume;
};
- auto propagateFlags = [=](NewMIVector &OutMIs) {
- for (auto MIB : OutMIs) {
+ auto propagateFlags = [&]() {
+ for (auto *MI : MTObserver.CreatedInsts) {
// Set the NoFPExcept flag when no original matched instruction could
// raise an FP exception, but the new instruction potentially might.
uint16_t MIBFlags = Flags;
- if (NoFPException && MIB->mayRaiseFPException())
+ if (NoFPException && MI->mayRaiseFPException())
MIBFlags |= MachineInstr::NoFPExcept;
- MIB.setMIFlags(MIBFlags);
+ Observer.changingInstr(*MI);
+ MI->setFlags(MIBFlags);
+ Observer.changedInstr(*MI);
}
return true;
@@ -901,6 +920,7 @@ bool GIMatchTableExecutor::executeMatchTable(
OutMIs[NewInsnID] = MachineInstrBuilder(*State.MIs[OldInsnID]->getMF(),
State.MIs[OldInsnID]);
OutMIs[NewInsnID]->setDesc(TII.get(NewOpcode));
+ MTObserver.CreatedInsts.insert(OutMIs[NewInsnID]);
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIR_MutateOpcode(OutMIs["
<< NewInsnID << "], MIs[" << OldInsnID << "], "
@@ -914,8 +934,7 @@ bool GIMatchTableExecutor::executeMatchTable(
if (NewInsnID >= OutMIs.size())
OutMIs.resize(NewInsnID + 1);
- OutMIs[NewInsnID] = BuildMI(*State.MIs[0]->getParent(), State.MIs[0],
- MIMetadata(*State.MIs[0]), TII.get(Opcode));
+ OutMIs[NewInsnID] = Builder.buildInstr(Opcode);
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIR_BuildMI(OutMIs["
<< NewInsnID << "], " << Opcode << ")\n");
@@ -1239,8 +1258,11 @@ bool GIMatchTableExecutor::executeMatchTable(
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIR_EraseFromParent(MIs["
<< InsnID << "])\n");
- if (Observer)
- Observer->erasingInstr(*MI);
+ // If we're erasing the insertion point, ensure we don't leave a dangling
+ // pointer in the builder.
+ if (Builder.getInsertPt() == MI)
+ Builder.setInsertPt(*MI->getParent(), ++MI->getIterator());
+ Observer.erasingInstr(*MI);
MI->eraseFromParent();
break;
}
@@ -1269,11 +1291,9 @@ bool GIMatchTableExecutor::executeMatchTable(
Register Old = State.MIs[OldInsnID]->getOperand(OldOpIdx).getReg();
Register New = State.MIs[NewInsnID]->getOperand(NewOpIdx).getReg();
- if (Observer)
- Observer->changingAllUsesOfReg(MRI, Old);
+ Observer.changingAllUsesOfReg(MRI, Old);
MRI.replaceRegWith(Old, New);
- if (Observer)
- Observer->finishedChangingAllUsesOfReg();
+ Observer.finishedChangingAllUsesOfReg();
break;
}
case GIR_ReplaceRegWithTempReg: {
@@ -1288,11 +1308,9 @@ bool GIMatchTableExecutor::executeMatchTable(
Register Old = State.MIs[OldInsnID]->getOperand(OldOpIdx).getReg();
Register New = State.TempRegisters[TempRegID];
- if (Observer)
- Observer->changingAllUsesOfReg(MRI, Old);
+ Observer.changingAllUsesOfReg(MRI, Old);
MRI.replaceRegWith(Old, New);
- if (Observer)
- Observer->finishedChangingAllUsesOfReg();
+ Observer.finishedChangingAllUsesOfReg();
break;
}
case GIR_Coverage: {
@@ -1309,11 +1327,7 @@ bool GIMatchTableExecutor::executeMatchTable(
case GIR_Done:
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIR_Done\n");
- if (Observer) {
- for (MachineInstr *MI : OutMIs)
- Observer->createdInstr(*MI);
- }
- propagateFlags(OutMIs);
+ propagateFlags();
return true;
default:
llvm_unreachable("Unexpected command");
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h b/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h
index e7db9547f03b694..99b821406b0f893 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h
@@ -20,6 +20,7 @@
#include "llvm/CodeGen/TargetOpcodes.h"
#include "llvm/IR/DebugLoc.h"
#include "llvm/IR/Module.h"
+#include "llvm/Support/SaveAndRestore.h"
namespace llvm {
@@ -364,6 +365,15 @@ class MachineIRBuilder {
State.Observer = &Observer;
}
+ GISelChangeObserver *getChangeObserver() const { return State.Observer; }
+
+ // Replaces the change observer with \p Observer and returns an object that
+ // restores the old Observer on destruction.
+ SaveAndRestore<GISelChangeObserver *>
+ setTemporaryChangeObserver(GISelChangeObserver &Observer) {
+ return SaveAndRestore<GISelChangeObserver *>(State.Observer, &Observer);
+ }
+
void stopObservingChanges() { State.Observer = nullptr; }
bool isObservingChanges() const { return State.Observer != nullptr; }
diff --git a/llvm/lib/CodeGen/GlobalISel/GIMatchTableExecutor.cpp b/llvm/lib/CodeGen/GlobalISel/GIMatchTableExecutor.cpp
index 26752369a7711a1..c1ababb8ed852d0 100644
--- a/llvm/lib/CodeGen/GlobalISel/GIMatchTableExecutor.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/GIMatchTableExecutor.cpp
@@ -21,6 +21,10 @@
using namespace llvm;
+GIMatchTableExecutor::GIMatchTableObserver::~GIMatchTableObserver() {
+ // anchor
+}
+
GIMatchTableExecutor::MatcherState::MatcherState(unsigned MaxRenderers)
: Renderers(MaxRenderers) {}
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/combine-sdiv.mir b/llvm/test/CodeGen/AArch64/GlobalISel/combine-sdiv.mir
index e99ee84100a3991..13f9998952e6ed3 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/combine-sdiv.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/combine-sdiv.mir
@@ -22,10 +22,10 @@ body: |
; CHECK: liveins: $w0
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $w0
- ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 3
- ; CHECK-NEXT: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 -991146299
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = exact G_CONSTANT i32 3
+ ; CHECK-NEXT: [[C1:%[0-9]+]]:_(s32) = exact G_CONSTANT i32 -991146299
; CHECK-NEXT: [[ASHR:%[0-9]+]]:_(s32) = exact G_ASHR [[COPY]], [[C]](s32)
- ; CHECK-NEXT: [[MUL:%[0-9]+]]:_(s32) = G_MUL [[ASHR]], [[C1]]
+ ; CHECK-NEXT: [[MUL:%[0-9]+]]:_(s32) = exact G_MUL [[ASHR]], [[C1]]
; CHECK-NEXT: $w0 = COPY [[MUL]](s32)
; CHECK-NEXT: RET_ReallyLR implicit $w0
%0:_(s32) = COPY $w0
@@ -87,13 +87,13 @@ body: |
; CHECK: liveins: $q0
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:_(<4 x s32>) = COPY $q0
- ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 3
- ; CHECK-NEXT: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 -991146299
- ; CHECK-NEXT: [[C2:%[0-9]+]]:_(s32) = G_CONSTANT i32 954437177
- ; CHECK-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<4 x s32>) = G_BUILD_VECTOR [[C]](s32), [[C]](s32), [[C]](s32), [[C]](s32)
- ; CHECK-NEXT: [[BUILD_VECTOR1:%[0-9]+]]:_(<4 x s32>) = G_BUILD_VECTOR [[C1]](s32), [[C2]](s32), [[C1]](s32), [[C2]](s32)
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = exact G_CONSTANT i32 3
+ ; CHECK-NEXT: [[C1:%[0-9]+]]:_(s32) = exact G_CONSTANT i32 -991146299
+ ; CHECK-NEXT: [[C2:%[0-9]+]]:_(s32) = exact G_CONSTANT i32 954437177
+ ; CHECK-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<4 x s32>) = exact G_BUILD_VECTOR [[C]](s32), [[C]](s32), [[C]](s32), [[C]](s32)
+ ; CHECK-NEXT: [[BUILD_VECTOR1:%[0-9]+]]:_(<4 x s32>) = exact G_BUILD_VECTOR [[C1]](s32), [[C2]](s32), [[C1]](s32), [[C2]](s32)
; CHECK-NEXT: [[ASHR:%[0-9]+]]:_(<4 x s32>) = exact G_ASHR [[COPY]], [[BUILD_VECTOR]](<4 x s32>)
- ; CHECK-NEXT: [[MUL:%[0-9]+]]:_(<4 x s32>) = G_MUL [[ASHR]], [[BUILD_VECTOR1]]
+ ; CHECK-NEXT: [[MUL:%[0-9]+]]:_(<4 x s32>) = exact G_MUL [[ASHR]], [[BUILD_VECTOR1]]
; CHECK-NEXT: $q0 = COPY [[MUL]](<4 x s32>)
; CHECK-NEXT: RET_ReallyLR implicit $q0
%0:_(<4 x s32>) = COPY $q0
@@ -115,12 +115,12 @@ body: |
; CHECK: liveins: $q0
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:_(<4 x s32>) = COPY $q0
- ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 3
- ; CHECK-NEXT: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 -991146299
- ; CHECK-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<4 x s32>) = G_BUILD_VECTOR [[C]](s32), [[C]](s32), [[C]](s32), [[C]](s32)
- ; CHECK-NEXT: [[BUILD_VECTOR1:%[0-9]+]]:_(<4 x s32>) = G_BUILD_VECTOR [[C1]](s32), [[C1]](s32), [[C1]](s32), [[C1]](s32)
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = exact G_CONSTANT i32 3
+ ; CHECK-NEXT: [[C1:%[0-9]+]]:_(s32) = exact G_CONSTANT i32 -991146299
+ ; CHECK-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<4 x s32>) = exact G_BUILD_VECTOR [[C]](s32), [[C]](s32), [[C]](s32), [[C]](s32)
+ ; CHECK-NEXT: [[BUILD_VECTOR1:%[0-9]+]]:_(<4 x s32>) = exact G_BUILD_VECTOR [[C1]](s32), [[C1]](s32), [[C1]](s32), [[C1]](s32)
; CHECK-NEXT: [[ASHR:%[0-9]+]]:_(<4 x s32>) = exact G_ASHR [[COPY]], [[BUILD_VECTOR]](<4 x s32>)
- ; CHECK-NEXT: [[MUL:%[0-9]+]]:_(<4 x s32>) = G_MUL [[ASHR]], [[BUILD_VECTOR1]]
+ ; CHECK-NEXT: [[MUL:%[0-9]+]]:_(<4 x s32>) = exact G_MUL [[ASHR]], [[BUILD_VECTOR1]]
; CHECK-NEXT: $q0 = COPY [[MUL]](<4 x s32>)
; CHECK-NEXT: RET_ReallyLR implicit $q0
%0:_(<4 x s32>) = COPY $q0
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/prelegalizercombiner-ashr-shl-to-sext-inreg.mir b/llvm/test/CodeGen/AArch64/GlobalISel/prelegalizercombiner-ashr-shl-to-sext-inreg.mir
index 9e540390dd37f43..9176328d873e619 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/prelegalizercombiner-ashr-shl-to-sext-inreg.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/prelegalizercombiner-ashr-shl-to-sext-inreg.mir
@@ -15,7 +15,7 @@ body: |
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $w0
; CHECK-NEXT: [[TRUNC:%[0-9]+]]:_(s16) = G_TRUNC [[COPY]](s32)
- ; CHECK-NEXT: [[SEXT_INREG:%[0-9]+]]:_(s16) = G_SEXT_INREG [[TRUNC]], 8
+ ; CHECK-NEXT: [[SEXT_INREG:%[0-9]+]]:_(s16) = exact G_SEXT_INREG [[TRUNC]], 8
; CHECK-NEXT: [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[SEXT_INREG]](s16)
; CHECK-NEXT: $w0 = COPY [[ANYEXT]](s32)
; CHECK-NEXT: RET_ReallyLR implicit $w0
@@ -75,7 +75,7 @@ body: |
; CHECK: liveins: $d0
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:_(<4 x s16>) = COPY $d0
- ; CHECK-NEXT: [[SEXT_INREG:%[0-9]+]]:_(<4 x s16>) = G_SEXT_INREG [[COPY]], 8
+ ; CHECK-NEXT: [[SEXT_INREG:%[0-9]+]]:_(<4 x s16>) = exact G_SEXT_INREG [[COPY]], 8
; CHECK-NEXT: $d0 = COPY [[SEXT_INREG]](<4 x s16>)
; CHECK-NEXT: RET_ReallyLR implicit $d0
%0:_(<4 x s16>) = COPY $d0
diff --git a/llvm/test/CodeGen/AMDGPU/GlobalISel/combine-fma-add-mul-pre-legalize.mir b/llvm/test/CodeGen/AMDGPU/GlobalISel/combine-fma-add-mul-pre-legalize.mir
index ee775dc674cfecd..90df73e85c9e7c7 100644
--- a/llvm/test/CodeGen/AMDGPU/GlobalISel/combine-fma-add-mul-pre-legalize.mir
+++ b/llvm/test/CodeGen/AMDGPU/GlobalISel/combine-fma-add-mul-pre-legalize.mir
@@ -31,7 +31,7 @@ body: |
; GFX9-CONTRACT-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $vgpr0
; GFX9-CONTRACT-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $vgpr1
; GFX9-CONTRACT-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $vgpr2
- ; GFX9-CONTRACT-NEXT: [[FMA:%[0-9]+]]:_(s32) = G_FMA [[COPY]], [[COPY1]], [[COPY2]]
+ ; GFX9-CONTRACT-NEXT: [[FMA:%[0-9]+]]:_(s32) = reassoc G_FMA [[COPY]], [[COPY1]], [[COPY2]]
; GFX9-CONTRACT-NEXT: $vgpr0 = COPY [[FMA]](s32)
; GFX9-CONTRACT-NEXT: S_SETPC_B64_return $sgpr30_sgpr31, implicit $vgpr0
;
@@ -52,7 +52,7 @@ body: |
; GFX9-UNSAFE-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $vgpr0
; GFX9-UNSAFE-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $vgpr1
; GFX9-UNSAFE-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $vgpr2
- ; GFX9-UNSAFE-NEXT: [[FMA:%[0-9]+]]:_(s32) = G_FMA [[COPY]], [[COPY1]], [[COPY2]]
+ ; GFX9-UNSAFE-NEXT: [[FMA:%[0-9]+]]:_(s32) = reassoc G_FMA [[COPY]], [[COPY1]], [[COPY2]]
; GFX9-UNSAFE-NEXT: $vgpr0 = COPY [[FMA]](s32)
; GFX9-UNSAFE-NEXT: S_SETPC_B64_return $sgpr30_sgpr31, implicit $vgpr0
;
@@ -73,7 +73,7 @@ body: |
; GFX10-CONTRACT-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $vgpr0
; GFX10-CONTRACT-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $vgpr1
; GFX10-CONTRACT-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $vgpr2
- ; GFX10-CONTRACT-NEXT: [[FMA:%[0-9]+]]:_(s32) = G_FMA [[COPY]], [[COPY1]], [[COPY2]]
+ ; GFX10-CONTRACT-NEXT: [[FMA:%[0-9]+]]:_(s32) = reassoc G_FMA [[COPY]], [[COPY1]], [[COPY2]]
; GFX10-CONTRACT-NEXT: $vgpr0 = COPY [[FMA]](s32)
; GFX10-CONTRACT-NEXT: S_SETPC_B64_return $sgpr30_sgpr31, implicit $vgpr0
;
@@ -94,7 +94,7 @@ body: |
; GFX10-UNSAFE-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $vgpr0
; GFX10-UNSAFE-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $vgpr1
; GFX10-UNSAFE-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $vgpr2
- ; GFX10-UNSAFE-NEXT: [[FMA:%[0-9]+]]:_(s32) = G_FMA [[COPY]], [[COPY1]], [[COPY2]]
+ ; GFX10-UNSAFE-NEXT: [[FMA:%[0-9]+]]:_(s32) = reassoc G_FMA [[COPY]], [[COPY1]], [[COPY2]]
; GFX10-UNSAFE-NEXT: $vgpr0 = COPY [[FMA]](s32)
; GFX10-UNSAFE-NEXT: S_SETPC_B64_return $sgpr30_sgpr31, implicit $vgpr0
%0:_(s32) = COPY $vgpr0
@@ -129,7 +129,7 @@ body: |
; GFX9-CONTRACT-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $vgpr0
; GFX9-CONTRACT-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $vgpr1
; GFX9-CONTRACT-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $vgpr2
- ; GFX9-CONTRACT-NEXT: [[FMA:%[0-9]+]]:_(s32) = G_FMA [[COPY]], [[COPY1]], [[COPY2]]
+ ; GFX9-CONTRACT-NEXT: [[FMA:%[0-9]+]]:_(s32) = reassoc G_FMA [[COPY]], [[COPY1]], [[COPY2]]
; GFX9-CONTRACT-NEXT: $vgpr0 = COPY [[FMA]](s32)
; GFX9-CONTRACT-NEXT: S_SETPC_B64_return $sgpr30_sgpr31, implicit $vgpr0
;
@@ -150,7 +150,7 @@ body: |
; GFX9-UNSAFE-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $vgpr0
; GFX9-UNSAFE-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $vgpr1
; GFX9-UNSAFE-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $vgpr2
- ; GFX9-UNSAFE-NEXT: [[FMA:%[0-9]+]]:_(s32) = G_FMA [[COPY]], [[COPY1]], [[COPY2]]
+ ; GFX9-UNSAFE-NEXT: [[FMA:%[0-9]+]]:_(s32) = reassoc G_FMA [[COPY]], [[COPY1]], [[COPY2]]
; GFX9-UNSAFE-NEXT: $vgpr0 = COPY [[FMA]](s32)
; GFX9-UNSAFE-NEXT: S_SETPC_B64_return $sgpr30_sgpr31, implicit $vgpr0
;
@@ -171,7 +171,7 @@ body: |
; GFX10-CONTRACT-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $vgpr0
; GFX10-CONTRACT-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $vgpr1
; GFX10-CONTRACT-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $vgpr2
- ; GFX10-CONTRACT-NEXT: [[FMA:%[0-9]+]]:_(s32) = G_FMA [[COPY]], [[COPY1]], [[COPY2]]
+ ; GFX10-CONTRACT-NEXT: [[FMA:%[0-9]+]]:_(s32) = reassoc G_FMA [[COPY]], [[COPY1]], [[COPY2]]
; GFX10-CONTRACT-NEXT: $vgpr0 = COPY [[FMA]](s32)
; GFX10-CONTRACT-NEXT: S_SETPC_B64_return $sgpr30_sgpr31, implicit $vgpr0
;
@@ -192,7 +192,7 @@ body: |
; GFX10-UNSAFE-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $vgpr0
; GFX10-UNSAFE-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $vgpr1
; GFX10-UNSAFE-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $vgpr2
- ; GFX10-UNSAFE-NEXT: [[FMA:%[0-9]+]]:_(s32) = G_FMA [[COPY]], [[COPY1]], [[COPY2]]
+ ; GFX10-UNSAFE-NEXT: [[FMA:%[0-9]+]]:_(s32) = reassoc G_FMA [[COPY]], [[COPY1]], [[COPY2]]
; GFX10-UNSAFE-NEXT: $vgpr0 = COPY [[FMA]](s32)
; GFX10-UNSAFE-NEXT: S_SETPC_B64_return $sgpr30_sgpr31, implicit $vgpr0
%0:_(s32) = COPY $vgpr0
@@ -234,7 +234,7 @@ body: |
; GFX9-CONTRACT-NEXT: [[TRUNC1:%[0-9]+]]:_(s16) = G_TRUNC [[COPY1]](s32)
; GFX9-CONTRACT-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $vgpr2
; GFX9-CONTRACT-NEXT: [[TRUNC2:%[0-9]+]]:_(s16) = G_TRUNC [[COPY2]](s32)
- ; GFX9-CONTRACT-NEXT: [[FMA:%[0-9]+]]:_(s16) = G_FMA [[TRUNC]], [[TRUNC1]], [[TRUNC2]]
+ ; GFX9-CONTRACT-NEXT: [[FMA:%[0-9]+]]:_(s16) = reassoc G_FMA [[TRUNC]], [[TRUNC1]], [[TRUNC2]]
; GFX9-CONTRACT-NEXT: [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[FMA]](s16)
; GFX9-CONTRACT-NEXT: $vgpr0 = COPY [[ANYEXT]](s32)
; GFX9-CONTRACT-NEXT: S_SETPC_B64_return $sgpr30_sgpr31, implicit $vgpr0
@@ -263,7 +263,7 @@ body: |
; GFX9-UNSAFE-NEXT: [[TRUNC1:%[0-9]+]]:_(s16) = G_TRUNC [[COPY1]](s32)
; GFX9-UNSAFE-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $vgpr2
; GFX9-UNSAFE-NEXT: [[TRUNC2:%[0-9]+]]:_(s16) = G_TRUNC [[COPY2]](s32)
- ; GFX9-UNSAFE-NEXT: [[FMA:%[0-9]+]]:_(s16) = G_FMA [[TRUNC]], [[TRUNC1]], [[TRUNC2]]
+ ; GFX9-UNSAFE-NEXT: [[FMA:%[0-9]+]]:_(s16) = reassoc G_FMA [[TRUNC]], [[TRUNC1]], [[TRUNC2]]
; GFX9-UNSAFE-NEXT: [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[FMA]](s16)
; GFX9-UNSAFE-NEXT: $vgpr0 = COPY [[ANYEXT]](s32)
; GFX9-UNSAFE-NEXT: S_SETPC_B64_return $sgpr30_sgpr31, implicit $vgpr0
@@ -292,7 +292,7 @@ body: |
; GFX10-CONTRACT-NEXT: [[TRUNC1:%[0-9]+]]:_(s16) = G_TRUNC [[COPY1]](s32)
; GFX10-CONTRACT-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $vgpr2
; GFX10-CONTRACT-NEXT: [[TRUNC2:%[0-9]+]]:_(s16) = G_TRUNC [[COPY2]](s32)
- ; GFX10-CONTRACT-NEXT: [[FMA:%[0-9]+]]:_(s16) = G_FMA [[TRUNC]], [[TRUNC1]], [[TRUNC2]]
+ ; GFX10-CONTRACT-NEXT: [[FMA:%[0-9]+]]:_(s16) = reassoc G_FMA [[TRUNC]], [[TRUNC1]], [[TRUNC2]]
; GFX10-CONTRACT-NEXT: [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[FMA]](s16)
; GFX10-CONTRACT-NEXT: $vgpr0 = COPY [[ANYEXT]](s32)
; GFX10-CONTRACT-NEXT: S_SETPC_B64_return $sgpr30_sgpr31, implicit $vgpr0
@@ -321,7 +321,7 @@ body: |
; GFX10-UNSAFE-NEXT: [[TRUNC1:%[0-9]+]]:_(s16) = G_TRUNC [[COPY1]](s32)
; GFX10-UNSAFE-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $vgpr2
; GFX10-UNSAFE-NEXT: [[TRUNC2:%[0-9]+]]:_(s16) = G_TRUNC [[COPY2]](s32)
- ; GFX10-UNSAFE-NEXT: [[FMA:%[0-9]+]]:_(s16) = G_FMA [[TRUNC]], [[TRUNC1]], [[TRUNC2]]
+ ; GFX10-UNSAFE-NEXT: [[FMA:%[0-9]+]]:_(s16) = reassoc G_FMA [[TRUNC]], [[TRUNC1]], [[TRUNC2]]
; GFX10-UNSAFE-NEXT: [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[FMA]](s16)
; GFX10-UNSAFE-NEXT: $vgpr0 = COPY [[ANYEXT]](s32)
; GFX10-UNSAFE-NEXT: S_SETPC_B64_return $sgpr30_sgpr31, implicit $vgpr0
@@ -368,7 +368,7 @@ body: |
; GFX9-CONTRACT-NEXT: [[TRUNC1:%[0-9]+]]:_(s16) = G_TRUNC [[COPY1]](s32)
; GFX9-CONTRACT-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $vgpr2
; GFX9-CONTRACT-NEXT: [[TRUNC2:%[0-9]+]]:_(s16) = G_TRUNC [[COPY2]](s32)
- ; GFX9-CONTRACT-NEXT: [[FMA:%[0-9]+]]:_(s16) = G_FMA [[TRUNC]], [[TRUNC1]], [[TRUNC2]]
+ ; GFX9-CONTRACT-NEXT: [[FMA:%[0-9]+]]:_(s16) = reassoc G_FMA [[TRUNC]], [[TRUNC1]], [[TRUNC2]]
; GFX9-CONTRACT-NEXT: [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[FMA]](s16)
; GFX9-CONTRACT-NEXT: $vgpr0 = COPY [[ANYEXT]](s32)
; GFX9-CONTRACT-NEXT: S_SETPC_B64_return $sgpr30_sgpr31, implicit $vgpr0
@@ -397,7 +397,7 @@ body: |
; GFX9-UNSAFE-NEXT: [[TRUNC1:%[0-9]+]]:_(s16) = G_TRUNC [[COPY1]](s32)
; GFX9-UNSAFE-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $vgpr2
; GFX9-UNSAFE-NEXT: [[TRUNC2:%[0-9]+]]:_(s16) = G_TRUNC [[COPY2]](s32)
- ; GFX9-UNSAFE-NEXT: [[FMA:%[0-9]+]]:_(s16) = G_FMA [[TRUNC]], [[TRUNC1]], [[TRUNC2]]
+ ; GFX9-UNSAFE-NEXT: [[FMA:%[0-9]+]]:_(s16) = reassoc G_FMA [[TRUNC]], [[TRUNC1]], [[TRUNC2]]
; GFX9-UNSAFE-NEXT: [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[FMA]](s16)
; GFX9-UNSAFE-NEXT: $vgpr0 = COPY [[ANYEXT]](s32)
; GFX9-UNSAFE-NEXT: S_SETPC_B64_return $sgpr30_sgpr31, implicit $vgpr0
@@ -426,7 +426,7 @@ body: |
; GFX10-CONTRACT-NEXT: [[TRUNC1:%[0-9]+]]:_(s16) = G_TRUNC [[COPY1]](s32)
; GFX10-CONTRACT-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $vgpr2
; GFX10-CONTRACT-NEXT: [[TRUNC2:%[0-9]+]]:_(s16) = G_TRUNC [[COPY2]](s32)
- ; GFX10-CONTRACT-NEXT: [[FMA:%[0-9]+]]:_(s16) = G_FMA [[TRUNC]], [[TRUNC1]], [[TRUNC2]]
+ ; GFX10-CONTRACT-NEXT: [[FMA:%[0-9]+]]:_(s16) = reassoc G_FMA [[TRUNC]], [[TRUNC1]], [[TRUNC2]]
; GFX10-CONTRACT-NEXT: [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[FMA]](s16)
; GFX10-CONTRACT-NEXT: $vgpr0 = COPY [[ANYEXT]](s32)
; GFX10-CONTRACT-NEXT: S_SETPC_B64_return $sgpr30_sgpr31, implicit $vgpr0
@@ -455,7 +455,7 @@ body: |
; GFX10-UNSAFE-NEXT: [[TRUNC1:%[0-9]+]]:_(s16) = G_TRUNC [[COPY1]](s32)
; GFX10-UNSAFE-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $vgpr2
; GFX10-UNSAFE-NEXT: [[TRUNC2:%[0-9]+]]:_(s16) = G_TRUNC [[COPY2]](s32)
- ; GFX10-UNSAFE-NEXT: [[FMA:%[0-9]+]]:_(s16) = G_FMA [[TRUNC]], [[TRUNC1]], [[TRUNC2]]
+ ; GFX10-UNSAFE-NEXT: [[FMA:%[0-9]+]]:_(s16) = reassoc G_FMA [[TRUNC]], [[TRUNC1]], [[TRUNC2]]
; GFX10-UNSAFE-NEXT: [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[FMA]](s16)
; GFX10-UNSAFE-NEXT: $vgpr0 = COPY [[ANYEXT]](s32)
; GFX10-UNSAFE-NEXT: S_SETPC_B64_return $sgpr30_sgpr31, implicit $vgpr0
@@ -509,7 +509,7 @@ body: |
; GFX9-CONTRACT-NEXT: [[COPY4:%[0-9]+]]:_(s32) = COPY $vgpr4
; GFX9-CONTRACT-NEXT: [[COPY5:%[0-9]+]]:_(s32) = COPY $vgpr5
; GFX9-CONTRACT-NEXT: [[MV2:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY4]](s32), [[COPY5]](s32)
- ; GFX9-CONTRACT-NEXT: [[FMA:%[0-9]+]]:_(s64) = G_FMA [[MV]], [[MV1]], [[MV2]]
+ ; GFX9-CONTRACT-NEXT: [[FMA:%[0-9]+]]:_(s64) = reassoc G_FMA [[MV]], [[MV1]], [[MV2]]
; GFX9-CONTRACT-NEXT: [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[FMA]](s64)
; GFX9-CONTRACT-NEXT: $vgpr0 = COPY [[UV]](s32)
; GFX9-CONTRACT-NEXT: $vgpr1 = COPY [[UV1]](s32)
@@ -546,7 +546,7 @@ body: |
; GFX9-UNSAFE-NEXT: [[COPY4:%[0-9]+]]:_(s32) = COPY $vgpr4
; GFX9-UNSAFE-NEXT: [[COPY5:%[0-9]+]]:_(s32) = COPY $vgpr5
; GFX9-UNSAFE-NEXT: [[MV2:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY4]](s32), [[COPY5]](s32)
- ; GFX9-UNSAFE-NEXT: [[FMA:%[0-9]+]]:_(s64) = G_FMA [[MV]], [[MV1]], [[MV2]]
+ ; GFX9-UNSAFE-NEXT: [[FMA:%[0-9]+]]:_(s64) = reassoc G_FMA [[MV]], [[MV1]], [[MV2]]
; GFX9-UNSAFE-NEXT: [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[FMA]](s64)
; GFX9-UNSAFE-NEXT: $vgpr0 = COPY [[UV]](s32)
; GFX9-UNSAFE-NEXT: $vgpr1 = COPY [[UV1]](s32)
@@ -583,7 +583,7 @@ body: |
; GFX10-CONTRACT-NEXT: [[COPY4:%[0-9]+]]:_(s32) = COPY $vgpr4
; GFX10-CONTRACT-NEXT: [[COPY5:%[0-9]+]]:_(s32) = COPY $vgpr5
; GFX10-CONTRACT-NEXT: [[MV2:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY4]](s32), [[COPY5]](s32)
- ; GFX10-CONTRACT-NEXT: [[FMA:%[0-9]+]]:_(s64) = G_FMA [[MV]], [[MV1]], [[MV2]]
+ ; GFX10-CONTRACT-NEXT: [[FMA:%[0-9]+]]:_(s64) = reassoc G_FMA [[MV]], [[MV1]], [[MV2]]
; GFX10-CONTRACT-NEXT: [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[FMA]](s64)
; GFX10-CONTRACT-NEXT: $vgpr0 = COPY [[UV]](s32)
; GFX10-CONTRACT-NEXT: $vgpr1 = COPY [[UV1]](s32)
@@ -620,7 +620,7 @@ body: |
; GFX10-UNSAFE-NEXT: [[COPY4:%[0-9]+]]:_(s32) = COPY $vgpr4
; GFX10-UNSAFE-NEXT: [[COPY5:%[0-9]+]]:_(s32) = COPY $vgpr5
; GFX10-UNSAFE-NEXT: [[MV2:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY4]](s32), [[COPY5]](s32)
- ; GFX10-UNSAFE-NEXT: [[FMA:%[0-9]+]]:_(s64) = G_FMA [[MV]], [[MV1]], [[MV2]]
+ ; GFX10-UNSAFE-NEXT: [[FMA:%[0-9]+]]:_(s64) = reassoc G_FMA [[MV]], [[MV1]], [[MV2]]
; GFX10-UNSAFE-NEXT: [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[FMA]](s64)
; GFX10-UNSAFE-NEXT: $vgpr0 = COPY [[UV]](s32)
; GFX10-UNSAFE-NEXT: $vgpr1 = COPY [[UV1]](s32)
@@ -679,7 +679,7 @@ body: |
; GFX9-CONTRACT-NEXT: [[COPY4:%[0-9]+]]:_(s32) = COPY $vgpr4
; GFX9-CONTRACT-NEXT: [[COPY5:%[0-9]+]]:_(s32) = COPY $vgpr5
; GFX9-CONTRACT-NEXT: [[MV2:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY4]](s32), [[COPY5]](s32)
- ; GFX9-CONTRACT-NEXT: [[FMA:%[0-9]+]]:_(s64) = G_FMA [[MV]], [[MV1]], [[MV2]]
+ ; GFX9-CONTRACT-NEXT: [[FMA:%[0-9]+]]:_(s64) = reassoc G_FMA [[MV]], [[MV1]], [[MV2]]
; GFX9-CONTRACT-NEXT: [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[FMA]](s64)
; GFX9-CONTRACT-NEXT: $vgpr0 = COPY [[UV]](s32)
; GFX9-CONTRACT-NEXT: $vgpr1 = COPY [[UV1]](s32)
@@ -716,7 +716,7 @@ body: |
; GFX9-UNSAFE-NEXT: [[COPY4:%[0-9]+]]:_(s32) = COPY $vgpr4
; GFX9-UNSAFE-NEXT: [[COPY5:%[0-9]+]]:_(s32) = COPY $vgpr5
; GFX9-UNSAFE-NEXT: [[MV2:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY4]](s32), [[COPY5]](s32)
- ; GFX9-UNSAFE-NEXT: [[FMA:%[0-9]+]]:_(s64) = G_FMA [[MV]], [[MV1]], [[MV2]]
+ ; GFX9-UNSAFE-NEXT: [[FMA:%[0-9]+]]:_(s64) = reassoc G_FMA [[MV]], [[MV1]], [[MV2]]
; GFX9-UNSAFE-NEXT: [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[FMA]](s64)
; GFX9-UNSAFE-NEXT: $vgpr0 = COPY [[UV]](s32)
; GFX9-UNSAFE-NEXT: $vgpr1 = COPY [[UV1]](s32)
@@ -753,7 +753,7 @@ body: |
; GFX10-CONTRACT-NEXT: [[COPY4:%[0-9]+]]:_(s32) = COPY $vgpr4
; GFX10-CONTRACT-NEXT: [[COPY5:%[0-9]+]]:_(s32) = COPY $vgpr5
; GFX10-CONTRACT-NEXT: [[MV2:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY4]](s32), [[COPY5]](s32)
- ; GFX10-CONTRACT-NEXT: [[FMA:%[0-9]+]]:_(s64) = G_FMA [[MV]], [[MV1]], [[MV2]]
+ ; GFX10-CONTRACT-NEXT: [[FMA:%[0-9]+]]:_(s64) = reassoc G_FMA [[MV]], [[MV1]], [[MV2]]
; GFX10-CONTRACT-NEXT: [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[FMA]](s64)
; GFX10-CONTRACT-NEXT: $vgpr0 = COPY [[UV]](s32)
; GFX10-CONTRACT-NEXT: $vgpr1 = COPY [[UV1]](s32)
@@ -790,7 +790,7 @@ body: |
; GFX10-UNSAFE-NEXT: [[COPY4:%[0-9]+]]:_(s32) = COPY $vgpr4
; GFX10-UNSAFE-NEXT: [[COPY5:%[0-9]+]]:_(s32) = COPY $vgpr5
; GFX10-UNSAFE-NEXT: [[MV2:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY4]](s32), [[COPY5]](s32)
- ; GFX10-UNSAFE-NEXT: [[FMA:%[0-9]+]]:_(s64) = G_FMA [[MV]], [[MV1]], [[MV2]]
+ ; GFX10-UNSAFE-NEXT: [[FMA:%[0-9]+]]:_(s64) = reassoc G_FMA [[MV]], [[MV1]], [[MV2]]
; GFX10-UNSAFE-NEXT: [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[FMA]](s64)
; GFX10-UNSAFE-NEXT: $vgpr0 = COPY [[UV]](s32)
; GFX10-UNSAFE-NEXT: $vgpr1 = COPY [[UV1]](s32)
@@ -863,7 +863,7 @@ body: |
; GFX9-CONTRACT-NEXT: [[COPY10:%[0-9]+]]:_(s32) = COPY $vgpr10
; GFX9-CONTRACT-NEXT: [[COPY11:%[0-9]+]]:_(s32) = COPY $vgpr11
; GFX9-CONTRACT-NEXT: [[BUILD_VECTOR2:%[0-9]+]]:_(<4 x s32>) = G_BUILD_VECTOR [[COPY8]](s32), [[COPY9]](s32), [[COPY10]](s32), [[COPY11]](s32)
- ; GFX9-CONTRACT-NEXT: [[FMA:%[0-9]+]]:_(<4 x s32>) = G_FMA [[BUILD_VECTOR]], [[BUILD_VECTOR1]], [[BUILD_VECTOR2]]
+ ; GFX9-CONTRACT-NEXT: [[FMA:%[0-9]+]]:_(<4 x s32>) = reassoc G_FMA [[BUILD_VECTOR]], [[BUILD_VECTOR1]], [[BUILD_VECTOR2]]
; GFX9-CONTRACT-NEXT: [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32), [[UV2:%[0-9]+]]:_(s32), [[UV3:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[FMA]](<4 x s32>)
; GFX9-CONTRACT-NEXT: $vgpr0 = COPY [[UV]](s32)
; GFX9-CONTRACT-NEXT: $vgpr1 = COPY [[UV1]](s32)
@@ -916,7 +916,7 @@ body: |
; GFX9-UNSAFE-NEXT: [[COPY10:%[0-9]+]]:_(s32) = COPY $vgpr10
; GFX9-UNSAFE-NEXT: [[COPY11:%[0-9]+]]:_(s32) = COPY $vgpr11
; GFX9-UNSAFE-NEXT: [[BUILD_VECTOR2:%[0-9]+]]:_(<4 x s32>) = G_BUILD_VECTOR [[COPY8]](s32), [[COPY9]](s32), [[COPY10]](s32), [[COPY11]](s32)
- ; GFX9-UNSAFE-NEXT: [[FMA:%[0-9]+]]:_(<4 x s32>) = G_FMA [[BUILD_VECTOR]], [[BUILD_VECTOR1]], [[BUILD_VECTOR2]]
+ ; GFX9-UNSAFE-NEXT: [[FMA:%[0-9]+]]:_(<4 x s32>) = reassoc G_FMA [[BUILD_VECTOR]], [[BUILD_VECTOR1]], [[BUILD_VECTOR2]]
; GFX9-UNSAFE-NEXT: [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32), [[UV2:%[0-9]+]]:_(s32), [[UV3:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[FMA]](<4 x s32>)
; GFX9-UNSAFE-NEXT: $vgpr0 = COPY [[UV]](s32)
; GFX9-UNSAFE-NEXT: $vgpr1 = COPY [[UV1]](s32)
@@ -969,7 +969,7 @@ body: |
; GFX10-CONTRACT-NEXT: [[COPY10:%[0-9]+]]:_(s32) = COPY $vgpr10
; GFX10-CONTRACT-NEXT: [[COPY11:%[0-9]+]]:_(s32) = COPY $vgpr11
; GFX10-CONTRACT-NEXT: [[BUILD_VECTOR2:%[0-9]+]]:_(<4 x s32>) = G_BUILD_VECTOR [[COPY8]](s32), [[COPY9]](s32), [[COPY10]](s32), [[COPY11]](s32)
- ; GFX10-CONTRACT-NEXT: [[FMA:%[0-9]+]]:_(<4 x s32>) = G_FMA [[BUILD_VECTOR]], [[BUILD_VECTOR1]], [[BUILD_VECTOR2]]
+ ; GFX10-CONTRACT-NEXT: [[FMA:%[0-9]+]]:_(<4 x s32>) = reassoc G_FMA [[BUILD_VECTOR]], [[BUILD_VECTOR1]], [[BUILD_VECTOR2]]
; GFX10-CONTRACT-NEXT: [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32), [[UV2:%[0-9]+]]:_(s32), [[UV3:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[FMA]](<4 x s32>)
; GFX10-CONTRACT-NEXT: $vgpr0 = COPY [[UV]](s32)
; GFX10-CONTRACT-NEXT: $vgpr1 = COPY [[UV1]](s32)
@@ -1022,7 +1022,7 @@ body: |
; GFX10-UNSAFE-NEXT: [[COPY10:%[0-9]+]]:_(s32) = COPY $vgpr10
; GFX10-UNSAFE-NEXT: [[COPY11:%[0-9]+]]:_(s32) = COPY $vgpr11
; GFX10-UNSAFE-NEXT: [[BUILD_VECTOR2:%[0-9]+]]:_(<4 x s32>) = G_BUILD_VECTOR [[COPY8]](s32), [[COPY9]](s32), [[COPY10]](s32), [[COPY11]](s32)
- ; GFX10-UNSAFE-NEXT: [[FMA:%[0-9]+]]:_(<4 x s32>) = G_FMA [[BUILD_VECTOR]], [[BUILD_VECTOR1]], [[BUILD_VECTOR2]]
+ ; GFX10-UNSAFE-NEXT: [[FMA:%[0-9]+]]:_(<4 x s32>) = reassoc G_FMA [[BUILD_VECTOR]], [[BUILD_VECTOR1]], [[BUILD_VECTOR2]]
; GFX10-UNSAFE-NEXT: [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32), [[UV2:%[0-9]+]]:_(s32), [[UV3:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[FMA]](<4 x s32>)
; GFX10-UNSAFE-NEXT: $vgpr0 = COPY [[UV]](s32)
; GFX10-UNSAFE-NEXT: $vgpr1 = COPY [[UV1]](s32)
@@ -1098,7 +1098,7 @@ body: |
; GFX9-CONTRACT-NEXT: [[COPY7:%[0-9]+]]:_(s32) = COPY $vgpr7
; GFX9-CONTRACT-NEXT: [[COPY8:%[0-9]+]]:_(s32) = COPY $vgpr8
; GFX9-CONTRACT-NEXT: [[BUILD_VECTOR2:%[0-9]+]]:_(<3 x s32>) = G_BUILD_VECTOR [[COPY6]](s32), [[COPY7]](s32), [[COPY8]](s32)
- ; GFX9-CONTRACT-NEXT: [[FMA:%[0-9]+]]:_(<3 x s32>) = G_FMA [[BUILD_VECTOR]], [[BUILD_VECTOR1]], [[BUILD_VECTOR2]]
+ ; GFX9-CONTRACT-NEXT: [[FMA:%[0-9]+]]:_(<3 x s32>) = reassoc G_FMA [[BUILD_VECTOR]], [[BUILD_VECTOR1]], [[BUILD_VECTOR2]]
; GFX9-CONTRACT-NEXT: [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32), [[UV2:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[FMA]](<3 x s32>)
; GFX9-CONTRACT-NEXT: $vgpr0 = COPY [[UV]](s32)
; GFX9-CONTRACT-NEXT: $vgpr1 = COPY [[UV1]](s32)
@@ -1143,7 +1143,7 @@ body: |
; GFX9-UNSAFE-NEXT: [[COPY7:%[0-9]+]]:_(s32) = COPY $vgpr7
; GFX9-UNSAFE-NEXT: [[COPY8:%[0-9]+]]:_(s32) = COPY $vgpr8
; GFX9-UNSAFE-NEXT: [[BUILD_VECTOR2:%[0-9]+]]:_(<3 x s32>) = G_BUILD_VECTOR [[COPY6]](s32), [[COPY7]](s32), [[COPY8]](s32)
- ; GFX9-UNSAFE-NEXT: [[FMA:%[0-9]+]]:_(<3 x s32>) = G_FMA [[BUILD_VECTOR]], [[BUILD_VECTOR1]], [[BUILD_VECTOR2]]
+ ; GFX9-UNSAFE-NEXT: [[FMA:%[0-9]+]]:_(<3 x s32>) = reassoc G_FMA [[BUILD_VECTOR]], [[BUILD_VECTOR1]], [[BUILD_VECTOR2]]
; GFX9-UNSAFE-NEXT: [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32), [[UV2:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[FMA]](<3 x s32>)
; GFX9-UNSAFE-NEXT: $vgpr0 = COPY [[UV]](s32)
; GFX9-UNSAFE-NEXT: $vgpr1 = COPY [[UV1]](s32)
@@ -1188,7 +1188,7 @@ body: |
; GFX10-CONTRACT-NEXT: [[COPY7:%[0-9]+]]:_(s32) = COPY $vgpr7
; GFX10-CONTRACT-NEXT: [[COPY8:%[0-9]+]]:_(s32) = COPY $vgpr8
; GFX10-CONTRACT-NEXT: [[BUILD_VECTOR2:%[0-9]+]]:_(<3 x s32>) = G_BUILD_VECTOR [[COPY6]](s32), [[COPY7]](s32), [[COPY8]](s32)
- ; GFX10-CONTRACT-NEXT: [[FMA:%[0-9]+]]:_(<3 x s32>) = G_FMA [[BUILD_VECTOR]], [[BUILD_VECTOR1]], [[BUILD_VECTOR2]]
+ ; GFX10-CONTRACT-NEXT: [[FMA:%[0-9]+]]:_(<3 x s32>) = reassoc G_FMA [[BUILD_VECTOR]], [[BUILD_VECTOR1]], [[BUILD_VECTOR2]]
; GFX10-CONTRACT-NEXT: [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32), [[UV2:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[FMA]](<3 x s32>)
; GFX10-CONTRACT-NEXT: $vgpr0 = COPY [[UV]](s32)
; GFX10-CONTRACT-NEXT: $vgpr1 = COPY [[UV1]](s32)
@@ -1233,7 +1233,7 @@ body: |
; GFX10-UNSAFE-NEXT: [[COPY7:%[0-9]+]]:_(s32) = COPY $vgpr7
; GFX10-UNSAFE-NEXT: [[COPY8:%[0-9]+]]:_(s32) = COPY $vgpr8
; GFX10-UNSAFE-NEXT: [[BUILD_VECTOR2:%[0-9]+]]:_(<3 x s32>) = G_BUILD_VECTOR [[COPY6]](s32), [[COPY7]](s32), [[COPY8]](s32)
- ; GFX10-UNSAFE-NEXT: [[FMA:%[0-9]+]]:_(<3 x s32>) = G_FMA [[BUILD_VECTOR]], [[BUILD_VECTOR1]], [[BUILD_VECTOR2]]
+ ; GFX10-UNSAFE-NEXT: [[FMA:%[0-9]+]]:_(<3 x s32>) = reassoc G_FMA [[BUILD_VECTOR]], [[BUILD_VECTOR1]], [[BUILD_VECTOR2]]
; GFX10-UNSAFE-NEXT: [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32), [[UV2:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[FMA]](<3 x s32>)
; GFX10-UNSAFE-NEXT: $vgpr0 = COPY [[UV]](s32)
; GFX10-UNSAFE-NEXT: $vgpr1 = COPY [[UV1]](s32)
@@ -1297,7 +1297,7 @@ body: |
; GFX9-CONTRACT-NEXT: [[COPY4:%[0-9]+]]:_(<2 x s16>) = COPY $vgpr4
; GFX9-CONTRACT-NEXT: [[COPY5:%[0-9]+]]:_(<2 x s16>) = COPY $vgpr5
; GFX9-CONTRACT-NEXT: [[CONCAT_VECTORS2:%[0-9]+]]:_(<4 x s16>) = G_CONCAT_VECTORS [[COPY4]](<2 x s16>), [[COPY5]](<2 x s16>)
- ; GFX9-CONTRACT-NEXT: [[FMA:%[0-9]+]]:_(<4 x s16>) = G_FMA [[CONCAT_VECTORS]], [[CONCAT_VECTORS1]], [[CONCAT_VECTORS2]]
+ ; GFX9-CONTRACT-NEXT: [[FMA:%[0-9]+]]:_(<4 x s16>) = reassoc G_FMA [[CONCAT_VECTORS]], [[CONCAT_VECTORS1]], [[CONCAT_VECTORS2]]
; GFX9-CONTRACT-NEXT: [[UV:%[0-9]+]]:_(<2 x s16>), [[UV1:%[0-9]+]]:_(<2 x s16>) = G_UNMERGE_VALUES [[FMA]](<4 x s16>)
; GFX9-CONTRACT-NEXT: $vgpr0 = COPY [[UV]](<2 x s16>)
; GFX9-CONTRACT-NEXT: $vgpr1 = COPY [[UV1]](<2 x s16>)
@@ -1334,7 +1334,7 @@ body: |
; GFX9-UNSAFE-NEXT: [[COPY4:%[0-9]+]]:_(<2 x s16>) = COPY $vgpr4
; GFX9-UNSAFE-NEXT: [[COPY5:%[0-9]+]]:_(<2 x s16>) = COPY $vgpr5
; GFX9-UNSAFE-NEXT: [[CONCAT_VECTORS2:%[0-9]+]]:_(<4 x s16>) = G_CONCAT_VECTORS [[COPY4]](<2 x s16>), [[COPY5]](<2 x s16>)
- ; GFX9-UNSAFE-NEXT: [[FMA:%[0-9]+]]:_(<4 x s16>) = G_FMA [[CONCAT_VECTORS]], [[CONCAT_VECTORS1]], [[CONCAT_VECTORS2]]
+ ; GFX9-UNSAFE-NEXT: [[FMA:%[0-9]+]]:_(<4 x s16>) = reassoc G_FMA [[CONCAT_VECTORS]], [[CONCAT_VECTORS1]], [[CONCAT_VECTORS2]]
; GFX9-UNSAFE-NEXT: [[UV:%[0-9]+]]:_(<2 x s16>), [[UV1:%[0-9]+]]:_(<2 x s16>) = G_UNMERGE_VALUES [[FMA]](<4 x s16>)
; GFX9-UNSAFE-NEXT: $vgpr0 = COPY [[UV]](<2 x s16>)
; GFX9-UNSAFE-NEXT: $vgpr1 = COPY [[UV1]](<2 x s16>)
@@ -1371,7 +1371,7 @@ body: |
; GFX10-CONTRACT-NEXT: [[COPY4:%[0-9]+]]:_(<2 x s16>) = COPY $vgpr4
; GFX10-CONTRACT-NEXT: [[COPY5:%[0-9]+]]:_(<2 x s16>) = COPY $vgpr5
; GFX10-CONTRACT-NEXT: [[CONCAT_VECTORS2:%[0-9]+]]:_(<4 x s16>) = G_CONCAT_VECTORS [[COPY4]](<2 x s16>), [[COPY5]](<2 x s16>)
- ; GFX10-CONTRACT-NEXT: [[FMA:%[0-9]+]]:_(<4 x s16>) = G_FMA [[CONCAT_VECTORS]], [[CONCAT_VECTORS1]], [[CONCAT_VECTORS2]]
+ ; GFX10-CONTRACT-NEXT: [[FMA:%[0-9]+]]:_(<4 x s16>) = reassoc G_FMA [[CONCAT_VECTORS]], [[CONCAT_VECTORS1]], [[CONCAT_VECTORS2]]
; GFX10-CONTRACT-NEXT: [[UV:%[0-9]+]]:_(<2 x s16>), [[UV1:%[0-9]+]]:_(<2 x s16>) = G_UNMERGE_VALUES [[FMA]](<4 x s16>)
; GFX10-CONTRACT-NEXT: $vgpr0 = COPY [[UV]](<2 x s16>)
; GFX10-CONTRACT-NEXT: $vgpr1 = COPY [[UV1]](<2 x s16>)
@@ -1408,7 +1408,7 @@ body: |
; GFX10-UNSAFE-NEXT: [[COPY4:%[0-9]+]]:_(<2 x s16>) = COPY $vgpr4
; GFX10-UNSAFE-NEXT: [[COPY5:%[0-9]+]]:_(<2 x s16>) = COPY $vgpr5
; GFX10-UNSAFE-NEXT: [[CONCAT_VECTORS2:%[0-9]+]]:_(<4 x s16>) = G_CONCAT_VECTORS [[COPY4]](<2 x s16>), [[COPY5]](<2 x s16>)
- ; GFX10-UNSAFE-NEXT: [[FMA:%[0-9]+]]:_(<4 x s16>) = G_FMA [[CONCAT_VECTORS]], [[CONCAT_VECTORS1]], [[CONCAT_VECTORS2]]
+ ; GFX10-UNSAFE-NEXT: [[FMA:%[0-9]+]]:_(<4 x s16>) = reassoc G_FMA [[CONCAT_VECTORS]], [[CONCAT_VECTORS1]], [[CONCAT_VECTORS2]]
; GFX10-UNSAFE-NEXT: [[UV:%[0-9]+]]:_(<2 x s16>), [[UV1:%[0-9]+]]:_(<2 x s16>) = G_UNMERGE_VALUES [[FMA]](<4 x s16>)
; GFX10-UNSAFE-NEXT: $vgpr0 = COPY [[UV]](<2 x s16>)
; GFX10-UNSAFE-NEXT: $vgpr1 = COPY [[UV1]](<2 x s16>)
@@ -1489,7 +1489,7 @@ body: |
; GFX9-CONTRACT-NEXT: [[BITCAST4:%[0-9]+]]:_(s96) = G_BITCAST [[CONCAT_VECTORS2]](<6 x s16>)
; GFX9-CONTRACT-NEXT: [[TRUNC2:%[0-9]+]]:_(s48) = G_TRUNC [[BITCAST4]](s96)
; GFX9-CONTRACT-NEXT: [[BITCAST5:%[0-9]+]]:_(<3 x s16>) = G_BITCAST [[TRUNC2]](s48)
- ; GFX9-CONTRACT-NEXT: [[FMA:%[0-9]+]]:_(<3 x s16>) = G_FMA [[BITCAST1]], [[BITCAST3]], [[BITCAST5]]
+ ; GFX9-CONTRACT-NEXT: [[FMA:%[0-9]+]]:_(<3 x s16>) = reassoc G_FMA [[BITCAST1]], [[BITCAST3]], [[BITCAST5]]
; GFX9-CONTRACT-NEXT: [[DEF1:%[0-9]+]]:_(<3 x s16>) = G_IMPLICIT_DEF
; GFX9-CONTRACT-NEXT: [[CONCAT_VECTORS3:%[0-9]+]]:_(<6 x s16>) = G_CONCAT_VECTORS [[FMA]](<3 x s16>), [[DEF1]](<3 x s16>)
; GFX9-CONTRACT-NEXT: [[UV:%[0-9]+]]:_(<2 x s16>), [[UV1:%[0-9]+]]:_(<2 x s16>), [[UV2:%[0-9]+]]:_(<2 x s16>) = G_UNMERGE_VALUES [[CONCAT_VECTORS3]](<6 x s16>)
@@ -1550,7 +1550,7 @@ body: |
; GFX9-UNSAFE-NEXT: [[BITCAST4:%[0-9]+]]:_(s96) = G_BITCAST [[CONCAT_VECTORS2]](<6 x s16>)
; GFX9-UNSAFE-NEXT: [[TRUNC2:%[0-9]+]]:_(s48) = G_TRUNC [[BITCAST4]](s96)
; GFX9-UNSAFE-NEXT: [[BITCAST5:%[0-9]+]]:_(<3 x s16>) = G_BITCAST [[TRUNC2]](s48)
- ; GFX9-UNSAFE-NEXT: [[FMA:%[0-9]+]]:_(<3 x s16>) = G_FMA [[BITCAST1]], [[BITCAST3]], [[BITCAST5]]
+ ; GFX9-UNSAFE-NEXT: [[FMA:%[0-9]+]]:_(<3 x s16>) = reassoc G_FMA [[BITCAST1]], [[BITCAST3]], [[BITCAST5]]
; GFX9-UNSAFE-NEXT: [[DEF1:%[0-9]+]]:_(<3 x s16>) = G_IMPLICIT_DEF
; GFX9-UNSAFE-NEXT: [[CONCAT_VECTORS3:%[0-9]+]]:_(<6 x s16>) = G_CONCAT_VECTORS [[FMA]](<3 x s16>), [[DEF1]](<3 x s16>)
; GFX9-UNSAFE-NEXT: [[UV:%[0-9]+]]:_(<2 x s16>), [[UV1:%[0-9]+]]:_(<2 x s16>), [[UV2:%[0-9]+]]:_(<2 x s16>) = G_UNMERGE_VALUES [[CONCAT_VECTORS3]](<6 x s16>)
@@ -1611,7 +1611,7 @@ body: |
; GFX10-CONTRACT-NEXT: [[BITCAST4:%[0-9]+]]:_(s96) = G_BITCAST [[CONCAT_VECTORS2]](<6 x s16>)
; GFX10-CONTRACT-NEXT: [[TRUNC2:%[0-9]+]]:_(s48) = G_TRUNC [[BITCAST4]](s96)
; GFX10-CONTRACT-NEXT: [[BITCAST5:%[0-9]+]]:_(<3 x s16>) = G_BITCAST [[TRUNC2]](s48)
- ; GFX10-CONTRACT-NEXT: [[FMA:%[0-9]+]]:_(<3 x s16>) = G_FMA [[BITCAST1]], [[BITCAST3]], [[BITCAST5]]
+ ; GFX10-CONTRACT-NEXT: [[FMA:%[0-9]+]]:_(<3 x s16>) = reassoc G_FMA [[BITCAST1]], [[BITCAST3]], [[BITCAST5]]
; GFX10-CONTRACT-NEXT: [[DEF1:%[0-9]+]]:_(<3 x s16>) = G_IMPLICIT_DEF
; GFX10-CONTRACT-NEXT: [[CONCAT_VECTORS3:%[0-9]+]]:_(<6 x s16>) = G_CONCAT_VECTORS [[FMA]](<3 x s16>), [[DEF1]](<3 x s16>)
; GFX10-CONTRACT-NEXT: [[UV:%[0-9]+]]:_(<2 x s16>), [[UV1:%[0-9]+]]:_(<2 x s16>), [[UV2:%[0-9]+]]:_(<2 x s16>) = G_UNMERGE_VALUES [[CONCAT_VECTORS3]](<6 x s16>)
@@ -1672,7 +1672,7 @@ body: |
; GFX10-UNSAFE-NEXT: [[BITCAST4:%[0-9]+]]:_(s96) = G_BITCAST [[CONCAT_VECTORS2]](<6 x s16>)
; GFX10-UNSAFE-NEXT: [[TRUNC2:%[0-9]+]]:_(s48) = G_TRUNC [[BITCAST4]](s96)
; GFX10-UNSAFE-NEXT: [[BITCAST5:%[0-9]+]]:_(<3 x s16>) = G_BITCAST [[TRUNC2]](s48)
- ; GFX10-UNSAFE-NEXT: [[FMA:%[0-9]+]]:_(<3 x s16>) = G_FMA [[BITCAST1]], [[BITCAST3]], [[BITCAST5]]
+ ; GFX10-UNSAFE-NEXT: [[FMA:%[0-9]+]]:_(<3 x s16>) = reassoc G_FMA [[BITCAST1]], [[BITCAST3]], [[BITCAST5]]
; GFX10-UNSAFE-NEXT: [[DEF1:%[0-9]+]]:_(<3 x s16>) = G_IMPLICIT_DEF
; GFX10-UNSAFE-NEXT: [[CONCAT_VECTORS3:%[0-9]+]]:_(<6 x s16>) = G_CONCAT_VECTORS [[FMA]](<3 x s16>), [[DEF1]](<3 x s16>)
; GFX10-UNSAFE-NEXT: [[UV:%[0-9]+]]:_(<2 x s16>), [[UV1:%[0-9]+]]:_(<2 x s16>), [[UV2:%[0-9]+]]:_(<2 x s16>) = G_UNMERGE_VALUES [[CONCAT_VECTORS3]](<6 x s16>)
@@ -1805,7 +1805,7 @@ body: |
; GFX9-CONTRACT-NEXT: [[MV10:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY20]](s32), [[COPY21]](s32)
; GFX9-CONTRACT-NEXT: [[MV11:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY22]](s32), [[COPY23]](s32)
; GFX9-CONTRACT-NEXT: [[BUILD_VECTOR2:%[0-9]+]]:_(<4 x s64>) = G_BUILD_VECTOR [[MV8]](s64), [[MV9]](s64), [[MV10]](s64), [[MV11]](s64)
- ; GFX9-CONTRACT-NEXT: [[FMA:%[0-9]+]]:_(<4 x s64>) = G_FMA [[BUILD_VECTOR]], [[BUILD_VECTOR1]], [[BUILD_VECTOR2]]
+ ; GFX9-CONTRACT-NEXT: [[FMA:%[0-9]+]]:_(<4 x s64>) = reassoc G_FMA [[BUILD_VECTOR]], [[BUILD_VECTOR1]], [[BUILD_VECTOR2]]
; GFX9-CONTRACT-NEXT: [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32), [[UV2:%[0-9]+]]:_(s32), [[UV3:%[0-9]+]]:_(s32), [[UV4:%[0-9]+]]:_(s32), [[UV5:%[0-9]+]]:_(s32), [[UV6:%[0-9]+]]:_(s32), [[UV7:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[FMA]](<4 x s64>)
; GFX9-CONTRACT-NEXT: $vgpr0 = COPY [[UV]](s32)
; GFX9-CONTRACT-NEXT: $vgpr1 = COPY [[UV1]](s32)
@@ -1914,7 +1914,7 @@ body: |
; GFX9-UNSAFE-NEXT: [[MV10:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY20]](s32), [[COPY21]](s32)
; GFX9-UNSAFE-NEXT: [[MV11:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY22]](s32), [[COPY23]](s32)
; GFX9-UNSAFE-NEXT: [[BUILD_VECTOR2:%[0-9]+]]:_(<4 x s64>) = G_BUILD_VECTOR [[MV8]](s64), [[MV9]](s64), [[MV10]](s64), [[MV11]](s64)
- ; GFX9-UNSAFE-NEXT: [[FMA:%[0-9]+]]:_(<4 x s64>) = G_FMA [[BUILD_VECTOR]], [[BUILD_VECTOR1]], [[BUILD_VECTOR2]]
+ ; GFX9-UNSAFE-NEXT: [[FMA:%[0-9]+]]:_(<4 x s64>) = reassoc G_FMA [[BUILD_VECTOR]], [[BUILD_VECTOR1]], [[BUILD_VECTOR2]]
; GFX9-UNSAFE-NEXT: [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32), [[UV2:%[0-9]+]]:_(s32), [[UV3:%[0-9]+]]:_(s32), [[UV4:%[0-9]+]]:_(s32), [[UV5:%[0-9]+]]:_(s32), [[UV6:%[0-9]+]]:_(s32), [[UV7:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[FMA]](<4 x s64>)
; GFX9-UNSAFE-NEXT: $vgpr0 = COPY [[UV]](s32)
; GFX9-UNSAFE-NEXT: $vgpr1 = COPY [[UV1]](s32)
@@ -2023,7 +2023,7 @@ body: |
; GFX10-CONTRACT-NEXT: [[MV10:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY20]](s32), [[COPY21]](s32)
; GFX10-CONTRACT-NEXT: [[MV11:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY22]](s32), [[COPY23]](s32)
; GFX10-CONTRACT-NEXT: [[BUILD_VECTOR2:%[0-9]+]]:_(<4 x s64>) = G_BUILD_VECTOR [[MV8]](s64), [[MV9]](s64), [[MV10]](s64), [[MV11]](s64)
- ; GFX10-CONTRACT-NEXT: [[FMA:%[0-9]+]]:_(<4 x s64>) = G_FMA [[BUILD_VECTOR]], [[BUILD_VECTOR1]], [[BUILD_VECTOR2]]
+ ; GFX10-CONTRACT-NEXT: [[FMA:%[0-9]+]]:_(<4 x s64>) = reassoc G_FMA [[BUILD_VECTOR]], [[BUILD_VECTOR1]], [[BUILD_VECTOR2]]
; GFX10-CONTRACT-NEXT: [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32), [[UV2:%[0-9]+]]:_(s32), [[UV3:%[0-9]+]]:_(s32), [[UV4:%[0-9]+]]:_(s32), [[UV5:%[0-9]+]]:_(s32), [[UV6:%[0-9]+]]:_(s32), [[UV7:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[FMA]](<4 x s64>)
; GFX10-CONTRACT-NEXT: $vgpr0 = COPY [[UV]](s32)
; GFX10-CONTRACT-NEXT: $vgpr1 = COPY [[UV1]](s32)
@@ -2132,7 +2132,7 @@ body: |
; GFX10-UNSAFE-NEXT: [[MV10:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY20]](s32), [[COPY21]](s32)
; GFX10-UNSAFE-NEXT: [[MV11:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY22]](s32), [[COPY23]](s32)
; GFX10-UNSAFE-NEXT: [[BUILD_VECTOR2:%[0-9]+]]:_(<4 x s64>) = G_BUILD_VECTOR [[MV8]](s64), [[MV9]](s64), [[MV10]](s64), [[MV11]](s64)
- ; GFX10-UNSAFE-NEXT: [[FMA:%[0-9]+]]:_(<4 x s64>) = G_FMA [[BUILD_VECTOR]], [[BUILD_VECTOR1]], [[BUILD_VECTOR2]]
+ ; GFX10-UNSAFE-NEXT: [[FMA:%[0-9]+]]:_(<4 x s64>) = reassoc G_FMA [[BUILD_VECTOR]], [[BUILD_VECTOR1]], [[BUILD_VECTOR2]]
; GFX10-UNSAFE-NEXT: [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32), [[UV2:%[0-9]+]]:_(s32), [[UV3:%[0-9]+]]:_(s32), [[UV4:%[0-9]+]]:_(s32), [[UV5:%[0-9]+]]:_(s32), [[UV6:%[0-9]+]]:_(s32), [[UV7:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[FMA]](<4 x s64>)
; GFX10-UNSAFE-NEXT: $vgpr0 = COPY [[UV]](s32)
; GFX10-UNSAFE-NEXT: $vgpr1 = COPY [[UV1]](s32)
@@ -2279,7 +2279,7 @@ body: |
; GFX9-CONTRACT-NEXT: [[MV7:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY14]](s32), [[COPY15]](s32)
; GFX9-CONTRACT-NEXT: [[MV8:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY16]](s32), [[COPY17]](s32)
; GFX9-CONTRACT-NEXT: [[BUILD_VECTOR2:%[0-9]+]]:_(<3 x s64>) = G_BUILD_VECTOR [[MV6]](s64), [[MV7]](s64), [[MV8]](s64)
- ; GFX9-CONTRACT-NEXT: [[FMA:%[0-9]+]]:_(<3 x s64>) = G_FMA [[BUILD_VECTOR]], [[BUILD_VECTOR1]], [[BUILD_VECTOR2]]
+ ; GFX9-CONTRACT-NEXT: [[FMA:%[0-9]+]]:_(<3 x s64>) = reassoc G_FMA [[BUILD_VECTOR]], [[BUILD_VECTOR1]], [[BUILD_VECTOR2]]
; GFX9-CONTRACT-NEXT: [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32), [[UV2:%[0-9]+]]:_(s32), [[UV3:%[0-9]+]]:_(s32), [[UV4:%[0-9]+]]:_(s32), [[UV5:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[FMA]](<3 x s64>)
; GFX9-CONTRACT-NEXT: $vgpr0 = COPY [[UV]](s32)
; GFX9-CONTRACT-NEXT: $vgpr1 = COPY [[UV1]](s32)
@@ -2366,7 +2366,7 @@ body: |
; GFX9-UNSAFE-NEXT: [[MV7:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY14]](s32), [[COPY15]](s32)
; GFX9-UNSAFE-NEXT: [[MV8:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY16]](s32), [[COPY17]](s32)
; GFX9-UNSAFE-NEXT: [[BUILD_VECTOR2:%[0-9]+]]:_(<3 x s64>) = G_BUILD_VECTOR [[MV6]](s64), [[MV7]](s64), [[MV8]](s64)
- ; GFX9-UNSAFE-NEXT: [[FMA:%[0-9]+]]:_(<3 x s64>) = G_FMA [[BUILD_VECTOR]], [[BUILD_VECTOR1]], [[BUILD_VECTOR2]]
+ ; GFX9-UNSAFE-NEXT: [[FMA:%[0-9]+]]:_(<3 x s64>) = reassoc G_FMA [[BUILD_VECTOR]], [[BUILD_VECTOR1]], [[BUILD_VECTOR2]]
; GFX9-UNSAFE-NEXT: [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32), [[UV2:%[0-9]+]]:_(s32), [[UV3:%[0-9]+]]:_(s32), [[UV4:%[0-9]+]]:_(s32), [[UV5:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[FMA]](<3 x s64>)
; GFX9-UNSAFE-NEXT: $vgpr0 = COPY [[UV]](s32)
; GFX9-UNSAFE-NEXT: $vgpr1 = COPY [[UV1]](s32)
@@ -2453,7 +2453,7 @@ body: |
; GFX10-CONTRACT-NEXT: [[MV7:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY14]](s32), [[COPY15]](s32)
; GFX10-CONTRACT-NEXT: [[MV8:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY16]](s32), [[COPY17]](s32)
; GFX10-CONTRACT-NEXT: [[BUILD_VECTOR2:%[0-9]+]]:_(<3 x s64>) = G_BUILD_VECTOR [[MV6]](s64), [[MV7]](s64), [[MV8]](s64)
- ; GFX10-CONTRACT-NEXT: [[FMA:%[0-9]+]]:_(<3 x s64>) = G_FMA [[BUILD_VECTOR]], [[BUILD_VECTOR1]], [[BUILD_VECTOR2]]
+ ; GFX10-CONTRACT-NEXT: [[FMA:%[0-9]+]]:_(<3 x s64>) = reassoc G_FMA [[BUILD_VECTOR]], [[BUILD_VECTOR1]], [[BUILD_VECTOR2]]
; GFX10-CONTRACT-NEXT: [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32), [[UV2:%[0-9]+]]:_(s32), [[UV3:%[0-9]+]]:_(s32), [[UV4:%[0-9]+]]:_(s32), [[UV5:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[FMA]](<3 x s64>)
; GFX10-CONTRACT-NEXT: $vgpr0 = COPY [[UV]](s32)
; GFX10-CONTRACT-NEXT: $vgpr1 = COPY [[UV1]](s32)
@@ -2540,7 +2540,7 @@ body: |
; GFX10-UNSAFE-NEXT: [[MV7:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY14]](s32), [[COPY15]](s32)
; GFX10-UNSAFE-NEXT: [[MV8:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY16]](s32), [[COPY17]](s32)
; GFX10-UNSAFE-NEXT: [[BUILD_VECTOR2:%[0-9]+]]:_(<3 x s64>) = G_BUILD_VECTOR [[MV6]](s64), [[MV7]](s64), [[MV8]](s64)
- ; GFX10-UNSAFE-NEXT: [[FMA:%[0-9]+]]:_(<3 x s64>) = G_FMA [[BUILD_VECTOR]], [[BUILD_VECTOR1]], [[BUILD_VECTOR2]]
+ ; GFX10-UNSAFE-NEXT: [[FMA:%[0-9]+]]:_(<3 x s64>) = reassoc G_FMA [[BUILD_VECTOR]], [[BUILD_VECTOR1]], [[BUILD_VECTOR2]]
; GFX10-UNSAFE-NEXT: [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32), [[UV2:%[0-9]+]]:_(s32), [[UV3:%[0-9]+]]:_(s32), [[UV4:%[0-9]+]]:_(s32), [[UV5:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[FMA]](<3 x s64>)
; GFX10-UNSAFE-NEXT: $vgpr0 = COPY [[UV]](s32)
; GFX10-UNSAFE-NEXT: $vgpr1 = COPY [[UV1]](s32)
diff --git a/llvm/test/CodeGen/AMDGPU/GlobalISel/combine-fma-unmerge-values.mir b/llvm/test/CodeGen/AMDGPU/GlobalISel/combine-fma-unmerge-values.mir
index 291f478e08faed9..dccf970a364a1bd 100644
--- a/llvm/test/CodeGen/AMDGPU/GlobalISel/combine-fma-unmerge-values.mir
+++ b/llvm/test/CodeGen/AMDGPU/GlobalISel/combine-fma-unmerge-values.mir
@@ -79,9 +79,9 @@ body: |
; GFX10-NEXT: %ptr:_(p1) = COPY $vgpr0_vgpr1
; GFX10-NEXT: %vec:_(<2 x s32>) = G_LOAD %ptr(p1) :: (load (<2 x s32>), addrspace 1)
; GFX10-NEXT: %el0:_(s32), %el1:_(s32) = G_UNMERGE_VALUES %vec(<2 x s32>)
- ; GFX10-NEXT: [[FPEXT:%[0-9]+]]:_(s32) = G_FPEXT [[TRUNC]](s16)
- ; GFX10-NEXT: [[FPEXT1:%[0-9]+]]:_(s32) = G_FPEXT [[TRUNC1]](s16)
- ; GFX10-NEXT: [[FMA:%[0-9]+]]:_(s32) = G_FMA [[FPEXT]], [[FPEXT1]], %el1
+ ; GFX10-NEXT: [[FPEXT:%[0-9]+]]:_(s32) = nnan ninf nsz arcp contract afn reassoc G_FPEXT [[TRUNC]](s16)
+ ; GFX10-NEXT: [[FPEXT1:%[0-9]+]]:_(s32) = nnan ninf nsz arcp contract afn reassoc G_FPEXT [[TRUNC1]](s16)
+ ; GFX10-NEXT: [[FMA:%[0-9]+]]:_(s32) = nnan ninf nsz arcp contract afn reassoc G_FMA [[FPEXT]], [[FPEXT1]], %el1
; GFX10-NEXT: $vgpr0 = COPY [[FMA]](s32)
%0:_(s32) = COPY $sgpr0
%1:_(s16) = G_TRUNC %0(s32)
@@ -116,9 +116,9 @@ body: |
; GFX10-NEXT: %ptr:_(p1) = COPY $vgpr0_vgpr1
; GFX10-NEXT: %vec:_(<2 x s32>) = G_LOAD %ptr(p1) :: (load (<2 x s32>), addrspace 1)
; GFX10-NEXT: %el0:_(s32), %el1:_(s32) = G_UNMERGE_VALUES %vec(<2 x s32>)
- ; GFX10-NEXT: [[FPEXT:%[0-9]+]]:_(s32) = G_FPEXT [[TRUNC]](s16)
- ; GFX10-NEXT: [[FPEXT1:%[0-9]+]]:_(s32) = G_FPEXT [[TRUNC1]](s16)
- ; GFX10-NEXT: [[FMA:%[0-9]+]]:_(s32) = G_FMA [[FPEXT]], [[FPEXT1]], %el1
+ ; GFX10-NEXT: [[FPEXT:%[0-9]+]]:_(s32) = nnan ninf nsz arcp contract afn reassoc G_FPEXT [[TRUNC]](s16)
+ ; GFX10-NEXT: [[FPEXT1:%[0-9]+]]:_(s32) = nnan ninf nsz arcp contract afn reassoc G_FPEXT [[TRUNC1]](s16)
+ ; GFX10-NEXT: [[FMA:%[0-9]+]]:_(s32) = nnan ninf nsz arcp contract afn reassoc G_FMA [[FPEXT]], [[FPEXT1]], %el1
; GFX10-NEXT: $vgpr0 = COPY [[FMA]](s32)
%0:_(s32) = COPY $sgpr0
%1:_(s16) = G_TRUNC %0(s32)
@@ -149,8 +149,8 @@ body: |
; GFX10-NEXT: %ptr:_(p1) = COPY $vgpr4_vgpr5
; GFX10-NEXT: %vec:_(<2 x s32>) = G_LOAD %ptr(p1) :: (load (<2 x s32>), addrspace 1)
; GFX10-NEXT: %el0:_(s32), %el1:_(s32) = G_UNMERGE_VALUES %vec(<2 x s32>)
- ; GFX10-NEXT: [[FMA:%[0-9]+]]:_(s32) = G_FMA [[COPY2]], [[COPY3]], %el1
- ; GFX10-NEXT: [[FMA1:%[0-9]+]]:_(s32) = G_FMA [[COPY]], [[COPY1]], [[FMA]]
+ ; GFX10-NEXT: [[FMA:%[0-9]+]]:_(s32) = nnan ninf nsz arcp contract afn reassoc G_FMA [[COPY2]], [[COPY3]], %el1
+ ; GFX10-NEXT: [[FMA1:%[0-9]+]]:_(s32) = nnan ninf nsz arcp contract afn reassoc G_FMA [[COPY]], [[COPY1]], [[FMA]]
; GFX10-NEXT: $vgpr0 = COPY [[FMA1]](s32)
%0:_(s32) = COPY $vgpr0
%1:_(s32) = COPY $vgpr1
@@ -181,8 +181,8 @@ body: |
; GFX10-NEXT: %ptr:_(p1) = COPY $vgpr4_vgpr5
; GFX10-NEXT: %vec:_(<2 x s32>) = G_LOAD %ptr(p1) :: (load (<2 x s32>), addrspace 1)
; GFX10-NEXT: %el0:_(s32), %el1:_(s32) = G_UNMERGE_VALUES %vec(<2 x s32>)
- ; GFX10-NEXT: [[FMA:%[0-9]+]]:_(s32) = G_FMA [[COPY2]], [[COPY3]], %el1
- ; GFX10-NEXT: [[FMA1:%[0-9]+]]:_(s32) = G_FMA [[COPY]], [[COPY1]], [[FMA]]
+ ; GFX10-NEXT: [[FMA:%[0-9]+]]:_(s32) = nnan ninf nsz arcp contract afn reassoc G_FMA [[COPY2]], [[COPY3]], %el1
+ ; GFX10-NEXT: [[FMA1:%[0-9]+]]:_(s32) = nnan ninf nsz arcp contract afn reassoc G_FMA [[COPY]], [[COPY1]], [[FMA]]
; GFX10-NEXT: $vgpr0 = COPY [[FMA1]](s32)
%0:_(s32) = COPY $vgpr0
%1:_(s32) = COPY $vgpr1
diff --git a/llvm/test/CodeGen/AMDGPU/GlobalISel/combine-fold-binop-into-select.mir b/llvm/test/CodeGen/AMDGPU/GlobalISel/combine-fold-binop-into-select.mir
index 9f3ad8b44444625..8a16ab53804a3b2 100644
--- a/llvm/test/CodeGen/AMDGPU/GlobalISel/combine-fold-binop-into-select.mir
+++ b/llvm/test/CodeGen/AMDGPU/GlobalISel/combine-fold-binop-into-select.mir
@@ -1034,8 +1034,8 @@ body: |
; CHECK-NEXT: %reg:_(s32) = COPY $vgpr0
; CHECK-NEXT: %zero:_(s32) = G_CONSTANT i32 0
; CHECK-NEXT: %cond:_(s1) = G_ICMP intpred(eq), %reg(s32), %zero
- ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_FCONSTANT float 1.800000e+01
- ; CHECK-NEXT: [[C1:%[0-9]+]]:_(s32) = G_FCONSTANT float 2.000000e+01
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = nnan G_FCONSTANT float 1.800000e+01
+ ; CHECK-NEXT: [[C1:%[0-9]+]]:_(s32) = nnan G_FCONSTANT float 2.000000e+01
; CHECK-NEXT: %fadd:_(s32) = nnan G_SELECT %cond(s1), [[C]], [[C1]]
; CHECK-NEXT: S_ENDPGM 0, implicit %fadd(s32)
%reg:_(s32) = COPY $vgpr0
@@ -1061,8 +1061,8 @@ body: |
; CHECK-NEXT: %reg:_(s32) = COPY $vgpr0
; CHECK-NEXT: %zero:_(s32) = G_CONSTANT i32 0
; CHECK-NEXT: %cond:_(s1) = G_ICMP intpred(eq), %reg(s32), %zero
- ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_FCONSTANT float 1.800000e+01
- ; CHECK-NEXT: [[C1:%[0-9]+]]:_(s32) = G_FCONSTANT float 2.000000e+01
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = nnan G_FCONSTANT float 1.800000e+01
+ ; CHECK-NEXT: [[C1:%[0-9]+]]:_(s32) = nnan G_FCONSTANT float 2.000000e+01
; CHECK-NEXT: %fadd:_(s32) = nnan G_SELECT %cond(s1), [[C]], [[C1]]
; CHECK-NEXT: S_ENDPGM 0, implicit %fadd(s32)
%reg:_(s32) = COPY $vgpr0
@@ -1088,8 +1088,8 @@ body: |
; CHECK-NEXT: %reg:_(s32) = COPY $vgpr0
; CHECK-NEXT: %zero:_(s32) = G_CONSTANT i32 0
; CHECK-NEXT: %cond:_(s1) = G_ICMP intpred(eq), %reg(s32), %zero
- ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_FCONSTANT float -1.400000e+01
- ; CHECK-NEXT: [[C1:%[0-9]+]]:_(s32) = G_FCONSTANT float -1.200000e+01
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = nnan G_FCONSTANT float -1.400000e+01
+ ; CHECK-NEXT: [[C1:%[0-9]+]]:_(s32) = nnan G_FCONSTANT float -1.200000e+01
; CHECK-NEXT: %fsub:_(s32) = nnan G_SELECT %cond(s1), [[C]], [[C1]]
; CHECK-NEXT: S_ENDPGM 0, implicit %fsub(s32)
%reg:_(s32) = COPY $vgpr0
@@ -1115,8 +1115,8 @@ body: |
; CHECK-NEXT: %reg:_(s32) = COPY $vgpr0
; CHECK-NEXT: %zero:_(s32) = G_CONSTANT i32 0
; CHECK-NEXT: %cond:_(s1) = G_ICMP intpred(eq), %reg(s32), %zero
- ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_FCONSTANT float 3.200000e+01
- ; CHECK-NEXT: [[C1:%[0-9]+]]:_(s32) = G_FCONSTANT float 6.400000e+01
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = nnan G_FCONSTANT float 3.200000e+01
+ ; CHECK-NEXT: [[C1:%[0-9]+]]:_(s32) = nnan G_FCONSTANT float 6.400000e+01
; CHECK-NEXT: %fmul:_(s32) = nnan G_SELECT %cond(s1), [[C]], [[C1]]
; CHECK-NEXT: S_ENDPGM 0, implicit %fmul(s32)
%reg:_(s32) = COPY $vgpr0
@@ -1142,8 +1142,8 @@ body: |
; CHECK-NEXT: %reg:_(s32) = COPY $vgpr0
; CHECK-NEXT: %zero:_(s32) = G_CONSTANT i32 0
; CHECK-NEXT: %cond:_(s1) = G_ICMP intpred(eq), %reg(s32), %zero
- ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_FCONSTANT float 1.250000e-01
- ; CHECK-NEXT: [[C1:%[0-9]+]]:_(s32) = G_FCONSTANT float 2.500000e-01
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = nnan G_FCONSTANT float 1.250000e-01
+ ; CHECK-NEXT: [[C1:%[0-9]+]]:_(s32) = nnan G_FCONSTANT float 2.500000e-01
; CHECK-NEXT: %fdiv:_(s32) = nnan G_SELECT %cond(s1), [[C]], [[C1]]
; CHECK-NEXT: S_ENDPGM 0, implicit %fdiv(s32)
%reg:_(s32) = COPY $vgpr0
diff --git a/llvm/test/CodeGen/AMDGPU/GlobalISel/combine-fsub-fneg.mir b/llvm/test/CodeGen/AMDGPU/GlobalISel/combine-fsub-fneg.mir
index 2bce20573529900..bb7014ae4546b25 100644
--- a/llvm/test/CodeGen/AMDGPU/GlobalISel/combine-fsub-fneg.mir
+++ b/llvm/test/CodeGen/AMDGPU/GlobalISel/combine-fsub-fneg.mir
@@ -13,8 +13,8 @@ body: |
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $vgpr0
; CHECK-NEXT: %input:_(s16) = G_TRUNC [[COPY]](s32)
- ; CHECK-NEXT: [[FNEG:%[0-9]+]]:_(s16) = G_FNEG %input
- ; CHECK-NEXT: [[FCANONICALIZE:%[0-9]+]]:_(s16) = G_FCANONICALIZE [[FNEG]]
+ ; CHECK-NEXT: [[FNEG:%[0-9]+]]:_(s16) = nsz G_FNEG %input
+ ; CHECK-NEXT: [[FCANONICALIZE:%[0-9]+]]:_(s16) = nsz G_FCANONICALIZE [[FNEG]]
; CHECK-NEXT: %res:_(s32) = G_ANYEXT [[FCANONICALIZE]](s16)
; CHECK-NEXT: $vgpr0 = COPY %res(s32)
%0:_(s32) = COPY $vgpr0
@@ -84,8 +84,8 @@ body: |
; CHECK: liveins: $vgpr0
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: %input:_(s32) = COPY $vgpr0
- ; CHECK-NEXT: [[FNEG:%[0-9]+]]:_(s32) = G_FNEG %input
- ; CHECK-NEXT: [[FCANONICALIZE:%[0-9]+]]:_(s32) = G_FCANONICALIZE [[FNEG]]
+ ; CHECK-NEXT: [[FNEG:%[0-9]+]]:_(s32) = nsz G_FNEG %input
+ ; CHECK-NEXT: [[FCANONICALIZE:%[0-9]+]]:_(s32) = nsz G_FCANONICALIZE [[FNEG]]
; CHECK-NEXT: $vgpr0 = COPY [[FCANONICALIZE]](s32)
%input:_(s32) = COPY $vgpr0
%cst:_(s32) = G_FCONSTANT float 0.0
@@ -144,8 +144,8 @@ body: |
; CHECK: liveins: $vgpr0_vgpr1
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: %input:_(s64) = COPY $vgpr0_vgpr1
- ; CHECK-NEXT: [[FNEG:%[0-9]+]]:_(s64) = G_FNEG %input
- ; CHECK-NEXT: [[FCANONICALIZE:%[0-9]+]]:_(s64) = G_FCANONICALIZE [[FNEG]]
+ ; CHECK-NEXT: [[FNEG:%[0-9]+]]:_(s64) = nsz G_FNEG %input
+ ; CHECK-NEXT: [[FCANONICALIZE:%[0-9]+]]:_(s64) = nsz G_FCANONICALIZE [[FNEG]]
; CHECK-NEXT: $vgpr0_vgpr1 = COPY [[FCANONICALIZE]](s64)
%input:_(s64) = COPY $vgpr0_vgpr1
%cst:_(s64) = G_FCONSTANT double 0.0
@@ -204,8 +204,8 @@ body: |
; CHECK: liveins: $vgpr0_vgpr1
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: %input:_(<4 x s16>) = COPY $vgpr0_vgpr1
- ; CHECK-NEXT: [[FNEG:%[0-9]+]]:_(<4 x s16>) = G_FNEG %input
- ; CHECK-NEXT: [[FCANONICALIZE:%[0-9]+]]:_(<4 x s16>) = G_FCANONICALIZE [[FNEG]]
+ ; CHECK-NEXT: [[FNEG:%[0-9]+]]:_(<4 x s16>) = nsz G_FNEG %input
+ ; CHECK-NEXT: [[FCANONICALIZE:%[0-9]+]]:_(<4 x s16>) = nsz G_FCANONICALIZE [[FNEG]]
; CHECK-NEXT: $vgpr0_vgpr1 = COPY [[FCANONICALIZE]](<4 x s16>)
%input:_(<4 x s16>) = COPY $vgpr0_vgpr1
%cst:_(s16) = G_FCONSTANT half 0.0
@@ -268,8 +268,8 @@ body: |
; CHECK: liveins: $vgpr0_vgpr1_vgpr2_vgpr3
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: %input:_(<4 x s32>) = COPY $vgpr0_vgpr1_vgpr2_vgpr3
- ; CHECK-NEXT: [[FNEG:%[0-9]+]]:_(<4 x s32>) = G_FNEG %input
- ; CHECK-NEXT: [[FCANONICALIZE:%[0-9]+]]:_(<4 x s32>) = G_FCANONICALIZE [[FNEG]]
+ ; CHECK-NEXT: [[FNEG:%[0-9]+]]:_(<4 x s32>) = nsz G_FNEG %input
+ ; CHECK-NEXT: [[FCANONICALIZE:%[0-9]+]]:_(<4 x s32>) = nsz G_FCANONICALIZE [[FNEG]]
; CHECK-NEXT: $vgpr0_vgpr1_vgpr2_vgpr3 = COPY [[FCANONICALIZE]](<4 x s32>)
%input:_(<4 x s32>) = COPY $vgpr0_vgpr1_vgpr2_vgpr3
%cst:_(s32) = G_FCONSTANT float 0.0
@@ -332,8 +332,8 @@ body: |
; CHECK: liveins: $vgpr0_vgpr1_vgpr2_vgpr3
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: %input:_(<4 x s32>) = COPY $vgpr0_vgpr1_vgpr2_vgpr3
- ; CHECK-NEXT: [[FNEG:%[0-9]+]]:_(<4 x s32>) = G_FNEG %input
- ; CHECK-NEXT: [[FCANONICALIZE:%[0-9]+]]:_(<4 x s32>) = G_FCANONICALIZE [[FNEG]]
+ ; CHECK-NEXT: [[FNEG:%[0-9]+]]:_(<4 x s32>) = nsz G_FNEG %input
+ ; CHECK-NEXT: [[FCANONICALIZE:%[0-9]+]]:_(<4 x s32>) = nsz G_FCANONICALIZE [[FNEG]]
; CHECK-NEXT: $vgpr0_vgpr1_vgpr2_vgpr3 = COPY [[FCANONICALIZE]](<4 x s32>)
%input:_(<4 x s32>) = COPY $vgpr0_vgpr1_vgpr2_vgpr3
%cst:_(s32) = G_FCONSTANT float 0.0
@@ -354,8 +354,8 @@ body: |
; CHECK: liveins: $vgpr0_vgpr1_vgpr2_vgpr3
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: %input:_(<2 x s64>) = COPY $vgpr0_vgpr1_vgpr2_vgpr3
- ; CHECK-NEXT: [[FNEG:%[0-9]+]]:_(<2 x s64>) = G_FNEG %input
- ; CHECK-NEXT: [[FCANONICALIZE:%[0-9]+]]:_(<2 x s64>) = G_FCANONICALIZE [[FNEG]]
+ ; CHECK-NEXT: [[FNEG:%[0-9]+]]:_(<2 x s64>) = nsz G_FNEG %input
+ ; CHECK-NEXT: [[FCANONICALIZE:%[0-9]+]]:_(<2 x s64>) = nsz G_FCANONICALIZE [[FNEG]]
; CHECK-NEXT: $vgpr0_vgpr1_vgpr2_vgpr3 = COPY [[FCANONICALIZE]](<2 x s64>)
%input:_(<2 x s64>) = COPY $vgpr0_vgpr1_vgpr2_vgpr3
%cst:_(s64) = G_FCONSTANT double 0.0
diff --git a/llvm/test/TableGen/GlobalISelCombinerEmitter/match-table.td b/llvm/test/TableGen/GlobalISelCombinerEmitter/match-table.td
index 0f20e75d38a5d27..3319dae71127b83 100644
--- a/llvm/test/TableGen/GlobalISelCombinerEmitter/match-table.td
+++ b/llvm/test/TableGen/GlobalISelCombinerEmitter/match-table.td
@@ -93,12 +93,12 @@ def MyCombiner: GICombiner<"GenMyCombiner", [
// CHECK: bool GenMyCombiner::tryCombineAll(MachineInstr &I) const {
// CHECK-NEXT: const TargetSubtargetInfo &ST = MF.getSubtarget();
// CHECK-NEXT: const PredicateBitset AvailableFeatures = getAvailableFeatures();
-// CHECK-NEXT: NewMIVector OutMIs;
+// CHECK-NEXT: B.setInstrAndDebugLoc(I);
// CHECK-NEXT: State.MIs.clear();
// CHECK-NEXT: State.MIs.push_back(&I);
// CHECK-NEXT: MatchInfos = MatchInfosTy();
// CHECK-EMPTY:
-// CHECK-NEXT: if (executeMatchTable(*this, OutMIs, State, ExecInfo, getMatchTable(), *ST.getInstrInfo(), MRI, *MRI.getTargetRegisterInfo(), *ST.getRegBankInfo(), AvailableFeatures, /*CoverageInfo*/ nullptr, &Observer))
+// CHECK-NEXT: if (executeMatchTable(*this, State, ExecInfo, B, getMatchTable(), *ST.getInstrInfo(), MRI, *MRI.getTargetRegisterInfo(), *ST.getRegBankInfo(), AvailableFeatures, /*CoverageInfo*/ nullptr))
// CHECK-NEXT: return true;
// CHECK-NEXT: }
// CHECK-EMPTY:
@@ -111,7 +111,7 @@ def MyCombiner: GICombiner<"GenMyCombiner", [
// CHECK-NEXT: GICXXCustomAction_CombineApplyGICombiner1,
// CHECK-NEXT: GICXXCustomAction_CombineApplyGICombiner2,
// CHECK-NEXT: };
-// CHECK-NEXT: void GenMyCombiner::runCustomAction(unsigned ApplyID, const MatcherState &State, NewMIVector &OutMIs) const {
+// CHECK-NEXT: void GenMyCombiner::runCustomAction(unsigned ApplyID, const MatcherState &State, ArrayRef<MachineInstrBuilder> OutMIs) const {
// CHECK-NEXT: switch(ApplyID) {
// CHECK-NEXT: case GICXXCustomAction_CombineApplyGICombiner0:{
// CHECK-NEXT: APPLY
diff --git a/llvm/test/TableGen/GlobalISelEmitter.td b/llvm/test/TableGen/GlobalISelEmitter.td
index 7cca2d52e4062e8..70602c8fa3ded15 100644
--- a/llvm/test/TableGen/GlobalISelEmitter.td
+++ b/llvm/test/TableGen/GlobalISelEmitter.td
@@ -82,7 +82,7 @@ def HasC : Predicate<"Subtarget->hasC()"> { let RecomputePerFunction = 1; }
// CHECK-NEXT: const int64_t *getMatchTable() const override;
// CHECK-NEXT: bool testMIPredicate_MI(unsigned PredicateID, const MachineInstr &MI, const MatcherState &State) const override;
// CHECK-NEXT: bool testSimplePredicate(unsigned PredicateID) const override;
-// CHECK-NEXT: void runCustomAction(unsigned FnID, const MatcherState &State, NewMIVector &OutMIs) const override;
+// CHECK-NEXT: void runCustomAction(unsigned FnID, const MatcherState &State, ArrayRef<MachineInstrBuilder> OutMIs) const override;
// CHECK-NEXT: #endif // ifdef GET_GLOBALISEL_TEMPORARIES_DECL
// CHECK-LABEL: #ifdef GET_GLOBALISEL_TEMPORARIES_INIT
@@ -216,11 +216,11 @@ def HasC : Predicate<"Subtarget->hasC()"> { let RecomputePerFunction = 1; }
// CHECK: bool MyTargetInstructionSelector::selectImpl(MachineInstr &I, CodeGenCoverage &CoverageInfo) const {
// CHECK-NEXT: const PredicateBitset AvailableFeatures = getAvailableFeatures();
-// CHECK-NEXT: NewMIVector OutMIs;
+// CHECK-NEXT: MachineIRBuilder B(I);
// CHECK-NEXT: State.MIs.clear();
// CHECK-NEXT: State.MIs.push_back(&I);
-// CHECK: if (executeMatchTable(*this, OutMIs, State, ExecInfo, getMatchTable(), TII, MF->getRegInfo(), TRI, RBI, AvailableFeatures, &CoverageInfo)) {
+// CHECK: if (executeMatchTable(*this, State, ExecInfo, B, getMatchTable(), TII, MF->getRegInfo(), TRI, RBI, AvailableFeatures, &CoverageInfo)) {
// CHECK-NEXT: return true;
// CHECK-NEXT: }
diff --git a/llvm/utils/TableGen/GlobalISelCombinerEmitter.cpp b/llvm/utils/TableGen/GlobalISelCombinerEmitter.cpp
index 08a4db2fb3dec91..e32ef8b9a7986b1 100644
--- a/llvm/utils/TableGen/GlobalISelCombinerEmitter.cpp
+++ b/llvm/utils/TableGen/GlobalISelCombinerEmitter.cpp
@@ -3465,15 +3465,15 @@ void GICombinerEmitter::emitAdditionalImpl(raw_ostream &OS) {
<< " const TargetSubtargetInfo &ST = MF.getSubtarget();\n"
<< " const PredicateBitset AvailableFeatures = "
"getAvailableFeatures();\n"
- << " NewMIVector OutMIs;\n"
+ << " B.setInstrAndDebugLoc(I);\n"
<< " State.MIs.clear();\n"
<< " State.MIs.push_back(&I);\n"
<< " " << MatchDataInfo::StructName << " = "
<< MatchDataInfo::StructTypeName << "();\n\n"
- << " if (executeMatchTable(*this, OutMIs, State, ExecInfo"
+ << " if (executeMatchTable(*this, State, ExecInfo, B"
<< ", getMatchTable(), *ST.getInstrInfo(), MRI, "
"*MRI.getTargetRegisterInfo(), *ST.getRegBankInfo(), AvailableFeatures"
- << ", /*CoverageInfo*/ nullptr, &Observer)) {\n"
+ << ", /*CoverageInfo*/ nullptr)) {\n"
<< " return true;\n"
<< " }\n\n"
<< " return false;\n"
@@ -3550,7 +3550,7 @@ void GICombinerEmitter::emitRunCustomAction(raw_ostream &OS) {
OS << "void " << getClassName()
<< "::runCustomAction(unsigned ApplyID, const MatcherState &State, "
- "NewMIVector &OutMIs) const "
+ "ArrayRef<MachineInstrBuilder> OutMIs) const "
"{\n";
if (!ApplyCode.empty()) {
OS << " switch(ApplyID) {\n";
diff --git a/llvm/utils/TableGen/GlobalISelEmitter.cpp b/llvm/utils/TableGen/GlobalISelEmitter.cpp
index 1dbd821f20fdc55..fa682620ed2f783 100644
--- a/llvm/utils/TableGen/GlobalISelEmitter.cpp
+++ b/llvm/utils/TableGen/GlobalISelEmitter.cpp
@@ -2263,10 +2263,10 @@ void GlobalISelEmitter::emitAdditionalImpl(raw_ostream &OS) {
"&CoverageInfo) const {\n"
<< " const PredicateBitset AvailableFeatures = "
"getAvailableFeatures();\n"
- << " NewMIVector OutMIs;\n"
+ << " MachineIRBuilder B(I);\n"
<< " State.MIs.clear();\n"
<< " State.MIs.push_back(&I);\n\n"
- << " if (executeMatchTable(*this, OutMIs, State, ExecInfo"
+ << " if (executeMatchTable(*this, State, ExecInfo, B"
<< ", getMatchTable(), TII, MF->getRegInfo(), TRI, RBI, AvailableFeatures"
<< ", &CoverageInfo)) {\n"
<< " return true;\n"
@@ -2348,7 +2348,8 @@ void GlobalISelEmitter::emitTestSimplePredicate(raw_ostream &OS) {
void GlobalISelEmitter::emitRunCustomAction(raw_ostream &OS) {
OS << "void " << getClassName()
- << "::runCustomAction(unsigned, const MatcherState&, NewMIVector &) const "
+ << "::runCustomAction(unsigned, const MatcherState&, "
+ "ArrayRef<MachineInstrBuilder>) const "
"{\n"
<< " llvm_unreachable(\"" + getClassName() +
" does not support custom C++ actions!\");\n"
diff --git a/llvm/utils/TableGen/GlobalISelMatchTableExecutorEmitter.cpp b/llvm/utils/TableGen/GlobalISelMatchTableExecutorEmitter.cpp
index c6cd3240a94e7b0..b6f9dbeb336ee7d 100644
--- a/llvm/utils/TableGen/GlobalISelMatchTableExecutorEmitter.cpp
+++ b/llvm/utils/TableGen/GlobalISelMatchTableExecutorEmitter.cpp
@@ -232,7 +232,7 @@ void GlobalISelMatchTableExecutorEmitter::emitTemporariesDecl(
"const override;\n"
<< " bool testSimplePredicate(unsigned PredicateID) const override;\n"
<< " void runCustomAction(unsigned FnID, const MatcherState &State, "
- "NewMIVector &OutMIs) "
+ "ArrayRef<MachineInstrBuilder> OutMIs) "
"const override;\n";
emitAdditionalTemporariesDecl(OS, " ");
OS << "#endif // ifdef " << IfDefName << "\n\n";
>From 0fa64364d782bc0c17422170ece94450a5a6a5a5 Mon Sep 17 00:00:00 2001
From: pvanhout <pierre.vanhoutryve at amd.com>
Date: Tue, 12 Sep 2023 10:49:32 +0200
Subject: [PATCH 2/3] [TableGen] Use buildConstant to emit apply pattern
immediates
Use ``MachineIRBuilder::buildConstant`` to emit typed immediates in 'apply' MIR patterns.
This allows us to seamlessly handle vector cases, wherre a ``G_BUILD_VECTOR`` is needed to create a splat.
Depends on #65955
---
llvm/docs/GlobalISel/MIRPatterns.rst | 4 +-
.../CodeGen/GlobalISel/GIMatchTableExecutor.h | 5 ++
.../GlobalISel/GIMatchTableExecutorImpl.h | 10 +++
.../match-table-imms.td | 12 ++--
.../match-table-patfrag-root.td | 24 +++----
.../match-table-permutations.td | 68 +++++++------------
.../GlobalISelCombinerEmitter/match-table.td | 8 +--
.../TableGen/GlobalISelCombinerEmitter.cpp | 11 ++-
llvm/utils/TableGen/GlobalISelMatchTable.cpp | 10 +++
llvm/utils/TableGen/GlobalISelMatchTable.h | 19 ++++++
10 files changed, 93 insertions(+), 78 deletions(-)
diff --git a/llvm/docs/GlobalISel/MIRPatterns.rst b/llvm/docs/GlobalISel/MIRPatterns.rst
index 51d1850a1236039..fa70311f48572de 100644
--- a/llvm/docs/GlobalISel/MIRPatterns.rst
+++ b/llvm/docs/GlobalISel/MIRPatterns.rst
@@ -257,8 +257,8 @@ Common Pattern #3: Emitting a Constant Value
When an immediate operand appears in an 'apply' pattern, the behavior
depends on whether it's typed or not.
-* If the immediate is typed, a ``G_CONSTANT`` is implicitly emitted
- (= a register operand is added to the instruction).
+* If the immediate is typed, ``MachineIRBuilder::buildConstant`` is used
+ to create a ``G_CONSTANT``. A ``G_BUILD_VECTOR`` will be used for vectors.
* If the immediate is untyped, a simple immediate is added
(``MachineInstrBuilder::addImm``).
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutor.h b/llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutor.h
index 8c1a067af3a6912..89c0b097281ddfa 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutor.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutor.h
@@ -293,6 +293,11 @@ enum {
/// - Opcode - The new opcode to use
GIR_BuildMI,
+ /// Builds a constant and stores its result in a TempReg.
+ /// - TempRegID - Temp Register to define.
+ /// - Imm - The immediate to add
+ GIR_BuildConstant,
+
/// Copy an operand to the specified instruction
/// - NewInsnID - Instruction ID to modify
/// - OldInsnID - Instruction ID to copy from
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h b/llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h
index 3b2718e11864a1a..92a1eb561fb10ae 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h
@@ -941,6 +941,16 @@ bool GIMatchTableExecutor::executeMatchTable(
break;
}
+ case GIR_BuildConstant: {
+ int64_t TempRegID = MatchTable[CurrentIdx++];
+ int64_t Imm = MatchTable[CurrentIdx++];
+ Builder.buildConstant(State.TempRegisters[TempRegID], Imm);
+ DEBUG_WITH_TYPE(TgtExecutor::getName(),
+ dbgs() << CurrentIdx << ": GIR_BuildConstant(TempReg["
+ << TempRegID << "], Imm=" << Imm << ")\n");
+ break;
+ }
+
case GIR_Copy: {
int64_t NewInsnID = MatchTable[CurrentIdx++];
int64_t OldInsnID = MatchTable[CurrentIdx++];
diff --git a/llvm/test/TableGen/GlobalISelCombinerEmitter/match-table-imms.td b/llvm/test/TableGen/GlobalISelCombinerEmitter/match-table-imms.td
index b3e7ba28b0fa3f1..ec08e8b92326f99 100644
--- a/llvm/test/TableGen/GlobalISelCombinerEmitter/match-table-imms.td
+++ b/llvm/test/TableGen/GlobalISelCombinerEmitter/match-table-imms.td
@@ -48,7 +48,7 @@ def MyCombiner: GICombiner<"GenMyCombiner", [
// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
// CHECK-NEXT: GIR_Done,
// CHECK-NEXT: // Label 0: @28
-// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 1*/ 67, // Rule ID 1 //
+// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 1*/ 59, // Rule ID 1 //
// CHECK-NEXT: GIM_CheckSimplePredicate, GICXXPred_Simple_IsRule1Enabled,
// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_ZEXT,
// CHECK-NEXT: // MIs[0] a
@@ -56,17 +56,15 @@ def MyCombiner: GICombiner<"GenMyCombiner", [
// CHECK-NEXT: // MIs[0] Operand 1
// CHECK-NEXT: GIM_CheckConstantInt, /*MI*/0, /*Op*/1, 0,
// CHECK-NEXT: GIR_MakeTempReg, /*TempRegID*/0, /*TypeID*/GILLT_s32,
-// CHECK-NEXT: GIR_BuildMI, /*InsnID*/1, /*Opcode*/TargetOpcode::G_CONSTANT,
-// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/1, /*TempRegID*/0, /*TempRegFlags*/0,
-// CHECK-NEXT: GIR_AddCImm, /*InsnID*/1, /*Type*/GILLT_s32, /*Imm*/0,
+// CHECK-NEXT: GIR_BuildConstant, /*TempRegID*/0, /*Val*/0,
// CHECK-NEXT: // Combiner Rule #1: InstTest1
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/TargetOpcode::COPY,
// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // a
// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/0, /*TempRegID*/0, /*TempRegFlags*/0,
// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
// CHECK-NEXT: GIR_Done,
-// CHECK-NEXT: // Label 1: @67
-// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 2*/ 96, // Rule ID 2 //
+// CHECK-NEXT: // Label 1: @59
+// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 2*/ 88, // Rule ID 2 //
// CHECK-NEXT: GIM_CheckSimplePredicate, GICXXPred_Simple_IsRule2Enabled,
// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_CONSTANT,
// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/1, /*Type*/GILLT_s32,
@@ -79,7 +77,7 @@ def MyCombiner: GICombiner<"GenMyCombiner", [
// CHECK-NEXT: GIR_AddCImm, /*InsnID*/0, /*Type*/GILLT_s32, /*Imm*/42,
// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
// CHECK-NEXT: GIR_Done,
-// CHECK-NEXT: // Label 2: @96
+// CHECK-NEXT: // Label 2: @88
// CHECK-NEXT: GIM_Reject,
// CHECK-NEXT: };
// CHECK-NEXT: return MatchTable0;
diff --git a/llvm/test/TableGen/GlobalISelCombinerEmitter/match-table-patfrag-root.td b/llvm/test/TableGen/GlobalISelCombinerEmitter/match-table-patfrag-root.td
index 21a31a9fc5bf5dd..c314b2a35d77af7 100644
--- a/llvm/test/TableGen/GlobalISelCombinerEmitter/match-table-patfrag-root.td
+++ b/llvm/test/TableGen/GlobalISelCombinerEmitter/match-table-patfrag-root.td
@@ -28,7 +28,7 @@ def MyCombiner: GICombiner<"GenMyCombiner", [
// CHECK: const int64_t *GenMyCombiner::getMatchTable() const {
// CHECK-NEXT: constexpr static int64_t MatchTable0[] = {
-// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 0*/ 44, // Rule ID 0 //
+// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 0*/ 36, // Rule ID 0 //
// CHECK-NEXT: GIM_CheckSimplePredicate, GICXXPred_Simple_IsRule0Enabled,
// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_ZEXT,
// CHECK-NEXT: // MIs[0] root
@@ -40,17 +40,15 @@ def MyCombiner: GICombiner<"GenMyCombiner", [
// CHECK-NEXT: // No operand predicates
// CHECK-NEXT: GIM_CheckIsSafeToFold, /*InsnID*/1,
// CHECK-NEXT: GIR_MakeTempReg, /*TempRegID*/0, /*TypeID*/GILLT_s32,
-// CHECK-NEXT: GIR_BuildMI, /*InsnID*/1, /*Opcode*/TargetOpcode::G_CONSTANT,
-// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/1, /*TempRegID*/0, /*TempRegFlags*/0,
-// CHECK-NEXT: GIR_AddCImm, /*InsnID*/1, /*Type*/GILLT_s32, /*Imm*/0,
+// CHECK-NEXT: GIR_BuildConstant, /*TempRegID*/0, /*Val*/0,
// CHECK-NEXT: // Combiner Rule #0: Test0 @ [__Test0_match_0[0]]
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/TargetOpcode::COPY,
// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // root
// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/0, /*TempRegID*/0, /*TempRegFlags*/0,
// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
// CHECK-NEXT: GIR_Done,
-// CHECK-NEXT: // Label 0: @44
-// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 1*/ 79, // Rule ID 1 //
+// CHECK-NEXT: // Label 0: @36
+// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 1*/ 63, // Rule ID 1 //
// CHECK-NEXT: GIM_CheckSimplePredicate, GICXXPred_Simple_IsRule0Enabled,
// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_TRUNC,
// CHECK-NEXT: // MIs[0] root
@@ -58,17 +56,15 @@ def MyCombiner: GICombiner<"GenMyCombiner", [
// CHECK-NEXT: // MIs[0] __Test0_match_0.z
// CHECK-NEXT: // No operand predicates
// CHECK-NEXT: GIR_MakeTempReg, /*TempRegID*/0, /*TypeID*/GILLT_s32,
-// CHECK-NEXT: GIR_BuildMI, /*InsnID*/1, /*Opcode*/TargetOpcode::G_CONSTANT,
-// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/1, /*TempRegID*/0, /*TempRegFlags*/0,
-// CHECK-NEXT: GIR_AddCImm, /*InsnID*/1, /*Type*/GILLT_s32, /*Imm*/0,
+// CHECK-NEXT: GIR_BuildConstant, /*TempRegID*/0, /*Val*/0,
// CHECK-NEXT: // Combiner Rule #0: Test0 @ [__Test0_match_0[1]]
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/TargetOpcode::COPY,
// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // root
// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/0, /*TempRegID*/0, /*TempRegFlags*/0,
// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
// CHECK-NEXT: GIR_Done,
-// CHECK-NEXT: // Label 1: @79
-// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 2*/ 114, // Rule ID 2 //
+// CHECK-NEXT: // Label 1: @63
+// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 2*/ 90, // Rule ID 2 //
// CHECK-NEXT: GIM_CheckSimplePredicate, GICXXPred_Simple_IsRule0Enabled,
// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_FPEXT,
// CHECK-NEXT: // MIs[0] root
@@ -76,16 +72,14 @@ def MyCombiner: GICombiner<"GenMyCombiner", [
// CHECK-NEXT: // MIs[0] __Test0_match_0.z
// CHECK-NEXT: // No operand predicates
// CHECK-NEXT: GIR_MakeTempReg, /*TempRegID*/0, /*TypeID*/GILLT_s32,
-// CHECK-NEXT: GIR_BuildMI, /*InsnID*/1, /*Opcode*/TargetOpcode::G_CONSTANT,
-// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/1, /*TempRegID*/0, /*TempRegFlags*/0,
-// CHECK-NEXT: GIR_AddCImm, /*InsnID*/1, /*Type*/GILLT_s32, /*Imm*/0,
+// CHECK-NEXT: GIR_BuildConstant, /*TempRegID*/0, /*Val*/0,
// CHECK-NEXT: // Combiner Rule #0: Test0 @ [__Test0_match_0[2]]
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/TargetOpcode::COPY,
// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // root
// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/0, /*TempRegID*/0, /*TempRegFlags*/0,
// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
// CHECK-NEXT: GIR_Done,
-// CHECK-NEXT: // Label 2: @114
+// CHECK-NEXT: // Label 2: @90
// CHECK-NEXT: GIM_Reject,
// CHECK-NEXT: };
// CHECK-NEXT: return MatchTable0;
diff --git a/llvm/test/TableGen/GlobalISelCombinerEmitter/match-table-permutations.td b/llvm/test/TableGen/GlobalISelCombinerEmitter/match-table-permutations.td
index e6825ba6607ea6a..1bede1a1587687a 100644
--- a/llvm/test/TableGen/GlobalISelCombinerEmitter/match-table-permutations.td
+++ b/llvm/test/TableGen/GlobalISelCombinerEmitter/match-table-permutations.td
@@ -159,9 +159,9 @@ def MyCombiner: GICombiner<"GenMyCombiner", [
// CHECK: const int64_t *GenMyCombiner::getMatchTable() const {
// CHECK-NEXT: constexpr static int64_t MatchTable0[] = {
-// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 0*/ 746,
+// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 0*/ 682,
// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_AND,
-// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 1*/ 111, // Rule ID 0 //
+// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 1*/ 103, // Rule ID 0 //
// CHECK-NEXT: GIM_CheckSimplePredicate, GICXXPred_Simple_IsRule0Enabled,
// CHECK-NEXT: // MIs[0] dst
// CHECK-NEXT: // No operand predicates
@@ -203,9 +203,7 @@ def MyCombiner: GICombiner<"GenMyCombiner", [
// CHECK-NEXT: GIM_CheckIsSafeToFold, /*InsnID*/6,
// CHECK-NEXT: GIM_CheckIsSafeToFold, /*InsnID*/7,
// CHECK-NEXT: GIR_MakeTempReg, /*TempRegID*/0, /*TypeID*/GILLT_s32,
-// CHECK-NEXT: GIR_BuildMI, /*InsnID*/1, /*Opcode*/TargetOpcode::G_CONSTANT,
-// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/1, /*TempRegID*/0, /*TempRegFlags*/0,
-// CHECK-NEXT: GIR_AddCImm, /*InsnID*/1, /*Type*/GILLT_s32, /*Imm*/0,
+// CHECK-NEXT: GIR_BuildConstant, /*TempRegID*/0, /*Val*/0,
// CHECK-NEXT: // Combiner Rule #0: Test0 @ [a[0], b[0], c[0]]
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/TargetOpcode::COPY,
// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
@@ -213,8 +211,8 @@ def MyCombiner: GICombiner<"GenMyCombiner", [
// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
// CHECK-NEXT: GIR_CustomAction, GICXXCustomAction_CombineApplyGICombiner0,
// CHECK-NEXT: GIR_Done,
-// CHECK-NEXT: // Label 1: @111
-// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 2*/ 208, // Rule ID 1 //
+// CHECK-NEXT: // Label 1: @103
+// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 2*/ 192, // Rule ID 1 //
// CHECK-NEXT: GIM_CheckSimplePredicate, GICXXPred_Simple_IsRule0Enabled,
// CHECK-NEXT: // MIs[0] dst
// CHECK-NEXT: // No operand predicates
@@ -252,9 +250,7 @@ def MyCombiner: GICombiner<"GenMyCombiner", [
// CHECK-NEXT: GIM_CheckIsSafeToFold, /*InsnID*/5,
// CHECK-NEXT: GIM_CheckIsSafeToFold, /*InsnID*/6,
// CHECK-NEXT: GIR_MakeTempReg, /*TempRegID*/0, /*TypeID*/GILLT_s32,
-// CHECK-NEXT: GIR_BuildMI, /*InsnID*/1, /*Opcode*/TargetOpcode::G_CONSTANT,
-// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/1, /*TempRegID*/0, /*TempRegFlags*/0,
-// CHECK-NEXT: GIR_AddCImm, /*InsnID*/1, /*Type*/GILLT_s32, /*Imm*/0,
+// CHECK-NEXT: GIR_BuildConstant, /*TempRegID*/0, /*Val*/0,
// CHECK-NEXT: // Combiner Rule #0: Test0 @ [a[0], b[0], c[1]]
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/TargetOpcode::COPY,
// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
@@ -262,8 +258,8 @@ def MyCombiner: GICombiner<"GenMyCombiner", [
// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
// CHECK-NEXT: GIR_CustomAction, GICXXCustomAction_CombineApplyGICombiner0,
// CHECK-NEXT: GIR_Done,
-// CHECK-NEXT: // Label 2: @208
-// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 3*/ 305, // Rule ID 2 //
+// CHECK-NEXT: // Label 2: @192
+// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 3*/ 281, // Rule ID 2 //
// CHECK-NEXT: GIM_CheckSimplePredicate, GICXXPred_Simple_IsRule0Enabled,
// CHECK-NEXT: // MIs[0] dst
// CHECK-NEXT: // No operand predicates
@@ -301,9 +297,7 @@ def MyCombiner: GICombiner<"GenMyCombiner", [
// CHECK-NEXT: GIM_CheckIsSafeToFold, /*InsnID*/5,
// CHECK-NEXT: GIM_CheckIsSafeToFold, /*InsnID*/6,
// CHECK-NEXT: GIR_MakeTempReg, /*TempRegID*/0, /*TypeID*/GILLT_s32,
-// CHECK-NEXT: GIR_BuildMI, /*InsnID*/1, /*Opcode*/TargetOpcode::G_CONSTANT,
-// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/1, /*TempRegID*/0, /*TempRegFlags*/0,
-// CHECK-NEXT: GIR_AddCImm, /*InsnID*/1, /*Type*/GILLT_s32, /*Imm*/0,
+// CHECK-NEXT: GIR_BuildConstant, /*TempRegID*/0, /*Val*/0,
// CHECK-NEXT: // Combiner Rule #0: Test0 @ [a[0], b[1], c[0]]
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/TargetOpcode::COPY,
// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
@@ -311,8 +305,8 @@ def MyCombiner: GICombiner<"GenMyCombiner", [
// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
// CHECK-NEXT: GIR_CustomAction, GICXXCustomAction_CombineApplyGICombiner0,
// CHECK-NEXT: GIR_Done,
-// CHECK-NEXT: // Label 3: @305
-// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 4*/ 393, // Rule ID 3 //
+// CHECK-NEXT: // Label 3: @281
+// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 4*/ 361, // Rule ID 3 //
// CHECK-NEXT: GIM_CheckSimplePredicate, GICXXPred_Simple_IsRule0Enabled,
// CHECK-NEXT: // MIs[0] dst
// CHECK-NEXT: // No operand predicates
@@ -346,9 +340,7 @@ def MyCombiner: GICombiner<"GenMyCombiner", [
// CHECK-NEXT: GIM_CheckIsSafeToFold, /*InsnID*/4,
// CHECK-NEXT: GIM_CheckIsSafeToFold, /*InsnID*/5,
// CHECK-NEXT: GIR_MakeTempReg, /*TempRegID*/0, /*TypeID*/GILLT_s32,
-// CHECK-NEXT: GIR_BuildMI, /*InsnID*/1, /*Opcode*/TargetOpcode::G_CONSTANT,
-// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/1, /*TempRegID*/0, /*TempRegFlags*/0,
-// CHECK-NEXT: GIR_AddCImm, /*InsnID*/1, /*Type*/GILLT_s32, /*Imm*/0,
+// CHECK-NEXT: GIR_BuildConstant, /*TempRegID*/0, /*Val*/0,
// CHECK-NEXT: // Combiner Rule #0: Test0 @ [a[0], b[1], c[1]]
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/TargetOpcode::COPY,
// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
@@ -356,8 +348,8 @@ def MyCombiner: GICombiner<"GenMyCombiner", [
// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
// CHECK-NEXT: GIR_CustomAction, GICXXCustomAction_CombineApplyGICombiner0,
// CHECK-NEXT: GIR_Done,
-// CHECK-NEXT: // Label 4: @393
-// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 5*/ 490, // Rule ID 4 //
+// CHECK-NEXT: // Label 4: @361
+// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 5*/ 450, // Rule ID 4 //
// CHECK-NEXT: GIM_CheckSimplePredicate, GICXXPred_Simple_IsRule0Enabled,
// CHECK-NEXT: // MIs[0] dst
// CHECK-NEXT: // No operand predicates
@@ -395,9 +387,7 @@ def MyCombiner: GICombiner<"GenMyCombiner", [
// CHECK-NEXT: GIM_CheckIsSafeToFold, /*InsnID*/5,
// CHECK-NEXT: GIM_CheckIsSafeToFold, /*InsnID*/6,
// CHECK-NEXT: GIR_MakeTempReg, /*TempRegID*/0, /*TypeID*/GILLT_s32,
-// CHECK-NEXT: GIR_BuildMI, /*InsnID*/1, /*Opcode*/TargetOpcode::G_CONSTANT,
-// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/1, /*TempRegID*/0, /*TempRegFlags*/0,
-// CHECK-NEXT: GIR_AddCImm, /*InsnID*/1, /*Type*/GILLT_s32, /*Imm*/0,
+// CHECK-NEXT: GIR_BuildConstant, /*TempRegID*/0, /*Val*/0,
// CHECK-NEXT: // Combiner Rule #0: Test0 @ [a[1], b[0], c[0]]
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/TargetOpcode::COPY,
// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
@@ -405,8 +395,8 @@ def MyCombiner: GICombiner<"GenMyCombiner", [
// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
// CHECK-NEXT: GIR_CustomAction, GICXXCustomAction_CombineApplyGICombiner0,
// CHECK-NEXT: GIR_Done,
-// CHECK-NEXT: // Label 5: @490
-// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 6*/ 578, // Rule ID 5 //
+// CHECK-NEXT: // Label 5: @450
+// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 6*/ 530, // Rule ID 5 //
// CHECK-NEXT: GIM_CheckSimplePredicate, GICXXPred_Simple_IsRule0Enabled,
// CHECK-NEXT: // MIs[0] dst
// CHECK-NEXT: // No operand predicates
@@ -440,9 +430,7 @@ def MyCombiner: GICombiner<"GenMyCombiner", [
// CHECK-NEXT: GIM_CheckIsSafeToFold, /*InsnID*/4,
// CHECK-NEXT: GIM_CheckIsSafeToFold, /*InsnID*/5,
// CHECK-NEXT: GIR_MakeTempReg, /*TempRegID*/0, /*TypeID*/GILLT_s32,
-// CHECK-NEXT: GIR_BuildMI, /*InsnID*/1, /*Opcode*/TargetOpcode::G_CONSTANT,
-// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/1, /*TempRegID*/0, /*TempRegFlags*/0,
-// CHECK-NEXT: GIR_AddCImm, /*InsnID*/1, /*Type*/GILLT_s32, /*Imm*/0,
+// CHECK-NEXT: GIR_BuildConstant, /*TempRegID*/0, /*Val*/0,
// CHECK-NEXT: // Combiner Rule #0: Test0 @ [a[1], b[0], c[1]]
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/TargetOpcode::COPY,
// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
@@ -450,8 +438,8 @@ def MyCombiner: GICombiner<"GenMyCombiner", [
// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
// CHECK-NEXT: GIR_CustomAction, GICXXCustomAction_CombineApplyGICombiner0,
// CHECK-NEXT: GIR_Done,
-// CHECK-NEXT: // Label 6: @578
-// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 7*/ 666, // Rule ID 6 //
+// CHECK-NEXT: // Label 6: @530
+// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 7*/ 610, // Rule ID 6 //
// CHECK-NEXT: GIM_CheckSimplePredicate, GICXXPred_Simple_IsRule0Enabled,
// CHECK-NEXT: // MIs[0] dst
// CHECK-NEXT: // No operand predicates
@@ -485,9 +473,7 @@ def MyCombiner: GICombiner<"GenMyCombiner", [
// CHECK-NEXT: GIM_CheckIsSafeToFold, /*InsnID*/4,
// CHECK-NEXT: GIM_CheckIsSafeToFold, /*InsnID*/5,
// CHECK-NEXT: GIR_MakeTempReg, /*TempRegID*/0, /*TypeID*/GILLT_s32,
-// CHECK-NEXT: GIR_BuildMI, /*InsnID*/1, /*Opcode*/TargetOpcode::G_CONSTANT,
-// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/1, /*TempRegID*/0, /*TempRegFlags*/0,
-// CHECK-NEXT: GIR_AddCImm, /*InsnID*/1, /*Type*/GILLT_s32, /*Imm*/0,
+// CHECK-NEXT: GIR_BuildConstant, /*TempRegID*/0, /*Val*/0,
// CHECK-NEXT: // Combiner Rule #0: Test0 @ [a[1], b[1], c[0]]
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/TargetOpcode::COPY,
// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
@@ -495,8 +481,8 @@ def MyCombiner: GICombiner<"GenMyCombiner", [
// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
// CHECK-NEXT: GIR_CustomAction, GICXXCustomAction_CombineApplyGICombiner0,
// CHECK-NEXT: GIR_Done,
-// CHECK-NEXT: // Label 7: @666
-// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 8*/ 745, // Rule ID 7 //
+// CHECK-NEXT: // Label 7: @610
+// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 8*/ 681, // Rule ID 7 //
// CHECK-NEXT: GIM_CheckSimplePredicate, GICXXPred_Simple_IsRule0Enabled,
// CHECK-NEXT: // MIs[0] dst
// CHECK-NEXT: // No operand predicates
@@ -526,9 +512,7 @@ def MyCombiner: GICombiner<"GenMyCombiner", [
// CHECK-NEXT: GIM_CheckIsSafeToFold, /*InsnID*/3,
// CHECK-NEXT: GIM_CheckIsSafeToFold, /*InsnID*/4,
// CHECK-NEXT: GIR_MakeTempReg, /*TempRegID*/0, /*TypeID*/GILLT_s32,
-// CHECK-NEXT: GIR_BuildMI, /*InsnID*/1, /*Opcode*/TargetOpcode::G_CONSTANT,
-// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/1, /*TempRegID*/0, /*TempRegFlags*/0,
-// CHECK-NEXT: GIR_AddCImm, /*InsnID*/1, /*Type*/GILLT_s32, /*Imm*/0,
+// CHECK-NEXT: GIR_BuildConstant, /*TempRegID*/0, /*Val*/0,
// CHECK-NEXT: // Combiner Rule #0: Test0 @ [a[1], b[1], c[1]]
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/TargetOpcode::COPY,
// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
@@ -536,9 +520,9 @@ def MyCombiner: GICombiner<"GenMyCombiner", [
// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
// CHECK-NEXT: GIR_CustomAction, GICXXCustomAction_CombineApplyGICombiner0,
// CHECK-NEXT: GIR_Done,
-// CHECK-NEXT: // Label 8: @745
+// CHECK-NEXT: // Label 8: @681
// CHECK-NEXT: GIM_Reject,
-// CHECK-NEXT: // Label 0: @746
+// CHECK-NEXT: // Label 0: @682
// CHECK-NEXT: GIM_Reject,
// CHECK-NEXT: };
// CHECK-NEXT: return MatchTable0;
diff --git a/llvm/test/TableGen/GlobalISelCombinerEmitter/match-table.td b/llvm/test/TableGen/GlobalISelCombinerEmitter/match-table.td
index 3319dae71127b83..a353d9b5aaf4e1d 100644
--- a/llvm/test/TableGen/GlobalISelCombinerEmitter/match-table.td
+++ b/llvm/test/TableGen/GlobalISelCombinerEmitter/match-table.td
@@ -225,7 +225,7 @@ def MyCombiner: GICombiner<"GenMyCombiner", [
// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
// CHECK-NEXT: GIR_Done,
// CHECK-NEXT: // Label 8: @143
-// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 9*/ 181, // Rule ID 7 //
+// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 9*/ 173, // Rule ID 7 //
// CHECK-NEXT: GIM_CheckSimplePredicate, GICXXPred_Simple_IsRule6Enabled,
// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_ZEXT,
// CHECK-NEXT: // MIs[0] dst
@@ -234,16 +234,14 @@ def MyCombiner: GICombiner<"GenMyCombiner", [
// CHECK-NEXT: // No operand predicates
// CHECK-NEXT: GIM_CheckCxxInsnPredicate, /*MI*/0, /*FnId*/GICXXPred_MI_Predicate_GICombiner1,
// CHECK-NEXT: GIR_MakeTempReg, /*TempRegID*/0, /*TypeID*/GILLT_s32,
-// CHECK-NEXT: GIR_BuildMI, /*InsnID*/1, /*Opcode*/TargetOpcode::G_CONSTANT,
-// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/1, /*TempRegID*/0, /*TempRegFlags*/0,
-// CHECK-NEXT: GIR_AddCImm, /*InsnID*/1, /*Type*/GILLT_s32, /*Imm*/0,
+// CHECK-NEXT: GIR_BuildConstant, /*TempRegID*/0, /*Val*/0,
// CHECK-NEXT: // Combiner Rule #6: PatFragTest0 @ [__PatFragTest0_match_1[0]]
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/TargetOpcode::COPY,
// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/0, /*TempRegID*/0, /*TempRegFlags*/0,
// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
// CHECK-NEXT: GIR_Done,
-// CHECK-NEXT: // Label 9: @181
+// CHECK-NEXT: // Label 9: @173
// CHECK-NEXT: GIM_Reject,
// CHECK-NEXT: };
// CHECK-NEXT: return MatchTable0;
diff --git a/llvm/utils/TableGen/GlobalISelCombinerEmitter.cpp b/llvm/utils/TableGen/GlobalISelCombinerEmitter.cpp
index e32ef8b9a7986b1..a6d4b7e4d1717fe 100644
--- a/llvm/utils/TableGen/GlobalISelCombinerEmitter.cpp
+++ b/llvm/utils/TableGen/GlobalISelCombinerEmitter.cpp
@@ -3108,13 +3108,10 @@ bool CombineRuleBuilder::emitCodeGenInstructionApplyImmOperand(
}
unsigned TempRegID = M.allocateTempRegID();
- auto ActIt = M.insertAction<BuildMIAction>(
- M.actions_begin(), M.allocateOutputInsnID(), &getGConstant());
- // Ensure MakeTempReg occurs before the BuildMI of th G_CONSTANT.
- M.insertAction<MakeTempRegisterAction>(ActIt, LLT, TempRegID);
- auto &ConstantMI = *static_cast<BuildMIAction *>(ActIt->get());
- ConstantMI.addRenderer<TempRegRenderer>(TempRegID);
- ConstantMI.addRenderer<ImmRenderer>(O.getImmValue(), LLT);
+ // Ensure MakeTempReg & the BuildConstantAction occur at the beginning.
+ auto InsertIt =
+ M.insertAction<MakeTempRegisterAction>(M.actions_begin(), LLT, TempRegID);
+ M.insertAction<BuildConstantAction>(++InsertIt, TempRegID, O.getImmValue());
DstMI.addRenderer<TempRegRenderer>(TempRegID);
return true;
}
diff --git a/llvm/utils/TableGen/GlobalISelMatchTable.cpp b/llvm/utils/TableGen/GlobalISelMatchTable.cpp
index dcfd0a34beb07f1..9a4a375f34bdb91 100644
--- a/llvm/utils/TableGen/GlobalISelMatchTable.cpp
+++ b/llvm/utils/TableGen/GlobalISelMatchTable.cpp
@@ -2014,6 +2014,16 @@ void BuildMIAction::emitActionOpcodes(MatchTable &Table,
EraseInstAction::emitActionOpcodes(Table, Rule, /*InsnID*/ 0);
}
+//===- BuildConstantAction ------------------------------------------------===//
+
+void BuildConstantAction::emitActionOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const {
+ Table << MatchTable::Opcode("GIR_BuildConstant")
+ << MatchTable::Comment("TempRegID") << MatchTable::IntValue(TempRegID)
+ << MatchTable::Comment("Val") << MatchTable::IntValue(Val)
+ << MatchTable::LineBreak;
+}
+
//===- EraseInstAction ----------------------------------------------------===//
void EraseInstAction::emitActionOpcodes(MatchTable &Table, RuleMatcher &Rule,
diff --git a/llvm/utils/TableGen/GlobalISelMatchTable.h b/llvm/utils/TableGen/GlobalISelMatchTable.h
index 549d7ccde18bdf2..5608bab482bfd34 100644
--- a/llvm/utils/TableGen/GlobalISelMatchTable.h
+++ b/llvm/utils/TableGen/GlobalISelMatchTable.h
@@ -2093,6 +2093,7 @@ class MatchAction {
AK_DebugComment,
AK_CustomCXX,
AK_BuildMI,
+ AK_BuildConstantMI,
AK_EraseInst,
AK_ReplaceReg,
AK_ConstraintOpsToDef,
@@ -2187,6 +2188,24 @@ class BuildMIAction : public MatchAction {
void emitActionOpcodes(MatchTable &Table, RuleMatcher &Rule) const override;
};
+/// Generates code to create a constant that defines a TempReg.
+/// The instruction created is usually a G_CONSTANT but it could also be a
+/// G_BUILD_VECTOR for vector types.
+class BuildConstantAction : public MatchAction {
+ unsigned TempRegID;
+ int64_t Val;
+
+public:
+ BuildConstantAction(unsigned TempRegID, int64_t Val)
+ : MatchAction(AK_BuildConstantMI), TempRegID(TempRegID), Val(Val) {}
+
+ static bool classof(const MatchAction *A) {
+ return A->getKind() == AK_BuildConstantMI;
+ }
+
+ void emitActionOpcodes(MatchTable &Table, RuleMatcher &Rule) const override;
+};
+
class EraseInstAction : public MatchAction {
unsigned InsnID;
>From 1f4c714b1c2c0295dd184fba9b88beb740e16bd8 Mon Sep 17 00:00:00 2001
From: pvanhout <pierre.vanhoutryve at amd.com>
Date: Tue, 12 Sep 2023 13:14:37 +0200
Subject: [PATCH 3/3] [GlobalISel] Add `GITypeOf` special type
Allows creating a register/immediate that uses the same type as a matched operand.
---
llvm/docs/GlobalISel/MIRPatterns.rst | 42 +++
.../llvm/CodeGen/GlobalISel/CombinerHelper.h | 3 -
.../CodeGen/GlobalISel/GIMatchTableExecutor.h | 16 +-
.../GlobalISel/GIMatchTableExecutorImpl.h | 49 ++--
.../include/llvm/Target/GlobalISel/Combine.td | 25 +-
.../lib/CodeGen/GlobalISel/CombinerHelper.cpp | 12 -
.../match-table-typeof.td | 49 ++++
.../operand-types.td | 28 +-
.../pattern-parsing.td | 25 +-
.../typeof-errors.td | 72 +++++
.../TableGen/GlobalISelCombinerEmitter.cpp | 277 +++++++++++++++---
llvm/utils/TableGen/GlobalISelMatchTable.cpp | 35 ++-
llvm/utils/TableGen/GlobalISelMatchTable.h | 89 +++++-
13 files changed, 620 insertions(+), 102 deletions(-)
create mode 100644 llvm/test/TableGen/GlobalISelCombinerEmitter/match-table-typeof.td
create mode 100644 llvm/test/TableGen/GlobalISelCombinerEmitter/typeof-errors.td
diff --git a/llvm/docs/GlobalISel/MIRPatterns.rst b/llvm/docs/GlobalISel/MIRPatterns.rst
index fa70311f48572de..a3883b14b3e0bd6 100644
--- a/llvm/docs/GlobalISel/MIRPatterns.rst
+++ b/llvm/docs/GlobalISel/MIRPatterns.rst
@@ -101,6 +101,48 @@ pattern, you can try naming your patterns to see exactly where the issue is.
// using $x again here copies operand 1 from G_AND into the new inst.
(apply (COPY $root, $x))
+Types
+-----
+
+ValueType
+~~~~~~~~~
+
+Subclasses of ``ValueType`` are valid types, e.g. ``i32``.
+
+GITypeOf
+~~~~~~~~
+
+``GITypeOf<"$x">`` is a ``GISpecialType`` that allows for the creation of a
+register or immediate with the same type as another (register) operand.
+
+Operand:
+
+* An operand name as a string, prefixed by ``$``.
+
+Semantics:
+
+* Can only appear in an 'apply' pattern.
+* The operand name used must appear in the 'match' pattern of the
+ same ``GICombineRule``.
+
+.. code-block:: text
+ :caption: Example: Immediate
+
+ def mul_by_neg_one: GICombineRule <
+ (defs root:$root),
+ (match (G_MUL $dst, $x, -1)),
+ (apply (G_SUB $dst, (GITypeOf<"$x"> 0), $x))
+ >;
+
+.. code-block:: text
+ :caption: Example: Temp Reg
+
+ def Test0 : GICombineRule<
+ (defs root:$dst),
+ (match (G_FMUL $dst, $src, -1)),
+ (apply (G_FSUB $dst, $src, $tmp),
+ (G_FNEG GITypeOf<"$dst">:$tmp, $src))>;
+
Builtin Operations
------------------
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h b/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h
index b7c0cd4fc47faff..a896232618948a0 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h
@@ -406,9 +406,6 @@ class CombinerHelper {
void applyCombineTruncOfShift(MachineInstr &MI,
std::pair<MachineInstr *, LLT> &MatchInfo);
- /// Transform G_MUL(x, -1) to G_SUB(0, x)
- void applyCombineMulByNegativeOne(MachineInstr &MI);
-
/// Return true if any explicit use operand on \p MI is defined by a
/// G_IMPLICIT_DEF.
bool matchAnyExplicitUseIsUndef(MachineInstr &MI);
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutor.h b/llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutor.h
index 89c0b097281ddfa..2a893b81db72abf 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutor.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutor.h
@@ -276,6 +276,12 @@ enum {
/// - StoreIdx - Store location in RecordedOperands.
GIM_RecordNamedOperand,
+ /// Records an operand's register type into the set of temporary types.
+ /// - InsnID - Instruction ID
+ /// - OpIdx - Operand index
+ /// - TempTypeIdx - Temp Type Index, always negative.
+ GIM_RecordRegType,
+
/// Fail the current try-block, or completely fail to match if there is no
/// current try-block.
GIM_Reject,
@@ -357,12 +363,6 @@ enum {
/// - Imm - The immediate to add
GIR_AddImm,
- /// Add an CImm to the specified instruction
- /// - InsnID - Instruction ID to modify
- /// - Ty - Type of the constant immediate.
- /// - Imm - The immediate to add
- GIR_AddCImm,
-
/// Render complex operands to the specified instruction
/// - InsnID - Instruction ID to modify
/// - RendererID - The renderer to call
@@ -538,6 +538,10 @@ class GIMatchTableExecutor {
/// list. Currently such predicates don't have more then 3 arguments.
std::array<const MachineOperand *, 3> RecordedOperands;
+ /// Types extracted from an instruction's operand.
+ /// Whenever a type index is negative, we look here instead.
+ SmallVector<LLT, 4> RecordedTypes;
+
MatcherState(unsigned MaxRenderers);
};
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h b/llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h
index 92a1eb561fb10ae..fa8bddf795a9a7f 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h
@@ -103,6 +103,14 @@ bool GIMatchTableExecutor::executeMatchTable(
return true;
};
+ // If the index is >= 0, it's an index in the type objects generated by TableGen.
+ // If the index is <0, it's an index in the recorded types object.
+ auto getTypeFromIdx = [&](int64_t Idx) -> const LLT& {
+ if(Idx >= 0)
+ return ExecInfo.TypeObjects[Idx];
+ return State.RecordedTypes[1 - Idx];
+ };
+
while (true) {
assert(CurrentIdx != ~0u && "Invalid MatchTable index");
int64_t MatcherOpcode = MatchTable[CurrentIdx++];
@@ -639,7 +647,7 @@ bool GIMatchTableExecutor::executeMatchTable(
assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
MachineOperand &MO = State.MIs[InsnID]->getOperand(OpIdx);
if (!MO.isReg() ||
- MRI.getType(MO.getReg()) != ExecInfo.TypeObjects[TypeID]) {
+ MRI.getType(MO.getReg()) != getTypeFromIdx(TypeID)) {
if (handleReject() == RejectAndGiveUp)
return false;
}
@@ -690,6 +698,25 @@ bool GIMatchTableExecutor::executeMatchTable(
State.RecordedOperands[StoreIdx] = &State.MIs[InsnID]->getOperand(OpIdx);
break;
}
+ case GIM_RecordRegType: {
+ int64_t InsnID = MatchTable[CurrentIdx++];
+ int64_t OpIdx = MatchTable[CurrentIdx++];
+ int64_t TypeIdx = MatchTable[CurrentIdx++];
+
+ DEBUG_WITH_TYPE(TgtExecutor::getName(),
+ dbgs() << CurrentIdx << ": GIM_RecordRegType(MIs["
+ << InsnID << "]->getOperand(" << OpIdx
+ << "), TypeIdx=" << TypeIdx << ")\n");
+ assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
+ assert(TypeIdx <= 0 && "Temp types always have negative indexes!");
+ // Indexes start at -1.
+ TypeIdx = 1 - TypeIdx;
+ const auto& Op = State.MIs[InsnID]->getOperand(OpIdx);
+ if(State.RecordedTypes.size() <= (uint64_t)TypeIdx)
+ State.RecordedTypes.resize(TypeIdx + 1, LLT());
+ State.RecordedTypes[TypeIdx] = MRI.getType(Op.getReg());
+ break;
+ }
case GIM_CheckRegBankForClass: {
int64_t InsnID = MatchTable[CurrentIdx++];
int64_t OpIdx = MatchTable[CurrentIdx++];
@@ -1076,24 +1103,6 @@ bool GIMatchTableExecutor::executeMatchTable(
<< "], " << Imm << ")\n");
break;
}
-
- case GIR_AddCImm: {
- int64_t InsnID = MatchTable[CurrentIdx++];
- int64_t TypeID = MatchTable[CurrentIdx++];
- int64_t Imm = MatchTable[CurrentIdx++];
- assert(OutMIs[InsnID] && "Attempted to add to undefined instruction");
-
- unsigned Width = ExecInfo.TypeObjects[TypeID].getScalarSizeInBits();
- LLVMContext &Ctx = MF->getFunction().getContext();
- OutMIs[InsnID].addCImm(
- ConstantInt::get(IntegerType::get(Ctx, Width), Imm, /*signed*/ true));
- DEBUG_WITH_TYPE(TgtExecutor::getName(),
- dbgs() << CurrentIdx << ": GIR_AddCImm(OutMIs[" << InsnID
- << "], TypeID=" << TypeID << ", Imm=" << Imm
- << ")\n");
- break;
- }
-
case GIR_ComplexRenderer: {
int64_t InsnID = MatchTable[CurrentIdx++];
int64_t RendererID = MatchTable[CurrentIdx++];
@@ -1282,7 +1291,7 @@ bool GIMatchTableExecutor::executeMatchTable(
int64_t TypeID = MatchTable[CurrentIdx++];
State.TempRegisters[TempRegID] =
- MRI.createGenericVirtualRegister(ExecInfo.TypeObjects[TypeID]);
+ MRI.createGenericVirtualRegister(getTypeFromIdx(TypeID));
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": TempRegs[" << TempRegID
<< "] = GIR_MakeTempReg(" << TypeID << ")\n");
diff --git a/llvm/include/llvm/Target/GlobalISel/Combine.td b/llvm/include/llvm/Target/GlobalISel/Combine.td
index 7e0691e1ee95048..31a337feed847ec 100644
--- a/llvm/include/llvm/Target/GlobalISel/Combine.td
+++ b/llvm/include/llvm/Target/GlobalISel/Combine.td
@@ -110,6 +110,24 @@ class GICombinePatFrag<dag outs, dag ins, list<dag> alts> {
list<dag> Alternatives = alts;
}
+//===----------------------------------------------------------------------===//
+// Pattern Special Types
+//===----------------------------------------------------------------------===//
+
+class GISpecialType;
+
+// In an apply pattern, GITypeOf can be used to set the type of a new temporary
+// register to match the type of a matched register.
+//
+// This can only be used on temporary registers defined by the apply pattern.
+//
+// TODO: Make this work in matchers as well?
+//
+// FIXME: Syntax is very ugly.
+class GITypeOf<string opName> : GISpecialType {
+ string OpName = opName;
+}
+
//===----------------------------------------------------------------------===//
// Pattern Builtins
//===----------------------------------------------------------------------===//
@@ -776,10 +794,9 @@ def trunc_shift: GICombineRule <
// Transform (mul x, -1) -> (sub 0, x)
def mul_by_neg_one: GICombineRule <
- (defs root:$root),
- (match (wip_match_opcode G_MUL):$root,
- [{ return Helper.matchConstantOp(${root}->getOperand(2), -1); }]),
- (apply [{ Helper.applyCombineMulByNegativeOne(*${root}); }])
+ (defs root:$dst),
+ (match (G_MUL $dst, $x, -1)),
+ (apply (G_SUB $dst, (GITypeOf<"$x"> 0), $x))
>;
// Fold (xor (and x, y), y) -> (and (not x), y)
diff --git a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
index 2ce68950424095e..4d99a6d10e84378 100644
--- a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
@@ -2282,18 +2282,6 @@ void CombinerHelper::applyCombineExtOfExt(
}
}
-void CombinerHelper::applyCombineMulByNegativeOne(MachineInstr &MI) {
- assert(MI.getOpcode() == TargetOpcode::G_MUL && "Expected a G_MUL");
- Register DstReg = MI.getOperand(0).getReg();
- Register SrcReg = MI.getOperand(1).getReg();
- LLT DstTy = MRI.getType(DstReg);
-
- Builder.setInstrAndDebugLoc(MI);
- Builder.buildSub(DstReg, Builder.buildConstant(DstTy, 0), SrcReg,
- MI.getFlags());
- MI.eraseFromParent();
-}
-
bool CombinerHelper::matchCombineTruncOfExt(
MachineInstr &MI, std::pair<Register, unsigned> &MatchInfo) {
assert(MI.getOpcode() == TargetOpcode::G_TRUNC && "Expected a G_TRUNC");
diff --git a/llvm/test/TableGen/GlobalISelCombinerEmitter/match-table-typeof.td b/llvm/test/TableGen/GlobalISelCombinerEmitter/match-table-typeof.td
new file mode 100644
index 000000000000000..496d86aeef2d10a
--- /dev/null
+++ b/llvm/test/TableGen/GlobalISelCombinerEmitter/match-table-typeof.td
@@ -0,0 +1,49 @@
+// RUN: llvm-tblgen -I %p/../../../include -gen-global-isel-combiner \
+// RUN: -combiners=MyCombiner %s | \
+// RUN: FileCheck %s
+
+include "llvm/Target/Target.td"
+include "llvm/Target/GlobalISel/Combine.td"
+
+def MyTargetISA : InstrInfo;
+def MyTarget : Target { let InstructionSet = MyTargetISA; }
+
+def Test0 : GICombineRule<
+ (defs root:$dst),
+ (match (G_MUL $dst, $src, -1)),
+ (apply (G_SUB $dst, (GITypeOf<"$src"> 0), $tmp),
+ (G_CONSTANT GITypeOf<"$dst">:$tmp, (GITypeOf<"$src"> 42)))>;
+
+// CHECK: const int64_t *GenMyCombiner::getMatchTable() const {
+// CHECK-NEXT: constexpr static int64_t MatchTable0[] = {
+// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 0*/ 57, // Rule ID 0 //
+// CHECK-NEXT: GIM_CheckSimplePredicate, GICXXPred_Simple_IsRule0Enabled,
+// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_MUL,
+// CHECK-NEXT: // MIs[0] dst
+// CHECK-NEXT: GIM_RecordRegType, /*MI*/0, /*Op*/0, /*TempTypeIdx*/-1,
+// CHECK-NEXT: // MIs[0] src
+// CHECK-NEXT: GIM_RecordRegType, /*MI*/0, /*Op*/1, /*TempTypeIdx*/-2,
+// CHECK-NEXT: // MIs[0] Operand 2
+// CHECK-NEXT: GIM_CheckConstantInt, /*MI*/0, /*Op*/2, -1,
+// CHECK-NEXT: GIR_MakeTempReg, /*TempRegID*/1, /*TypeID*/-2,
+// CHECK-NEXT: GIR_BuildConstant, /*TempRegID*/1, /*Val*/0,
+// CHECK-NEXT: GIR_MakeTempReg, /*TempRegID*/0, /*TypeID*/-1,
+// CHECK-NEXT: // Combiner Rule #0: Test0
+// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/TargetOpcode::G_CONSTANT,
+// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/0, /*TempRegID*/0, /*TempRegFlags*/0,
+// CHECK-NEXT: GIR_AddCImm, /*InsnID*/0, /*Type*/-2, /*Imm*/42,
+// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
+// CHECK-NEXT: GIR_BuildMI, /*InsnID*/1, /*Opcode*/TargetOpcode::G_SUB,
+// CHECK-NEXT: GIR_Copy, /*NewInsnID*/1, /*OldInsnID*/0, /*OpIdx*/0, // dst
+// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/1, /*TempRegID*/1, /*TempRegFlags*/0,
+// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/1, /*TempRegID*/0, /*TempRegFlags*/0,
+// CHECK-NEXT: GIR_Done,
+// CHECK-NEXT: // Label 0: @57
+// CHECK-NEXT: GIM_Reject,
+// CHECK-NEXT: };
+// CHECK-NEXT: return MatchTable0;
+// CHECK-NEXT: }
+
+def MyCombiner: GICombiner<"GenMyCombiner", [
+ Test0
+]>;
diff --git a/llvm/test/TableGen/GlobalISelCombinerEmitter/operand-types.td b/llvm/test/TableGen/GlobalISelCombinerEmitter/operand-types.td
index c871e603e4e05aa..4769bed97240125 100644
--- a/llvm/test/TableGen/GlobalISelCombinerEmitter/operand-types.td
+++ b/llvm/test/TableGen/GlobalISelCombinerEmitter/operand-types.td
@@ -79,7 +79,33 @@ def PatFragTest0 : GICombineRule<
(match (FooPF $dst)),
(apply (COPY $dst, (i32 0)))>;
+
+// CHECK: (CombineRule name:TypeOfProp id:2 root:x
+// CHECK-NEXT: (MatchPats
+// CHECK-NEXT: <match_root>__TypeOfProp_match_0:(CodeGenInstructionPattern G_ZEXT operands:[<def>$x, $y])
+// CHECK-NEXT: )
+// CHECK-NEXT: (ApplyPats
+// CHECK-NEXT: <apply_root>__TypeOfProp_apply_0:(CodeGenInstructionPattern G_ANYEXT operands:[<def>$x, GITypeOf<$y>:$tmp])
+// CHECK-NEXT: __TypeOfProp_apply_1:(CodeGenInstructionPattern G_ANYEXT operands:[<def>GITypeOf<$y>:$tmp, $y])
+// CHECK-NEXT: )
+// CHECK-NEXT: (OperandTable MatchPats
+// CHECK-NEXT: x -> __TypeOfProp_match_0
+// CHECK-NEXT: y -> <live-in>
+// CHECK-NEXT: )
+// CHECK-NEXT: (OperandTable ApplyPats
+// CHECK-NEXT: tmp -> __TypeOfProp_apply_1
+// CHECK-NEXT: x -> __TypeOfProp_apply_0
+// CHECK-NEXT: y -> <live-in>
+// CHECK-NEXT: )
+// CHECK-NEXT: )
+def TypeOfProp : GICombineRule<
+ (defs root:$x),
+ (match (G_ZEXT $x, $y)),
+ (apply (G_ANYEXT $x, GITypeOf<"$y">:$tmp),
+ (G_ANYEXT $tmp, $y))>;
+
def MyCombiner: GICombiner<"GenMyCombiner", [
InstTest0,
- PatFragTest0
+ PatFragTest0,
+ TypeOfProp
]>;
diff --git a/llvm/test/TableGen/GlobalISelCombinerEmitter/pattern-parsing.td b/llvm/test/TableGen/GlobalISelCombinerEmitter/pattern-parsing.td
index bc75b15233b5519..fd41a7d1d72417e 100644
--- a/llvm/test/TableGen/GlobalISelCombinerEmitter/pattern-parsing.td
+++ b/llvm/test/TableGen/GlobalISelCombinerEmitter/pattern-parsing.td
@@ -297,6 +297,28 @@ def VariadicsOutTest : GICombineRule<
(apply (COPY $a, (i32 0)),
(COPY $b, (i32 0)))>;
+// CHECK: (CombineRule name:TypeOfTest id:10 root:dst
+// CHECK-NEXT: (MatchPats
+// CHECK-NEXT: <match_root>__TypeOfTest_match_0:(CodeGenInstructionPattern COPY operands:[<def>$dst, $tmp])
+// CHECK-NEXT: __TypeOfTest_match_1:(CodeGenInstructionPattern G_ZEXT operands:[<def>$tmp, $src])
+// CHECK-NEXT: )
+// CHECK-NEXT: (ApplyPats
+// CHECK-NEXT: <apply_root>__TypeOfTest_apply_0:(CodeGenInstructionPattern G_MUL operands:[<def>$dst, (GITypeOf<$src> 0), (GITypeOf<$dst> -1)])
+// CHECK-NEXT: )
+// CHECK-NEXT: (OperandTable MatchPats
+// CHECK-NEXT: dst -> __TypeOfTest_match_0
+// CHECK-NEXT: src -> <live-in>
+// CHECK-NEXT: tmp -> __TypeOfTest_match_1
+// CHECK-NEXT: )
+// CHECK-NEXT: (OperandTable ApplyPats
+// CHECK-NEXT: dst -> __TypeOfTest_apply_0
+// CHECK-NEXT: )
+// CHECK-NEXT: )
+def TypeOfTest : GICombineRule<
+ (defs root:$dst),
+ (match (COPY $dst, $tmp),
+ (G_ZEXT $tmp, $src)),
+ (apply (G_MUL $dst, (GITypeOf<"$src"> 0), (GITypeOf<"$dst"> -1)))>;
def MyCombiner: GICombiner<"GenMyCombiner", [
WipOpcodeTest0,
@@ -308,5 +330,6 @@ def MyCombiner: GICombiner<"GenMyCombiner", [
PatFragTest0,
PatFragTest1,
VariadicsInTest,
- VariadicsOutTest
+ VariadicsOutTest,
+ TypeOfTest
]>;
diff --git a/llvm/test/TableGen/GlobalISelCombinerEmitter/typeof-errors.td b/llvm/test/TableGen/GlobalISelCombinerEmitter/typeof-errors.td
new file mode 100644
index 000000000000000..6040d6def449766
--- /dev/null
+++ b/llvm/test/TableGen/GlobalISelCombinerEmitter/typeof-errors.td
@@ -0,0 +1,72 @@
+// RUN: not llvm-tblgen -I %p/../../../include -gen-global-isel-combiner \
+// RUN: -combiners=MyCombiner %s 2>&1| \
+// RUN: FileCheck %s -implicit-check-not=error:
+
+include "llvm/Target/Target.td"
+include "llvm/Target/GlobalISel/Combine.td"
+
+def MyTargetISA : InstrInfo;
+def MyTarget : Target { let InstructionSet = MyTargetISA; }
+
+// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: invalid operand name format 'unknown' in GITypeOf: expected '$' followed by an operand name
+def NoDollarSign : GICombineRule<
+ (defs root:$dst),
+ (match (G_ZEXT $dst, $src)),
+ (apply (G_ANYEXT $dst, (GITypeOf<"unknown"> 0)))>;
+
+// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: 'unknown' ('GITypeOf<$unknown>') does not refer to a matched operand!
+def UnknownOperand : GICombineRule<
+ (defs root:$dst),
+ (match (G_ZEXT $dst, $src)),
+ (apply (G_ANYEXT $dst, (GITypeOf<"$unknown"> 0)))>;
+
+// CHECK: :[[@LINE+2]]:{{[0-9]+}}: error: GISpecialType is not supported in 'match' patterns
+// CHECK: :[[@LINE+1]]:{{[0-9]+}}: note: operand 1 of '__UseInMatch_match_0' has type 'GITypeOf<$dst>'
+def UseInMatch : GICombineRule<
+ (defs root:$dst),
+ (match (G_ZEXT $dst, (GITypeOf<"$dst"> 0))),
+ (apply (G_ANYEXT $dst, (i32 0)))>;
+
+// CHECK: :[[@LINE+3]]:{{[0-9]+}}: error: GISpecialType is not supported in GICombinePatFrag
+// CHECK: :[[@LINE+2]]:{{[0-9]+}}: note: operand 1 of '__PFWithTypeOF_alt0_pattern_0' has type 'GITypeOf<$dst>
+// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: Could not parse GICombinePatFrag 'PFWithTypeOF'
+def PFWithTypeOF: GICombinePatFrag<
+ (outs $dst), (ins),
+ [(pattern (G_ANYEXT $dst, (GITypeOf<"$dst"> 0)))]>;
+
+// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: Failed to parse pattern: '(PFWithTypeOF ?:$dst)'
+def UseInPF: GICombineRule<
+ (defs root:$dst),
+ (match (PFWithTypeOF $dst)),
+ (apply (G_ANYEXT $dst, (i32 0)))>;
+
+// CHECK: :[[@LINE+2]]:{{[0-9]+}}: error: GISpecialType is not supported in 'match' patterns
+// CHECK: :[[@LINE+1]]:{{[0-9]+}}: note: operand 1 of '__InferredUseInMatch_match_0' has type 'GITypeOf<$dst>'
+def InferredUseInMatch : GICombineRule<
+ (defs root:$dst),
+ (match (G_ZEXT $dst, $src)),
+ (apply (G_ANYEXT $dst, GITypeOf<"$dst">:$src))>;
+
+// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: conflicting types for operand 'src': first seen with 'i32' in '__InferenceConflict_match_0, now seen with 'GITypeOf<$dst>' in '__InferenceConflict_apply_0'
+def InferenceConflict : GICombineRule<
+ (defs root:$dst),
+ (match (G_ZEXT $dst, i32:$src)),
+ (apply (G_ANYEXT $dst, GITypeOf<"$dst">:$src))>;
+
+// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: 'tmp' ('GITypeOf<$tmp>') does not refer to a matched operand!
+def TypeOfApplyTmp : GICombineRule<
+ (defs root:$dst),
+ (match (G_ZEXT $dst, $src)),
+ (apply (G_ANYEXT $dst, i32:$tmp),
+ (G_ANYEXT $tmp, (GITypeOf<"$tmp"> 0)))>;
+
+// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: Failed to parse one or more rules
+def MyCombiner: GICombiner<"GenMyCombiner", [
+ NoDollarSign,
+ UnknownOperand,
+ UseInMatch,
+ UseInPF,
+ InferredUseInMatch,
+ InferenceConflict,
+ TypeOfApplyTmp
+]>;
diff --git a/llvm/utils/TableGen/GlobalISelCombinerEmitter.cpp b/llvm/utils/TableGen/GlobalISelCombinerEmitter.cpp
index a6d4b7e4d1717fe..cfc891e80f7fd45 100644
--- a/llvm/utils/TableGen/GlobalISelCombinerEmitter.cpp
+++ b/llvm/utils/TableGen/GlobalISelCombinerEmitter.cpp
@@ -73,6 +73,8 @@ constexpr StringLiteral CXXApplyPrefix = "GICXXCustomAction_CombineApply";
constexpr StringLiteral CXXPredPrefix = "GICXXPred_MI_Predicate_";
constexpr StringLiteral PatFragClassName = "GICombinePatFrag";
constexpr StringLiteral BuiltinInstClassName = "GIBuiltinInst";
+constexpr StringLiteral SpecialTyClassName = "GISpecialType";
+constexpr StringLiteral TypeOfClassName = "GITypeOf";
std::string getIsEnabledPredicateEnumName(unsigned CombinerRuleID) {
return "GICXXPred_Simple_IsRule" + to_string(CombinerRuleID) + "Enabled";
@@ -123,11 +125,6 @@ template <typename Container> auto values(Container &&C) {
return map_range(C, [](auto &Entry) -> auto & { return Entry.second; });
}
-LLTCodeGen getLLTCodeGenFromRecord(const Record *Ty) {
- assert(Ty->isSubClassOf("ValueType"));
- return LLTCodeGen(*MVTToLLT(getValueType(Ty)));
-}
-
//===- MatchData Handling -------------------------------------------------===//
/// Represents MatchData defined by the match stage and required by the apply
@@ -292,6 +289,117 @@ class CXXPredicateCode {
CXXPredicateCode::CXXPredicateCodePool CXXPredicateCode::AllCXXMatchCode;
CXXPredicateCode::CXXPredicateCodePool CXXPredicateCode::AllCXXApplyCode;
+//===- PatternType --------------------------------------------------------===//
+
+/// Simple wrapper around a Record* of a type.
+///
+/// Types have two form:
+/// - LLTs, which are straightforward.
+/// - Special types, e.g. GITypeOf
+class PatternType {
+public:
+ PatternType() = default;
+ PatternType(const Record *R) : R(R) {}
+
+ bool isValidType() const { return !R || isLLT() || isSpecial(); }
+
+ bool isLLT() const { return R && R->isSubClassOf("ValueType"); }
+ bool isSpecial() const { return R && R->isSubClassOf(SpecialTyClassName); }
+ bool isTypeOf() const { return R && R->isSubClassOf(TypeOfClassName); }
+
+ StringRef getTypeOfOpName() const;
+ LLTCodeGen getLLTCodeGen() const;
+
+ bool checkSemantics(ArrayRef<SMLoc> DiagLoc) const;
+
+ LLTCodeGenOrTempType getLLTCodeGenOrTempType(RuleMatcher &RM) const;
+
+ explicit operator bool() const { return R != nullptr; }
+
+ bool operator==(const PatternType &Other) const;
+ bool operator!=(const PatternType &Other) const { return !operator==(Other); }
+
+ std::string str() const;
+
+private:
+ StringRef getRawOpName() const { return R->getValueAsString("OpName"); }
+
+ const Record *R = nullptr;
+};
+
+StringRef PatternType::getTypeOfOpName() const {
+ assert(isTypeOf());
+ StringRef Name = getRawOpName();
+ Name.consume_front("$");
+ return Name;
+}
+
+LLTCodeGen PatternType::getLLTCodeGen() const {
+ assert(isLLT());
+ return *MVTToLLT(getValueType(R));
+}
+
+LLTCodeGenOrTempType
+PatternType::getLLTCodeGenOrTempType(RuleMatcher &RM) const {
+ assert(isValidType());
+
+ if (isLLT())
+ return getLLTCodeGen();
+
+ assert(isTypeOf());
+ auto &OM = RM.getOperandMatcher(getTypeOfOpName());
+ return OM.getTempTypeIdx(RM);
+}
+
+bool PatternType::checkSemantics(ArrayRef<SMLoc> DiagLoc) const {
+ if (!isTypeOf())
+ return true;
+
+ auto RawOpName = getRawOpName();
+ if (RawOpName.starts_with("$"))
+ return true;
+
+ PrintError(DiagLoc, "invalid operand name format '" + RawOpName + "' in " +
+ TypeOfClassName +
+ ": expected '$' followed by an operand name");
+ return false;
+}
+
+bool PatternType::operator==(const PatternType &Other) const {
+ if (R == Other.R) {
+ if (R && R->getName() != Other.R->getName()) {
+ dbgs() << "Same ptr but: " << R->getName() << " and "
+ << Other.R->getName() << "?\n";
+ assert(false);
+ }
+ return true;
+ }
+
+ if (isTypeOf() && Other.isTypeOf())
+ return getTypeOfOpName() == Other.getTypeOfOpName();
+
+ return false;
+}
+
+std::string PatternType::str() const {
+ if (!R)
+ return "";
+
+ if (!isValidType())
+ return "<invalid>";
+
+ if (isLLT())
+ return R->getName().str();
+
+ assert(isSpecial());
+
+ // TODO: Use an enum for these?
+ if (isTypeOf())
+ return (TypeOfClassName + "<$" + getTypeOfOpName() + ">").str();
+
+ llvm_unreachable("Unknown type!");
+}
+
//===- Pattern Base Class -------------------------------------------------===//
/// Base class for all patterns that can be written in an `apply`, `match` or
@@ -499,13 +607,15 @@ class InstructionOperand {
public:
using IntImmTy = int64_t;
- InstructionOperand(IntImmTy Imm, StringRef Name, const Record *Type)
+ InstructionOperand(IntImmTy Imm, StringRef Name, PatternType Type)
: Value(Imm), Name(insertStrRef(Name)), Type(Type) {
- assert(!Type || Type->isSubClassOf("ValueType"));
+ assert(Type.isValidType());
}
- InstructionOperand(StringRef Name, const Record *Type)
- : Name(insertStrRef(Name)), Type(Type) {}
+ InstructionOperand(StringRef Name, PatternType Type)
+ : Name(insertStrRef(Name)), Type(Type) {
+ assert(Type.isValidType());
+ }
bool isNamedImmediate() const { return hasImmValue() && isNamedOperand(); }
@@ -527,11 +637,12 @@ class InstructionOperand {
void setIsDef(bool Value = true) { Def = Value; }
bool isDef() const { return Def; }
- void setType(const Record *R) {
- assert((!Type || (Type == R)) && "Overwriting type!");
- Type = R;
+ void setType(PatternType NewType) {
+ assert((!Type || (Type == NewType)) && "Overwriting type!");
+ assert(NewType.isValidType());
+ Type = NewType;
}
- const Record *getType() const { return Type; }
+ PatternType getType() const { return Type; }
std::string describe() const {
if (!hasImmValue())
@@ -547,11 +658,11 @@ class InstructionOperand {
OS << "<def>";
bool NeedsColon = true;
- if (const Record *Ty = getType()) {
+ if (Type) {
if (hasImmValue())
- OS << "(" << Ty->getName() << " " << getImmValue() << ")";
+ OS << "(" << Type.str() << " " << getImmValue() << ")";
else
- OS << Ty->getName();
+ OS << Type.str();
} else if (hasImmValue())
OS << getImmValue();
else
@@ -566,7 +677,7 @@ class InstructionOperand {
private:
std::optional<int64_t> Value;
StringRef Name;
- const Record *Type = nullptr;
+ PatternType Type;
bool Def = false;
};
@@ -622,6 +733,10 @@ class InstructionPattern : public Pattern {
virtual StringRef getInstName() const = 0;
+ /// Diagnoses all uses of special types in this Pattern and returns true if at
+ /// least one diagnostic was emitted.
+ bool diagnoseAllSpecialTypes(ArrayRef<SMLoc> Loc, Twine Msg) const;
+
void reportUnreachable(ArrayRef<SMLoc> Locs) const;
virtual bool checkSemantics(ArrayRef<SMLoc> Loc);
@@ -633,6 +748,20 @@ class InstructionPattern : public Pattern {
SmallVector<InstructionOperand, 4> Operands;
};
+bool InstructionPattern::diagnoseAllSpecialTypes(ArrayRef<SMLoc> Loc,
+ Twine Msg) const {
+ bool HasDiag = false;
+ for (const auto &[Idx, Op] : enumerate(operands())) {
+ if (Op.getType().isSpecial()) {
+ PrintError(Loc, Msg);
+ PrintNote(Loc, "operand " + Twine(Idx) + " of '" + getName() +
+ "' has type '" + Op.getType().str() + "'");
+ HasDiag = true;
+ }
+ }
+ return HasDiag;
+}
+
void InstructionPattern::reportUnreachable(ArrayRef<SMLoc> Locs) const {
PrintError(Locs, "pattern '" + getName() + "' ('" + getInstName() +
"') is unreachable from the pattern root!");
@@ -829,17 +958,20 @@ unsigned CodeGenInstructionPattern::getNumInstOperands() const {
/// It infers the type of each operand, check it's consistent with the known
/// type of the operand, and then sets all of the types in all operands in
/// setAllOperandTypes.
+///
+/// It also handles verifying correctness of special types.
class OperandTypeChecker {
public:
OperandTypeChecker(ArrayRef<SMLoc> DiagLoc) : DiagLoc(DiagLoc) {}
- bool check(InstructionPattern *P);
+ bool check(InstructionPattern *P,
+ std::function<bool(const PatternType &)> VerifyTypeOfOperand);
void setAllOperandTypes();
private:
struct OpTypeInfo {
- const Record *Type = nullptr;
+ PatternType Type;
InstructionPattern *TypeSrc = nullptr;
};
@@ -849,16 +981,26 @@ class OperandTypeChecker {
SmallVector<InstructionPattern *, 16> Pats;
};
-bool OperandTypeChecker::check(InstructionPattern *P) {
+bool OperandTypeChecker::check(
+ InstructionPattern *P,
+ std::function<bool(const PatternType &)> VerifyTypeOfOperand) {
Pats.push_back(P);
- for (auto &Op : P->named_operands()) {
- const Record *Ty = Op.getType();
+ for (auto &Op : P->operands()) {
+ const auto Ty = Op.getType();
if (!Ty)
continue;
- auto &Info = Types[Op.getOperandName()];
+ if (!Ty.checkSemantics(DiagLoc))
+ return false;
+
+ if (Ty.isTypeOf() && !VerifyTypeOfOperand(Ty))
+ return false;
+ if (!Op.isNamedOperand())
+ continue;
+
+ auto &Info = Types[Op.getOperandName()];
if (!Info.Type) {
Info.Type = Ty;
Info.TypeSrc = P;
@@ -868,9 +1010,9 @@ bool OperandTypeChecker::check(InstructionPattern *P) {
if (Info.Type != Ty) {
PrintError(DiagLoc, "conflicting types for operand '" +
Op.getOperandName() + "': first seen with '" +
- Info.Type->getName() + "' in '" +
+ Info.Type.str() + "' in '" +
Info.TypeSrc->getName() + ", now seen with '" +
- Ty->getName() + "' in '" + P->getName() + "'");
+ Ty.str() + "' in '" + P->getName() + "'");
return false;
}
}
@@ -1058,7 +1200,12 @@ bool PatFrag::checkSemantics() {
PatFragClassName);
return false;
case Pattern::K_CXX:
+ continue;
case Pattern::K_CodeGenInstruction:
+ if (cast<CodeGenInstructionPattern>(Pat.get())->diagnoseAllSpecialTypes(
+ Def.getLoc(), SpecialTyClassName + " is not supported in " +
+ PatFragClassName))
+ return false;
continue;
case Pattern::K_PatFrag:
// TODO: It's just that the emitter doesn't handle it but technically
@@ -1142,12 +1289,16 @@ bool PatFrag::checkSemantics() {
// TODO: find unused params
+ const auto CheckTypeOf = [&](const PatternType &) -> bool {
+ llvm_unreachable("GITypeOf should have been rejected earlier!");
+ };
+
// Now, typecheck all alternatives.
for (auto &Alt : Alts) {
OperandTypeChecker OTC(Def.getLoc());
for (auto &Pat : Alt.Pats) {
if (auto *IP = dyn_cast<InstructionPattern>(Pat.get())) {
- if (!OTC.check(IP))
+ if (!OTC.check(IP, CheckTypeOf))
return false;
}
}
@@ -1954,21 +2105,48 @@ bool CombineRuleBuilder::hasEraseRoot() const {
bool CombineRuleBuilder::typecheckPatterns() {
OperandTypeChecker OTC(RuleDef.getLoc());
+ const auto CheckMatchTypeOf = [&](const PatternType &) -> bool {
+ // We'll reject those after we're done inferring
+ return true;
+ };
+
for (auto &Pat : values(MatchPats)) {
if (auto *IP = dyn_cast<InstructionPattern>(Pat.get())) {
- if (!OTC.check(IP))
+ if (!OTC.check(IP, CheckMatchTypeOf))
return false;
}
}
+ const auto CheckApplyTypeOf = [&](const PatternType &Ty) {
+ // GITypeOf<"$x"> can only be used if "$x" is a matched operand.
+ const auto OpName = Ty.getTypeOfOpName();
+ if (MatchOpTable.lookup(OpName).Found)
+ return true;
+
+ PrintError("'" + OpName + "' ('" + Ty.str() +
+ "') does not refer to a matched operand!");
+ return false;
+ };
+
for (auto &Pat : values(ApplyPats)) {
if (auto *IP = dyn_cast<InstructionPattern>(Pat.get())) {
- if (!OTC.check(IP))
+ if (!OTC.check(IP, CheckApplyTypeOf))
return false;
}
}
OTC.setAllOperandTypes();
+
+ // Always check this after in case inference adds some special types to the match patterns.
+ for (auto &Pat : values(MatchPats)) {
+ if (auto *IP = dyn_cast<InstructionPattern>(Pat.get())) {
+ if (IP->diagnoseAllSpecialTypes(
+ RuleDef.getLoc(),
+ SpecialTyClassName + " is not supported in 'match' patterns")) {
+ return false;
+ }
+ }
+ }
return true;
}
@@ -2461,10 +2639,12 @@ bool CombineRuleBuilder::parseInstructionPatternOperand(
if (DagOp->getNumArgs() != 1)
return ParseErr();
- Record *ImmTy = DagOp->getOperatorAsDef(RuleDef.getLoc());
- if (!ImmTy->isSubClassOf("ValueType")) {
+ const Record *TyDef = DagOp->getOperatorAsDef(RuleDef.getLoc());
+ PatternType ImmTy(TyDef);
+ if (!ImmTy.isValidType()) {
PrintError("cannot parse immediate '" + OpInit->getAsUnquotedString() +
- "', '" + ImmTy->getName() + "' is not a ValueType!");
+ "', '" + TyDef->getName() + "' is not a ValueType or " +
+ SpecialTyClassName);
return false;
}
@@ -2491,12 +2671,13 @@ bool CombineRuleBuilder::parseInstructionPatternOperand(
return false;
}
const Record *Def = DefI->getDef();
- if (!Def->isSubClassOf("ValueType")) {
+ PatternType Ty(Def);
+ if (!Ty.isValidType()) {
PrintError("invalid operand type: '" + Def->getName() +
"' is not a ValueType");
return false;
}
- IP.addOperand(OpName->getAsUnquotedString(), Def);
+ IP.addOperand(OpName->getAsUnquotedString(), Ty);
return true;
}
@@ -2823,8 +3004,8 @@ bool CombineRuleBuilder::emitPatFragMatchPattern(
StringRef PFName = PF.getName();
PrintWarning("impossible type constraints: operand " + Twine(PIdx) +
" of '" + PFP.getName() + "' has type '" +
- ArgOp.getType()->getName() + "', but '" + PFName +
- "' constrains it to '" + O.getType()->getName() + "'");
+ ArgOp.getType().str() + "', but '" + PFName +
+ "' constrains it to '" + O.getType().str() + "'");
if (ArgOp.isNamedOperand())
PrintNote("operand " + Twine(PIdx) + " of '" + PFP.getName() +
"' is '" + ArgOp.getOperandName() + "'");
@@ -3055,17 +3236,18 @@ bool CombineRuleBuilder::emitInstructionApplyPattern(
// This is a brand new register.
TempRegID = M.allocateTempRegID();
OperandToTempRegID[OpName] = TempRegID;
- const Record *Ty = Op.getType();
+ const auto Ty = Op.getType();
if (!Ty) {
PrintError("def of a new register '" + OpName +
"' in the apply patterns must have a type");
return false;
}
+
declareTempRegExpansion(CE, TempRegID, OpName);
// Always insert the action at the beginning, otherwise we may end up
// using the temp reg before it's available.
M.insertAction<MakeTempRegisterAction>(
- M.actions_begin(), getLLTCodeGenFromRecord(Ty), TempRegID);
+ M.actions_begin(), Ty.getLLTCodeGenOrTempType(M), TempRegID);
}
DstMI.addRenderer<TempRegRenderer>(TempRegID);
@@ -3088,7 +3270,7 @@ bool CombineRuleBuilder::emitCodeGenInstructionApplyImmOperand(
// G_CONSTANT is a special case and needs a CImm though so this is likely a
// mistake.
const bool isGConstant = P.is("G_CONSTANT");
- const Record *Ty = O.getType();
+ const auto Ty = O.getType();
if (!Ty) {
if (isGConstant) {
PrintError("'G_CONSTANT' immediate must be typed!");
@@ -3101,16 +3283,17 @@ bool CombineRuleBuilder::emitCodeGenInstructionApplyImmOperand(
return true;
}
- LLTCodeGen LLT = getLLTCodeGenFromRecord(Ty);
+ auto ImmTy = Ty.getLLTCodeGenOrTempType(M);
+
if (isGConstant) {
- DstMI.addRenderer<ImmRenderer>(O.getImmValue(), LLT);
+ DstMI.addRenderer<ImmRenderer>(O.getImmValue(), ImmTy);
return true;
}
unsigned TempRegID = M.allocateTempRegID();
// Ensure MakeTempReg & the BuildConstantAction occur at the beginning.
- auto InsertIt =
- M.insertAction<MakeTempRegisterAction>(M.actions_begin(), LLT, TempRegID);
+ auto InsertIt = M.insertAction<MakeTempRegisterAction>(M.actions_begin(),
+ ImmTy, TempRegID);
M.insertAction<BuildConstantAction>(++InsertIt, TempRegID, O.getImmValue());
DstMI.addRenderer<TempRegRenderer>(TempRegID);
return true;
@@ -3227,8 +3410,14 @@ bool CombineRuleBuilder::emitCodeGenInstructionMatchPattern(
// Always emit a check for unnamed operands.
if (OpName.empty() ||
!M.getOperandMatcher(OpName).contains<LLTOperandMatcher>()) {
- if (const Record *Ty = RemappedO.getType())
- OM.addPredicate<LLTOperandMatcher>(getLLTCodeGenFromRecord(Ty));
+ if (const auto Ty = RemappedO.getType()) {
+ // TODO: We could support GITypeOf here on the condition that the
+ // OperandMatcher exists already. Though it's clunky to make this work
+ // and isn't all that useful so it's just rejected in typecheckPatterns
+ // at this time.
+ assert(Ty.isLLT() && "Only LLTs are supported in match patterns!");
+ OM.addPredicate<LLTOperandMatcher>(Ty.getLLTCodeGen());
+ }
}
// Stop here if the operand is a def, or if it had no name.
diff --git a/llvm/utils/TableGen/GlobalISelMatchTable.cpp b/llvm/utils/TableGen/GlobalISelMatchTable.cpp
index 9a4a375f34bdb91..f6e9240a322fce2 100644
--- a/llvm/utils/TableGen/GlobalISelMatchTable.cpp
+++ b/llvm/utils/TableGen/GlobalISelMatchTable.cpp
@@ -822,6 +822,15 @@ const OperandMatcher &RuleMatcher::getPhysRegOperandMatcher(Record *Reg) const {
return *I->second;
}
+OperandMatcher &RuleMatcher::getOperandMatcher(StringRef Name) {
+ const auto &I = DefinedOperands.find(Name);
+
+ if (I == DefinedOperands.end())
+ PrintFatalError(SrcLoc, "Operand " + Name + " was not declared in matcher");
+
+ return *I->second;
+}
+
const OperandMatcher &RuleMatcher::getOperandMatcher(StringRef Name) const {
const auto &I = DefinedOperands.find(Name);
@@ -1081,6 +1090,17 @@ void RecordNamedOperandMatcher::emitPredicateOpcodes(MatchTable &Table,
<< MatchTable::Comment("Name : " + Name) << MatchTable::LineBreak;
}
+//===- RecordRegisterType ------------------------------------------===//
+
+void RecordRegisterType::emitPredicateOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const {
+ assert(Idx < 0 && "Temp types always have negative indexes!");
+ Table << MatchTable::Opcode("GIM_RecordRegType") << MatchTable::Comment("MI")
+ << MatchTable::IntValue(InsnVarID) << MatchTable::Comment("Op")
+ << MatchTable::IntValue(OpIdx) << MatchTable::Comment("TempTypeIdx")
+ << MatchTable::IntValue(Idx) << MatchTable::LineBreak;
+}
+
//===- ComplexPatternOperandMatcher ---------------------------------------===//
void ComplexPatternOperandMatcher::emitPredicateOpcodes(
@@ -1196,6 +1216,17 @@ std::string OperandMatcher::getOperandExpr(unsigned InsnVarID) const {
unsigned OperandMatcher::getInsnVarID() const { return Insn.getInsnVarID(); }
+TempTypeIdx OperandMatcher::getTempTypeIdx(RuleMatcher &Rule) {
+ if(TTIdx >= 0) {
+ // Temp type index not assigned yet, so assign one and add the necessary predicate.
+ TTIdx = Rule.getNextTempTypeIdx();
+ assert(TTIdx < 0);
+ addPredicate<RecordRegisterType>(TTIdx);
+ return TTIdx;
+ }
+ return TTIdx;
+}
+
void OperandMatcher::emitPredicateOpcodes(MatchTable &Table,
RuleMatcher &Rule) {
if (!Optimized) {
@@ -2092,9 +2123,7 @@ void MakeTempRegisterAction::emitActionOpcodes(MatchTable &Table,
RuleMatcher &Rule) const {
Table << MatchTable::Opcode("GIR_MakeTempReg")
<< MatchTable::Comment("TempRegID") << MatchTable::IntValue(TempRegID)
- << MatchTable::Comment("TypeID")
- << MatchTable::NamedValue(Ty.getCxxEnumValue())
- << MatchTable::LineBreak;
+ << MatchTable::Comment("TypeID") << Ty << MatchTable::LineBreak;
}
} // namespace gi
diff --git a/llvm/utils/TableGen/GlobalISelMatchTable.h b/llvm/utils/TableGen/GlobalISelMatchTable.h
index 5608bab482bfd34..364f2a1ec725d53 100644
--- a/llvm/utils/TableGen/GlobalISelMatchTable.h
+++ b/llvm/utils/TableGen/GlobalISelMatchTable.h
@@ -273,6 +273,40 @@ extern std::set<LLTCodeGen> KnownTypes;
/// MVTs that don't map cleanly to an LLT (e.g., iPTR, *any, ...).
std::optional<LLTCodeGen> MVTToLLT(MVT::SimpleValueType SVT);
+using TempTypeIdx = int64_t;
+class LLTCodeGenOrTempType {
+public:
+ LLTCodeGenOrTempType(const LLTCodeGen &LLT) : Data(LLT) {}
+ LLTCodeGenOrTempType(TempTypeIdx TempTy) : Data(TempTy) {}
+
+ bool isLLTCodeGen() const { return std::holds_alternative<LLTCodeGen>(Data); }
+ bool isTempTypeIdx() const {
+ return std::holds_alternative<TempTypeIdx>(Data);
+ }
+
+ const LLTCodeGen &getLLTCodeGen() const {
+ assert(isLLTCodeGen());
+ return std::get<LLTCodeGen>(Data);
+ }
+
+ TempTypeIdx getTempTypeIdx() const {
+ assert(isTempTypeIdx());
+ return std::get<TempTypeIdx>(Data);
+ }
+
+private:
+ std::variant<LLTCodeGen, TempTypeIdx> Data;
+};
+
+inline MatchTable &operator<<(MatchTable &Table,
+ const LLTCodeGenOrTempType &Ty) {
+ if (Ty.isLLTCodeGen())
+ Table << MatchTable::NamedValue(Ty.getLLTCodeGen().getCxxEnumValue());
+ else
+ Table << MatchTable::IntValue(Ty.getTempTypeIdx());
+ return Table;
+}
+
//===- Matchers -----------------------------------------------------------===//
class Matcher {
public:
@@ -459,6 +493,9 @@ class RuleMatcher : public Matcher {
/// ID for the next temporary register ID allocated with allocateTempRegID()
unsigned NextTempRegID;
+ /// ID for the next recorded type. Starts at -1 and counts down.
+ TempTypeIdx NextTempTypeIdx = -1;
+
// HwMode predicate index for this rule. -1 if no HwMode.
int HwModeIdx = -1;
@@ -498,6 +535,8 @@ class RuleMatcher : public Matcher {
RuleMatcher(RuleMatcher &&Other) = default;
RuleMatcher &operator=(RuleMatcher &&Other) = default;
+ TempTypeIdx getNextTempTypeIdx() { return NextTempTypeIdx--; }
+
uint64_t getRuleID() const { return RuleID; }
InstructionMatcher &addInstructionMatcher(StringRef SymbolicName);
@@ -602,6 +641,7 @@ class RuleMatcher : public Matcher {
}
InstructionMatcher &getInstructionMatcher(StringRef SymbolicName) const;
+ OperandMatcher &getOperandMatcher(StringRef Name);
const OperandMatcher &getOperandMatcher(StringRef Name) const;
const OperandMatcher &getPhysRegOperandMatcher(Record *) const;
@@ -762,6 +802,7 @@ class PredicateMatcher {
OPM_RegBank,
OPM_MBB,
OPM_RecordNamedOperand,
+ OPM_RecordRegType,
};
protected:
@@ -963,6 +1004,30 @@ class RecordNamedOperandMatcher : public OperandPredicateMatcher {
RuleMatcher &Rule) const override;
};
+/// Generates code to store a register operand's type into the set of temporary
+/// LLTs.
+class RecordRegisterType : public OperandPredicateMatcher {
+protected:
+ TempTypeIdx Idx;
+
+public:
+ RecordRegisterType(unsigned InsnVarID, unsigned OpIdx, TempTypeIdx Idx)
+ : OperandPredicateMatcher(OPM_RecordRegType, InsnVarID, OpIdx), Idx(Idx) {
+ }
+
+ static bool classof(const PredicateMatcher *P) {
+ return P->getKind() == OPM_RecordRegType;
+ }
+
+ bool isIdentical(const PredicateMatcher &B) const override {
+ return OperandPredicateMatcher::isIdentical(B) &&
+ Idx == cast<RecordRegisterType>(&B)->Idx;
+ }
+
+ void emitPredicateOpcodes(MatchTable &Table,
+ RuleMatcher &Rule) const override;
+};
+
/// Generates code to check that an operand is a particular target constant.
class ComplexPatternOperandMatcher : public OperandPredicateMatcher {
protected:
@@ -1169,6 +1234,8 @@ class OperandMatcher : public PredicateListMatcher<OperandPredicateMatcher> {
/// countRendererFns().
unsigned AllocatedTemporariesBaseID;
+ TempTypeIdx TTIdx = 0;
+
public:
OperandMatcher(InstructionMatcher &Insn, unsigned OpIdx,
const std::string &SymbolicName,
@@ -1196,6 +1263,11 @@ class OperandMatcher : public PredicateListMatcher<OperandPredicateMatcher> {
unsigned getOpIdx() const { return OpIdx; }
unsigned getInsnVarID() const;
+ /// If this OperandMatcher has not been assigned a TempTypeIdx yet, assigns it
+ /// one and adds a `RecordRegisterType` predicate to this matcher. If one has
+ /// already been assigned, simply returns it.
+ TempTypeIdx getTempTypeIdx(RuleMatcher &Rule);
+
std::string getOperandExpr(unsigned InsnVarID) const;
InstructionMatcher &getInstructionMatcher() const { return Insn; }
@@ -1955,15 +2027,16 @@ class ImmRenderer : public OperandRenderer {
protected:
unsigned InsnID;
int64_t Imm;
- std::optional<LLTCodeGen> CImmLLT;
+ std::optional<LLTCodeGenOrTempType> CImmLLT;
public:
ImmRenderer(unsigned InsnID, int64_t Imm)
: OperandRenderer(OR_Imm), InsnID(InsnID), Imm(Imm) {}
- ImmRenderer(unsigned InsnID, int64_t Imm, const LLTCodeGen &CImmLLT)
+ ImmRenderer(unsigned InsnID, int64_t Imm, const LLTCodeGenOrTempType &CImmLLT)
: OperandRenderer(OR_Imm), InsnID(InsnID), Imm(Imm), CImmLLT(CImmLLT) {
- KnownTypes.insert(CImmLLT);
+ if (CImmLLT.isLLTCodeGen())
+ KnownTypes.insert(CImmLLT.getLLTCodeGen());
}
static bool classof(const OperandRenderer *R) {
@@ -1976,8 +2049,7 @@ class ImmRenderer : public OperandRenderer {
"ConstantInt immediate are only for combiners!");
Table << MatchTable::Opcode("GIR_AddCImm")
<< MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID)
- << MatchTable::Comment("Type")
- << MatchTable::NamedValue(CImmLLT->getCxxEnumValue())
+ << MatchTable::Comment("Type") << *CImmLLT
<< MatchTable::Comment("Imm") << MatchTable::IntValue(Imm)
<< MatchTable::LineBreak;
} else {
@@ -2290,13 +2362,14 @@ class ConstrainOperandToRegClassAction : public MatchAction {
/// instructions together.
class MakeTempRegisterAction : public MatchAction {
private:
- LLTCodeGen Ty;
+ LLTCodeGenOrTempType Ty;
unsigned TempRegID;
public:
- MakeTempRegisterAction(const LLTCodeGen &Ty, unsigned TempRegID)
+ MakeTempRegisterAction(const LLTCodeGenOrTempType &Ty, unsigned TempRegID)
: MatchAction(AK_MakeTempReg), Ty(Ty), TempRegID(TempRegID) {
- KnownTypes.insert(Ty);
+ if (Ty.isLLTCodeGen())
+ KnownTypes.insert(Ty.getLLTCodeGen());
}
static bool classof(const MatchAction *A) {
More information about the llvm-commits
mailing list