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), %1:fpr64, %subreg.dsub
800 // %7:fpr128 = INSvi64lane %5:fpr128(tied-def 0), 1, %3:fpr128, 0
801 if (MI.getOperand(2).getImm() != 1)
802 return false;
803 MachineInstr *Low64MI = MRI->getVRegDef(MI.getOperand(1).getReg());
804 if (!Low64MI || Low64MI->getOpcode() != AArch64::INSERT_SUBREG)
805 return false;
806 Low64MI = MRI->getUniqueVRegDef(Low64MI->getOperand(2).getReg());
807 if (!Low64MI || !is64bitDefwithZeroHigh64bit(Low64MI, MRI, TII))
808 return false;
809
810 // Check there is `mov 0` MI for high 64-bits.
811 // We are expecting below cases.
812 //
813 // %2:fpr64 = MOVID 0
814 // %4:fpr128 = IMPLICIT_DEF
815 // %3:fpr128 = INSERT_SUBREG %4:fpr128(tied-def 0), %2:fpr64, %subreg.dsub
816 // %7:fpr128 = INSvi64lane %5:fpr128(tied-def 0), 1, %3:fpr128, 0
817 // or
818 // %5:fpr128 = MOVIv2d_ns 0
819 // %6:fpr64 = COPY %5.dsub:fpr128
820 // %8:fpr128 = IMPLICIT_DEF
821 // %7:fpr128 = INSERT_SUBREG %8:fpr128(tied-def 0), %6:fpr64, %subreg.dsub
822 // %11:fpr128 = INSvi64lane %9:fpr128(tied-def 0), 1, %7:fpr128, 0
823 MachineInstr *High64MI = MRI->getUniqueVRegDef(MI.getOperand(3).getReg());
824 if (!High64MI || High64MI->getOpcode() != AArch64::INSERT_SUBREG)
825 return false;
826 High64MI = MRI->getUniqueVRegDef(High64MI->getOperand(2).getReg());
827 if (High64MI && High64MI->getOpcode() == TargetOpcode::COPY)
828 High64MI = MRI->getUniqueVRegDef(High64MI->getOperand(1).getReg());
829 if (!High64MI || (High64MI->getOpcode() != AArch64::MOVID &&
830 High64MI->getOpcode() != AArch64::MOVIv2d_ns))
831 return false;
832 if (High64MI->getOperand(1).getImm() != 0)
833 return false;
834
835 // Let's remove MIs for high 64-bits.
836 Register OldDef = MI.getOperand(0).getReg();
837 Register NewDef = MI.getOperand(1).getReg();
838 LLVM_DEBUG(dbgs() << "Removing: " << MI << "\n");
839 MRI->constrainRegClass(NewDef, MRI->getRegClass(OldDef));
840 MRI->replaceRegWith(OldDef, NewDef);
841 MI.eraseFromParent();
842
843 return true;
844}
845
846bool AArch64MIPeepholeOptImpl::visitFMOVDr(MachineInstr &MI) {
847 // An FMOVDr sets the high 64-bits to zero implicitly, similar to ORR for GPR.
848 MachineInstr *Low64MI = MRI->getUniqueVRegDef(MI.getOperand(1).getReg());
849 if (!Low64MI || !is64bitDefwithZeroHigh64bit(Low64MI, MRI, TII))
850 return false;
851
852 // Let's remove MIs for high 64-bits.
853 Register OldDef = MI.getOperand(0).getReg();
854 Register NewDef = MI.getOperand(1).getReg();
855 LLVM_DEBUG(dbgs() << "Removing: " << MI << "\n");
856 MRI->constrainRegClass(NewDef, MRI->getRegClass(OldDef));
857 MRI->replaceRegWith(OldDef, NewDef);
858 MI.eraseFromParent();
859
860 return true;
861}
862
863bool AArch64MIPeepholeOptImpl::visitUBFMXri(MachineInstr &MI) {
864 // Check if the instruction is equivalent to a 32 bit LSR or LSL alias of
865 // UBFM, and replace the UBFMXri instruction with its 32 bit variant, UBFMWri.
866 int64_t Immr = MI.getOperand(2).getImm();
867 int64_t Imms = MI.getOperand(3).getImm();
868
869 bool IsLSR = Imms == 31 && Immr <= Imms;
870 bool IsLSL = Immr == Imms + 33;
871 if (!IsLSR && !IsLSL)
872 return false;
873
874 if (IsLSL) {
875 Immr -= 32;
876 }
877
878 const TargetRegisterClass *DstRC64 =
879 TII->getRegClass(TII->get(MI.getOpcode()), 0);
880 const TargetRegisterClass *DstRC32 =
881 TRI->getSubRegisterClass(DstRC64, AArch64::sub_32);
882 assert(DstRC32 && "Destination register class of UBFMXri doesn't have a "
883 "sub_32 subregister class");
884
885 const TargetRegisterClass *SrcRC64 =
886 TII->getRegClass(TII->get(MI.getOpcode()), 1);
887 const TargetRegisterClass *SrcRC32 =
888 TRI->getSubRegisterClass(SrcRC64, AArch64::sub_32);
889 assert(SrcRC32 && "Source register class of UBFMXri doesn't have a sub_32 "
890 "subregister class");
891
892 Register DstReg64 = MI.getOperand(0).getReg();
893 Register DstReg32 = MRI->createVirtualRegister(DstRC32);
894 Register SrcReg64 = MI.getOperand(1).getReg();
895 Register SrcReg32 = MRI->createVirtualRegister(SrcRC32);
896
897 BuildMI(*MI.getParent(), MI, MI.getDebugLoc(), TII->get(AArch64::COPY),
898 SrcReg32)
899 .addReg(SrcReg64, {}, AArch64::sub_32);
900 BuildMI(*MI.getParent(), MI, MI.getDebugLoc(), TII->get(AArch64::UBFMWri),
901 DstReg32)
902 .addReg(SrcReg32)
903 .addImm(Immr)
904 .addImm(Imms);
905 BuildMI(*MI.getParent(), MI, MI.getDebugLoc(),
906 TII->get(AArch64::SUBREG_TO_REG), DstReg64)
907 .addReg(DstReg32)
908 .addImm(AArch64::sub_32);
909 MI.eraseFromParent();
910 return true;
911}
912
913// Across a basic-block we might have in i32 extract from a value that only
914// operates on upper bits (for example a sxtw). We can replace the COPY with a
915// new version skipping the sxtw.
916bool AArch64MIPeepholeOptImpl::visitCopy(MachineInstr &MI) {
917 Register InputReg = MI.getOperand(1).getReg();
918 if (MI.getOperand(1).getSubReg() != AArch64::sub_32 ||
919 !MRI->hasOneNonDBGUse(InputReg))
920 return false;
921
922 MachineInstr *SrcMI = MRI->getUniqueVRegDef(InputReg);
923 SmallPtrSet<MachineInstr *, 4> DeadInstrs;
924 DeadInstrs.insert(SrcMI);
925 while (SrcMI && SrcMI->isFullCopy() &&
926 MRI->hasOneNonDBGUse(SrcMI->getOperand(1).getReg())) {
927 SrcMI = MRI->getUniqueVRegDef(SrcMI->getOperand(1).getReg());
928 DeadInstrs.insert(SrcMI);
929 }
930
931 if (!SrcMI)
932 return false;
933
934 // Look for SXTW(X) and return Reg.
935 auto getSXTWSrcReg = [](MachineInstr *SrcMI) -> Register {
936 if (SrcMI->getOpcode() != AArch64::SBFMXri ||
937 SrcMI->getOperand(2).getImm() != 0 ||
938 SrcMI->getOperand(3).getImm() != 31)
939 return Register();
940 return SrcMI->getOperand(1).getReg();
941 };
942 // Look for SUBREG_TO_REG(ORRWrr(WZR, COPY(X.sub_32)))
943 auto getUXTWSrcReg = [&](MachineInstr *SrcMI) -> Register {
944 if (SrcMI->getOpcode() != AArch64::SUBREG_TO_REG ||
945 SrcMI->getOperand(2).getImm() != AArch64::sub_32 ||
946 !MRI->hasOneNonDBGUse(SrcMI->getOperand(1).getReg()))
947 return Register();
948 MachineInstr *Orr = MRI->getUniqueVRegDef(SrcMI->getOperand(1).getReg());
949 if (!Orr || Orr->getOpcode() != AArch64::ORRWrr ||
950 Orr->getOperand(1).getReg() != AArch64::WZR ||
952 return Register();
953 MachineInstr *Cpy = MRI->getUniqueVRegDef(Orr->getOperand(2).getReg());
954 if (!Cpy || Cpy->getOpcode() != AArch64::COPY ||
955 Cpy->getOperand(1).getSubReg() != AArch64::sub_32)
956 return Register();
957 DeadInstrs.insert(Orr);
958 return Cpy->getOperand(1).getReg();
959 };
960
961 Register SrcReg = getSXTWSrcReg(SrcMI);
962 if (!SrcReg)
963 SrcReg = getUXTWSrcReg(SrcMI);
964 if (!SrcReg)
965 return false;
966
967 MRI->constrainRegClass(SrcReg, MRI->getRegClass(InputReg));
968 LLVM_DEBUG(dbgs() << "Optimizing: " << MI);
969 MI.getOperand(1).setReg(SrcReg);
970 LLVM_DEBUG(dbgs() << " to: " << MI);
971 for (auto *DeadMI : DeadInstrs) {
972 LLVM_DEBUG(dbgs() << " Removing: " << *DeadMI);
973 DeadMI->eraseFromParent();
974 }
975 return true;
976}
977
978bool AArch64MIPeepholeOptImpl::run(MachineFunction &MF) {
979 TII = static_cast<const AArch64InstrInfo *>(MF.getSubtarget().getInstrInfo());
980 TRI = static_cast<const AArch64RegisterInfo *>(
981 MF.getSubtarget().getRegisterInfo());
982 MRI = &MF.getRegInfo();
983
984 assert(MRI->isSSA() && "Expected to be run on SSA form!");
985
986 bool Changed = false;
987
988 for (MachineBasicBlock &MBB : MF) {
989 for (MachineInstr &MI : make_early_inc_range(MBB)) {
990 switch (MI.getOpcode()) {
991 default:
992 break;
993 case AArch64::INSERT_SUBREG:
994 Changed |= visitINSERT(MI);
995 break;
996 case AArch64::ANDWrr:
997 Changed |= trySplitLogicalImm<uint32_t>(AArch64::ANDWri, MI,
998 SplitStrategy::Intersect);
999 break;
1000 case AArch64::ANDXrr:
1001 Changed |= trySplitLogicalImm<uint64_t>(AArch64::ANDXri, MI,
1002 SplitStrategy::Intersect);
1003 break;
1004 case AArch64::ANDSWrr:
1005 Changed |= trySplitLogicalImm<uint32_t>(
1006 AArch64::ANDWri, MI, SplitStrategy::Intersect, AArch64::ANDSWri);
1007 break;
1008 case AArch64::ANDSXrr:
1009 Changed |= trySplitLogicalImm<uint64_t>(
1010 AArch64::ANDXri, MI, SplitStrategy::Intersect, AArch64::ANDSXri);
1011 break;
1012 case AArch64::EORWrr:
1013 Changed |= trySplitLogicalImm<uint32_t>(AArch64::EORWri, MI,
1014 SplitStrategy::Disjoint);
1015 break;
1016 case AArch64::EORXrr:
1017 Changed |= trySplitLogicalImm<uint64_t>(AArch64::EORXri, MI,
1018 SplitStrategy::Disjoint);
1019 break;
1020 case AArch64::ORRWrr:
1021 Changed |= trySplitLogicalImm<uint32_t>(AArch64::ORRWri, MI,
1022 SplitStrategy::Disjoint);
1023 break;
1024 case AArch64::ORRXrr:
1025 Changed |= trySplitLogicalImm<uint64_t>(AArch64::ORRXri, MI,
1026 SplitStrategy::Disjoint);
1027 break;
1028 case AArch64::ORRWrs:
1029 Changed |= visitORR(MI);
1030 break;
1031 case AArch64::ADDWrr:
1032 Changed |= visitADDSUB<uint32_t>(AArch64::ADDWri, AArch64::SUBWri, MI);
1033 break;
1034 case AArch64::SUBWrr:
1035 Changed |= visitADDSUB<uint32_t>(AArch64::SUBWri, AArch64::ADDWri, MI);
1036 break;
1037 case AArch64::ADDXrr:
1038 Changed |= visitADDSUB<uint64_t>(AArch64::ADDXri, AArch64::SUBXri, MI);
1039 break;
1040 case AArch64::SUBXrr:
1041 Changed |= visitADDSUB<uint64_t>(AArch64::SUBXri, AArch64::ADDXri, MI);
1042 break;
1043 case AArch64::ADDSWrr:
1044 Changed |=
1045 visitADDSSUBS<uint32_t>({AArch64::ADDWri, AArch64::ADDSWri},
1046 {AArch64::SUBWri, AArch64::SUBSWri}, MI);
1047 break;
1048 case AArch64::SUBSWrr:
1049 Changed |=
1050 visitADDSSUBS<uint32_t>({AArch64::SUBWri, AArch64::SUBSWri},
1051 {AArch64::ADDWri, AArch64::ADDSWri}, MI);
1052 break;
1053 case AArch64::ADDSXrr:
1054 Changed |=
1055 visitADDSSUBS<uint64_t>({AArch64::ADDXri, AArch64::ADDSXri},
1056 {AArch64::SUBXri, AArch64::SUBSXri}, MI);
1057 break;
1058 case AArch64::SUBSXrr:
1059 Changed |=
1060 visitADDSSUBS<uint64_t>({AArch64::SUBXri, AArch64::SUBSXri},
1061 {AArch64::ADDXri, AArch64::ADDSXri}, MI);
1062 break;
1063 case AArch64::CSELWr:
1064 case AArch64::CSELXr:
1065 Changed |= visitCSEL(MI);
1066 break;
1067 case AArch64::INSvi64gpr:
1068 Changed |= visitINSviGPR(MI, AArch64::INSvi64lane);
1069 break;
1070 case AArch64::INSvi32gpr:
1071 Changed |= visitINSviGPR(MI, AArch64::INSvi32lane);
1072 break;
1073 case AArch64::INSvi16gpr:
1074 Changed |= visitINSviGPR(MI, AArch64::INSvi16lane);
1075 break;
1076 case AArch64::INSvi8gpr:
1077 Changed |= visitINSviGPR(MI, AArch64::INSvi8lane);
1078 break;
1079 case AArch64::INSvi64lane:
1080 Changed |= visitINSvi64lane(MI);
1081 break;
1082 case AArch64::FMOVDr:
1083 Changed |= visitFMOVDr(MI);
1084 break;
1085 case AArch64::UBFMXri:
1086 Changed |= visitUBFMXri(MI);
1087 break;
1088 case AArch64::COPY:
1089 Changed |= visitCopy(MI);
1090 break;
1091 }
1092 }
1093 }
1094
1095 return Changed;
1096}
1097
1098bool AArch64MIPeepholeOptLegacy::runOnMachineFunction(MachineFunction &MF) {
1099 if (skipFunction(MF.getFunction()))
1100 return false;
1101
1102 MachineLoopInfo &MLI = getAnalysis<MachineLoopInfoWrapperPass>().getLI();
1103 return AArch64MIPeepholeOptImpl(MLI).run(MF);
1104}
1105
1107 return new AArch64MIPeepholeOptLegacy();
1108}
1109
1114 const bool Changed = AArch64MIPeepholeOptImpl(MLI).run(MF);
1115 if (!Changed)
1116 return PreservedAnalyses::all();
1119 return PA;
1120}
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