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/CodeGen/TargetPassConfig.h"
31#include "llvm/IR/Instructions.h"
32#include <memory>
33
34#define GET_GICOMBINER_DEPS
35#include "AArch64GenO0PreLegalizeGICombiner.inc"
36#undef GET_GICOMBINER_DEPS
37
38#define DEBUG_TYPE "aarch64-O0-prelegalizer-combiner"
39
40using namespace llvm;
41using namespace MIPatternMatch;
42
43#define GET_GICOMBINER_TYPES
44#include "AArch64GenO0PreLegalizeGICombiner.inc"
45#undef GET_GICOMBINER_TYPES
46
47namespace {
48
49class AArch64O0PreLegalizerCombinerImpl : public Combiner {
50protected:
51 const CombinerHelper Helper;
52 const AArch64O0PreLegalizerCombinerImplRuleConfig &RuleConfig;
53 const AArch64Subtarget &STI;
54 const LibcallLoweringInfo &Libcalls;
55
56public:
57 AArch64O0PreLegalizerCombinerImpl(
58 MachineFunction &MF, CombinerInfo &CInfo, GISelValueTracking &VT,
59 GISelCSEInfo *CSEInfo,
60 const AArch64O0PreLegalizerCombinerImplRuleConfig &RuleConfig,
61 const AArch64Subtarget &STI, const LibcallLoweringInfo &Libcalls);
62
63 static const char *getName() { return "AArch64O0PreLegalizerCombiner"; }
64
65 bool tryCombineAll(MachineInstr &I) const override;
66
67 bool tryCombineAllImpl(MachineInstr &I) const;
68
69private:
70#define GET_GICOMBINER_CLASS_MEMBERS
71#include "AArch64GenO0PreLegalizeGICombiner.inc"
72#undef GET_GICOMBINER_CLASS_MEMBERS
73};
74
75#define GET_GICOMBINER_IMPL
76#include "AArch64GenO0PreLegalizeGICombiner.inc"
77#undef GET_GICOMBINER_IMPL
78
79AArch64O0PreLegalizerCombinerImpl::AArch64O0PreLegalizerCombinerImpl(
80 MachineFunction &MF, CombinerInfo &CInfo, GISelValueTracking &VT,
81 GISelCSEInfo *CSEInfo,
82 const AArch64O0PreLegalizerCombinerImplRuleConfig &RuleConfig,
83 const AArch64Subtarget &STI, const LibcallLoweringInfo &Libcalls)
84 : Combiner(MF, CInfo, &VT, CSEInfo),
85 Helper(Observer, B, /*IsPreLegalize*/ true, &VT), RuleConfig(RuleConfig),
86 STI(STI), Libcalls(Libcalls),
87#define GET_GICOMBINER_CONSTRUCTOR_INITS
88#include "AArch64GenO0PreLegalizeGICombiner.inc"
89#undef GET_GICOMBINER_CONSTRUCTOR_INITS
90{
91}
92
93bool AArch64O0PreLegalizerCombinerImpl::tryCombineAll(MachineInstr &MI) const {
94 if (tryCombineAllImpl(I&: MI))
95 return true;
96
97 unsigned Opc = MI.getOpcode();
98 switch (Opc) {
99 case TargetOpcode::G_SHUFFLE_VECTOR:
100 return Helper.tryCombineShuffleVector(MI);
101 case TargetOpcode::G_MEMCPY_INLINE:
102 return Helper.tryEmitMemcpyInline(MI);
103 case TargetOpcode::G_MEMCPY:
104 case TargetOpcode::G_MEMMOVE:
105 case TargetOpcode::G_MEMSET: {
106 // At -O0 set a maxlen of 32 to inline;
107 unsigned MaxLen = 32;
108 // Try to inline memcpy type calls if optimizations are enabled.
109 if (Helper.tryCombineMemCpyFamily(MI, MaxLen))
110 return true;
111 if (Opc == TargetOpcode::G_MEMSET)
112 return llvm::AArch64GISelUtils::tryEmitBZero(MI, MIRBuilder&: B, Libcalls,
113 MinSize: CInfo.EnableMinSize);
114 return false;
115 }
116 }
117
118 return false;
119}
120
121bool runCombiner(
122 MachineFunction &MF, GISelValueTracking *VT,
123 const LibcallLoweringInfo &Libcalls,
124 const AArch64O0PreLegalizerCombinerImplRuleConfig &RuleConfig) {
125 const Function &F = MF.getFunction();
126 const AArch64Subtarget &ST = MF.getSubtarget<AArch64Subtarget>();
127
128 CombinerInfo CInfo(/*AllowIllegalOps=*/true, /*ShouldLegalizeIllegal=*/false,
129 /*LegalizerInfo=*/nullptr, /*EnableOpt=*/false,
130 F.hasOptSize(), F.hasMinSize());
131 // Disable fixed-point iteration in the Combiner. This improves compile-time
132 // at the cost of possibly missing optimizations. See PR#94291 for details.
133 CInfo.MaxIterations = 1;
134
135 AArch64O0PreLegalizerCombinerImpl Impl(MF, CInfo, *VT,
136 /*CSEInfo*/ nullptr, RuleConfig, ST,
137 Libcalls);
138 return Impl.combineMachineInstrs();
139}
140
141// Pass boilerplate
142// ================
143
144class AArch64O0PreLegalizerCombinerLegacy : public MachineFunctionPass {
145public:
146 static char ID;
147
148 AArch64O0PreLegalizerCombinerLegacy();
149
150 StringRef getPassName() const override {
151 return "AArch64O0PreLegalizerCombiner";
152 }
153
154 bool runOnMachineFunction(MachineFunction &MF) override;
155
156 void getAnalysisUsage(AnalysisUsage &AU) const override;
157
158private:
159 AArch64O0PreLegalizerCombinerImplRuleConfig RuleConfig;
160};
161} // end anonymous namespace
162
163void AArch64O0PreLegalizerCombinerLegacy::getAnalysisUsage(
164 AnalysisUsage &AU) const {
165 AU.setPreservesCFG();
166 getSelectionDAGFallbackAnalysisUsage(AU);
167 AU.addRequired<GISelValueTrackingAnalysisLegacy>();
168 AU.addPreserved<GISelValueTrackingAnalysisLegacy>();
169 AU.addRequired<LibcallLoweringInfoWrapper>();
170 MachineFunctionPass::getAnalysisUsage(AU);
171}
172
173AArch64O0PreLegalizerCombinerLegacy::AArch64O0PreLegalizerCombinerLegacy()
174 : MachineFunctionPass(ID) {
175 if (!RuleConfig.parseCommandLineOption())
176 report_fatal_error(reason: "Invalid rule identifier");
177}
178
179bool AArch64O0PreLegalizerCombinerLegacy::runOnMachineFunction(
180 MachineFunction &MF) {
181 if (MF.getProperties().hasFailedISel())
182 return false;
183
184 const Function &F = MF.getFunction();
185 GISelValueTracking *VT =
186 &getAnalysis<GISelValueTrackingAnalysisLegacy>().get(MF);
187
188 const AArch64Subtarget &ST = MF.getSubtarget<AArch64Subtarget>();
189 const LibcallLoweringInfo &Libcalls =
190 getAnalysis<LibcallLoweringInfoWrapper>().getLibcallLowering(
191 M: *F.getParent(), Subtarget: ST);
192
193 return runCombiner(MF, VT, Libcalls, RuleConfig);
194}
195
196char AArch64O0PreLegalizerCombinerLegacy::ID = 0;
197INITIALIZE_PASS_BEGIN(AArch64O0PreLegalizerCombinerLegacy, DEBUG_TYPE,
198 "Combine AArch64 machine instrs before legalization",
199 false, false)
200INITIALIZE_PASS_DEPENDENCY(GISelValueTrackingAnalysisLegacy)
201INITIALIZE_PASS_DEPENDENCY(GISelCSEAnalysisWrapperPass)
202INITIALIZE_PASS_DEPENDENCY(LibcallLoweringInfoWrapper)
203INITIALIZE_PASS_END(AArch64O0PreLegalizerCombinerLegacy, DEBUG_TYPE,
204 "Combine AArch64 machine instrs before legalization", false,
205 false)
206
207AArch64O0PreLegalizerCombinerPass::AArch64O0PreLegalizerCombinerPass()
208 : RuleConfig(
209 std::make_unique<AArch64O0PreLegalizerCombinerImplRuleConfig>()) {
210 if (!RuleConfig->parseCommandLineOption())
211 report_fatal_error(reason: "Invalid rule identifier");
212}
213
214AArch64O0PreLegalizerCombinerPass::AArch64O0PreLegalizerCombinerPass(
215 AArch64O0PreLegalizerCombinerPass &&) = default;
216
217AArch64O0PreLegalizerCombinerPass::~AArch64O0PreLegalizerCombinerPass() =
218 default;
219
220PreservedAnalyses
221AArch64O0PreLegalizerCombinerPass::run(MachineFunction &MF,
222 MachineFunctionAnalysisManager &MFAM) {
223 if (MF.getProperties().hasFailedISel())
224 return PreservedAnalyses::all();
225
226 GISelValueTracking &VT = MFAM.getResult<GISelValueTrackingAnalysis>(IR&: MF);
227
228 const AArch64Subtarget &ST = MF.getSubtarget<AArch64Subtarget>();
229 auto &MAMProxy =
230 MFAM.getResult<ModuleAnalysisManagerMachineFunctionProxy>(IR&: MF);
231 const LibcallLoweringModuleAnalysisResult *LibcallResult =
232 MAMProxy.getCachedResult<LibcallLoweringModuleAnalysis>(
233 IR&: *MF.getFunction().getParent());
234 if (!LibcallResult)
235 reportFatalUsageError(reason: "LibcallLoweringModuleAnalysis result not available");
236
237 const LibcallLoweringInfo &Libcalls = LibcallResult->getLibcallLowering(Subtarget: ST);
238
239 if (!runCombiner(MF, VT: &VT, Libcalls, RuleConfig: *RuleConfig))
240 return PreservedAnalyses::all();
241
242 PreservedAnalyses PA = getMachineFunctionPassPreservedAnalyses();
243 PA.preserveSet<CFGAnalyses>();
244 PA.preserve<GISelValueTrackingAnalysis>();
245 return PA;
246}
247
248namespace llvm {
249FunctionPass *createAArch64O0PreLegalizerCombiner() {
250 return new AArch64O0PreLegalizerCombinerLegacy();
251}
252} // end namespace llvm
253