xref: /freebsd/contrib/llvm-project/llvm/lib/Target/AArch64/GISel/AArch64PreLegalizerCombiner.cpp (revision dc318a4ffabcbfa23bb56a33403aad36e6de30af)
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.
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.
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:
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:
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 
93 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   switch (MI.getOpcode()) {
100   case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
101     switch (MI.getIntrinsicID()) {
102     case Intrinsic::memcpy:
103     case Intrinsic::memmove:
104     case Intrinsic::memset: {
105       // If we're at -O0 set a maxlen of 32 to inline, otherwise let the other
106       // heuristics decide.
107       unsigned MaxLen = EnableOpt ? 0 : 32;
108       // Try to inline memcpy type calls if optimizations are enabled.
109       return (!EnableMinSize) ? Helper.tryCombineMemCpyFamily(MI, MaxLen)
110                               : false;
111     }
112     default:
113       break;
114     }
115   }
116 
117   if (Generated.tryCombineAll(Observer, MI, B))
118     return true;
119 
120   switch (MI.getOpcode()) {
121   case TargetOpcode::G_CONCAT_VECTORS:
122     return Helper.tryCombineConcatVectors(MI);
123   case TargetOpcode::G_SHUFFLE_VECTOR:
124     return Helper.tryCombineShuffleVector(MI);
125   }
126 
127   return false;
128 }
129 
130 #define AARCH64PRELEGALIZERCOMBINERHELPER_GENCOMBINERHELPER_CPP
131 #include "AArch64GenPreLegalizeGICombiner.inc"
132 #undef AARCH64PRELEGALIZERCOMBINERHELPER_GENCOMBINERHELPER_CPP
133 
134 // Pass boilerplate
135 // ================
136 
137 class AArch64PreLegalizerCombiner : public MachineFunctionPass {
138 public:
139   static char ID;
140 
141   AArch64PreLegalizerCombiner(bool IsOptNone = false);
142 
143   StringRef getPassName() const override { return "AArch64PreLegalizerCombiner"; }
144 
145   bool runOnMachineFunction(MachineFunction &MF) override;
146 
147   void getAnalysisUsage(AnalysisUsage &AU) const override;
148 private:
149   bool IsOptNone;
150 };
151 } // end anonymous namespace
152 
153 void AArch64PreLegalizerCombiner::getAnalysisUsage(AnalysisUsage &AU) const {
154   AU.addRequired<TargetPassConfig>();
155   AU.setPreservesCFG();
156   getSelectionDAGFallbackAnalysisUsage(AU);
157   AU.addRequired<GISelKnownBitsAnalysis>();
158   AU.addPreserved<GISelKnownBitsAnalysis>();
159   if (!IsOptNone) {
160     AU.addRequired<MachineDominatorTree>();
161     AU.addPreserved<MachineDominatorTree>();
162   }
163   MachineFunctionPass::getAnalysisUsage(AU);
164 }
165 
166 AArch64PreLegalizerCombiner::AArch64PreLegalizerCombiner(bool IsOptNone)
167     : MachineFunctionPass(ID), IsOptNone(IsOptNone) {
168   initializeAArch64PreLegalizerCombinerPass(*PassRegistry::getPassRegistry());
169 }
170 
171 bool AArch64PreLegalizerCombiner::runOnMachineFunction(MachineFunction &MF) {
172   if (MF.getProperties().hasProperty(
173           MachineFunctionProperties::Property::FailedISel))
174     return false;
175   auto *TPC = &getAnalysis<TargetPassConfig>();
176   const Function &F = MF.getFunction();
177   bool EnableOpt =
178       MF.getTarget().getOptLevel() != CodeGenOpt::None && !skipFunction(F);
179   GISelKnownBits *KB = &getAnalysis<GISelKnownBitsAnalysis>().get(MF);
180   MachineDominatorTree *MDT =
181       IsOptNone ? nullptr : &getAnalysis<MachineDominatorTree>();
182   AArch64PreLegalizerCombinerInfo PCInfo(EnableOpt, F.hasOptSize(),
183                                          F.hasMinSize(), KB, MDT);
184   Combiner C(PCInfo, TPC);
185   return C.combineMachineInstrs(MF, /*CSEInfo*/ nullptr);
186 }
187 
188 char AArch64PreLegalizerCombiner::ID = 0;
189 INITIALIZE_PASS_BEGIN(AArch64PreLegalizerCombiner, DEBUG_TYPE,
190                       "Combine AArch64 machine instrs before legalization",
191                       false, false)
192 INITIALIZE_PASS_DEPENDENCY(TargetPassConfig)
193 INITIALIZE_PASS_DEPENDENCY(GISelKnownBitsAnalysis)
194 INITIALIZE_PASS_END(AArch64PreLegalizerCombiner, DEBUG_TYPE,
195                     "Combine AArch64 machine instrs before legalization", false,
196                     false)
197 
198 
199 namespace llvm {
200 FunctionPass *createAArch64PreLegalizeCombiner(bool IsOptNone) {
201   return new AArch64PreLegalizerCombiner(IsOptNone);
202 }
203 } // end namespace llvm
204