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