LLVM 24.0.0git
AArch64MIPeepholeOpt.cpp
Go to the documentation of this file.
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 + (ANDS?|EOR|ORR)Wrr ==> (AND|EOR|ORR)Wri + (ANDS?|EOR|ORR)Wri
12// MOVi64imm + (ANDS?|EOR|ORR)Xrr ==> (AND|EOR|ORR)Xri + (ANDS?|EOR|ORR)Xri
13//
14// 2. MOVi32imm + ADDWrr ==> ADDWRi + ADDWRi
15// MOVi64imm + ADDXrr ==> ADDXri + ADDXri
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 %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// 5. %reg = INSERT_SUBREG %reg(tied-def 0), %subreg, subidx
36// ==> %reg:subidx = SUBREG_TO_REG %subreg, subidx
37//
38// 6. %intermediate:gpr32 = COPY %src:fpr128
39// %dst:fpr128 = INSvi32gpr %dst_vec:fpr128, dst_index, %intermediate:gpr32
40// ==> %dst:fpr128 = INSvi32lane %dst_vec:fpr128, dst_index, %src:fpr128, 0
41//
42// In cases where a source FPR is copied to a GPR in order to be copied
43// to a destination FPR, we can directly copy the values between the FPRs,
44// eliminating the use of the Integer unit. When we match a pattern of
45// INSvi[X]gpr that is preceded by a chain of COPY instructions from a FPR
46// source, we use the INSvi[X]lane to replace the COPY & INSvi[X]gpr
47// instructions.
48//
49// 7. If MI sets zero for high 64-bits implicitly, remove `mov 0` for high
50// 64-bits. For example,
51//
52// %1:fpr64 = nofpexcept FCVTNv4i16 %0:fpr128, implicit $fpcr
53// %2:fpr64 = MOVID 0
54// %4:fpr128 = IMPLICIT_DEF
55// %3:fpr128 = INSERT_SUBREG %4:fpr128(tied-def 0), %2:fpr64, %subreg.dsub
56// %6:fpr128 = IMPLICIT_DEF
57// %5:fpr128 = INSERT_SUBREG %6:fpr128(tied-def 0), %1:fpr64, %subreg.dsub
58// %7:fpr128 = INSvi64lane %5:fpr128(tied-def 0), 1, %3:fpr128, 0
59// ==>
60// %1:fpr64 = nofpexcept FCVTNv4i16 %0:fpr128, implicit $fpcr
61// %6:fpr128 = IMPLICIT_DEF
62// %7:fpr128 = INSERT_SUBREG %6:fpr128(tied-def 0), %1:fpr64, %subreg.dsub
63//
64// 8. Remove redundant CSELs that select between identical registers, by
65// replacing them with unconditional moves.
66//
67// 9. Replace UBFMXri with UBFMWri if the instruction is equivalent to a 32 bit
68// LSR or LSL alias of UBFM.
69//
70//===----------------------------------------------------------------------===//
71
72#include "AArch64ExpandImm.h"
73#include "AArch64InstrInfo.h"
77
78using namespace llvm;
79
80#define DEBUG_TYPE "aarch64-mi-peephole-opt"
81
82namespace {
83
84class AArch64MIPeepholeOptImpl {
85public:
86 const AArch64InstrInfo *TII;
88 MachineLoopInfo *MLI;
90
91 explicit AArch64MIPeepholeOptImpl(MachineLoopInfo &MLI) : MLI(&MLI) {}
92
93 bool run(MachineFunction &MF);
94
95private:
96 using OpcodePair = std::pair<unsigned, unsigned>;
97 template <typename T>
98 using SplitAndOpcFunc =
99 std::function<std::optional<OpcodePair>(T, unsigned, T &, T &)>;
100 using BuildMIFunc =
101 std::function<void(MachineInstr &, OpcodePair, unsigned, unsigned,
103
104 /// For instructions where an immediate operand could be split into two
105 /// separate immediate instructions, use the splitTwoPartImm two handle the
106 /// optimization.
107 ///
108 /// To implement, the following function types must be passed to
109 /// splitTwoPartImm. A SplitAndOpcFunc must be implemented that determines if
110 /// splitting the immediate is valid and returns the associated new opcode. A
111 /// BuildMIFunc must be implemented to build the two immediate instructions.
112 ///
113 /// Example Pattern (where IMM would require 2+ MOV instructions):
114 /// %dst = <Instr>rr %src IMM [...]
115 /// becomes:
116 /// %tmp = <Instr>ri %src (encode half IMM) [...]
117 /// %dst = <Instr>ri %tmp (encode half IMM) [...]
118 template <typename T>
119 bool splitTwoPartImm(MachineInstr &MI,
120 SplitAndOpcFunc<T> SplitAndOpc, BuildMIFunc BuildInstr);
121
122 bool checkMovImmInstr(MachineInstr &MI, MachineInstr *&MovMI,
123 MachineInstr *&SubregToRegMI);
124
125 template <typename T>
126 bool visitADDSUB(unsigned PosOpc, unsigned NegOpc, MachineInstr &MI);
127 template <typename T>
128 bool visitADDSSUBS(OpcodePair PosOpcs, OpcodePair NegOpcs, MachineInstr &MI);
129
130 // Strategy used to split logical immediate bitmasks.
131 enum class SplitStrategy {
132 Intersect,
133 Disjoint,
134 };
135 template <typename T>
136 bool trySplitLogicalImm(unsigned Opc, MachineInstr &MI,
137 SplitStrategy Strategy, unsigned OtherOpc = 0);
138 bool visitORR(MachineInstr &MI);
139 bool visitCSEL(MachineInstr &MI);
140 bool visitINSERT(MachineInstr &MI);
141 bool visitINSviGPR(MachineInstr &MI, unsigned Opc);
142 bool visitINSvi64lane(MachineInstr &MI);
143 bool visitFMOVDr(MachineInstr &MI);
144 bool visitUBFMXri(MachineInstr &MI);
145 bool visitCopy(MachineInstr &MI);
146};
147
148struct AArch64MIPeepholeOptLegacy : public MachineFunctionPass {
149 static char ID;
150
151 AArch64MIPeepholeOptLegacy() : MachineFunctionPass(ID) {}
152
153 bool runOnMachineFunction(MachineFunction &MF) override;
154
155 StringRef getPassName() const override {
156 return "AArch64 MI Peephole Optimization pass";
157 }
158
159 void getAnalysisUsage(AnalysisUsage &AU) const override {
160 AU.setPreservesCFG();
163 }
164};
165
166char AArch64MIPeepholeOptLegacy::ID = 0;
167
168} // end anonymous namespace
169
170INITIALIZE_PASS(AArch64MIPeepholeOptLegacy, "aarch64-mi-peephole-opt",
171 "AArch64 MI Peephole Optimization", false, false)
172
173template <typename T>
174static bool splitBitmaskImm(T Imm, unsigned RegSize, T &Imm1Enc, T &Imm2Enc) {
175 T UImm = static_cast<T>(Imm);
176 assert(UImm && (UImm != ~static_cast<T>(0)) && "Invalid immediate!");
177
178 // The bitmask immediate consists of consecutive ones. Let's say there is
179 // constant 0b00000000001000000000010000000000 which does not consist of
180 // consecutive ones. We can split it in to two bitmask immediate like
181 // 0b00000000001111111111110000000000 and 0b11111111111000000000011111111111.
182 // If we do AND with these two bitmask immediate, we can see original one.
184 unsigned HighestBitSet = Log2_64(UImm);
185
186 // Create a mask which is filled with one from the position of lowest bit set
187 // to the position of highest bit set.
188 T NewImm1 = (static_cast<T>(2) << HighestBitSet) -
189 (static_cast<T>(1) << LowestBitSet);
190 // Create a mask which is filled with one outside the position of lowest bit
191 // set and the position of highest bit set.
193
194 // If the split value is not valid bitmask immediate, do not split this
195 // constant.
197 return false;
198
201 return true;
202}
203
204template <typename T>
206 T &Imm2Enc) {
207 assert(Imm && (Imm != ~static_cast<T>(0)) && "Invalid immediate!");
208
209 // Try to split a bitmask of the form 0b00000000011000000000011110000000 into
210 // two disjoint masks such as 0b00000000011000000000000000000000 and
211 // 0b00000000000000000000011110000000 where the inclusive/exclusive OR of the
212 // new masks match the original mask.
214 unsigned LowestGapBitUnset =
216
217 // Create a mask for the least significant group of consecutive ones.
218 assert(LowestGapBitUnset < sizeof(T) * CHAR_BIT && "Undefined behaviour!");
219 T NewImm1 = (static_cast<T>(1) << LowestGapBitUnset) -
220 (static_cast<T>(1) << LowestBitSet);
221 // Create a disjoint mask for the remaining ones.
222 T NewImm2 = Imm & ~NewImm1;
223
224 // Do not split if NewImm2 is not a valid bitmask immediate.
226 return false;
227
230 return true;
231}
232
233template <typename T>
234bool AArch64MIPeepholeOptImpl::trySplitLogicalImm(unsigned Opc,
236 SplitStrategy Strategy,
237 unsigned OtherOpc) {
238 // Try below transformations.
239 //
240 // MOVi32imm + (ANDS?|EOR|ORR)Wrr ==> (AND|EOR|ORR)Wri + (ANDS?|EOR|ORR)Wri
241 // MOVi64imm + (ANDS?|EOR|ORR)Xrr ==> (AND|EOR|ORR)Xri + (ANDS?|EOR|ORR)Xri
242 //
243 // The mov pseudo instruction could be expanded to multiple mov instructions
244 // later. Let's try to split the constant operand of mov instruction into two
245 // bitmask immediates based on the given split strategy. It makes only two
246 // logical instructions instead of multiple mov + logic instructions.
247
248 return splitTwoPartImm<T>(
249 MI,
250 [Opc, Strategy, OtherOpc](T Imm, unsigned RegSize, T &Imm0,
251 T &Imm1) -> std::optional<OpcodePair> {
252 // If this immediate is already a suitable bitmask, don't split it.
253 // TODO: Should we just combine the two instructions in this case?
255 return std::nullopt;
256
257 // If this immediate can be handled by one instruction, don't split it.
260 if (Insn.size() == 1)
261 return std::nullopt;
262
263 bool SplitSucc = false;
264 switch (Strategy) {
265 case SplitStrategy::Intersect:
266 SplitSucc = splitBitmaskImm(Imm, RegSize, Imm0, Imm1);
267 break;
268 case SplitStrategy::Disjoint:
269 SplitSucc = splitDisjointBitmaskImm(Imm, RegSize, Imm0, Imm1);
270 break;
271 }
272 if (SplitSucc)
273 return std::make_pair(Opc, !OtherOpc ? Opc : OtherOpc);
274 return std::nullopt;
275 },
276 [&TII = TII](MachineInstr &MI, OpcodePair Opcode, unsigned Imm0,
277 unsigned Imm1, Register SrcReg, Register NewTmpReg,
278 Register NewDstReg) {
279 DebugLoc DL = MI.getDebugLoc();
280 MachineBasicBlock *MBB = MI.getParent();
281 BuildMI(*MBB, MI, DL, TII->get(Opcode.first), NewTmpReg)
282 .addReg(SrcReg)
283 .addImm(Imm0);
284 BuildMI(*MBB, MI, DL, TII->get(Opcode.second), NewDstReg)
285 .addReg(NewTmpReg)
286 .addImm(Imm1);
287 });
288}
289
290bool AArch64MIPeepholeOptImpl::visitORR(MachineInstr &MI) {
291 // Check this ORR comes from below zero-extend pattern.
292 //
293 // def : Pat<(i64 (zext GPR32:$src)),
294 // (SUBREG_TO_REG (ORRWrs WZR, GPR32:$src, 0), sub_32)>;
295 if (MI.getOperand(3).getImm() != 0)
296 return false;
297
298 if (MI.getOperand(1).getReg() != AArch64::WZR)
299 return false;
300
301 if (MI.getOperand(2).getSubReg())
302 return false;
303
304 Register DefReg = MI.getOperand(0).getReg();
305 Register SrcReg = MI.getOperand(2).getReg();
306 if (!DefReg.isVirtual() || !SrcReg.isVirtual())
307 return false;
308
309 MachineInstr *SrcMI = MRI->getVRegDef(SrcReg);
310 if (!SrcMI)
311 return false;
312
313 // From https://developer.arm.com/documentation/dui0801/b/BABBGCAC
314 //
315 // When you use the 32-bit form of an instruction, the upper 32 bits of the
316 // source registers are ignored and the upper 32 bits of the destination
317 // register are set to zero.
318 //
319 // If AArch64's 32-bit form of instruction defines the source operand of
320 // zero-extend, we do not need the zero-extend. Let's check the MI's opcode is
321 // real AArch64 instruction and if it is not, do not process the opcode
322 // conservatively.
323 if (SrcMI->getOpcode() == TargetOpcode::COPY &&
324 SrcMI->getOperand(1).getReg().isVirtual()) {
325 const TargetRegisterClass *RC =
326 MRI->getRegClass(SrcMI->getOperand(1).getReg());
327
328 // A COPY from an FPR will become a FMOVSWr, so do so now so that we know
329 // that the upper bits are zero.
330 if (RC != &AArch64::FPR32RegClass &&
331 ((RC != &AArch64::FPR64RegClass && RC != &AArch64::FPR128RegClass &&
332 RC != &AArch64::ZPRRegClass) ||
333 SrcMI->getOperand(1).getSubReg() != AArch64::ssub))
334 return false;
335 Register CpySrc;
336 if (SrcMI->getOperand(1).getSubReg() == AArch64::ssub) {
337 CpySrc = MRI->createVirtualRegister(&AArch64::FPR32RegClass);
338 BuildMI(*SrcMI->getParent(), SrcMI, SrcMI->getDebugLoc(),
339 TII->get(TargetOpcode::COPY), CpySrc)
340 .add(SrcMI->getOperand(1));
341 } else {
342 CpySrc = SrcMI->getOperand(1).getReg();
343 }
344 BuildMI(*SrcMI->getParent(), SrcMI, SrcMI->getDebugLoc(),
345 TII->get(AArch64::FMOVSWr), SrcMI->getOperand(0).getReg())
346 .addReg(CpySrc);
347 SrcMI->eraseFromParent();
348 }
349 else if (SrcMI->getOpcode() <= TargetOpcode::GENERIC_OP_END)
350 return false;
351
352 MRI->replaceRegWith(DefReg, SrcReg);
353 LLVM_DEBUG(dbgs() << "Removed: " << MI << "\n");
354 MI.eraseFromParent();
355
356 return true;
357}
358
359bool AArch64MIPeepholeOptImpl::visitCSEL(MachineInstr &MI) {
360 // Replace CSEL with MOV when both inputs are the same register.
361 if (MI.getOperand(1).getReg() != MI.getOperand(2).getReg())
362 return false;
363
364 auto ZeroReg =
365 MI.getOpcode() == AArch64::CSELXr ? AArch64::XZR : AArch64::WZR;
366 auto OrOpcode =
367 MI.getOpcode() == AArch64::CSELXr ? AArch64::ORRXrs : AArch64::ORRWrs;
368
369 BuildMI(*MI.getParent(), MI, MI.getDebugLoc(), TII->get(OrOpcode))
370 .addReg(MI.getOperand(0).getReg(), RegState::Define)
371 .addReg(ZeroReg)
372 .addReg(MI.getOperand(1).getReg())
373 .addImm(0);
374
375 MI.eraseFromParent();
376 return true;
377}
378
379bool AArch64MIPeepholeOptImpl::visitINSERT(MachineInstr &MI) {
380 // Check this INSERT_SUBREG comes from below zero-extend pattern.
381 //
382 // From %reg = INSERT_SUBREG %reg(tied-def 0), %subreg, subidx
383 // To %reg:subidx = SUBREG_TO_REG %subreg, subidx
384 //
385 // We're assuming the first operand to INSERT_SUBREG is irrelevant because a
386 // COPY would destroy the upper part of the register anyway
387 if (!MI.isRegTiedToDefOperand(1))
388 return false;
389
390 Register DstReg = MI.getOperand(0).getReg();
391 const TargetRegisterClass *RC = MRI->getRegClass(DstReg);
392 MachineInstr *SrcMI = MRI->getUniqueVRegDef(MI.getOperand(2).getReg());
393 if (!SrcMI)
394 return false;
395
396 // From https://developer.arm.com/documentation/dui0801/b/BABBGCAC
397 //
398 // When you use the 32-bit form of an instruction, the upper 32 bits of the
399 // source registers are ignored and the upper 32 bits of the destination
400 // register are set to zero.
401 //
402 // If AArch64's 32-bit form of instruction defines the source operand of
403 // zero-extend, we do not need the zero-extend. Let's check the MI's opcode is
404 // real AArch64 instruction and if it is not, do not process the opcode
405 // conservatively.
406 if ((SrcMI->getOpcode() <= TargetOpcode::GENERIC_OP_END) ||
407 !AArch64::GPR64allRegClass.hasSubClassEq(RC))
408 return false;
409
410 // Build a SUBREG_TO_REG instruction
411 MachineInstr *SubregMI =
412 BuildMI(*MI.getParent(), MI, MI.getDebugLoc(),
413 TII->get(TargetOpcode::SUBREG_TO_REG), DstReg)
414 .add(MI.getOperand(2))
415 .add(MI.getOperand(3));
416 LLVM_DEBUG(dbgs() << MI << " replace by:\n: " << *SubregMI << "\n");
417 (void)SubregMI;
418 MI.eraseFromParent();
419
420 return true;
421}
422
423template <typename T>
424static bool splitAddSubImm(T Imm, unsigned RegSize, T &Imm0, T &Imm1) {
425 // The immediate must be in the form of ((imm0 << 12) + imm1), in which both
426 // imm0 and imm1 are non-zero 12-bit unsigned int.
427 if ((Imm & 0xfff000) == 0 || (Imm & 0xfff) == 0 ||
428 (Imm & ~static_cast<T>(0xffffff)) != 0)
429 return false;
430
431 // The immediate can not be composed via a single instruction.
434 if (Insn.size() == 1)
435 return false;
436
437 // Split Imm into (Imm0 << 12) + Imm1;
438 Imm0 = (Imm >> 12) & 0xfff;
439 Imm1 = Imm & 0xfff;
440 return true;
441}
442
443template <typename T>
444bool AArch64MIPeepholeOptImpl::visitADDSUB(unsigned PosOpc, unsigned NegOpc,
445 MachineInstr &MI) {
446 // Try below transformation.
447 //
448 // ADDWrr X, MOVi32imm ==> ADDWri + ADDWri
449 // ADDXrr X, MOVi64imm ==> ADDXri + ADDXri
450 //
451 // SUBWrr X, MOVi32imm ==> SUBWri + SUBWri
452 // SUBXrr X, MOVi64imm ==> SUBXri + SUBXri
453 //
454 // The mov pseudo instruction could be expanded to multiple mov instructions
455 // later. Let's try to split the constant operand of mov instruction into two
456 // legal add/sub immediates. It makes only two ADD/SUB instructions instead of
457 // multiple `mov` + `and/sub` instructions.
458
459 // We can sometimes have ADDWrr WZR, MULi32imm that have not been constant
460 // folded. Make sure that we don't generate invalid instructions that use XZR
461 // in those cases.
462 if (MI.getOperand(1).getReg() == AArch64::XZR ||
463 MI.getOperand(1).getReg() == AArch64::WZR)
464 return false;
465
466 return splitTwoPartImm<T>(
467 MI,
468 [PosOpc, NegOpc](T Imm, unsigned RegSize, T &Imm0,
469 T &Imm1) -> std::optional<OpcodePair> {
470 if (splitAddSubImm(Imm, RegSize, Imm0, Imm1))
471 return std::make_pair(PosOpc, PosOpc);
472 if (splitAddSubImm(-Imm, RegSize, Imm0, Imm1))
473 return std::make_pair(NegOpc, NegOpc);
474 return std::nullopt;
475 },
476 [&TII = TII](MachineInstr &MI, OpcodePair Opcode, unsigned Imm0,
477 unsigned Imm1, Register SrcReg, Register NewTmpReg,
478 Register NewDstReg) {
479 DebugLoc DL = MI.getDebugLoc();
480 MachineBasicBlock *MBB = MI.getParent();
481 BuildMI(*MBB, MI, DL, TII->get(Opcode.first), NewTmpReg)
482 .addReg(SrcReg)
483 .addImm(Imm0)
484 .addImm(12);
485 BuildMI(*MBB, MI, DL, TII->get(Opcode.second), NewDstReg)
486 .addReg(NewTmpReg)
487 .addImm(Imm1)
488 .addImm(0);
489 });
490}
491
492template <typename T>
493bool AArch64MIPeepholeOptImpl::visitADDSSUBS(OpcodePair PosOpcs,
494 OpcodePair NegOpcs,
495 MachineInstr &MI) {
496 // Try the same transformation as ADDSUB but with additional requirement
497 // that the condition code usages are only for Equal and Not Equal
498
499 if (MI.getOperand(1).getReg() == AArch64::XZR ||
500 MI.getOperand(1).getReg() == AArch64::WZR)
501 return false;
502
503 return splitTwoPartImm<T>(
504 MI,
505 [PosOpcs, NegOpcs, &MI, &TRI = TRI,
506 &MRI = MRI](T Imm, unsigned RegSize, T &Imm0,
507 T &Imm1) -> std::optional<OpcodePair> {
508 OpcodePair OP;
509 if (splitAddSubImm(Imm, RegSize, Imm0, Imm1))
510 OP = PosOpcs;
511 else if (splitAddSubImm(-Imm, RegSize, Imm0, Imm1))
512 OP = NegOpcs;
513 else
514 return std::nullopt;
515 // Check conditional uses last since it is expensive for scanning
516 // proceeding instructions
517 MachineInstr *SrcMI = MRI->getVRegDef(MI.getOperand(1).getReg());
518 if (!SrcMI)
519 return std::nullopt;
520 std::optional<UsedNZCV> NZCVUsed = examineCFlagsUse(*SrcMI, MI, *TRI);
521 if (!NZCVUsed || NZCVUsed->C || NZCVUsed->V)
522 return std::nullopt;
523 return OP;
524 },
525 [&TII = TII](MachineInstr &MI, OpcodePair Opcode, unsigned Imm0,
526 unsigned Imm1, Register SrcReg, Register NewTmpReg,
527 Register NewDstReg) {
528 DebugLoc DL = MI.getDebugLoc();
529 MachineBasicBlock *MBB = MI.getParent();
530 BuildMI(*MBB, MI, DL, TII->get(Opcode.first), NewTmpReg)
531 .addReg(SrcReg)
532 .addImm(Imm0)
533 .addImm(12);
534 BuildMI(*MBB, MI, DL, TII->get(Opcode.second), NewDstReg)
535 .addReg(NewTmpReg)
536 .addImm(Imm1)
537 .addImm(0);
538 });
539}
540
541// Checks if the corresponding MOV immediate instruction is applicable for
542// this peephole optimization.
543bool AArch64MIPeepholeOptImpl::checkMovImmInstr(MachineInstr &MI,
544 MachineInstr *&MovMI,
545 MachineInstr *&SubregToRegMI) {
546 // Check whether current MBB is in loop and the AND is loop invariant.
547 MachineBasicBlock *MBB = MI.getParent();
548 MachineLoop *L = MLI->getLoopFor(MBB);
549 if (L && !L->isLoopInvariant(MI))
550 return false;
551
552 // Check whether current MI's operand is MOV with immediate.
553 MovMI = MRI->getUniqueVRegDef(MI.getOperand(2).getReg());
554 if (!MovMI)
555 return false;
556
557 // If it is SUBREG_TO_REG, check its operand.
558 SubregToRegMI = nullptr;
559 if (MovMI->getOpcode() == TargetOpcode::SUBREG_TO_REG) {
560 SubregToRegMI = MovMI;
561 MovMI = MRI->getUniqueVRegDef(MovMI->getOperand(1).getReg());
562 if (!MovMI)
563 return false;
564 }
565
566 if (MovMI->getOpcode() != AArch64::MOVi32imm &&
567 MovMI->getOpcode() != AArch64::MOVi64imm)
568 return false;
569
570 // If the MOV has multiple uses, do not split the immediate because it causes
571 // more instructions.
572 if (!MRI->hasOneNonDBGUse(MovMI->getOperand(0).getReg()))
573 return false;
574 if (SubregToRegMI &&
575 !MRI->hasOneNonDBGUse(SubregToRegMI->getOperand(0).getReg()))
576 return false;
577
578 // It is OK to perform this peephole optimization.
579 return true;
580}
581
582template <typename T>
583bool AArch64MIPeepholeOptImpl::splitTwoPartImm(MachineInstr &MI,
584 SplitAndOpcFunc<T> SplitAndOpc,
585 BuildMIFunc BuildInstr) {
586 unsigned RegSize = sizeof(T) * 8;
587 assert((RegSize == 32 || RegSize == 64) &&
588 "Invalid RegSize for legal immediate peephole optimization");
589
590 // Perform several essential checks against current MI.
591 MachineInstr *MovMI, *SubregToRegMI;
592 if (!checkMovImmInstr(MI, MovMI, SubregToRegMI))
593 return false;
594
595 // Split the immediate to Imm0 and Imm1, and calculate the Opcode.
596 T Imm = static_cast<T>(MovMI->getOperand(1).getImm()), Imm0, Imm1;
597 // For the 32 bit form of instruction, the upper 32 bits of the destination
598 // register are set to zero. If there is SUBREG_TO_REG, set the upper 32 bits
599 // of Imm to zero. This is essential if the Immediate value was a negative
600 // number since it was sign extended when we assign to the 64-bit Imm.
601 if (SubregToRegMI)
602 Imm &= 0xFFFFFFFF;
603 OpcodePair Opcode;
604 if (auto R = SplitAndOpc(Imm, RegSize, Imm0, Imm1))
605 Opcode = *R;
606 else
607 return false;
608
609 // Create new MIs using the first and second opcodes. Opcodes might differ for
610 // flag setting operations that should only set flags on second instruction.
611 // NewTmpReg = Opcode.first SrcReg Imm0
612 // NewDstReg = Opcode.second NewTmpReg Imm1
613
614 // Determine register classes for destinations and register operands
615 const TargetRegisterClass *FirstInstrDstRC =
616 TII->getRegClass(TII->get(Opcode.first), 0);
617 const TargetRegisterClass *FirstInstrOperandRC =
618 TII->getRegClass(TII->get(Opcode.first), 1);
619 const TargetRegisterClass *SecondInstrDstRC =
620 (Opcode.first == Opcode.second)
621 ? FirstInstrDstRC
622 : TII->getRegClass(TII->get(Opcode.second), 0);
623 const TargetRegisterClass *SecondInstrOperandRC =
624 (Opcode.first == Opcode.second)
625 ? FirstInstrOperandRC
626 : TII->getRegClass(TII->get(Opcode.second), 1);
627
628 // Get old registers destinations and new register destinations
629 Register DstReg = MI.getOperand(0).getReg();
630 Register SrcReg = MI.getOperand(1).getReg();
631 Register NewTmpReg = MRI->createVirtualRegister(FirstInstrDstRC);
632 // In the situation that DstReg is not Virtual (likely WZR or XZR), we want to
633 // reuse that same destination register.
634 Register NewDstReg = DstReg.isVirtual()
635 ? MRI->createVirtualRegister(SecondInstrDstRC)
636 : DstReg;
637
638 // Constrain registers based on their new uses
639 MRI->constrainRegClass(SrcReg, FirstInstrOperandRC);
640 MRI->constrainRegClass(NewTmpReg, SecondInstrOperandRC);
641 if (DstReg != NewDstReg)
642 MRI->constrainRegClass(NewDstReg, MRI->getRegClass(DstReg));
643
644 // Call the delegating operation to build the instruction
645 BuildInstr(MI, Opcode, Imm0, Imm1, SrcReg, NewTmpReg, NewDstReg);
646
647 // replaceRegWith changes MI's definition register. Keep it for SSA form until
648 // deleting MI. Only if we made a new destination register.
649 if (DstReg != NewDstReg) {
650 MRI->replaceRegWith(DstReg, NewDstReg);
651 MI.getOperand(0).setReg(DstReg);
652 }
653
654 auto SalvageDebugUses = [&](Register Reg, int64_t Val) {
655 for (MachineOperand &MO : make_early_inc_range(MRI->use_operands(Reg))) {
656 MachineInstr &DbgMI = *MO.getParent();
657 if (!DbgMI.isDebugValue())
658 continue;
659 // An immediate cannot express a value in memory at that address.
660 if (DbgMI.isNonListDebugValue() && DbgMI.isIndirectDebugValue())
661 DbgMI.setDebugValueUndef();
662 else
663 MO.ChangeToImmediate(Val);
664 }
665 };
666
667 // Record the MIs need to be removed.
668 MI.eraseFromParent();
669 if (SubregToRegMI) {
670 SalvageDebugUses(SubregToRegMI->getOperand(0).getReg(), Imm);
671 SubregToRegMI->eraseFromParent();
672 }
673 SalvageDebugUses(MovMI->getOperand(0).getReg(),
674 MovMI->getOperand(1).getImm());
675 MovMI->eraseFromParent();
676
677 return true;
678}
679
680bool AArch64MIPeepholeOptImpl::visitINSviGPR(MachineInstr &MI, unsigned Opc) {
681 // Check if this INSvi[X]gpr comes from COPY of a source FPR128
682 //
683 // From
684 // %intermediate1:gpr64 = COPY %src:fpr128
685 // %intermediate2:gpr32 = COPY %intermediate1:gpr64
686 // %dst:fpr128 = INSvi[X]gpr %dst_vec:fpr128, dst_index, %intermediate2:gpr32
687 // To
688 // %dst:fpr128 = INSvi[X]lane %dst_vec:fpr128, dst_index, %src:fpr128,
689 // src_index
690 // where src_index = 0, X = [8|16|32|64]
691
692 MachineInstr *SrcMI = MRI->getUniqueVRegDef(MI.getOperand(3).getReg());
693
694 // For a chain of COPY instructions, find the initial source register
695 // and check if it's an FPR128
696 while (true) {
697 if (!SrcMI || SrcMI->getOpcode() != TargetOpcode::COPY)
698 return false;
699
700 if (!SrcMI->getOperand(1).getReg().isVirtual())
701 return false;
702
703 if (MRI->getRegClass(SrcMI->getOperand(1).getReg()) ==
704 &AArch64::FPR128RegClass) {
705 break;
706 }
707 SrcMI = MRI->getUniqueVRegDef(SrcMI->getOperand(1).getReg());
708 }
709
710 Register DstReg = MI.getOperand(0).getReg();
711 Register SrcReg = SrcMI->getOperand(1).getReg();
712 MachineInstr *INSvilaneMI =
713 BuildMI(*MI.getParent(), MI, MI.getDebugLoc(), TII->get(Opc), DstReg)
714 .add(MI.getOperand(1))
715 .add(MI.getOperand(2))
716 .addUse(SrcReg, getRegState(SrcMI->getOperand(1)))
717 .addImm(0);
718
719 LLVM_DEBUG(dbgs() << MI << " replace by:\n: " << *INSvilaneMI << "\n");
720 (void)INSvilaneMI;
721 MI.eraseFromParent();
722 return true;
723}
724
725// All instructions that set a FPR64 will implicitly zero the top bits of the
726// register. When the def is expressed as a COPY from a GPR, turn it into an
727// explicit FMOV so it cannot be elided later in further passes.
730 const AArch64InstrInfo *TII) {
731 if (!MI->getOperand(0).isReg() || !MI->getOperand(0).isDef())
732 return false;
733 const TargetRegisterClass *RC = MRI->getRegClass(MI->getOperand(0).getReg());
734 if (RC != &AArch64::FPR64RegClass)
735 return false;
736 if (MI->getOpcode() == TargetOpcode::COPY) {
737 MachineOperand &SrcOp = MI->getOperand(1);
738 if (!SrcOp.isReg())
739 return false;
740 Register SrcReg = SrcOp.getReg();
741 if (SrcOp.getSubReg()) {
742 // If operand is defined by a LD1/2/3/4 that define a D subreg tuple
743 // then upper bits of the tuple's registers are implicitly zeroed
744 // and the FMOV is unneeded.
745 if (!SrcReg.isVirtual())
746 return false;
747
748 MachineInstr *SrcDef = MRI->getUniqueVRegDef(SrcReg);
749 if (!SrcDef || SrcDef->getOpcode() <= TargetOpcode::GENERIC_OP_END ||
750 SrcDef->getDesc().isPseudo() || !SrcDef->mayLoad())
751 return false;
752
753 const TargetRegisterClass *RC = MRI->getRegClass(SrcReg);
754 return RC == &AArch64::DDRegClass || RC == &AArch64::DDDRegClass ||
755 RC == &AArch64::DDDDRegClass;
756 }
757 auto IsGPR64Like = [&]() -> bool {
758 if (SrcReg.isVirtual())
759 return AArch64::GPR64allRegClass.hasSubClassEq(
760 MRI->getRegClass(SrcReg));
761 return AArch64::GPR64allRegClass.contains(SrcReg);
762 };
763 if (!IsGPR64Like())
764 return false;
765 assert(TII && "Expected InstrInfo when materializing COPYs");
766 // FMOVXDr insists on strict GPR64 operands, so fix up the COPY source.
767 MachineOperand &SrcMO = MI->getOperand(1);
768 bool SrcKill = SrcMO.isKill();
769 if (SrcReg.isVirtual()) {
770 if (MRI->getRegClass(SrcReg) != &AArch64::GPR64RegClass) {
771 // Pass the value through a temporary GPR64 vreg to satisfy the
772 // verifier.
773 Register NewSrc = MRI->createVirtualRegister(&AArch64::GPR64RegClass);
774 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(),
775 TII->get(TargetOpcode::COPY), NewSrc)
776 .addReg(SrcReg, getKillRegState(SrcKill));
777 SrcReg = NewSrc;
778 }
779 } else if (!AArch64::GPR64RegClass.contains(SrcReg)) {
780 return false;
781 }
782 SrcMO.setReg(SrcReg);
783 SrcMO.setSubReg(0);
784 SrcMO.setIsKill(SrcKill);
785 // Replace the COPY with an explicit FMOV so the zeroing behaviour stays
786 // visible.
787 MI->setDesc(TII->get(AArch64::FMOVXDr));
788 return true;
789 }
790 return MI->getOpcode() > TargetOpcode::GENERIC_OP_END;
791}
792
793bool AArch64MIPeepholeOptImpl::visitINSvi64lane(MachineInstr &MI) {
794 // Check the MI for low 64-bits sets zero for high 64-bits implicitly.
795 // We are expecting below case.
796 //
797 // %1:fpr64 = nofpexcept FCVTNv4i16 %0:fpr128, implicit $fpcr
798 // %6:fpr128 = IMPLICIT_DEF
799 // %5:fpr128 = INSERT_SUBREG %6:fpr128(tied-def 0), killed %1:fpr64, %subreg.dsub
800 // %7:fpr128 = INSvi64lane %5:fpr128(tied-def 0), 1, killed %3:fpr128, 0
801 MachineInstr *Low64MI = MRI->getVRegDef(MI.getOperand(1).getReg());
802 if (!Low64MI || Low64MI->getOpcode() != AArch64::INSERT_SUBREG)
803 return false;
804 Low64MI = MRI->getUniqueVRegDef(Low64MI->getOperand(2).getReg());
805 if (!Low64MI || !is64bitDefwithZeroHigh64bit(Low64MI, MRI, TII))
806 return false;
807
808 // Check there is `mov 0` MI for high 64-bits.
809 // We are expecting below cases.
810 //
811 // %2:fpr64 = MOVID 0
812 // %4:fpr128 = IMPLICIT_DEF
813 // %3:fpr128 = INSERT_SUBREG %4:fpr128(tied-def 0), killed %2:fpr64, %subreg.dsub
814 // %7:fpr128 = INSvi64lane %5:fpr128(tied-def 0), 1, killed %3:fpr128, 0
815 // or
816 // %5:fpr128 = MOVIv2d_ns 0
817 // %6:fpr64 = COPY %5.dsub:fpr128
818 // %8:fpr128 = IMPLICIT_DEF
819 // %7:fpr128 = INSERT_SUBREG %8:fpr128(tied-def 0), killed %6:fpr64, %subreg.dsub
820 // %11:fpr128 = INSvi64lane %9:fpr128(tied-def 0), 1, killed %7:fpr128, 0
821 MachineInstr *High64MI = MRI->getUniqueVRegDef(MI.getOperand(3).getReg());
822 if (!High64MI || High64MI->getOpcode() != AArch64::INSERT_SUBREG)
823 return false;
824 High64MI = MRI->getUniqueVRegDef(High64MI->getOperand(2).getReg());
825 if (High64MI && High64MI->getOpcode() == TargetOpcode::COPY)
826 High64MI = MRI->getUniqueVRegDef(High64MI->getOperand(1).getReg());
827 if (!High64MI || (High64MI->getOpcode() != AArch64::MOVID &&
828 High64MI->getOpcode() != AArch64::MOVIv2d_ns))
829 return false;
830 if (High64MI->getOperand(1).getImm() != 0)
831 return false;
832
833 // Let's remove MIs for high 64-bits.
834 Register OldDef = MI.getOperand(0).getReg();
835 Register NewDef = MI.getOperand(1).getReg();
836 LLVM_DEBUG(dbgs() << "Removing: " << MI << "\n");
837 MRI->constrainRegClass(NewDef, MRI->getRegClass(OldDef));
838 MRI->replaceRegWith(OldDef, NewDef);
839 MI.eraseFromParent();
840
841 return true;
842}
843
844bool AArch64MIPeepholeOptImpl::visitFMOVDr(MachineInstr &MI) {
845 // An FMOVDr sets the high 64-bits to zero implicitly, similar to ORR for GPR.
846 MachineInstr *Low64MI = MRI->getUniqueVRegDef(MI.getOperand(1).getReg());
847 if (!Low64MI || !is64bitDefwithZeroHigh64bit(Low64MI, MRI, TII))
848 return false;
849
850 // Let's remove MIs for high 64-bits.
851 Register OldDef = MI.getOperand(0).getReg();
852 Register NewDef = MI.getOperand(1).getReg();
853 LLVM_DEBUG(dbgs() << "Removing: " << MI << "\n");
854 MRI->constrainRegClass(NewDef, MRI->getRegClass(OldDef));
855 MRI->replaceRegWith(OldDef, NewDef);
856 MI.eraseFromParent();
857
858 return true;
859}
860
861bool AArch64MIPeepholeOptImpl::visitUBFMXri(MachineInstr &MI) {
862 // Check if the instruction is equivalent to a 32 bit LSR or LSL alias of
863 // UBFM, and replace the UBFMXri instruction with its 32 bit variant, UBFMWri.
864 int64_t Immr = MI.getOperand(2).getImm();
865 int64_t Imms = MI.getOperand(3).getImm();
866
867 bool IsLSR = Imms == 31 && Immr <= Imms;
868 bool IsLSL = Immr == Imms + 33;
869 if (!IsLSR && !IsLSL)
870 return false;
871
872 if (IsLSL) {
873 Immr -= 32;
874 }
875
876 const TargetRegisterClass *DstRC64 =
877 TII->getRegClass(TII->get(MI.getOpcode()), 0);
878 const TargetRegisterClass *DstRC32 =
879 TRI->getSubRegisterClass(DstRC64, AArch64::sub_32);
880 assert(DstRC32 && "Destination register class of UBFMXri doesn't have a "
881 "sub_32 subregister class");
882
883 const TargetRegisterClass *SrcRC64 =
884 TII->getRegClass(TII->get(MI.getOpcode()), 1);
885 const TargetRegisterClass *SrcRC32 =
886 TRI->getSubRegisterClass(SrcRC64, AArch64::sub_32);
887 assert(SrcRC32 && "Source register class of UBFMXri doesn't have a sub_32 "
888 "subregister class");
889
890 Register DstReg64 = MI.getOperand(0).getReg();
891 Register DstReg32 = MRI->createVirtualRegister(DstRC32);
892 Register SrcReg64 = MI.getOperand(1).getReg();
893 Register SrcReg32 = MRI->createVirtualRegister(SrcRC32);
894
895 BuildMI(*MI.getParent(), MI, MI.getDebugLoc(), TII->get(AArch64::COPY),
896 SrcReg32)
897 .addReg(SrcReg64, {}, AArch64::sub_32);
898 BuildMI(*MI.getParent(), MI, MI.getDebugLoc(), TII->get(AArch64::UBFMWri),
899 DstReg32)
900 .addReg(SrcReg32)
901 .addImm(Immr)
902 .addImm(Imms);
903 BuildMI(*MI.getParent(), MI, MI.getDebugLoc(),
904 TII->get(AArch64::SUBREG_TO_REG), DstReg64)
905 .addReg(DstReg32)
906 .addImm(AArch64::sub_32);
907 MI.eraseFromParent();
908 return true;
909}
910
911// Across a basic-block we might have in i32 extract from a value that only
912// operates on upper bits (for example a sxtw). We can replace the COPY with a
913// new version skipping the sxtw.
914bool AArch64MIPeepholeOptImpl::visitCopy(MachineInstr &MI) {
915 Register InputReg = MI.getOperand(1).getReg();
916 if (MI.getOperand(1).getSubReg() != AArch64::sub_32 ||
917 !MRI->hasOneNonDBGUse(InputReg))
918 return false;
919
920 MachineInstr *SrcMI = MRI->getUniqueVRegDef(InputReg);
921 SmallPtrSet<MachineInstr *, 4> DeadInstrs;
922 DeadInstrs.insert(SrcMI);
923 while (SrcMI && SrcMI->isFullCopy() &&
924 MRI->hasOneNonDBGUse(SrcMI->getOperand(1).getReg())) {
925 SrcMI = MRI->getUniqueVRegDef(SrcMI->getOperand(1).getReg());
926 DeadInstrs.insert(SrcMI);
927 }
928
929 if (!SrcMI)
930 return false;
931
932 // Look for SXTW(X) and return Reg.
933 auto getSXTWSrcReg = [](MachineInstr *SrcMI) -> Register {
934 if (SrcMI->getOpcode() != AArch64::SBFMXri ||
935 SrcMI->getOperand(2).getImm() != 0 ||
936 SrcMI->getOperand(3).getImm() != 31)
937 return Register();
938 return SrcMI->getOperand(1).getReg();
939 };
940 // Look for SUBREG_TO_REG(ORRWrr(WZR, COPY(X.sub_32)))
941 auto getUXTWSrcReg = [&](MachineInstr *SrcMI) -> Register {
942 if (SrcMI->getOpcode() != AArch64::SUBREG_TO_REG ||
943 SrcMI->getOperand(2).getImm() != AArch64::sub_32 ||
944 !MRI->hasOneNonDBGUse(SrcMI->getOperand(1).getReg()))
945 return Register();
946 MachineInstr *Orr = MRI->getUniqueVRegDef(SrcMI->getOperand(1).getReg());
947 if (!Orr || Orr->getOpcode() != AArch64::ORRWrr ||
948 Orr->getOperand(1).getReg() != AArch64::WZR ||
950 return Register();
951 MachineInstr *Cpy = MRI->getUniqueVRegDef(Orr->getOperand(2).getReg());
952 if (!Cpy || Cpy->getOpcode() != AArch64::COPY ||
953 Cpy->getOperand(1).getSubReg() != AArch64::sub_32)
954 return Register();
955 DeadInstrs.insert(Orr);
956 return Cpy->getOperand(1).getReg();
957 };
958
959 Register SrcReg = getSXTWSrcReg(SrcMI);
960 if (!SrcReg)
961 SrcReg = getUXTWSrcReg(SrcMI);
962 if (!SrcReg)
963 return false;
964
965 MRI->constrainRegClass(SrcReg, MRI->getRegClass(InputReg));
966 LLVM_DEBUG(dbgs() << "Optimizing: " << MI);
967 MI.getOperand(1).setReg(SrcReg);
968 LLVM_DEBUG(dbgs() << " to: " << MI);
969 for (auto *DeadMI : DeadInstrs) {
970 LLVM_DEBUG(dbgs() << " Removing: " << *DeadMI);
971 DeadMI->eraseFromParent();
972 }
973 return true;
974}
975
976bool AArch64MIPeepholeOptImpl::run(MachineFunction &MF) {
977 TII = static_cast<const AArch64InstrInfo *>(MF.getSubtarget().getInstrInfo());
978 TRI = static_cast<const AArch64RegisterInfo *>(
979 MF.getSubtarget().getRegisterInfo());
980 MRI = &MF.getRegInfo();
981
982 assert(MRI->isSSA() && "Expected to be run on SSA form!");
983
984 bool Changed = false;
985
986 for (MachineBasicBlock &MBB : MF) {
987 for (MachineInstr &MI : make_early_inc_range(MBB)) {
988 switch (MI.getOpcode()) {
989 default:
990 break;
991 case AArch64::INSERT_SUBREG:
992 Changed |= visitINSERT(MI);
993 break;
994 case AArch64::ANDWrr:
995 Changed |= trySplitLogicalImm<uint32_t>(AArch64::ANDWri, MI,
996 SplitStrategy::Intersect);
997 break;
998 case AArch64::ANDXrr:
999 Changed |= trySplitLogicalImm<uint64_t>(AArch64::ANDXri, MI,
1000 SplitStrategy::Intersect);
1001 break;
1002 case AArch64::ANDSWrr:
1003 Changed |= trySplitLogicalImm<uint32_t>(
1004 AArch64::ANDWri, MI, SplitStrategy::Intersect, AArch64::ANDSWri);
1005 break;
1006 case AArch64::ANDSXrr:
1007 Changed |= trySplitLogicalImm<uint64_t>(
1008 AArch64::ANDXri, MI, SplitStrategy::Intersect, AArch64::ANDSXri);
1009 break;
1010 case AArch64::EORWrr:
1011 Changed |= trySplitLogicalImm<uint32_t>(AArch64::EORWri, MI,
1012 SplitStrategy::Disjoint);
1013 break;
1014 case AArch64::EORXrr:
1015 Changed |= trySplitLogicalImm<uint64_t>(AArch64::EORXri, MI,
1016 SplitStrategy::Disjoint);
1017 break;
1018 case AArch64::ORRWrr:
1019 Changed |= trySplitLogicalImm<uint32_t>(AArch64::ORRWri, MI,
1020 SplitStrategy::Disjoint);
1021 break;
1022 case AArch64::ORRXrr:
1023 Changed |= trySplitLogicalImm<uint64_t>(AArch64::ORRXri, MI,
1024 SplitStrategy::Disjoint);
1025 break;
1026 case AArch64::ORRWrs:
1027 Changed |= visitORR(MI);
1028 break;
1029 case AArch64::ADDWrr:
1030 Changed |= visitADDSUB<uint32_t>(AArch64::ADDWri, AArch64::SUBWri, MI);
1031 break;
1032 case AArch64::SUBWrr:
1033 Changed |= visitADDSUB<uint32_t>(AArch64::SUBWri, AArch64::ADDWri, MI);
1034 break;
1035 case AArch64::ADDXrr:
1036 Changed |= visitADDSUB<uint64_t>(AArch64::ADDXri, AArch64::SUBXri, MI);
1037 break;
1038 case AArch64::SUBXrr:
1039 Changed |= visitADDSUB<uint64_t>(AArch64::SUBXri, AArch64::ADDXri, MI);
1040 break;
1041 case AArch64::ADDSWrr:
1042 Changed |=
1043 visitADDSSUBS<uint32_t>({AArch64::ADDWri, AArch64::ADDSWri},
1044 {AArch64::SUBWri, AArch64::SUBSWri}, MI);
1045 break;
1046 case AArch64::SUBSWrr:
1047 Changed |=
1048 visitADDSSUBS<uint32_t>({AArch64::SUBWri, AArch64::SUBSWri},
1049 {AArch64::ADDWri, AArch64::ADDSWri}, MI);
1050 break;
1051 case AArch64::ADDSXrr:
1052 Changed |=
1053 visitADDSSUBS<uint64_t>({AArch64::ADDXri, AArch64::ADDSXri},
1054 {AArch64::SUBXri, AArch64::SUBSXri}, MI);
1055 break;
1056 case AArch64::SUBSXrr:
1057 Changed |=
1058 visitADDSSUBS<uint64_t>({AArch64::SUBXri, AArch64::SUBSXri},
1059 {AArch64::ADDXri, AArch64::ADDSXri}, MI);
1060 break;
1061 case AArch64::CSELWr:
1062 case AArch64::CSELXr:
1063 Changed |= visitCSEL(MI);
1064 break;
1065 case AArch64::INSvi64gpr:
1066 Changed |= visitINSviGPR(MI, AArch64::INSvi64lane);
1067 break;
1068 case AArch64::INSvi32gpr:
1069 Changed |= visitINSviGPR(MI, AArch64::INSvi32lane);
1070 break;
1071 case AArch64::INSvi16gpr:
1072 Changed |= visitINSviGPR(MI, AArch64::INSvi16lane);
1073 break;
1074 case AArch64::INSvi8gpr:
1075 Changed |= visitINSviGPR(MI, AArch64::INSvi8lane);
1076 break;
1077 case AArch64::INSvi64lane:
1078 Changed |= visitINSvi64lane(MI);
1079 break;
1080 case AArch64::FMOVDr:
1081 Changed |= visitFMOVDr(MI);
1082 break;
1083 case AArch64::UBFMXri:
1084 Changed |= visitUBFMXri(MI);
1085 break;
1086 case AArch64::COPY:
1087 Changed |= visitCopy(MI);
1088 break;
1089 }
1090 }
1091 }
1092
1093 return Changed;
1094}
1095
1096bool AArch64MIPeepholeOptLegacy::runOnMachineFunction(MachineFunction &MF) {
1097 if (skipFunction(MF.getFunction()))
1098 return false;
1099
1100 MachineLoopInfo &MLI = getAnalysis<MachineLoopInfoWrapperPass>().getLI();
1101 return AArch64MIPeepholeOptImpl(MLI).run(MF);
1102}
1103
1105 return new AArch64MIPeepholeOptLegacy();
1106}
1107
1112 const bool Changed = AArch64MIPeepholeOptImpl(MLI).run(MF);
1113 if (!Changed)
1114 return PreservedAnalyses::all();
1117 return PA;
1118}
static const TargetRegisterClass * getRegClass(const MachineInstr &MI, Register Reg)
static bool is64bitDefwithZeroHigh64bit(MachineInstr *MI, MachineRegisterInfo *MRI, const AArch64InstrInfo *TII)
static bool splitDisjointBitmaskImm(T Imm, unsigned RegSize, T &Imm1Enc, T &Imm2Enc)
unsigned HighestBitSet
unsigned T T & Imm2Enc
unsigned T & Imm1Enc
unsigned RegSize
static bool splitAddSubImm(T Imm, unsigned RegSize, T &Imm0, T &Imm1)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
unsigned LowestBitSet
uint64_t Imm
MachineBasicBlock & MBB
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
Register Reg
Register const TargetRegisterInfo * TRI
Promote Memory to Register
Definition Mem2Reg.cpp:110
#define T
if(PassOpts->AAPipeline)
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
MachineRegisterInfo & MRI
#define OP(OPC)
Definition Instruction.h:46
static bool contains(SmallPtrSetImpl< ConstantExpr * > &Cache, ConstantExpr *Expr, Constant *C)
Definition Value.cpp:479
#define LLVM_DEBUG(...)
Definition Debug.h:119
PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
Represent the analysis usage information of a pass.
AnalysisUsage & addRequired()
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
Definition Pass.cpp:280
Represents analyses that only rely on functions' control flow.
Definition Analysis.h:73
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:312
LoopT * getLoopFor(const BlockT *BB) const
Return the inner most loop that BB lives in.
bool isPseudo() const
Return true if this is a pseudo instruction that doesn't correspond to a real machine instruction.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Function & getFunction()
Return the LLVM function that this machine code represents.
const MachineInstrBuilder & addUse(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register use operand.
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & add(const MachineOperand &MO) const
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
void setDebugValueUndef()
Sets all register debug operands in this debug value instruction to be undef.
const MachineBasicBlock * getParent() const
bool mayLoad(QueryType Type=AnyInBundle) const
Return true if this instruction could possibly read memory.
bool isFullCopy() const
const MCInstrDesc & getDesc() const
Returns the target instruction descriptor of this MachineInstr.
bool isNonListDebugValue() const
const DebugLoc & getDebugLoc() const
Returns the debug location id of this MachineInstr.
bool isDebugValue() const
const MachineOperand & getOperand(unsigned i) const
bool isIndirectDebugValue() const
A DBG_VALUE is indirect iff the location operand is a register and the offset operand is an immediate...
LLVM_ABI MachineInstrBundleIterator< MachineInstr > eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
Analysis pass that exposes the MachineLoopInfo for a machine function.
MachineOperand class - Representation of each machine instruction operand.
void setSubReg(unsigned subReg)
unsigned getSubReg() const
int64_t getImm() const
LLVM_ABI void setReg(Register Reg)
Change the register this operand corresponds to.
void setIsKill(bool Val=true)
Register getReg() const
getReg - Returns the register number.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI bool hasOneNonDBGUse(Register RegNo) const
hasOneNonDBGUse - Return true if there is exactly one non-Debug use of the specified register.
const TargetRegisterClass * getRegClass(Register Reg) const
Return the register class of the specified virtual register.
LLVM_ABI LLVM_READONLY MachineInstr * getVRegDef(Register Reg) const
getVRegDef - Return the machine instr that defines the specified virtual register or null if none is ...
LLVM_ABI Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
LLVM_ABI const TargetRegisterClass * constrainRegClass(Register Reg, const TargetRegisterClass *RC, unsigned MinNumRegs=0)
constrainRegClass - Constrain the register class of the specified virtual register to be a common sub...
iterator_range< use_iterator > use_operands(Register Reg) const
LLVM_ABI void replaceRegWith(Register FromReg, Register ToReg)
replaceRegWith - Replace all instances of FromReg with ToReg in the machine function.
LLVM_ABI LLVM_READONLY MachineInstr * getUniqueVRegDef(Register Reg) const
getUniqueVRegDef - Return the unique machine instr that defines the specified virtual register or nul...
A set of analyses that are preserved following a run of a transformation pass.
Definition Analysis.h:112
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
Definition Analysis.h:151
Wrapper class representing virtual and physical registers.
Definition Register.h:20
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
Definition Register.h:79
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Register getReg() const
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
static bool isLogicalImmediate(uint64_t imm, unsigned regSize)
isLogicalImmediate - Return true if the immediate is valid for a logical immediate instruction of the...
static uint64_t encodeLogicalImmediate(uint64_t imm, unsigned regSize)
encodeLogicalImmediate - Return the encoded immediate value for a logical immediate instruction of th...
void expandMOVImm(uint64_t Imm, unsigned BitSize, SmallVectorImpl< ImmInsnModel > &Insn)
Expand a MOVi32imm or MOVi64imm pseudo instruction to one or more real move-immediate instructions to...
This is an optimization pass for GlobalISel generic memory operations.
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
constexpr RegState getKillRegState(bool B)
int countr_one(T Value)
Count the number of ones from the least significant bit to the first zero bit.
Definition bit.h:315
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
Definition STLExtras.h:649
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
unsigned Log2_64(uint64_t Value)
Return the floor log base 2 of the specified value, -1 if the value is zero.
Definition MathExtras.h:332
int countr_zero(T Val)
Count number of 0's from the least significant bit to the most stopping at the first 1.
Definition bit.h:204
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
FunctionPass * createAArch64MIPeepholeOptLegacyPass()
MachineInstr * getImm(const MachineOperand &MO, const MachineRegisterInfo *MRI)
decltype(auto) get(const PointerIntPair< PointerTy, IntBits, IntType, PtrTraits, Info > &Pair)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
std::optional< UsedNZCV > examineCFlagsUse(MachineInstr &MI, MachineInstr &CmpInstr, const TargetRegisterInfo &TRI, SmallVectorImpl< MachineInstr * > *CCUseInstrs=nullptr)
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
RegState getRegState(const MachineOperand &RegOp)
Get all register state flags from machine operand RegOp.
MCRegisterClass TargetRegisterClass
Definition FastISel.h:58