1 //===- AArch64MIPeepholeOpt.cpp - AArch64 MI peephole optimization pass ---===//
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 performs below peephole optimizations on MIR level.
10 //
11 // 1. MOVi32imm + ANDWrr ==> ANDWri + ANDWri
12 //    MOVi64imm + ANDXrr ==> ANDXri + ANDXri
13 //
14 // 2. MOVi32imm + ADDWrr ==> ADDWRi + ADDWRi
15 //    MOVi64imm + ADDXrr ==> ANDXri + ANDXri
16 //
17 // 3. MOVi32imm + SUBWrr ==> SUBWRi + SUBWRi
18 //    MOVi64imm + SUBXrr ==> SUBXri + SUBXri
19 //
20 //    The mov pseudo instruction could be expanded to multiple mov instructions
21 //    later. In this case, we could try to split the constant  operand of mov
22 //    instruction into two immediates which can be directly encoded into
23 //    *Wri/*Xri instructions. It makes two AND/ADD/SUB instructions instead of
24 //    multiple `mov` + `and/add/sub` instructions.
25 //
26 // 4. Remove redundant ORRWrs which is generated by zero-extend.
27 //
28 //    %3:gpr32 = ORRWrs $wzr, %2, 0
29 //    %4:gpr64 = SUBREG_TO_REG 0, %3, %subreg.sub_32
30 //
31 //    If AArch64's 32-bit form of instruction defines the source operand of
32 //    ORRWrs, we can remove the ORRWrs because the upper 32 bits of the source
33 //    operand are set to zero.
34 //
35 //===----------------------------------------------------------------------===//
36 
37 #include "AArch64ExpandImm.h"
38 #include "AArch64InstrInfo.h"
39 #include "MCTargetDesc/AArch64AddressingModes.h"
40 #include "llvm/ADT/SetVector.h"
41 #include "llvm/CodeGen/MachineDominators.h"
42 #include "llvm/CodeGen/MachineLoopInfo.h"
43 
44 using namespace llvm;
45 
46 #define DEBUG_TYPE "aarch64-mi-peephole-opt"
47 
48 namespace {
49 
50 struct AArch64MIPeepholeOpt : public MachineFunctionPass {
51   static char ID;
52 
53   AArch64MIPeepholeOpt() : MachineFunctionPass(ID) {
54     initializeAArch64MIPeepholeOptPass(*PassRegistry::getPassRegistry());
55   }
56 
57   const AArch64InstrInfo *TII;
58   MachineLoopInfo *MLI;
59   MachineRegisterInfo *MRI;
60 
61   bool checkMovImmInstr(MachineInstr &MI, MachineInstr *&MovMI,
62                         MachineInstr *&SubregToRegMI);
63 
64   template <typename T>
65   bool visitADDSUB(MachineInstr &MI,
66                    SmallSetVector<MachineInstr *, 8> &ToBeRemoved, bool IsAdd);
67   template <typename T>
68   bool visitAND(MachineInstr &MI,
69                 SmallSetVector<MachineInstr *, 8> &ToBeRemoved);
70   bool visitORR(MachineInstr &MI,
71                 SmallSetVector<MachineInstr *, 8> &ToBeRemoved);
72   bool runOnMachineFunction(MachineFunction &MF) override;
73 
74   StringRef getPassName() const override {
75     return "AArch64 MI Peephole Optimization pass";
76   }
77 
78   void getAnalysisUsage(AnalysisUsage &AU) const override {
79     AU.setPreservesCFG();
80     AU.addRequired<MachineLoopInfo>();
81     MachineFunctionPass::getAnalysisUsage(AU);
82   }
83 };
84 
85 char AArch64MIPeepholeOpt::ID = 0;
86 
87 } // end anonymous namespace
88 
89 INITIALIZE_PASS(AArch64MIPeepholeOpt, "aarch64-mi-peephole-opt",
90                 "AArch64 MI Peephole Optimization", false, false)
91 
92 template <typename T>
93 static bool splitBitmaskImm(T Imm, unsigned RegSize, T &Imm1Enc, T &Imm2Enc) {
94   T UImm = static_cast<T>(Imm);
95   if (AArch64_AM::isLogicalImmediate(UImm, RegSize))
96     return false;
97 
98   // If this immediate can be handled by one instruction, do not split it.
99   SmallVector<AArch64_IMM::ImmInsnModel, 4> Insn;
100   AArch64_IMM::expandMOVImm(UImm, RegSize, Insn);
101   if (Insn.size() == 1)
102     return false;
103 
104   // The bitmask immediate consists of consecutive ones.  Let's say there is
105   // constant 0b00000000001000000000010000000000 which does not consist of
106   // consecutive ones. We can split it in to two bitmask immediate like
107   // 0b00000000001111111111110000000000 and 0b11111111111000000000011111111111.
108   // If we do AND with these two bitmask immediate, we can see original one.
109   unsigned LowestBitSet = countTrailingZeros(UImm);
110   unsigned HighestBitSet = Log2_64(UImm);
111 
112   // Create a mask which is filled with one from the position of lowest bit set
113   // to the position of highest bit set.
114   T NewImm1 = (static_cast<T>(2) << HighestBitSet) -
115               (static_cast<T>(1) << LowestBitSet);
116   // Create a mask which is filled with one outside the position of lowest bit
117   // set and the position of highest bit set.
118   T NewImm2 = UImm | ~NewImm1;
119 
120   // If the split value is not valid bitmask immediate, do not split this
121   // constant.
122   if (!AArch64_AM::isLogicalImmediate(NewImm2, RegSize))
123     return false;
124 
125   Imm1Enc = AArch64_AM::encodeLogicalImmediate(NewImm1, RegSize);
126   Imm2Enc = AArch64_AM::encodeLogicalImmediate(NewImm2, RegSize);
127   return true;
128 }
129 
130 template <typename T>
131 bool AArch64MIPeepholeOpt::visitAND(
132     MachineInstr &MI, SmallSetVector<MachineInstr *, 8> &ToBeRemoved) {
133   // Try below transformation.
134   //
135   // MOVi32imm + ANDWrr ==> ANDWri + ANDWri
136   // MOVi64imm + ANDXrr ==> ANDXri + ANDXri
137   //
138   // The mov pseudo instruction could be expanded to multiple mov instructions
139   // later. Let's try to split the constant operand of mov instruction into two
140   // bitmask immediates. It makes only two AND instructions intead of multiple
141   // mov + and instructions.
142 
143   unsigned RegSize = sizeof(T) * 8;
144   assert((RegSize == 32 || RegSize == 64) &&
145          "Invalid RegSize for AND bitmask peephole optimization");
146 
147   // Perform several essential checks against current MI.
148   MachineInstr *MovMI = nullptr, *SubregToRegMI = nullptr;
149   if (!checkMovImmInstr(MI, MovMI, SubregToRegMI))
150     return false;
151 
152   // Split the bitmask immediate into two.
153   T UImm = static_cast<T>(MovMI->getOperand(1).getImm());
154   // For the 32 bit form of instruction, the upper 32 bits of the destination
155   // register are set to zero. If there is SUBREG_TO_REG, set the upper 32 bits
156   // of UImm to zero.
157   if (SubregToRegMI)
158     UImm &= 0xFFFFFFFF;
159   T Imm1Enc;
160   T Imm2Enc;
161   if (!splitBitmaskImm(UImm, RegSize, Imm1Enc, Imm2Enc))
162     return false;
163 
164   // Create new AND MIs.
165   DebugLoc DL = MI.getDebugLoc();
166   MachineBasicBlock *MBB = MI.getParent();
167   const TargetRegisterClass *ANDImmRC =
168       (RegSize == 32) ? &AArch64::GPR32spRegClass : &AArch64::GPR64spRegClass;
169   Register DstReg = MI.getOperand(0).getReg();
170   Register SrcReg = MI.getOperand(1).getReg();
171   Register NewTmpReg = MRI->createVirtualRegister(ANDImmRC);
172   Register NewDstReg = MRI->createVirtualRegister(ANDImmRC);
173   unsigned Opcode = (RegSize == 32) ? AArch64::ANDWri : AArch64::ANDXri;
174 
175   MRI->constrainRegClass(NewTmpReg, MRI->getRegClass(SrcReg));
176   BuildMI(*MBB, MI, DL, TII->get(Opcode), NewTmpReg)
177       .addReg(SrcReg)
178       .addImm(Imm1Enc);
179 
180   MRI->constrainRegClass(NewDstReg, MRI->getRegClass(DstReg));
181   BuildMI(*MBB, MI, DL, TII->get(Opcode), NewDstReg)
182       .addReg(NewTmpReg)
183       .addImm(Imm2Enc);
184 
185   MRI->replaceRegWith(DstReg, NewDstReg);
186   // replaceRegWith changes MI's definition register. Keep it for SSA form until
187   // deleting MI.
188   MI.getOperand(0).setReg(DstReg);
189 
190   ToBeRemoved.insert(&MI);
191   if (SubregToRegMI)
192     ToBeRemoved.insert(SubregToRegMI);
193   ToBeRemoved.insert(MovMI);
194 
195   return true;
196 }
197 
198 bool AArch64MIPeepholeOpt::visitORR(
199     MachineInstr &MI, SmallSetVector<MachineInstr *, 8> &ToBeRemoved) {
200   // Check this ORR comes from below zero-extend pattern.
201   //
202   // def : Pat<(i64 (zext GPR32:$src)),
203   //           (SUBREG_TO_REG (i32 0), (ORRWrs WZR, GPR32:$src, 0), sub_32)>;
204   if (MI.getOperand(3).getImm() != 0)
205     return false;
206 
207   if (MI.getOperand(1).getReg() != AArch64::WZR)
208     return false;
209 
210   MachineInstr *SrcMI = MRI->getUniqueVRegDef(MI.getOperand(2).getReg());
211   if (!SrcMI)
212     return false;
213 
214   // From https://developer.arm.com/documentation/dui0801/b/BABBGCAC
215   //
216   // When you use the 32-bit form of an instruction, the upper 32 bits of the
217   // source registers are ignored and the upper 32 bits of the destination
218   // register are set to zero.
219   //
220   // If AArch64's 32-bit form of instruction defines the source operand of
221   // zero-extend, we do not need the zero-extend. Let's check the MI's opcode is
222   // real AArch64 instruction and if it is not, do not process the opcode
223   // conservatively.
224   if (SrcMI->getOpcode() <= TargetOpcode::GENERIC_OP_END)
225     return false;
226 
227   Register DefReg = MI.getOperand(0).getReg();
228   Register SrcReg = MI.getOperand(2).getReg();
229   MRI->replaceRegWith(DefReg, SrcReg);
230   MRI->clearKillFlags(SrcReg);
231   // replaceRegWith changes MI's definition register. Keep it for SSA form until
232   // deleting MI.
233   MI.getOperand(0).setReg(DefReg);
234   ToBeRemoved.insert(&MI);
235 
236   LLVM_DEBUG(dbgs() << "Removed: " << MI << "\n");
237 
238   return true;
239 }
240 
241 template <typename T>
242 static bool splitAddSubImm(T Imm, unsigned RegSize, T &Imm0, T &Imm1) {
243   // The immediate must be in the form of ((imm0 << 12) + imm1), in which both
244   // imm0 and imm1 are non-zero 12-bit unsigned int.
245   if ((Imm & 0xfff000) == 0 || (Imm & 0xfff) == 0 ||
246       (Imm & ~static_cast<T>(0xffffff)) != 0)
247     return false;
248 
249   // The immediate can not be composed via a single instruction.
250   SmallVector<AArch64_IMM::ImmInsnModel, 4> Insn;
251   AArch64_IMM::expandMOVImm(Imm, RegSize, Insn);
252   if (Insn.size() == 1)
253     return false;
254 
255   // Split Imm into (Imm0 << 12) + Imm1;
256   Imm0 = (Imm >> 12) & 0xfff;
257   Imm1 = Imm & 0xfff;
258   return true;
259 }
260 
261 template <typename T>
262 bool AArch64MIPeepholeOpt::visitADDSUB(
263     MachineInstr &MI, SmallSetVector<MachineInstr *, 8> &ToBeRemoved,
264     bool IsAdd) {
265   // Try below transformation.
266   //
267   // MOVi32imm + ADDWrr ==> ADDWri + ADDWri
268   // MOVi64imm + ADDXrr ==> ADDXri + ADDXri
269   //
270   // MOVi32imm + SUBWrr ==> SUBWri + SUBWri
271   // MOVi64imm + SUBXrr ==> SUBXri + SUBXri
272   //
273   // The mov pseudo instruction could be expanded to multiple mov instructions
274   // later. Let's try to split the constant operand of mov instruction into two
275   // legal add/sub immediates. It makes only two ADD/SUB instructions intead of
276   // multiple `mov` + `and/sub` instructions.
277 
278   unsigned RegSize = sizeof(T) * 8;
279   assert((RegSize == 32 || RegSize == 64) &&
280          "Invalid RegSize for legal add/sub immediate peephole optimization");
281 
282   // Perform several essential checks against current MI.
283   MachineInstr *MovMI, *SubregToRegMI;
284   if (!checkMovImmInstr(MI, MovMI, SubregToRegMI))
285     return false;
286 
287   // Split the immediate to Imm0 and Imm1, and calculate the Opcode.
288   T Imm = static_cast<T>(MovMI->getOperand(1).getImm()), Imm0, Imm1;
289   unsigned Opcode;
290   if (splitAddSubImm(Imm, RegSize, Imm0, Imm1)) {
291     if (IsAdd)
292       Opcode = RegSize == 32 ? AArch64::ADDWri : AArch64::ADDXri;
293     else
294       Opcode = RegSize == 32 ? AArch64::SUBWri : AArch64::SUBXri;
295   } else if (splitAddSubImm(-Imm, RegSize, Imm0, Imm1)) {
296     if (IsAdd)
297       Opcode = RegSize == 32 ? AArch64::SUBWri : AArch64::SUBXri;
298     else
299       Opcode = RegSize == 32 ? AArch64::ADDWri : AArch64::ADDXri;
300   } else {
301     return false;
302   }
303 
304   // Create new ADD/SUB MIs.
305   DebugLoc DL = MI.getDebugLoc();
306   MachineBasicBlock *MBB = MI.getParent();
307   const TargetRegisterClass *RC =
308       (RegSize == 32) ? &AArch64::GPR32spRegClass : &AArch64::GPR64spRegClass;
309   Register DstReg = MI.getOperand(0).getReg();
310   Register SrcReg = MI.getOperand(1).getReg();
311   Register NewTmpReg = MRI->createVirtualRegister(RC);
312   Register NewDstReg = MRI->createVirtualRegister(RC);
313 
314   MRI->constrainRegClass(SrcReg, RC);
315   BuildMI(*MBB, MI, DL, TII->get(Opcode), NewTmpReg)
316       .addReg(SrcReg)
317       .addImm(Imm0)
318       .addImm(12);
319 
320   MRI->constrainRegClass(NewDstReg, MRI->getRegClass(DstReg));
321   BuildMI(*MBB, MI, DL, TII->get(Opcode), NewDstReg)
322       .addReg(NewTmpReg)
323       .addImm(Imm1)
324       .addImm(0);
325 
326   MRI->replaceRegWith(DstReg, NewDstReg);
327   // replaceRegWith changes MI's definition register. Keep it for SSA form until
328   // deleting MI.
329   MI.getOperand(0).setReg(DstReg);
330 
331   // Record the MIs need to be removed.
332   ToBeRemoved.insert(&MI);
333   if (SubregToRegMI)
334     ToBeRemoved.insert(SubregToRegMI);
335   ToBeRemoved.insert(MovMI);
336 
337   return true;
338 }
339 
340 // Checks if the corresponding MOV immediate instruction is applicable for
341 // this peephole optimization.
342 bool AArch64MIPeepholeOpt::checkMovImmInstr(MachineInstr &MI,
343                                             MachineInstr *&MovMI,
344                                             MachineInstr *&SubregToRegMI) {
345   // Check whether current MBB is in loop and the AND is loop invariant.
346   MachineBasicBlock *MBB = MI.getParent();
347   MachineLoop *L = MLI->getLoopFor(MBB);
348   if (L && !L->isLoopInvariant(MI))
349     return false;
350 
351   // Check whether current MI's operand is MOV with immediate.
352   MovMI = MRI->getUniqueVRegDef(MI.getOperand(2).getReg());
353   if (!MovMI)
354     return false;
355 
356   // If it is SUBREG_TO_REG, check its operand.
357   SubregToRegMI = nullptr;
358   if (MovMI->getOpcode() == TargetOpcode::SUBREG_TO_REG) {
359     SubregToRegMI = MovMI;
360     MovMI = MRI->getUniqueVRegDef(MovMI->getOperand(2).getReg());
361     if (!MovMI)
362       return false;
363   }
364 
365   if (MovMI->getOpcode() != AArch64::MOVi32imm &&
366       MovMI->getOpcode() != AArch64::MOVi64imm)
367     return false;
368 
369   // If the MOV has multiple uses, do not split the immediate because it causes
370   // more instructions.
371   if (!MRI->hasOneUse(MovMI->getOperand(0).getReg()))
372     return false;
373   if (SubregToRegMI && !MRI->hasOneUse(SubregToRegMI->getOperand(0).getReg()))
374     return false;
375 
376   // It is OK to perform this peephole optimization.
377   return true;
378 }
379 
380 bool AArch64MIPeepholeOpt::runOnMachineFunction(MachineFunction &MF) {
381   if (skipFunction(MF.getFunction()))
382     return false;
383 
384   TII = static_cast<const AArch64InstrInfo *>(MF.getSubtarget().getInstrInfo());
385   MLI = &getAnalysis<MachineLoopInfo>();
386   MRI = &MF.getRegInfo();
387 
388   assert (MRI->isSSA() && "Expected to be run on SSA form!");
389 
390   bool Changed = false;
391   SmallSetVector<MachineInstr *, 8> ToBeRemoved;
392 
393   for (MachineBasicBlock &MBB : MF) {
394     for (MachineInstr &MI : MBB) {
395       switch (MI.getOpcode()) {
396       default:
397         break;
398       case AArch64::ANDWrr:
399         Changed = visitAND<uint32_t>(MI, ToBeRemoved);
400         break;
401       case AArch64::ANDXrr:
402         Changed = visitAND<uint64_t>(MI, ToBeRemoved);
403         break;
404       case AArch64::ORRWrs:
405         Changed = visitORR(MI, ToBeRemoved);
406         break;
407       case AArch64::ADDWrr:
408         Changed = visitADDSUB<uint32_t>(MI, ToBeRemoved, true);
409         break;
410       case AArch64::SUBWrr:
411         Changed = visitADDSUB<uint32_t>(MI, ToBeRemoved, false);
412         break;
413       case AArch64::ADDXrr:
414         Changed = visitADDSUB<uint64_t>(MI, ToBeRemoved, true);
415         break;
416       case AArch64::SUBXrr:
417         Changed = visitADDSUB<uint64_t>(MI, ToBeRemoved, false);
418         break;
419       }
420     }
421   }
422 
423   for (MachineInstr *MI : ToBeRemoved)
424     MI->eraseFromParent();
425 
426   return Changed;
427 }
428 
429 FunctionPass *llvm::createAArch64MIPeepholeOptPass() {
430   return new AArch64MIPeepholeOpt();
431 }
432