1//===-- SPIRVPreLegalizerCombiner.cpp - combine legalization ----*- C++ -*-===//
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 "SPIRV.h"
15#include "SPIRVCombinerHelper.h"
16#include "llvm/CodeGen/GlobalISel/CSEInfo.h"
17#include "llvm/CodeGen/GlobalISel/Combiner.h"
18#include "llvm/CodeGen/GlobalISel/CombinerInfo.h"
19#include "llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h"
20#include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h"
21#include "llvm/CodeGen/GlobalISel/GISelValueTracking.h"
22#include "llvm/CodeGen/GlobalISel/MIPatternMatch.h"
23#include "llvm/CodeGen/MachineDominators.h"
24#include "llvm/CodeGen/MachineFunctionAnalysisManager.h"
25#include "llvm/CodeGen/MachineFunctionPass.h"
26#include "llvm/CodeGen/MachinePassManager.h"
27#include "llvm/CodeGen/TargetPassConfig.h"
28#include "llvm/IR/Analysis.h"
29#include "llvm/IR/IntrinsicsSPIRV.h"
30
31#define GET_GICOMBINER_DEPS
32#include "SPIRVGenPreLegalizeGICombiner.inc"
33#undef GET_GICOMBINER_DEPS
34
35#define DEBUG_TYPE "spirv-prelegalizer-combiner"
36
37using namespace llvm;
38using namespace MIPatternMatch;
39
40namespace {
41
42#define GET_GICOMBINER_TYPES
43#include "SPIRVGenPreLegalizeGICombiner.inc"
44#undef GET_GICOMBINER_TYPES
45
46class SPIRVPreLegalizerCombinerImpl : public Combiner {
47protected:
48 const SPIRVCombinerHelper Helper;
49 const SPIRVPreLegalizerCombinerImplRuleConfig &RuleConfig;
50 const SPIRVSubtarget &STI;
51
52public:
53 SPIRVPreLegalizerCombinerImpl(
54 MachineFunction &MF, CombinerInfo &CInfo, GISelValueTracking &VT,
55 GISelCSEInfo *CSEInfo,
56 const SPIRVPreLegalizerCombinerImplRuleConfig &RuleConfig,
57 const SPIRVSubtarget &STI, MachineDominatorTree *MDT,
58 const LegalizerInfo *LI);
59
60 static const char *getName() { return "SPIRVPreLegalizerCombiner"; }
61
62 bool tryCombineAll(MachineInstr &I) const override;
63
64 bool tryCombineAllImpl(MachineInstr &I) const;
65
66private:
67#define GET_GICOMBINER_CLASS_MEMBERS
68#include "SPIRVGenPreLegalizeGICombiner.inc"
69#undef GET_GICOMBINER_CLASS_MEMBERS
70};
71
72#define GET_GICOMBINER_IMPL
73#include "SPIRVGenPreLegalizeGICombiner.inc"
74#undef GET_GICOMBINER_IMPL
75
76SPIRVPreLegalizerCombinerImpl::SPIRVPreLegalizerCombinerImpl(
77 MachineFunction &MF, CombinerInfo &CInfo, GISelValueTracking &VT,
78 GISelCSEInfo *CSEInfo,
79 const SPIRVPreLegalizerCombinerImplRuleConfig &RuleConfig,
80 const SPIRVSubtarget &STI, MachineDominatorTree *MDT,
81 const LegalizerInfo *LI)
82 : Combiner(MF, CInfo, &VT, CSEInfo),
83 Helper(Observer, B, /*IsPreLegalize*/ true, &VT, MDT, LI, STI),
84 RuleConfig(RuleConfig), STI(STI),
85#define GET_GICOMBINER_CONSTRUCTOR_INITS
86#include "SPIRVGenPreLegalizeGICombiner.inc"
87#undef GET_GICOMBINER_CONSTRUCTOR_INITS
88{
89}
90
91bool SPIRVPreLegalizerCombinerImpl::tryCombineAll(MachineInstr &MI) const {
92 return tryCombineAllImpl(I&: MI);
93}
94
95// Pass boilerplate
96// ================
97
98class SPIRVPreLegalizerCombinerLegacy : public MachineFunctionPass {
99public:
100 static char ID;
101
102 SPIRVPreLegalizerCombinerLegacy();
103
104 StringRef getPassName() const override { return "SPIRVPreLegalizerCombiner"; }
105
106 bool runOnMachineFunction(MachineFunction &MF) override;
107
108 void getAnalysisUsage(AnalysisUsage &AU) const override;
109};
110
111} // end anonymous namespace
112
113void SPIRVPreLegalizerCombinerLegacy::getAnalysisUsage(
114 AnalysisUsage &AU) const {
115 AU.setPreservesCFG();
116 getSelectionDAGFallbackAnalysisUsage(AU);
117 AU.addRequired<GISelValueTrackingAnalysisLegacy>();
118 AU.addPreserved<GISelValueTrackingAnalysisLegacy>();
119 AU.addRequired<MachineDominatorTreeWrapperPass>();
120 MachineFunctionPass::getAnalysisUsage(AU);
121}
122
123SPIRVPreLegalizerCombinerLegacy::SPIRVPreLegalizerCombinerLegacy()
124 : MachineFunctionPass(ID) {}
125
126static bool
127runPreLegalizerCombiner(MachineFunction &MF, bool ShouldSkip,
128 function_ref<GISelValueTracking *()> GetVT,
129 function_ref<MachineDominatorTree *()> GetMDT) {
130 if (MF.getProperties().hasFailedISel())
131 return false;
132
133 SPIRVPreLegalizerCombinerImplRuleConfig RuleConfig;
134 if (!RuleConfig.parseCommandLineOption())
135 reportFatalUsageError(reason: "Invalid rule identifier");
136
137 const SPIRVSubtarget &ST = MF.getSubtarget<SPIRVSubtarget>();
138 const auto *LI = ST.getLegalizerInfo();
139
140 const Function &F = MF.getFunction();
141 bool EnableOpt =
142 MF.getTarget().getOptLevel() != CodeGenOptLevel::None && !ShouldSkip;
143 GISelValueTracking *VT = GetVT();
144 MachineDominatorTree *MDT = GetMDT();
145 CombinerInfo CInfo(/*AllowIllegalOps*/ true, /*ShouldLegalizeIllegal*/ false,
146 /*LegalizerInfo*/ nullptr, EnableOpt, F.hasOptSize(),
147 F.hasMinSize());
148 // Disable fixed-point iteration to reduce compile-time
149 CInfo.MaxIterations = 1;
150 CInfo.ObserverLvl = CombinerInfo::ObserverLevel::SinglePass;
151 // This is the first Combiner, so the input IR might contain dead
152 // instructions.
153 CInfo.EnableFullDCE = false;
154 SPIRVPreLegalizerCombinerImpl Impl(MF, CInfo, *VT, /*CSEInfo*/ nullptr,
155 RuleConfig, ST, MDT, LI);
156 return Impl.combineMachineInstrs();
157}
158
159char SPIRVPreLegalizerCombinerLegacy::ID = 0;
160INITIALIZE_PASS_BEGIN(SPIRVPreLegalizerCombinerLegacy, DEBUG_TYPE,
161 "Combine SPIRV machine instrs before legalization", false,
162 false)
163INITIALIZE_PASS_DEPENDENCY(GISelValueTrackingAnalysisLegacy)
164INITIALIZE_PASS_END(SPIRVPreLegalizerCombinerLegacy, DEBUG_TYPE,
165 "Combine SPIRV machine instrs before legalization", false,
166 false)
167
168namespace llvm {
169FunctionPass *createSPIRVPreLegalizerCombinerLegacyPass() {
170 return new SPIRVPreLegalizerCombinerLegacy();
171}
172} // end namespace llvm
173
174bool SPIRVPreLegalizerCombinerLegacy::runOnMachineFunction(
175 MachineFunction &MF) {
176 return runPreLegalizerCombiner(
177 MF, ShouldSkip: skipFunction(F: MF.getFunction()),
178 GetVT: [&]() {
179 return &getAnalysis<GISelValueTrackingAnalysisLegacy>().get(MF);
180 },
181 GetMDT: [&]() {
182 return &getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();
183 });
184}
185
186PreservedAnalyses
187SPIRVPreLegalizerCombinerPass::run(MachineFunction &MF,
188 MachineFunctionAnalysisManager &MFAM) {
189 bool Changed = runPreLegalizerCombiner(
190 MF,
191 ShouldSkip: MF.getFunction().hasOptNone() ||
192 shouldSkipOptimizationForOptBisect(IR: MF.getFunction()),
193 GetVT: [&]() { return &MFAM.getResult<GISelValueTrackingAnalysis>(IR&: MF); },
194 GetMDT: [&]() { return &MFAM.getResult<MachineDominatorTreeAnalysis>(IR&: MF); });
195 if (!Changed)
196 return PreservedAnalyses::all();
197 return getMachineFunctionPassPreservedAnalyses()
198 .preserveSet<CFGAnalyses>()
199 .preserve<GISelValueTrackingAnalysis>();
200}
201