1 //=== lib/CodeGen/GlobalISel/AArch64PreLegalizerCombiner.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 "AArch64TargetMachine.h"
15 #include "llvm/CodeGen/GlobalISel/Combiner.h"
16 #include "llvm/CodeGen/GlobalISel/CombinerHelper.h"
17 #include "llvm/CodeGen/GlobalISel/CombinerInfo.h"
18 #include "llvm/CodeGen/GlobalISel/GISelKnownBits.h"
19 #include "llvm/CodeGen/GlobalISel/MIPatternMatch.h"
20 #include "llvm/CodeGen/MachineDominators.h"
21 #include "llvm/CodeGen/MachineFunctionPass.h"
22 #include "llvm/CodeGen/TargetPassConfig.h"
23 #include "llvm/Support/Debug.h"
24
25 #define DEBUG_TYPE "aarch64-prelegalizer-combiner"
26
27 using namespace llvm;
28 using namespace MIPatternMatch;
29
30 /// Return true if a G_FCONSTANT instruction is known to be better-represented
31 /// as a G_CONSTANT.
matchFConstantToConstant(MachineInstr & MI,MachineRegisterInfo & MRI)32 static bool matchFConstantToConstant(MachineInstr &MI,
33 MachineRegisterInfo &MRI) {
34 assert(MI.getOpcode() == TargetOpcode::G_FCONSTANT);
35 Register DstReg = MI.getOperand(0).getReg();
36 const unsigned DstSize = MRI.getType(DstReg).getSizeInBits();
37 if (DstSize != 32 && DstSize != 64)
38 return false;
39
40 // When we're storing a value, it doesn't matter what register bank it's on.
41 // Since not all floating point constants can be materialized using a fmov,
42 // it makes more sense to just use a GPR.
43 return all_of(MRI.use_nodbg_instructions(DstReg),
44 [](const MachineInstr &Use) { return Use.mayStore(); });
45 }
46
47 /// Change a G_FCONSTANT into a G_CONSTANT.
applyFConstantToConstant(MachineInstr & MI)48 static void applyFConstantToConstant(MachineInstr &MI) {
49 assert(MI.getOpcode() == TargetOpcode::G_FCONSTANT);
50 MachineIRBuilder MIB(MI);
51 const APFloat &ImmValAPF = MI.getOperand(1).getFPImm()->getValueAPF();
52 MIB.buildConstant(MI.getOperand(0).getReg(), ImmValAPF.bitcastToAPInt());
53 MI.eraseFromParent();
54 }
55
56 class AArch64PreLegalizerCombinerHelperState {
57 protected:
58 CombinerHelper &Helper;
59
60 public:
AArch64PreLegalizerCombinerHelperState(CombinerHelper & Helper)61 AArch64PreLegalizerCombinerHelperState(CombinerHelper &Helper)
62 : Helper(Helper) {}
63 };
64
65 #define AARCH64PRELEGALIZERCOMBINERHELPER_GENCOMBINERHELPER_DEPS
66 #include "AArch64GenPreLegalizeGICombiner.inc"
67 #undef AARCH64PRELEGALIZERCOMBINERHELPER_GENCOMBINERHELPER_DEPS
68
69 namespace {
70 #define AARCH64PRELEGALIZERCOMBINERHELPER_GENCOMBINERHELPER_H
71 #include "AArch64GenPreLegalizeGICombiner.inc"
72 #undef AARCH64PRELEGALIZERCOMBINERHELPER_GENCOMBINERHELPER_H
73
74 class AArch64PreLegalizerCombinerInfo : public CombinerInfo {
75 GISelKnownBits *KB;
76 MachineDominatorTree *MDT;
77 AArch64GenPreLegalizerCombinerHelperRuleConfig GeneratedRuleCfg;
78
79 public:
AArch64PreLegalizerCombinerInfo(bool EnableOpt,bool OptSize,bool MinSize,GISelKnownBits * KB,MachineDominatorTree * MDT)80 AArch64PreLegalizerCombinerInfo(bool EnableOpt, bool OptSize, bool MinSize,
81 GISelKnownBits *KB, MachineDominatorTree *MDT)
82 : CombinerInfo(/*AllowIllegalOps*/ true, /*ShouldLegalizeIllegal*/ false,
83 /*LegalizerInfo*/ nullptr, EnableOpt, OptSize, MinSize),
84 KB(KB), MDT(MDT) {
85 if (!GeneratedRuleCfg.parseCommandLineOption())
86 report_fatal_error("Invalid rule identifier");
87 }
88
89 virtual bool combine(GISelChangeObserver &Observer, MachineInstr &MI,
90 MachineIRBuilder &B) const override;
91 };
92
combine(GISelChangeObserver & Observer,MachineInstr & MI,MachineIRBuilder & B) const93 bool AArch64PreLegalizerCombinerInfo::combine(GISelChangeObserver &Observer,
94 MachineInstr &MI,
95 MachineIRBuilder &B) const {
96 CombinerHelper Helper(Observer, B, KB, MDT);
97 AArch64GenPreLegalizerCombinerHelper Generated(GeneratedRuleCfg, Helper);
98
99 if (Generated.tryCombineAll(Observer, MI, B))
100 return true;
101
102 switch (MI.getOpcode()) {
103 case TargetOpcode::G_CONCAT_VECTORS:
104 return Helper.tryCombineConcatVectors(MI);
105 case TargetOpcode::G_SHUFFLE_VECTOR:
106 return Helper.tryCombineShuffleVector(MI);
107 case TargetOpcode::G_MEMCPY:
108 case TargetOpcode::G_MEMMOVE:
109 case TargetOpcode::G_MEMSET: {
110 // If we're at -O0 set a maxlen of 32 to inline, otherwise let the other
111 // heuristics decide.
112 unsigned MaxLen = EnableOpt ? 0 : 32;
113 // Try to inline memcpy type calls if optimizations are enabled.
114 return !EnableMinSize ? Helper.tryCombineMemCpyFamily(MI, MaxLen) : false;
115 }
116 }
117
118 return false;
119 }
120
121 #define AARCH64PRELEGALIZERCOMBINERHELPER_GENCOMBINERHELPER_CPP
122 #include "AArch64GenPreLegalizeGICombiner.inc"
123 #undef AARCH64PRELEGALIZERCOMBINERHELPER_GENCOMBINERHELPER_CPP
124
125 // Pass boilerplate
126 // ================
127
128 class AArch64PreLegalizerCombiner : public MachineFunctionPass {
129 public:
130 static char ID;
131
132 AArch64PreLegalizerCombiner(bool IsOptNone = false);
133
getPassName() const134 StringRef getPassName() const override { return "AArch64PreLegalizerCombiner"; }
135
136 bool runOnMachineFunction(MachineFunction &MF) override;
137
138 void getAnalysisUsage(AnalysisUsage &AU) const override;
139 private:
140 bool IsOptNone;
141 };
142 } // end anonymous namespace
143
getAnalysisUsage(AnalysisUsage & AU) const144 void AArch64PreLegalizerCombiner::getAnalysisUsage(AnalysisUsage &AU) const {
145 AU.addRequired<TargetPassConfig>();
146 AU.setPreservesCFG();
147 getSelectionDAGFallbackAnalysisUsage(AU);
148 AU.addRequired<GISelKnownBitsAnalysis>();
149 AU.addPreserved<GISelKnownBitsAnalysis>();
150 if (!IsOptNone) {
151 AU.addRequired<MachineDominatorTree>();
152 AU.addPreserved<MachineDominatorTree>();
153 }
154 MachineFunctionPass::getAnalysisUsage(AU);
155 }
156
AArch64PreLegalizerCombiner(bool IsOptNone)157 AArch64PreLegalizerCombiner::AArch64PreLegalizerCombiner(bool IsOptNone)
158 : MachineFunctionPass(ID), IsOptNone(IsOptNone) {
159 initializeAArch64PreLegalizerCombinerPass(*PassRegistry::getPassRegistry());
160 }
161
runOnMachineFunction(MachineFunction & MF)162 bool AArch64PreLegalizerCombiner::runOnMachineFunction(MachineFunction &MF) {
163 if (MF.getProperties().hasProperty(
164 MachineFunctionProperties::Property::FailedISel))
165 return false;
166 auto *TPC = &getAnalysis<TargetPassConfig>();
167 const Function &F = MF.getFunction();
168 bool EnableOpt =
169 MF.getTarget().getOptLevel() != CodeGenOpt::None && !skipFunction(F);
170 GISelKnownBits *KB = &getAnalysis<GISelKnownBitsAnalysis>().get(MF);
171 MachineDominatorTree *MDT =
172 IsOptNone ? nullptr : &getAnalysis<MachineDominatorTree>();
173 AArch64PreLegalizerCombinerInfo PCInfo(EnableOpt, F.hasOptSize(),
174 F.hasMinSize(), KB, MDT);
175 Combiner C(PCInfo, TPC);
176 return C.combineMachineInstrs(MF, /*CSEInfo*/ nullptr);
177 }
178
179 char AArch64PreLegalizerCombiner::ID = 0;
180 INITIALIZE_PASS_BEGIN(AArch64PreLegalizerCombiner, DEBUG_TYPE,
181 "Combine AArch64 machine instrs before legalization",
182 false, false)
183 INITIALIZE_PASS_DEPENDENCY(TargetPassConfig)
184 INITIALIZE_PASS_DEPENDENCY(GISelKnownBitsAnalysis)
185 INITIALIZE_PASS_END(AArch64PreLegalizerCombiner, DEBUG_TYPE,
186 "Combine AArch64 machine instrs before legalization", false,
187 false)
188
189
190 namespace llvm {
createAArch64PreLegalizerCombiner(bool IsOptNone)191 FunctionPass *createAArch64PreLegalizerCombiner(bool IsOptNone) {
192 return new AArch64PreLegalizerCombiner(IsOptNone);
193 }
194 } // end namespace llvm
195