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