LLVM 24.0.0git
AMDGPUPreLegalizerCombiner.cpp
Go to the documentation of this file.
1//=== lib/CodeGen/GlobalISel/AMDGPUPreLegalizerCombiner.cpp ---------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This pass does combining of machine instructions at the generic MI level,
10// before the legalizer.
11//
12//===----------------------------------------------------------------------===//
13
14#include "AMDGPU.h"
16#include "AMDGPULegalizerInfo.h"
17#include "GCNSubtarget.h"
28
29#define GET_GICOMBINER_DEPS
30#include "AMDGPUGenPreLegalizeGICombiner.inc"
31#undef GET_GICOMBINER_DEPS
32
33#define DEBUG_TYPE "amdgpu-prelegalizer-combiner"
34
35using namespace llvm;
36using namespace MIPatternMatch;
37namespace {
38
39#define GET_GICOMBINER_TYPES
40#include "AMDGPUGenPreLegalizeGICombiner.inc"
41#undef GET_GICOMBINER_TYPES
42
43class AMDGPUPreLegalizerCombinerImpl : public Combiner {
44protected:
45 const AMDGPUPreLegalizerCombinerImplRuleConfig &RuleConfig;
46 const GCNSubtarget &STI;
47 const AMDGPUCombinerHelper Helper;
48
49public:
50 AMDGPUPreLegalizerCombinerImpl(
52 GISelCSEInfo *CSEInfo,
53 const AMDGPUPreLegalizerCombinerImplRuleConfig &RuleConfig,
54 const GCNSubtarget &STI, MachineDominatorTree *MDT,
55 const LegalizerInfo *LI);
56
57 static const char *getName() { return "AMDGPUPreLegalizerCombinerImpl"; }
58
59 bool tryCombineAllImpl(MachineInstr &MI) const;
60 bool tryCombineAll(MachineInstr &I) const override;
61
62 struct ClampI64ToI16MatchInfo {
63 int64_t Cmp1 = 0;
64 int64_t Cmp2 = 0;
65 Register Origin;
66 };
67
68 bool matchClampI64ToI16(MachineInstr &MI, const MachineRegisterInfo &MRI,
69 const MachineFunction &MF,
70 ClampI64ToI16MatchInfo &MatchInfo) const;
71
72 void applyClampI64ToI16(MachineInstr &MI,
73 const ClampI64ToI16MatchInfo &MatchInfo) const;
74
75private:
76#define GET_GICOMBINER_CLASS_MEMBERS
77#define AMDGPUSubtarget GCNSubtarget
78#include "AMDGPUGenPreLegalizeGICombiner.inc"
79#undef GET_GICOMBINER_CLASS_MEMBERS
80#undef AMDGPUSubtarget
81};
82
83#define GET_GICOMBINER_IMPL
84#define AMDGPUSubtarget GCNSubtarget
85#include "AMDGPUGenPreLegalizeGICombiner.inc"
86#undef AMDGPUSubtarget
87#undef GET_GICOMBINER_IMPL
88
89AMDGPUPreLegalizerCombinerImpl::AMDGPUPreLegalizerCombinerImpl(
91 GISelCSEInfo *CSEInfo,
92 const AMDGPUPreLegalizerCombinerImplRuleConfig &RuleConfig,
93 const GCNSubtarget &STI, MachineDominatorTree *MDT, const LegalizerInfo *LI)
94 : Combiner(MF, CInfo, &VT, CSEInfo), RuleConfig(RuleConfig), STI(STI),
95 Helper(Observer, B, /*IsPreLegalize*/ true, &VT, MDT, LI, STI),
97#include "AMDGPUGenPreLegalizeGICombiner.inc"
99{
100}
101
102bool AMDGPUPreLegalizerCombinerImpl::tryCombineAll(MachineInstr &MI) const {
103 if (tryCombineAllImpl(MI))
104 return true;
105 return false;
106}
107
108bool AMDGPUPreLegalizerCombinerImpl::matchClampI64ToI16(
109 MachineInstr &MI, const MachineRegisterInfo &MRI, const MachineFunction &MF,
110 ClampI64ToI16MatchInfo &MatchInfo) const {
111 assert(MI.getOpcode() == TargetOpcode::G_TRUNC && "Invalid instruction!");
112
113 // Try to find a pattern where an i64 value should get clamped to short.
114 const LLT SrcType = MRI.getType(MI.getOperand(1).getReg());
115 if (SrcType != LLT::scalar(64))
116 return false;
117
118 const LLT DstType = MRI.getType(MI.getOperand(0).getReg());
119 if (DstType != LLT::scalar(16))
120 return false;
121
123
124 // Lo must not exceed Hi: with inverted bounds smin(smax(X, Lo), Hi) is
125 // constant, but the med3 built below would still clamp X to [Hi, Lo].
126 auto IsApplicableForCombine = [&MatchInfo](bool OuterIsMin) -> bool {
127 const int64_t Lo = OuterIsMin ? MatchInfo.Cmp2 : MatchInfo.Cmp1;
128 const int64_t Hi = OuterIsMin ? MatchInfo.Cmp1 : MatchInfo.Cmp2;
129
130 // Range-check first so Hi - Lo below can't overflow.
131 const int64_t Min = std::numeric_limits<int16_t>::min();
132 const int64_t Max = std::numeric_limits<int16_t>::max();
133 if (Lo < Min || Lo > Max || Hi < Min || Hi > Max)
134 return false;
135
136 // Reject inverted bounds, and bounds so close there is no need to clamp.
137 return Hi - Lo > 1;
138 };
139
140 // Try to match a combination of min / max MIR opcodes.
141 if (mi_match(MI.getOperand(1).getReg(), MRI,
142 m_GSMin(m_Reg(Base), m_ICst(MatchInfo.Cmp1)))) {
143 if (mi_match(Base, MRI,
144 m_GSMax(m_Reg(MatchInfo.Origin), m_ICst(MatchInfo.Cmp2)))) {
145 return IsApplicableForCombine(/*OuterIsMin=*/true);
146 }
147 }
148
149 if (mi_match(MI.getOperand(1).getReg(), MRI,
150 m_GSMax(m_Reg(Base), m_ICst(MatchInfo.Cmp1)))) {
151 if (mi_match(Base, MRI,
152 m_GSMin(m_Reg(MatchInfo.Origin), m_ICst(MatchInfo.Cmp2)))) {
153 return IsApplicableForCombine(/*OuterIsMin=*/false);
154 }
155 }
156
157 return false;
158}
159
160// We want to find a combination of instructions that
161// gets generated when an i64 gets clamped to i16.
162// The corresponding pattern is:
163// G_MAX / G_MAX for i16 <= G_TRUNC i64.
164// This can be efficiently written as following:
165// v_cvt_pk_i16_i32 v0, v0, v1
166// v_med3_i32 v0, Clamp_Min, v0, Clamp_Max
167void AMDGPUPreLegalizerCombinerImpl::applyClampI64ToI16(
168 MachineInstr &MI, const ClampI64ToI16MatchInfo &MatchInfo) const {
169
170 Register Src = MatchInfo.Origin;
171 assert(MI.getMF()->getRegInfo().getType(Src) == LLT::scalar(64));
172 const LLT I32 = LLT::integer(32);
173
174 auto Unmerge = B.buildUnmerge(I32, Src);
175
176 assert(MI.getOpcode() != AMDGPU::G_AMDGPU_CVT_PK_I16_I32);
177
178 const LLT V2S16 = LLT::fixed_vector(2, 16);
179 auto CvtPk =
180 B.buildInstr(AMDGPU::G_AMDGPU_CVT_PK_I16_I32, {V2S16},
181 {Unmerge.getReg(0), Unmerge.getReg(1)}, MI.getFlags());
182
183 auto MinBoundary = std::min(MatchInfo.Cmp1, MatchInfo.Cmp2);
184 auto MaxBoundary = std::max(MatchInfo.Cmp1, MatchInfo.Cmp2);
185 auto MinBoundaryDst = B.buildConstant(I32, MinBoundary);
186 auto MaxBoundaryDst = B.buildConstant(I32, MaxBoundary);
187
188 auto Bitcast = B.buildBitcast({I32}, CvtPk);
189
190 auto Med3 = B.buildInstr(
191 AMDGPU::G_AMDGPU_SMED3, {I32},
192 {MinBoundaryDst.getReg(0), Bitcast.getReg(0), MaxBoundaryDst.getReg(0)},
193 MI.getFlags());
194
195 B.buildTrunc(MI.getOperand(0).getReg(), Med3);
196
197 MI.eraseFromParent();
198}
199
200// Pass boilerplate
201// ================
202
203class AMDGPUPreLegalizerCombiner : public MachineFunctionPass {
204public:
205 static char ID;
206
207 AMDGPUPreLegalizerCombiner(bool IsOptNone = false);
208
209 StringRef getPassName() const override {
210 return "AMDGPUPreLegalizerCombiner";
211 }
212
213 bool runOnMachineFunction(MachineFunction &MF) override;
214
215 void getAnalysisUsage(AnalysisUsage &AU) const override;
216
217private:
218 bool IsOptNone;
219 AMDGPUPreLegalizerCombinerImplRuleConfig RuleConfig;
220};
221} // end anonymous namespace
222
223void AMDGPUPreLegalizerCombiner::getAnalysisUsage(AnalysisUsage &AU) const {
224 AU.addRequired<TargetPassConfig>();
225 AU.setPreservesCFG();
227 AU.addRequired<GISelValueTrackingAnalysisLegacy>();
228 AU.addPreserved<GISelValueTrackingAnalysisLegacy>();
229 if (!IsOptNone) {
230 AU.addRequired<MachineDominatorTreeWrapperPass>();
231 }
232
233 AU.addRequired<GISelCSEAnalysisWrapperPass>();
234 AU.addPreserved<GISelCSEAnalysisWrapperPass>();
236}
237
238AMDGPUPreLegalizerCombiner::AMDGPUPreLegalizerCombiner(bool IsOptNone)
239 : MachineFunctionPass(ID), IsOptNone(IsOptNone) {
240 if (!RuleConfig.parseCommandLineOption())
241 report_fatal_error("Invalid rule identifier");
242}
243
244bool AMDGPUPreLegalizerCombiner::runOnMachineFunction(MachineFunction &MF) {
245 if (MF.getProperties().hasFailedISel())
246 return false;
247 auto *TPC = &getAnalysis<TargetPassConfig>();
248 const Function &F = MF.getFunction();
249 bool EnableOpt =
250 MF.getTarget().getOptLevel() != CodeGenOptLevel::None && !skipFunction(F);
252 &getAnalysis<GISelValueTrackingAnalysisLegacy>().get(MF);
253
254 // Enable CSE.
256 getAnalysis<GISelCSEAnalysisWrapperPass>().getCSEWrapper();
257 auto *CSEInfo = &Wrapper.get(TPC->getCSEConfig());
258
259 const GCNSubtarget &STI = MF.getSubtarget<GCNSubtarget>();
261 IsOptNone ? nullptr
262 : &getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();
263 CombinerInfo CInfo(/*AllowIllegalOps*/ true, /*ShouldLegalizeIllegal*/ false,
264 nullptr, EnableOpt, F.hasOptSize(), F.hasMinSize());
265 // Disable fixed-point iteration to reduce compile-time
266 CInfo.MaxIterations = 1;
267 CInfo.ObserverLvl = CombinerInfo::ObserverLevel::SinglePass;
268 // This is the first Combiner, so the input IR might contain dead
269 // instructions.
270 CInfo.EnableFullDCE = true;
271 AMDGPUPreLegalizerCombinerImpl Impl(MF, CInfo, *VT, CSEInfo, RuleConfig, STI,
272 MDT, STI.getLegalizerInfo());
273 return Impl.combineMachineInstrs();
274}
275
276char AMDGPUPreLegalizerCombiner::ID = 0;
277INITIALIZE_PASS_BEGIN(AMDGPUPreLegalizerCombiner, DEBUG_TYPE,
278 "Combine AMDGPU machine instrs before legalization",
279 false, false)
282INITIALIZE_PASS_END(AMDGPUPreLegalizerCombiner, DEBUG_TYPE,
283 "Combine AMDGPU machine instrs before legalization", false,
284 false)
285
287 return new AMDGPUPreLegalizerCombiner(IsOptNone);
288}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
#define GET_GICOMBINER_CONSTRUCTOR_INITS
amdgpu aa AMDGPU Address space based Alias Analysis Wrapper
This contains common combine transformations that may be used in a combine pass.
constexpr LLT V2S16
This file declares the targeting of the Machinelegalizer class for AMDGPU.
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
Provides analysis for continuously CSEing during GISel passes.
This contains common combine transformations that may be used in a combine pass,or by the target else...
Option class for Targets to specify which operations are combined how and when.
This contains the base class for all Combiners generated by TableGen.
AMD GCN specific subclass of TargetSubtarget.
Provides analysis for querying information about KnownBits during GISel passes.
#define DEBUG_TYPE
IRTranslator LLVM IR MI
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
Contains matchers for matching SSA Machine Instructions.
Promote Memory to Register
Definition Mem2Reg.cpp:110
#define INITIALIZE_PASS_DEPENDENCY(depName)
Definition PassSupport.h:42
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
Definition PassSupport.h:44
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
Definition PassSupport.h:39
static StringRef getName(Value *V)
Target-Independent Code Generator Pass Configuration Options pass.
AnalysisUsage & addRequired()
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
Definition Pass.cpp:275
Combiner implementation.
Definition Combiner.h:33
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:314
const LegalizerInfo * getLegalizerInfo() const override
Simple wrapper that does the following.
Definition CSEInfo.h:214
The CSE Analysis object.
Definition CSEInfo.h:72
To use KnownBitsInfo analysis in a pass, KnownBitsInfo &Info = getAnalysis<GISelValueTrackingInfoAnal...
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
static constexpr LLT fixed_vector(unsigned NumElements, unsigned ScalarSizeInBits)
Get a low-level fixed-width vector of some number of elements and element width.
static LLT integer(unsigned SizeInBits)
DominatorTree Class - Concrete subclass of DominatorTreeBase that is used to compute a normal dominat...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
Function & getFunction()
Return the LLVM function that this machine code represents.
const MachineFunctionProperties & getProperties() const
Get the function properties.
const TargetMachine & getTarget() const
getTarget - Return the target machine this machine code is compiled with
Representation of each machine instruction.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLT getType(Register Reg) const
Get the low-level type of Reg or LLT{} if Reg is not a generic (target independent) virtual register.
Wrapper class representing virtual and physical registers.
Definition Register.h:20
CodeGenOptLevel getOptLevel() const
Returns the optimization level: None, Less, Default, or Aggressive.
Target-Independent Code Generator Pass Configuration Options.
@ Bitcast
Perform the operation on a different, but equivalently sized type.
operand_type_match m_Reg()
ConstantMatch< APInt > m_ICst(APInt &Cst)
bool mi_match(Reg R, const MachineRegisterInfo &MRI, Pattern &&P)
BinaryOp_match< LHS, RHS, TargetOpcode::G_SMIN, true > m_GSMin(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_SMAX, true > m_GSMax(const LHS &L, const RHS &R)
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:163
LLVM_ABI void getSelectionDAGFallbackAnalysisUsage(AnalysisUsage &AU)
Modify analysis usage so it preserves passes required for the SelectionDAG fallback.
Definition Utils.cpp:1137
FunctionPass * createAMDGPUPreLegalizeCombiner(bool IsOptNone)
@ SinglePass
Enables Observer-based DCE and additional heuristics that retry combining defined and used instructio...