1//=== lib/CodeGen/GlobalISel/AArch64O0PreLegalizerCombiner.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 "AArch64.h"
15#include "AArch64GlobalISelUtils.h"
16#include "AArch64TargetMachine.h"
17#include "llvm/CodeGen/GlobalISel/Combiner.h"
18#include "llvm/CodeGen/GlobalISel/CombinerHelper.h"
19#include "llvm/CodeGen/GlobalISel/CombinerInfo.h"
20#include "llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h"
21#include "llvm/CodeGen/GlobalISel/GISelValueTracking.h"
22#include "llvm/CodeGen/GlobalISel/MIPatternMatch.h"
23#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
24#include "llvm/CodeGen/LibcallLoweringInfo.h"
25#include "llvm/CodeGen/MachineDominators.h"
26#include "llvm/CodeGen/MachineFunction.h"
27#include "llvm/CodeGen/MachineFunctionAnalysisManager.h"
28#include "llvm/CodeGen/MachineFunctionPass.h"
29#include "llvm/CodeGen/MachinePassManager.h"
30#include "llvm/IR/Instructions.h"
31#include <memory>
32
33#define GET_GICOMBINER_DEPS
34#include "AArch64GenO0PreLegalizeGICombiner.inc"
35#undef GET_GICOMBINER_DEPS
36
37#define DEBUG_TYPE "aarch64-O0-prelegalizer-combiner"
38
39using namespace llvm;
40using namespace MIPatternMatch;
41
42#define GET_GICOMBINER_TYPES
43#include "AArch64GenO0PreLegalizeGICombiner.inc"
44#undef GET_GICOMBINER_TYPES
45
46namespace {
47
48class AArch64O0PreLegalizerCombinerImpl : public Combiner {
49protected:
50 const CombinerHelper Helper;
51 const AArch64O0PreLegalizerCombinerImplRuleConfig &RuleConfig;
52 const AArch64Subtarget &STI;
53 const LibcallLoweringInfo &Libcalls;
54
55public:
56 AArch64O0PreLegalizerCombinerImpl(
57 MachineFunction &MF, CombinerInfo &CInfo, GISelCSEInfo *CSEInfo,
58 const AArch64O0PreLegalizerCombinerImplRuleConfig &RuleConfig,
59 const AArch64Subtarget &STI, const LibcallLoweringInfo &Libcalls);
60
61 static const char *getName() { return "AArch64O0PreLegalizerCombiner"; }
62
63 bool tryCombineAll(MachineInstr &I) const override;
64
65 bool tryCombineAllImpl(MachineInstr &I) const;
66
67private:
68#define GET_GICOMBINER_CLASS_MEMBERS
69#include "AArch64GenO0PreLegalizeGICombiner.inc"
70#undef GET_GICOMBINER_CLASS_MEMBERS
71};
72
73#define GET_GICOMBINER_IMPL
74#include "AArch64GenO0PreLegalizeGICombiner.inc"
75#undef GET_GICOMBINER_IMPL
76
77AArch64O0PreLegalizerCombinerImpl::AArch64O0PreLegalizerCombinerImpl(
78 MachineFunction &MF, CombinerInfo &CInfo, GISelCSEInfo *CSEInfo,
79 const AArch64O0PreLegalizerCombinerImplRuleConfig &RuleConfig,
80 const AArch64Subtarget &STI, const LibcallLoweringInfo &Libcalls)
81 : Combiner(MF, CInfo, /*VT=*/nullptr, CSEInfo),
82 Helper(Observer, B, /*IsPreLegalize*/ true, /*VT=*/nullptr),
83 RuleConfig(RuleConfig), STI(STI), Libcalls(Libcalls),
84#define GET_GICOMBINER_CONSTRUCTOR_INITS
85#include "AArch64GenO0PreLegalizeGICombiner.inc"
86#undef GET_GICOMBINER_CONSTRUCTOR_INITS
87{
88}
89
90bool AArch64O0PreLegalizerCombinerImpl::tryCombineAll(MachineInstr &MI) const {
91 if (tryCombineAllImpl(I&: MI))
92 return true;
93
94 return false;
95}
96
97bool runCombiner(
98 MachineFunction &MF, const LibcallLoweringInfo &Libcalls,
99 const AArch64O0PreLegalizerCombinerImplRuleConfig &RuleConfig) {
100 const Function &F = MF.getFunction();
101 const AArch64Subtarget &ST = MF.getSubtarget<AArch64Subtarget>();
102
103 CombinerInfo CInfo(/*AllowIllegalOps=*/true, /*ShouldLegalizeIllegal=*/false,
104 /*LegalizerInfo=*/nullptr, /*EnableOpt=*/false,
105 F.hasOptSize(), F.hasMinSize());
106 // Disable fixed-point iteration in the Combiner. This improves compile-time
107 // at the cost of possibly missing optimizations. See PR#94291 for details.
108 CInfo.MaxIterations = 1;
109
110 AArch64O0PreLegalizerCombinerImpl Impl(MF, CInfo,
111 /*CSEInfo*/ nullptr, RuleConfig, ST,
112 Libcalls);
113 return Impl.combineMachineInstrs();
114}
115
116// Pass boilerplate
117// ================
118
119class AArch64O0PreLegalizerCombinerLegacy : public MachineFunctionPass {
120public:
121 static char ID;
122
123 AArch64O0PreLegalizerCombinerLegacy();
124
125 StringRef getPassName() const override {
126 return "AArch64O0PreLegalizerCombiner";
127 }
128
129 bool runOnMachineFunction(MachineFunction &MF) override;
130
131 void getAnalysisUsage(AnalysisUsage &AU) const override;
132
133private:
134 AArch64O0PreLegalizerCombinerImplRuleConfig RuleConfig;
135};
136} // end anonymous namespace
137
138void AArch64O0PreLegalizerCombinerLegacy::getAnalysisUsage(
139 AnalysisUsage &AU) const {
140 AU.setPreservesCFG();
141 getSelectionDAGFallbackAnalysisUsage(AU);
142 AU.addRequired<LibcallLoweringInfoWrapper>();
143 MachineFunctionPass::getAnalysisUsage(AU);
144}
145
146AArch64O0PreLegalizerCombinerLegacy::AArch64O0PreLegalizerCombinerLegacy()
147 : MachineFunctionPass(ID) {
148 if (!RuleConfig.parseCommandLineOption())
149 report_fatal_error(reason: "Invalid rule identifier");
150}
151
152bool AArch64O0PreLegalizerCombinerLegacy::runOnMachineFunction(
153 MachineFunction &MF) {
154 if (MF.getProperties().hasFailedISel())
155 return false;
156
157 const Function &F = MF.getFunction();
158
159 const AArch64Subtarget &ST = MF.getSubtarget<AArch64Subtarget>();
160 const LibcallLoweringInfo &Libcalls =
161 getAnalysis<LibcallLoweringInfoWrapper>().getLibcallLowering(
162 M: *F.getParent(), Subtarget: ST);
163
164 return runCombiner(MF, Libcalls, RuleConfig);
165}
166
167char AArch64O0PreLegalizerCombinerLegacy::ID = 0;
168INITIALIZE_PASS_BEGIN(AArch64O0PreLegalizerCombinerLegacy, DEBUG_TYPE,
169 "Combine AArch64 machine instrs before legalization",
170 false, false)
171INITIALIZE_PASS_DEPENDENCY(GISelCSEAnalysisWrapperPass)
172INITIALIZE_PASS_DEPENDENCY(LibcallLoweringInfoWrapper)
173INITIALIZE_PASS_END(AArch64O0PreLegalizerCombinerLegacy, DEBUG_TYPE,
174 "Combine AArch64 machine instrs before legalization", false,
175 false)
176
177AArch64O0PreLegalizerCombinerPass::AArch64O0PreLegalizerCombinerPass()
178 : RuleConfig(
179 std::make_unique<AArch64O0PreLegalizerCombinerImplRuleConfig>()) {
180 if (!RuleConfig->parseCommandLineOption())
181 report_fatal_error(reason: "Invalid rule identifier");
182}
183
184AArch64O0PreLegalizerCombinerPass::AArch64O0PreLegalizerCombinerPass(
185 AArch64O0PreLegalizerCombinerPass &&) = default;
186
187AArch64O0PreLegalizerCombinerPass::~AArch64O0PreLegalizerCombinerPass() =
188 default;
189
190PreservedAnalyses
191AArch64O0PreLegalizerCombinerPass::run(MachineFunction &MF,
192 MachineFunctionAnalysisManager &MFAM) {
193 if (MF.getProperties().hasFailedISel())
194 return PreservedAnalyses::all();
195
196 const AArch64Subtarget &ST = MF.getSubtarget<AArch64Subtarget>();
197 auto &MAMProxy =
198 MFAM.getResult<ModuleAnalysisManagerMachineFunctionProxy>(IR&: MF);
199 const ModuleLibcallLoweringInfo *LibcallResult =
200 MAMProxy.getCachedResult<LibcallLoweringModuleAnalysis>(
201 IR&: *MF.getFunction().getParent());
202 if (!LibcallResult)
203 reportFatalUsageError(reason: "LibcallLoweringModuleAnalysis result not available");
204
205 const LibcallLoweringInfo &Libcalls = getLibcallLowering(ModuleInfo: *LibcallResult, Subtarget: ST);
206
207 if (!runCombiner(MF, Libcalls, RuleConfig: *RuleConfig))
208 return PreservedAnalyses::all();
209
210 PreservedAnalyses PA = getMachineFunctionPassPreservedAnalyses();
211 PA.preserveSet<CFGAnalyses>();
212 return PA;
213}
214
215namespace llvm {
216FunctionPass *createAArch64O0PreLegalizerCombiner() {
217 return new AArch64O0PreLegalizerCombinerLegacy();
218}
219} // end namespace llvm
220