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 MRI->clearKillFlags(SrcReg);
354 LLVM_DEBUG(dbgs() << "Removed: " << MI << "\n");
355 MI.eraseFromParent();
356
357 return true;
358}
359
360bool AArch64MIPeepholeOptImpl::visitCSEL(MachineInstr &MI) {
361 // Replace CSEL with MOV when both inputs are the same register.
362 if (MI.getOperand(1).getReg() != MI.getOperand(2).getReg())
363 return false;
364
365 auto ZeroReg =
366 MI.getOpcode() == AArch64::CSELXr ? AArch64::XZR : AArch64::WZR;
367 auto OrOpcode =
368 MI.getOpcode() == AArch64::CSELXr ? AArch64::ORRXrs : AArch64::ORRWrs;
369
370 BuildMI(*MI.getParent(), MI, MI.getDebugLoc(), TII->get(OrOpcode))
371 .addReg(MI.getOperand(0).getReg(), RegState::Define)
372 .addReg(ZeroReg)
373 .addReg(MI.getOperand(1).getReg())
374 .addImm(0);
375
376 MI.eraseFromParent();
377 return true;
378}
379
380bool AArch64MIPeepholeOptImpl::visitINSERT(MachineInstr &MI) {
381 // Check this INSERT_SUBREG comes from below zero-extend pattern.
382 //
383 // From %reg = INSERT_SUBREG %reg(tied-def 0), %subreg, subidx
384 // To %reg:subidx = SUBREG_TO_REG %subreg, subidx
385 //
386 // We're assuming the first operand to INSERT_SUBREG is irrelevant because a
387 // COPY would destroy the upper part of the register anyway
388 if (!MI.isRegTiedToDefOperand(1))
389 return false;
390
391 Register DstReg = MI.getOperand(0).getReg();
392 const TargetRegisterClass *RC = MRI->getRegClass(DstReg);
393 MachineInstr *SrcMI = MRI->getUniqueVRegDef(MI.getOperand(2).getReg());
394 if (!SrcMI)
395 return false;
396
397 // From https://developer.arm.com/documentation/dui0801/b/BABBGCAC
398 //
399 // When you use the 32-bit form of an instruction, the upper 32 bits of the
400 // source registers are ignored and the upper 32 bits of the destination
401 // register are set to zero.
402 //
403 // If AArch64's 32-bit form of instruction defines the source operand of
404 // zero-extend, we do not need the zero-extend. Let's check the MI's opcode is
405 // real AArch64 instruction and if it is not, do not process the opcode
406 // conservatively.
407 if ((SrcMI->getOpcode() <= TargetOpcode::GENERIC_OP_END) ||
408 !AArch64::GPR64allRegClass.hasSubClassEq(RC))
409 return false;
410
411 // Build a SUBREG_TO_REG instruction
412 MachineInstr *SubregMI =
413 BuildMI(*MI.getParent(), MI, MI.getDebugLoc(),
414 TII->get(TargetOpcode::SUBREG_TO_REG), DstReg)
415 .add(MI.getOperand(2))
416 .add(MI.getOperand(3));
417 LLVM_DEBUG(dbgs() << MI << " replace by:\n: " << *SubregMI << "\n");
418 (void)SubregMI;
419 MI.eraseFromParent();
420
421 return true;
422}
423
424template <typename T>
425static bool splitAddSubImm(T Imm, unsigned RegSize, T &Imm0, T &Imm1) {
426 // The immediate must be in the form of ((imm0 << 12) + imm1), in which both
427 // imm0 and imm1 are non-zero 12-bit unsigned int.
428 if ((Imm & 0xfff000) == 0 || (Imm & 0xfff) == 0 ||
429 (Imm & ~static_cast<T>(0xffffff)) != 0)
430 return false;
431
432 // The immediate can not be composed via a single instruction.
435 if (Insn.size() == 1)
436 return false;
437
438 // Split Imm into (Imm0 << 12) + Imm1;
439 Imm0 = (Imm >> 12) & 0xfff;
440 Imm1 = Imm & 0xfff;
441 return true;
442}
443
444template <typename T>
445bool AArch64MIPeepholeOptImpl::visitADDSUB(unsigned PosOpc, unsigned NegOpc,
446 MachineInstr &MI) {
447 // Try below transformation.
448 //
449 // ADDWrr X, MOVi32imm ==> ADDWri + ADDWri
450 // ADDXrr X, MOVi64imm ==> ADDXri + ADDXri
451 //
452 // SUBWrr X, MOVi32imm ==> SUBWri + SUBWri
453 // SUBXrr X, MOVi64imm ==> SUBXri + SUBXri
454 //
455 // The mov pseudo instruction could be expanded to multiple mov instructions
456 // later. Let's try to split the constant operand of mov instruction into two
457 // legal add/sub immediates. It makes only two ADD/SUB instructions instead of
458 // multiple `mov` + `and/sub` instructions.
459
460 // We can sometimes have ADDWrr WZR, MULi32imm that have not been constant
461 // folded. Make sure that we don't generate invalid instructions that use XZR
462 // in those cases.
463 if (MI.getOperand(1).getReg() == AArch64::XZR ||
464 MI.getOperand(1).getReg() == AArch64::WZR)
465 return false;
466
467 return splitTwoPartImm<T>(
468 MI,
469 [PosOpc, NegOpc](T Imm, unsigned RegSize, T &Imm0,
470 T &Imm1) -> std::optional<OpcodePair> {
471 if (splitAddSubImm(Imm, RegSize, Imm0, Imm1))
472 return std::make_pair(PosOpc, PosOpc);
473 if (splitAddSubImm(-Imm, RegSize, Imm0, Imm1))
474 return std::make_pair(NegOpc, NegOpc);
475 return std::nullopt;
476 },
477 [&TII = TII](MachineInstr &MI, OpcodePair Opcode, unsigned Imm0,
478 unsigned Imm1, Register SrcReg, Register NewTmpReg,
479 Register NewDstReg) {
480 DebugLoc DL = MI.getDebugLoc();
481 MachineBasicBlock *MBB = MI.getParent();
482 BuildMI(*MBB, MI, DL, TII->get(Opcode.first), NewTmpReg)
483 .addReg(SrcReg)
484 .addImm(Imm0)
485 .addImm(12);
486 BuildMI(*MBB, MI, DL, TII->get(Opcode.second), NewDstReg)
487 .addReg(NewTmpReg)
488 .addImm(Imm1)
489 .addImm(0);
490 });
491}
492
493template <typename T>
494bool AArch64MIPeepholeOptImpl::visitADDSSUBS(OpcodePair PosOpcs,
495 OpcodePair NegOpcs,
496 MachineInstr &MI) {
497 // Try the same transformation as ADDSUB but with additional requirement
498 // that the condition code usages are only for Equal and Not Equal
499
500 if (MI.getOperand(1).getReg() == AArch64::XZR ||
501 MI.getOperand(1).getReg() == AArch64::WZR)
502 return false;
503
504 return splitTwoPartImm<T>(
505 MI,
506 [PosOpcs, NegOpcs, &MI, &TRI = TRI,
507 &MRI = MRI](T Imm, unsigned RegSize, T &Imm0,
508 T &Imm1) -> std::optional<OpcodePair> {
509 OpcodePair OP;
510 if (splitAddSubImm(Imm, RegSize, Imm0, Imm1))
511 OP = PosOpcs;
512 else if (splitAddSubImm(-Imm, RegSize, Imm0, Imm1))
513 OP = NegOpcs;
514 else
515 return std::nullopt;
516 // Check conditional uses last since it is expensive for scanning
517 // proceeding instructions
518 MachineInstr *SrcMI = MRI->getVRegDef(MI.getOperand(1).getReg());
519 if (!SrcMI)
520 return std::nullopt;
521 std::optional<UsedNZCV> NZCVUsed = examineCFlagsUse(*SrcMI, MI, *TRI);
522 if (!NZCVUsed || NZCVUsed->C || NZCVUsed->V)
523 return std::nullopt;
524 return OP;
525 },
526 [&TII = TII](MachineInstr &MI, OpcodePair Opcode, unsigned Imm0,
527 unsigned Imm1, Register SrcReg, Register NewTmpReg,
528 Register NewDstReg) {
529 DebugLoc DL = MI.getDebugLoc();
530 MachineBasicBlock *MBB = MI.getParent();
531 BuildMI(*MBB, MI, DL, TII->get(Opcode.first), NewTmpReg)
532 .addReg(SrcReg)
533 .addImm(Imm0)
534 .addImm(12);
535 BuildMI(*MBB, MI, DL, TII->get(Opcode.second), NewDstReg)
536 .addReg(NewTmpReg)
537 .addImm(Imm1)
538 .addImm(0);
539 });
540}
541
542// Checks if the corresponding MOV immediate instruction is applicable for
543// this peephole optimization.
544bool AArch64MIPeepholeOptImpl::checkMovImmInstr(MachineInstr &MI,
545 MachineInstr *&MovMI,
546 MachineInstr *&SubregToRegMI) {
547 // Check whether current MBB is in loop and the AND is loop invariant.
548 MachineBasicBlock *MBB = MI.getParent();
549 MachineLoop *L = MLI->getLoopFor(MBB);
550 if (L && !L->isLoopInvariant(MI))
551 return false;
552
553 // Check whether current MI's operand is MOV with immediate.
554 MovMI = MRI->getUniqueVRegDef(MI.getOperand(2).getReg());
555 if (!MovMI)
556 return false;
557
558 // If it is SUBREG_TO_REG, check its operand.
559 SubregToRegMI = nullptr;
560 if (MovMI->getOpcode() == TargetOpcode::SUBREG_TO_REG) {
561 SubregToRegMI = MovMI;
562 MovMI = MRI->getUniqueVRegDef(MovMI->getOperand(1).getReg());
563 if (!MovMI)
564 return false;
565 }
566
567 if (MovMI->getOpcode() != AArch64::MOVi32imm &&
568 MovMI->getOpcode() != AArch64::MOVi64imm)
569 return false;
570
571 // If the MOV has multiple uses, do not split the immediate because it causes
572 // more instructions.
573 if (!MRI->hasOneNonDBGUse(MovMI->getOperand(0).getReg()))
574 return false;
575 if (SubregToRegMI &&
576 !MRI->hasOneNonDBGUse(SubregToRegMI->getOperand(0).getReg()))
577 return false;
578
579 // It is OK to perform this peephole optimization.
580 return true;
581}
582
583template <typename T>
584bool AArch64MIPeepholeOptImpl::splitTwoPartImm(MachineInstr &MI,
585 SplitAndOpcFunc<T> SplitAndOpc,
586 BuildMIFunc BuildInstr) {
587 unsigned RegSize = sizeof(T) * 8;
588 assert((RegSize == 32 || RegSize == 64) &&
589 "Invalid RegSize for legal immediate peephole optimization");
590
591 // Perform several essential checks against current MI.
592 MachineInstr *MovMI, *SubregToRegMI;
593 if (!checkMovImmInstr(MI, MovMI, SubregToRegMI))
594 return false;
595
596 // Split the immediate to Imm0 and Imm1, and calculate the Opcode.
597 T Imm = static_cast<T>(MovMI->getOperand(1).getImm()), Imm0, Imm1;
598 // For the 32 bit form of instruction, the upper 32 bits of the destination
599 // register are set to zero. If there is SUBREG_TO_REG, set the upper 32 bits
600 // of Imm to zero. This is essential if the Immediate value was a negative
601 // number since it was sign extended when we assign to the 64-bit Imm.
602 if (SubregToRegMI)
603 Imm &= 0xFFFFFFFF;
604 OpcodePair Opcode;
605 if (auto R = SplitAndOpc(Imm, RegSize, Imm0, Imm1))
606 Opcode = *R;
607 else
608 return false;
609
610 // Create new MIs using the first and second opcodes. Opcodes might differ for
611 // flag setting operations that should only set flags on second instruction.
612 // NewTmpReg = Opcode.first SrcReg Imm0
613 // NewDstReg = Opcode.second NewTmpReg Imm1
614
615 // Determine register classes for destinations and register operands
616 const TargetRegisterClass *FirstInstrDstRC =
617 TII->getRegClass(TII->get(Opcode.first), 0);
618 const TargetRegisterClass *FirstInstrOperandRC =
619 TII->getRegClass(TII->get(Opcode.first), 1);
620 const TargetRegisterClass *SecondInstrDstRC =
621 (Opcode.first == Opcode.second)
622 ? FirstInstrDstRC
623 : TII->getRegClass(TII->get(Opcode.second), 0);
624 const TargetRegisterClass *SecondInstrOperandRC =
625 (Opcode.first == Opcode.second)
626 ? FirstInstrOperandRC
627 : TII->getRegClass(TII->get(Opcode.second), 1);
628
629 // Get old registers destinations and new register destinations
630 Register DstReg = MI.getOperand(0).getReg();
631 Register SrcReg = MI.getOperand(1).getReg();
632 Register NewTmpReg = MRI->createVirtualRegister(FirstInstrDstRC);
633 // In the situation that DstReg is not Virtual (likely WZR or XZR), we want to
634 // reuse that same destination register.
635 Register NewDstReg = DstReg.isVirtual()
636 ? MRI->createVirtualRegister(SecondInstrDstRC)
637 : DstReg;
638
639 // Constrain registers based on their new uses
640 MRI->constrainRegClass(SrcReg, FirstInstrOperandRC);
641 MRI->constrainRegClass(NewTmpReg, SecondInstrOperandRC);
642 if (DstReg != NewDstReg)
643 MRI->constrainRegClass(NewDstReg, MRI->getRegClass(DstReg));
644
645 // Call the delegating operation to build the instruction
646 BuildInstr(MI, Opcode, Imm0, Imm1, SrcReg, NewTmpReg, NewDstReg);
647
648 // replaceRegWith changes MI's definition register. Keep it for SSA form until
649 // deleting MI. Only if we made a new destination register.
650 if (DstReg != NewDstReg) {
651 MRI->replaceRegWith(DstReg, NewDstReg);
652 MI.getOperand(0).setReg(DstReg);
653 }
654
655 auto SalvageDebugUses = [&](Register Reg, int64_t Val) {
656 for (MachineOperand &MO : make_early_inc_range(MRI->use_operands(Reg))) {
657 MachineInstr &DbgMI = *MO.getParent();
658 if (!DbgMI.isDebugValue())
659 continue;
660 // An immediate cannot express a value in memory at that address.
661 if (DbgMI.isNonListDebugValue() && DbgMI.isIndirectDebugValue())
662 DbgMI.setDebugValueUndef();
663 else
664 MO.ChangeToImmediate(Val);
665 }
666 };
667
668 // Record the MIs need to be removed.
669 MI.eraseFromParent();
670 if (SubregToRegMI) {
671 SalvageDebugUses(SubregToRegMI->getOperand(0).getReg(), Imm);
672 SubregToRegMI->eraseFromParent();
673 }
674 SalvageDebugUses(MovMI->getOperand(0).getReg(),
675 MovMI->getOperand(1).getImm());
676 MovMI->eraseFromParent();
677
678 return true;
679}
680
681bool AArch64MIPeepholeOptImpl::visitINSviGPR(MachineInstr &MI, unsigned Opc) {
682 // Check if this INSvi[X]gpr comes from COPY of a source FPR128
683 //
684 // From
685 // %intermediate1:gpr64 = COPY %src:fpr128
686 // %intermediate2:gpr32 = COPY %intermediate1:gpr64
687 // %dst:fpr128 = INSvi[X]gpr %dst_vec:fpr128, dst_index, %intermediate2:gpr32
688 // To
689 // %dst:fpr128 = INSvi[X]lane %dst_vec:fpr128, dst_index, %src:fpr128,
690 // src_index
691 // where src_index = 0, X = [8|16|32|64]
692
693 MachineInstr *SrcMI = MRI->getUniqueVRegDef(MI.getOperand(3).getReg());
694
695 // For a chain of COPY instructions, find the initial source register
696 // and check if it's an FPR128
697 while (true) {
698 if (!SrcMI || SrcMI->getOpcode() != TargetOpcode::COPY)
699 return false;
700
701 if (!SrcMI->getOperand(1).getReg().isVirtual())
702 return false;
703
704 if (MRI->getRegClass(SrcMI->getOperand(1).getReg()) ==
705 &AArch64::FPR128RegClass) {
706 break;
707 }
708 SrcMI = MRI->getUniqueVRegDef(SrcMI->getOperand(1).getReg());
709 }
710
711 Register DstReg = MI.getOperand(0).getReg();
712 Register SrcReg = SrcMI->getOperand(1).getReg();
713 MachineInstr *INSvilaneMI =
714 BuildMI(*MI.getParent(), MI, MI.getDebugLoc(), TII->get(Opc), DstReg)
715 .add(MI.getOperand(1))
716 .add(MI.getOperand(2))
717 .addUse(SrcReg, getRegState(SrcMI->getOperand(1)))
718 .addImm(0);
719
720 LLVM_DEBUG(dbgs() << MI << " replace by:\n: " << *INSvilaneMI << "\n");
721 (void)INSvilaneMI;
722 MI.eraseFromParent();
723 return true;
724}
725
726// All instructions that set a FPR64 will implicitly zero the top bits of the
727// register. When the def is expressed as a COPY from a GPR, turn it into an
728// explicit FMOV so it cannot be elided later in further passes.
731 const AArch64InstrInfo *TII) {
732 if (!MI->getOperand(0).isReg() || !MI->getOperand(0).isDef())
733 return false;
734 const TargetRegisterClass *RC = MRI->getRegClass(MI->getOperand(0).getReg());
735 if (RC != &AArch64::FPR64RegClass)
736 return false;
737 if (MI->getOpcode() == TargetOpcode::COPY) {
738 MachineOperand &SrcOp = MI->getOperand(1);
739 if (!SrcOp.isReg())
740 return false;
741 Register SrcReg = SrcOp.getReg();
742 if (SrcOp.getSubReg()) {
743 // If operand is defined by a LD1/2/3/4 that define a D subreg tuple
744 // then upper bits of the tuple's registers are implicitly zeroed
745 // and the FMOV is unneeded.
746 if (!SrcReg.isVirtual())
747 return false;
748
749 MachineInstr *SrcDef = MRI->getUniqueVRegDef(SrcReg);
750 if (!SrcDef || SrcDef->getOpcode() <= TargetOpcode::GENERIC_OP_END ||
751 SrcDef->getDesc().isPseudo() || !SrcDef->mayLoad())
752 return false;
753
754 const TargetRegisterClass *RC = MRI->getRegClass(SrcReg);
755 return RC == &AArch64::DDRegClass || RC == &AArch64::DDDRegClass ||
756 RC == &AArch64::DDDDRegClass;
757 }
758 auto IsGPR64Like = [&]() -> bool {
759 if (SrcReg.isVirtual())
760 return AArch64::GPR64allRegClass.hasSubClassEq(
761 MRI->getRegClass(SrcReg));
762 return AArch64::GPR64allRegClass.contains(SrcReg);
763 };
764 if (!IsGPR64Like())
765 return false;
766 assert(TII && "Expected InstrInfo when materializing COPYs");
767 // FMOVXDr insists on strict GPR64 operands, so fix up the COPY source.
768 MachineOperand &SrcMO = MI->getOperand(1);
769 bool SrcKill = SrcMO.isKill();
770 if (SrcReg.isVirtual()) {
771 if (MRI->getRegClass(SrcReg) != &AArch64::GPR64RegClass) {
772 // Pass the value through a temporary GPR64 vreg to satisfy the
773 // verifier.
774 Register NewSrc = MRI->createVirtualRegister(&AArch64::GPR64RegClass);
775 BuildMI(*MI->getParent(), MI, MI->getDebugLoc(),
776 TII->get(TargetOpcode::COPY), NewSrc)
777 .addReg(SrcReg, getKillRegState(SrcKill));
778 SrcReg = NewSrc;
779 }
780 } else if (!AArch64::GPR64RegClass.contains(SrcReg)) {
781 return false;
782 }
783 SrcMO.setReg(SrcReg);
784 SrcMO.setSubReg(0);
785 SrcMO.setIsKill(SrcKill);
786 // Replace the COPY with an explicit FMOV so the zeroing behaviour stays
787 // visible.
788 MI->setDesc(TII->get(AArch64::FMOVXDr));
789 return true;
790 }
791 return MI->getOpcode() > TargetOpcode::GENERIC_OP_END;
792}
793
794bool AArch64MIPeepholeOptImpl::visitINSvi64lane(MachineInstr &MI) {
795 // Check the MI for low 64-bits sets zero for high 64-bits implicitly.
796 // We are expecting below case.
797 //
798 // %1:fpr64 = nofpexcept FCVTNv4i16 %0:fpr128, implicit $fpcr
799 // %6:fpr128 = IMPLICIT_DEF
800 // %5:fpr128 = INSERT_SUBREG %6:fpr128(tied-def 0), killed %1:fpr64, %subreg.dsub
801 // %7:fpr128 = INSvi64lane %5:fpr128(tied-def 0), 1, killed %3:fpr128, 0
802 MachineInstr *Low64MI = MRI->getVRegDef(MI.getOperand(1).getReg());
803 if (!Low64MI || Low64MI->getOpcode() != AArch64::INSERT_SUBREG)
804 return false;
805 Low64MI = MRI->getUniqueVRegDef(Low64MI->getOperand(2).getReg());
806 if (!Low64MI || !is64bitDefwithZeroHigh64bit(Low64MI, MRI, TII))
807 return false;
808
809 // Check there is `mov 0` MI for high 64-bits.
810 // We are expecting below cases.
811 //
812 // %2:fpr64 = MOVID 0
813 // %4:fpr128 = IMPLICIT_DEF
814 // %3:fpr128 = INSERT_SUBREG %4:fpr128(tied-def 0), killed %2:fpr64, %subreg.dsub
815 // %7:fpr128 = INSvi64lane %5:fpr128(tied-def 0), 1, killed %3:fpr128, 0
816 // or
817 // %5:fpr128 = MOVIv2d_ns 0
818 // %6:fpr64 = COPY %5.dsub:fpr128
819 // %8:fpr128 = IMPLICIT_DEF
820 // %7:fpr128 = INSERT_SUBREG %8:fpr128(tied-def 0), killed %6:fpr64, %subreg.dsub
821 // %11:fpr128 = INSvi64lane %9:fpr128(tied-def 0), 1, killed %7:fpr128, 0
822 MachineInstr *High64MI = MRI->getUniqueVRegDef(MI.getOperand(3).getReg());
823 if (!High64MI || High64MI->getOpcode() != AArch64::INSERT_SUBREG)
824 return false;
825 High64MI = MRI->getUniqueVRegDef(High64MI->getOperand(2).getReg());
826 if (High64MI && High64MI->getOpcode() == TargetOpcode::COPY)
827 High64MI = MRI->getUniqueVRegDef(High64MI->getOperand(1).getReg());
828 if (!High64MI || (High64MI->getOpcode() != AArch64::MOVID &&
829 High64MI->getOpcode() != AArch64::MOVIv2d_ns))
830 return false;
831 if (High64MI->getOperand(1).getImm() != 0)
832 return false;
833
834 // Let's remove MIs for high 64-bits.
835 Register OldDef = MI.getOperand(0).getReg();
836 Register NewDef = MI.getOperand(1).getReg();
837 LLVM_DEBUG(dbgs() << "Removing: " << MI << "\n");
838 MRI->constrainRegClass(NewDef, MRI->getRegClass(OldDef));
839 MRI->replaceRegWith(OldDef, NewDef);
840 MRI->clearKillFlags(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->clearKillFlags(OldDef);
857 MRI->clearKillFlags(NewDef);
858 MRI->constrainRegClass(NewDef, MRI->getRegClass(OldDef));
859 MRI->replaceRegWith(OldDef, NewDef);
860 MI.eraseFromParent();
861
862 return true;
863}
864
865bool AArch64MIPeepholeOptImpl::visitUBFMXri(MachineInstr &MI) {
866 // Check if the instruction is equivalent to a 32 bit LSR or LSL alias of
867 // UBFM, and replace the UBFMXri instruction with its 32 bit variant, UBFMWri.
868 int64_t Immr = MI.getOperand(2).getImm();
869 int64_t Imms = MI.getOperand(3).getImm();
870
871 bool IsLSR = Imms == 31 && Immr <= Imms;
872 bool IsLSL = Immr == Imms + 33;
873 if (!IsLSR && !IsLSL)
874 return false;
875
876 if (IsLSL) {
877 Immr -= 32;
878 }
879
880 const TargetRegisterClass *DstRC64 =
881 TII->getRegClass(TII->get(MI.getOpcode()), 0);
882 const TargetRegisterClass *DstRC32 =
883 TRI->getSubRegisterClass(DstRC64, AArch64::sub_32);
884 assert(DstRC32 && "Destination register class of UBFMXri doesn't have a "
885 "sub_32 subregister class");
886
887 const TargetRegisterClass *SrcRC64 =
888 TII->getRegClass(TII->get(MI.getOpcode()), 1);
889 const TargetRegisterClass *SrcRC32 =
890 TRI->getSubRegisterClass(SrcRC64, AArch64::sub_32);
891 assert(SrcRC32 && "Source register class of UBFMXri doesn't have a sub_32 "
892 "subregister class");
893
894 Register DstReg64 = MI.getOperand(0).getReg();
895 Register DstReg32 = MRI->createVirtualRegister(DstRC32);
896 Register SrcReg64 = MI.getOperand(1).getReg();
897 Register SrcReg32 = MRI->createVirtualRegister(SrcRC32);
898
899 BuildMI(*MI.getParent(), MI, MI.getDebugLoc(), TII->get(AArch64::COPY),
900 SrcReg32)
901 .addReg(SrcReg64, {}, AArch64::sub_32);
902 BuildMI(*MI.getParent(), MI, MI.getDebugLoc(), TII->get(AArch64::UBFMWri),
903 DstReg32)
904 .addReg(SrcReg32)
905 .addImm(Immr)
906 .addImm(Imms);
907 BuildMI(*MI.getParent(), MI, MI.getDebugLoc(),
908 TII->get(AArch64::SUBREG_TO_REG), DstReg64)
909 .addReg(DstReg32)
910 .addImm(AArch64::sub_32);
911 MI.eraseFromParent();
912 return true;
913}
914
915// Across a basic-block we might have in i32 extract from a value that only
916// operates on upper bits (for example a sxtw). We can replace the COPY with a
917// new version skipping the sxtw.
918bool AArch64MIPeepholeOptImpl::visitCopy(MachineInstr &MI) {
919 Register InputReg = MI.getOperand(1).getReg();
920 if (MI.getOperand(1).getSubReg() != AArch64::sub_32 ||
921 !MRI->hasOneNonDBGUse(InputReg))
922 return false;
923
924 MachineInstr *SrcMI = MRI->getUniqueVRegDef(InputReg);
925 SmallPtrSet<MachineInstr *, 4> DeadInstrs;
926 DeadInstrs.insert(SrcMI);
927 while (SrcMI && SrcMI->isFullCopy() &&
928 MRI->hasOneNonDBGUse(SrcMI->getOperand(1).getReg())) {
929 SrcMI = MRI->getUniqueVRegDef(SrcMI->getOperand(1).getReg());
930 DeadInstrs.insert(SrcMI);
931 }
932
933 if (!SrcMI)
934 return false;
935
936 // Look for SXTW(X) and return Reg.
937 auto getSXTWSrcReg = [](MachineInstr *SrcMI) -> Register {
938 if (SrcMI->getOpcode() != AArch64::SBFMXri ||
939 SrcMI->getOperand(2).getImm() != 0 ||
940 SrcMI->getOperand(3).getImm() != 31)
941 return Register();
942 return SrcMI->getOperand(1).getReg();
943 };
944 // Look for SUBREG_TO_REG(ORRWrr(WZR, COPY(X.sub_32)))
945 auto getUXTWSrcReg = [&](MachineInstr *SrcMI) -> Register {
946 if (SrcMI->getOpcode() != AArch64::SUBREG_TO_REG ||
947 SrcMI->getOperand(2).getImm() != AArch64::sub_32 ||
948 !MRI->hasOneNonDBGUse(SrcMI->getOperand(1).getReg()))
949 return Register();
950 MachineInstr *Orr = MRI->getUniqueVRegDef(SrcMI->getOperand(1).getReg());
951 if (!Orr || Orr->getOpcode() != AArch64::ORRWrr ||
952 Orr->getOperand(1).getReg() != AArch64::WZR ||
953 !MRI->hasOneNonDBGUse(Orr->getOperand(2).getReg()))
954 return Register();
955 MachineInstr *Cpy = MRI->getUniqueVRegDef(Orr->getOperand(2).getReg());
956 if (!Cpy || Cpy->getOpcode() != AArch64::COPY ||
957 Cpy->getOperand(1).getSubReg() != AArch64::sub_32)
958 return Register();
959 DeadInstrs.insert(Orr);
960 return Cpy->getOperand(1).getReg();
961 };
962
963 Register SrcReg = getSXTWSrcReg(SrcMI);
964 if (!SrcReg)
965 SrcReg = getUXTWSrcReg(SrcMI);
966 if (!SrcReg)
967 return false;
968
969 MRI->constrainRegClass(SrcReg, MRI->getRegClass(InputReg));
970 LLVM_DEBUG(dbgs() << "Optimizing: " << MI);
971 MI.getOperand(1).setReg(SrcReg);
972 LLVM_DEBUG(dbgs() << " to: " << MI);
973 for (auto *DeadMI : DeadInstrs) {
974 LLVM_DEBUG(dbgs() << " Removing: " << *DeadMI);
975 DeadMI->eraseFromParent();
976 }
977 return true;
978}
979
980bool AArch64MIPeepholeOptImpl::run(MachineFunction &MF) {
981 TII = static_cast<const AArch64InstrInfo *>(MF.getSubtarget().getInstrInfo());
982 TRI = static_cast<const AArch64RegisterInfo *>(
983 MF.getSubtarget().getRegisterInfo());
984 MRI = &MF.getRegInfo();
985
986 assert(MRI->isSSA() && "Expected to be run on SSA form!");
987
988 bool Changed = false;
989
990 for (MachineBasicBlock &MBB : MF) {
991 for (MachineInstr &MI : make_early_inc_range(MBB)) {
992 switch (MI.getOpcode()) {
993 default:
994 break;
995 case AArch64::INSERT_SUBREG:
996 Changed |= visitINSERT(MI);
997 break;
998 case AArch64::ANDWrr:
999 Changed |= trySplitLogicalImm<uint32_t>(AArch64::ANDWri, MI,
1000 SplitStrategy::Intersect);
1001 break;
1002 case AArch64::ANDXrr:
1003 Changed |= trySplitLogicalImm<uint64_t>(AArch64::ANDXri, MI,
1004 SplitStrategy::Intersect);
1005 break;
1006 case AArch64::ANDSWrr:
1007 Changed |= trySplitLogicalImm<uint32_t>(
1008 AArch64::ANDWri, MI, SplitStrategy::Intersect, AArch64::ANDSWri);
1009 break;
1010 case AArch64::ANDSXrr:
1011 Changed |= trySplitLogicalImm<uint64_t>(
1012 AArch64::ANDXri, MI, SplitStrategy::Intersect, AArch64::ANDSXri);
1013 break;
1014 case AArch64::EORWrr:
1015 Changed |= trySplitLogicalImm<uint32_t>(AArch64::EORWri, MI,
1016 SplitStrategy::Disjoint);
1017 break;
1018 case AArch64::EORXrr:
1019 Changed |= trySplitLogicalImm<uint64_t>(AArch64::EORXri, MI,
1020 SplitStrategy::Disjoint);
1021 break;
1022 case AArch64::ORRWrr:
1023 Changed |= trySplitLogicalImm<uint32_t>(AArch64::ORRWri, MI,
1024 SplitStrategy::Disjoint);
1025 break;
1026 case AArch64::ORRXrr:
1027 Changed |= trySplitLogicalImm<uint64_t>(AArch64::ORRXri, MI,
1028 SplitStrategy::Disjoint);
1029 break;
1030 case AArch64::ORRWrs:
1031 Changed |= visitORR(MI);
1032 break;
1033 case AArch64::ADDWrr:
1034 Changed |= visitADDSUB<uint32_t>(AArch64::ADDWri, AArch64::SUBWri, MI);
1035 break;
1036 case AArch64::SUBWrr:
1037 Changed |= visitADDSUB<uint32_t>(AArch64::SUBWri, AArch64::ADDWri, MI);
1038 break;
1039 case AArch64::ADDXrr:
1040 Changed |= visitADDSUB<uint64_t>(AArch64::ADDXri, AArch64::SUBXri, MI);
1041 break;
1042 case AArch64::SUBXrr:
1043 Changed |= visitADDSUB<uint64_t>(AArch64::SUBXri, AArch64::ADDXri, MI);
1044 break;
1045 case AArch64::ADDSWrr:
1046 Changed |=
1047 visitADDSSUBS<uint32_t>({AArch64::ADDWri, AArch64::ADDSWri},
1048 {AArch64::SUBWri, AArch64::SUBSWri}, MI);
1049 break;
1050 case AArch64::SUBSWrr:
1051 Changed |=
1052 visitADDSSUBS<uint32_t>({AArch64::SUBWri, AArch64::SUBSWri},
1053 {AArch64::ADDWri, AArch64::ADDSWri}, MI);
1054 break;
1055 case AArch64::ADDSXrr:
1056 Changed |=
1057 visitADDSSUBS<uint64_t>({AArch64::ADDXri, AArch64::ADDSXri},
1058 {AArch64::SUBXri, AArch64::SUBSXri}, MI);
1059 break;
1060 case AArch64::SUBSXrr:
1061 Changed |=
1062 visitADDSSUBS<uint64_t>({AArch64::SUBXri, AArch64::SUBSXri},
1063 {AArch64::ADDXri, AArch64::ADDSXri}, MI);
1064 break;
1065 case AArch64::CSELWr:
1066 case AArch64::CSELXr:
1067 Changed |= visitCSEL(MI);
1068 break;
1069 case AArch64::INSvi64gpr:
1070 Changed |= visitINSviGPR(MI, AArch64::INSvi64lane);
1071 break;
1072 case AArch64::INSvi32gpr:
1073 Changed |= visitINSviGPR(MI, AArch64::INSvi32lane);
1074 break;
1075 case AArch64::INSvi16gpr:
1076 Changed |= visitINSviGPR(MI, AArch64::INSvi16lane);
1077 break;
1078 case AArch64::INSvi8gpr:
1079 Changed |= visitINSviGPR(MI, AArch64::INSvi8lane);
1080 break;
1081 case AArch64::INSvi64lane:
1082 Changed |= visitINSvi64lane(MI);
1083 break;
1084 case AArch64::FMOVDr:
1085 Changed |= visitFMOVDr(MI);
1086 break;
1087 case AArch64::UBFMXri:
1088 Changed |= visitUBFMXri(MI);
1089 break;
1090 case AArch64::COPY:
1091 Changed |= visitCopy(MI);
1092 break;
1093 }
1094 }
1095 }
1096
1097 return Changed;
1098}
1099
1100bool AArch64MIPeepholeOptLegacy::runOnMachineFunction(MachineFunction &MF) {
1101 if (skipFunction(MF.getFunction()))
1102 return false;
1103
1104 MachineLoopInfo &MLI = getAnalysis<MachineLoopInfoWrapperPass>().getLI();
1105 return AArch64MIPeepholeOptImpl(MLI).run(MF);
1106}
1107
1109 return new AArch64MIPeepholeOptLegacy();
1110}
1111
1116 const bool Changed = AArch64MIPeepholeOptImpl(MLI).run(MF);
1117 if (!Changed)
1118 return PreservedAnalyses::all();
1121 return PA;
1122}
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
#define OP(OPC)
Definition Instruction.h:46
static bool contains(SmallPtrSetImpl< ConstantExpr * > &Cache, ConstantExpr *Expr, Constant *C)
Definition Value.cpp:480
#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 void clearKillFlags(Register Reg) const
clearKillFlags - Iterate over all the uses of the given register and clear the kill flag from the Mac...
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
Changed
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