LLVM 24.0.0git
AArch64ExpandPseudoInsts.cpp
Go to the documentation of this file.
1//===- AArch64ExpandPseudoInsts.cpp - Expand pseudo instructions ----------===//
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 file contains a pass that expands pseudo instructions into target
10// instructions to allow proper scheduling and other late optimizations. This
11// pass should be run after register allocation but before the post-regalloc
12// scheduling pass.
13//
14//===----------------------------------------------------------------------===//
15
16#include "AArch64ExpandImm.h"
17#include "AArch64InstrInfo.h"
19#include "AArch64Subtarget.h"
31#include "llvm/IR/DebugLoc.h"
32#include "llvm/MC/MCInstrDesc.h"
33#include "llvm/Pass.h"
37#include <cassert>
38#include <cstdint>
39#include <iterator>
40
41using namespace llvm;
42
43#define AARCH64_EXPAND_PSEUDO_NAME "AArch64 pseudo instruction expansion pass"
44
45namespace {
46
47class AArch64ExpandPseudoImpl {
48public:
49 const AArch64InstrInfo *TII;
50
51 bool run(MachineFunction &MF);
52
53private:
54 bool expandMBB(MachineBasicBlock &MBB);
57 bool expandMultiVecPseudo(MachineBasicBlock &MBB,
59 const TargetRegisterClass &ContiguousClass,
60 const TargetRegisterClass &StridedClass,
61 unsigned ContiguousOpc, unsigned StridedOpc);
62 bool expandCopyIntoTuplePseudo(MachineInstr &MI, MachineBasicBlock &MBB,
65 unsigned BitSize);
66
67 bool expand_DestructiveOp(MachineInstr &MI, MachineBasicBlock &MBB,
69 bool expandSVEBitwisePseudo(MachineInstr &MI, MachineBasicBlock &MBB,
72 unsigned LdarOp, unsigned StlrOp, unsigned CmpOp,
73 unsigned ExtendImm, unsigned ZeroReg,
75 bool expandCMP_SWAP_128(MachineBasicBlock &MBB,
78 bool expandSetTagLoop(MachineBasicBlock &MBB,
81 bool expandSVESpillFill(MachineBasicBlock &MBB,
83 unsigned N);
84 bool expandCALL_RVMARKER(MachineBasicBlock &MBB,
87 bool expandStoreSwiftAsyncContext(MachineBasicBlock &MBB,
89 struct ConditionalBlocks {
90 MachineBasicBlock &CondBB;
91 MachineBasicBlock &EndBB;
92 };
93 ConditionalBlocks expandConditionalPseudo(MachineBasicBlock &MBB,
96 MachineInstrBuilder &Branch);
97 MachineBasicBlock *expandRestoreZASave(MachineBasicBlock &MBB,
99 MachineBasicBlock *expandCommitZASave(MachineBasicBlock &MBB,
101 MachineBasicBlock *expandCondSMToggle(MachineBasicBlock &MBB,
103};
104
105class AArch64ExpandPseudoLegacy : public MachineFunctionPass {
106public:
107 static char ID;
108
109 AArch64ExpandPseudoLegacy() : MachineFunctionPass(ID) {}
110
111 bool runOnMachineFunction(MachineFunction &MF) override;
112
113 void getAnalysisUsage(AnalysisUsage &AU) const override {
116 }
117
118 StringRef getPassName() const override { return AARCH64_EXPAND_PSEUDO_NAME; }
119};
120
121} // end anonymous namespace
122
123char AArch64ExpandPseudoLegacy::ID = 0;
124
125INITIALIZE_PASS(AArch64ExpandPseudoLegacy, "aarch64-expand-pseudo",
126 AARCH64_EXPAND_PSEUDO_NAME, false, false)
127
128/// Transfer implicit operands on the pseudo instruction to the
129/// instructions created from the expansion.
132 const MCInstrDesc &Desc = OldMI.getDesc();
133 for (const MachineOperand &MO :
134 llvm::drop_begin(OldMI.operands(), Desc.getNumOperands())) {
135 assert(MO.isReg() && MO.getReg());
136 if (MO.isUse())
137 UseMI.add(MO);
138 else
139 DefMI.add(MO);
140 }
141}
142
143/// Expand a MOVi32imm or MOVi64imm pseudo instruction to one or more
144/// real move-immediate instructions to synthesize the immediate.
145bool AArch64ExpandPseudoImpl::expandMOVImm(MachineBasicBlock &MBB,
147 unsigned BitSize) {
148 MachineInstr &MI = *MBBI;
149 Register DstReg = MI.getOperand(0).getReg();
150 RegState RenamableState =
151 getRenamableRegState(MI.getOperand(0).isRenamable());
152 uint64_t Imm = MI.getOperand(1).getImm();
153
154 if (DstReg == AArch64::XZR || DstReg == AArch64::WZR) {
155 // Useless def, and we don't want to risk creating an invalid ORR (which
156 // would really write to sp).
157 MI.eraseFromParent();
158 return true;
159 }
160
162 AArch64_IMM::expandMOVImm(Imm, BitSize, Insn);
163 assert(Insn.size() != 0);
164
165 SmallVector<MachineInstrBuilder, 4> MIBS;
166 for (auto I = Insn.begin(), E = Insn.end(); I != E; ++I) {
167 bool LastItem = std::next(I) == E;
168 switch (I->Opcode)
169 {
170 default: llvm_unreachable("unhandled!"); break;
171
172 case AArch64::ORRWri:
173 case AArch64::ORRXri:
174 case AArch64::ANDXri:
175 case AArch64::EORXri:
176 if (I->Op1 == 0) {
177 MIBS.push_back(BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(I->Opcode))
178 .add(MI.getOperand(0))
179 .addReg(BitSize == 32 ? AArch64::WZR : AArch64::XZR)
180 .addImm(*I->Op2));
181 } else {
182 Register DstReg = MI.getOperand(0).getReg();
183 bool DstIsDead = MI.getOperand(0).isDead();
184 MIBS.push_back(
185 BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(I->Opcode))
186 .addReg(DstReg, RegState::Define |
187 getDeadRegState(DstIsDead && LastItem) |
188 RenamableState)
189 .addReg(DstReg)
190 .addImm(*I->Op2));
191 }
192 break;
193 case AArch64::EONXrs:
194 case AArch64::EORXrs:
195 case AArch64::ORRWrs:
196 case AArch64::ORRXrs: {
197 Register DstReg = MI.getOperand(0).getReg();
198 bool DstIsDead = MI.getOperand(0).isDead();
199 MIBS.push_back(
200 BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(I->Opcode))
201 .addReg(DstReg, RegState::Define |
202 getDeadRegState(DstIsDead && LastItem) |
203 RenamableState)
204 .addReg(DstReg)
205 .addReg(DstReg)
206 .addImm(*I->Op2));
207 } break;
208 case AArch64::MOVNWi:
209 case AArch64::MOVNXi:
210 case AArch64::MOVZWi:
211 case AArch64::MOVZXi: {
212 bool DstIsDead = MI.getOperand(0).isDead();
213 MIBS.push_back(
214 BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(I->Opcode))
215 .addReg(DstReg, RegState::Define |
216 getDeadRegState(DstIsDead && LastItem) |
217 RenamableState)
218 .addImm(*I->Op1)
219 .addImm(*I->Op2));
220 } break;
221 case AArch64::MOVKWi:
222 case AArch64::MOVKXi: {
223 Register DstReg = MI.getOperand(0).getReg();
224 bool DstIsDead = MI.getOperand(0).isDead();
225 MIBS.push_back(
226 BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(I->Opcode))
227 .addReg(DstReg, RegState::Define |
228 getDeadRegState(DstIsDead && LastItem) |
229 RenamableState)
230 .addReg(DstReg)
231 .addImm(*I->Op1)
232 .addImm(*I->Op2));
233 } break;
234 }
235 }
236 transferImpOps(MI, MIBS.front(), MIBS.back());
237 MI.eraseFromParent();
238 return true;
239}
240
241bool AArch64ExpandPseudoImpl::expandCMP_SWAP(
242 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, unsigned LdarOp,
243 unsigned StlrOp, unsigned CmpOp, unsigned ExtendImm, unsigned ZeroReg,
244 MachineBasicBlock::iterator &NextMBBI) {
245 MachineInstr &MI = *MBBI;
246 MIMetadata MIMD(MI);
247 const MachineOperand &Dest = MI.getOperand(0);
248 Register StatusReg = MI.getOperand(1).getReg();
249 bool StatusDead = MI.getOperand(1).isDead();
250 // Duplicating undef operands into 2 instructions does not guarantee the same
251 // value on both; However undef should be replaced by xzr anyway.
252 assert(!MI.getOperand(2).isUndef() && "cannot handle undef");
253 Register AddrReg = MI.getOperand(2).getReg();
254 Register DesiredReg = MI.getOperand(3).getReg();
255 Register NewReg = MI.getOperand(4).getReg();
256
258 auto LoadCmpBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
259 auto StoreBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
260 auto DoneBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
261
262 MF->insert(++MBB.getIterator(), LoadCmpBB);
263 MF->insert(++LoadCmpBB->getIterator(), StoreBB);
264 MF->insert(++StoreBB->getIterator(), DoneBB);
265
266 // .Lloadcmp:
267 // mov wStatus, 0
268 // ldaxr xDest, [xAddr]
269 // cmp xDest, xDesired
270 // b.ne .Ldone
271 if (!StatusDead)
272 BuildMI(LoadCmpBB, MIMD, TII->get(AArch64::MOVZWi), StatusReg)
273 .addImm(0).addImm(0);
274 BuildMI(LoadCmpBB, MIMD, TII->get(LdarOp), Dest.getReg())
275 .addReg(AddrReg);
276 BuildMI(LoadCmpBB, MIMD, TII->get(CmpOp), ZeroReg)
277 .addReg(Dest.getReg(), getKillRegState(Dest.isDead()))
278 .addReg(DesiredReg)
279 .addImm(ExtendImm);
280 BuildMI(LoadCmpBB, MIMD, TII->get(AArch64::Bcc))
282 .addMBB(DoneBB)
283 .addReg(AArch64::NZCV, RegState::Implicit | RegState::Kill);
284 LoadCmpBB->addSuccessor(DoneBB);
285 LoadCmpBB->addSuccessor(StoreBB);
286
287 // .Lstore:
288 // stlxr wStatus, xNew, [xAddr]
289 // cbnz wStatus, .Lloadcmp
290 BuildMI(StoreBB, MIMD, TII->get(StlrOp), StatusReg)
291 .addReg(NewReg)
292 .addReg(AddrReg);
293 BuildMI(StoreBB, MIMD, TII->get(AArch64::CBNZW))
294 .addReg(StatusReg, getKillRegState(StatusDead))
295 .addMBB(LoadCmpBB);
296 StoreBB->addSuccessor(LoadCmpBB);
297 StoreBB->addSuccessor(DoneBB);
298
299 DoneBB->splice(DoneBB->end(), &MBB, MI, MBB.end());
300 DoneBB->transferSuccessors(&MBB);
301
302 MBB.addSuccessor(LoadCmpBB);
303
304 NextMBBI = MBB.end();
305 MI.eraseFromParent();
306
307 // Recompute livein lists.
308 LivePhysRegs LiveRegs;
309 computeAndAddLiveIns(LiveRegs, *DoneBB);
310 computeAndAddLiveIns(LiveRegs, *StoreBB);
311 computeAndAddLiveIns(LiveRegs, *LoadCmpBB);
312 // Do an extra pass around the loop to get loop carried registers right.
313 StoreBB->clearLiveIns();
314 computeAndAddLiveIns(LiveRegs, *StoreBB);
315 LoadCmpBB->clearLiveIns();
316 computeAndAddLiveIns(LiveRegs, *LoadCmpBB);
317
318 return true;
319}
320
321bool AArch64ExpandPseudoImpl::expandCMP_SWAP_128(
322 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
323 MachineBasicBlock::iterator &NextMBBI) {
324 MachineInstr &MI = *MBBI;
325 MIMetadata MIMD(MI);
326 MachineOperand &DestLo = MI.getOperand(0);
327 MachineOperand &DestHi = MI.getOperand(1);
328 Register StatusReg = MI.getOperand(2).getReg();
329 bool StatusDead = MI.getOperand(2).isDead();
330 // Duplicating undef operands into 2 instructions does not guarantee the same
331 // value on both; However undef should be replaced by xzr anyway.
332 assert(!MI.getOperand(3).isUndef() && "cannot handle undef");
333 Register AddrReg = MI.getOperand(3).getReg();
334 Register DesiredLoReg = MI.getOperand(4).getReg();
335 Register DesiredHiReg = MI.getOperand(5).getReg();
336 Register NewLoReg = MI.getOperand(6).getReg();
337 Register NewHiReg = MI.getOperand(7).getReg();
338
339 auto &STI = MBB.getParent()->getSubtarget<AArch64Subtarget>();
340 bool LittleEndian = STI.isLittleEndian();
341 MachineOperand &Dest0 = LittleEndian ? DestLo : DestHi;
342 MachineOperand &Dest1 = LittleEndian ? DestHi : DestLo;
343 Register New0Reg = LittleEndian ? NewLoReg : NewHiReg;
344 Register New1Reg = LittleEndian ? NewHiReg : NewLoReg;
345
346 unsigned LdxpOp, StxpOp;
347
348 switch (MI.getOpcode()) {
349 case AArch64::CMP_SWAP_128_MONOTONIC:
350 LdxpOp = AArch64::LDXPX;
351 StxpOp = AArch64::STXPX;
352 break;
353 case AArch64::CMP_SWAP_128_RELEASE:
354 LdxpOp = AArch64::LDXPX;
355 StxpOp = AArch64::STLXPX;
356 break;
357 case AArch64::CMP_SWAP_128_ACQUIRE:
358 LdxpOp = AArch64::LDAXPX;
359 StxpOp = AArch64::STXPX;
360 break;
361 case AArch64::CMP_SWAP_128:
362 LdxpOp = AArch64::LDAXPX;
363 StxpOp = AArch64::STLXPX;
364 break;
365 default:
366 llvm_unreachable("Unexpected opcode");
367 }
368
370 auto LoadCmpBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
371 auto StoreBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
372 auto FailBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
373 auto DoneBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
374
375 MF->insert(++MBB.getIterator(), LoadCmpBB);
376 MF->insert(++LoadCmpBB->getIterator(), StoreBB);
377 MF->insert(++StoreBB->getIterator(), FailBB);
378 MF->insert(++FailBB->getIterator(), DoneBB);
379
380 // .Lloadcmp:
381 // ldaxp xDestLo, xDestHi, [xAddr]
382 // cmp xDestLo, xDesiredLo
383 // sbcs xDestHi, xDesiredHi
384 // b.ne .Ldone
385 BuildMI(LoadCmpBB, MIMD, TII->get(LdxpOp))
386 .addReg(Dest0.getReg(), RegState::Define)
387 .addReg(Dest1.getReg(), RegState::Define)
388 .addReg(AddrReg);
389 BuildMI(LoadCmpBB, MIMD, TII->get(AArch64::SUBSXrs), AArch64::XZR)
390 .addReg(DestLo.getReg(), getKillRegState(DestLo.isDead()))
391 .addReg(DesiredLoReg)
392 .addImm(0);
393 BuildMI(LoadCmpBB, MIMD, TII->get(AArch64::CSINCWr), StatusReg)
394 .addUse(AArch64::WZR)
395 .addUse(AArch64::WZR)
397 BuildMI(LoadCmpBB, MIMD, TII->get(AArch64::SUBSXrs), AArch64::XZR)
398 .addReg(DestHi.getReg(), getKillRegState(DestHi.isDead()))
399 .addReg(DesiredHiReg)
400 .addImm(0);
401 BuildMI(LoadCmpBB, MIMD, TII->get(AArch64::CSINCWr), StatusReg)
402 .addUse(StatusReg, RegState::Kill)
403 .addUse(StatusReg, RegState::Kill)
405 BuildMI(LoadCmpBB, MIMD, TII->get(AArch64::CBNZW))
406 .addUse(StatusReg, getKillRegState(StatusDead))
407 .addMBB(FailBB);
408 LoadCmpBB->addSuccessor(FailBB);
409 LoadCmpBB->addSuccessor(StoreBB);
410
411 // .Lstore:
412 // stlxp wStatus, xNewLo, xNewHi, [xAddr]
413 // cbnz wStatus, .Lloadcmp
414 BuildMI(StoreBB, MIMD, TII->get(StxpOp), StatusReg)
415 .addReg(New0Reg)
416 .addReg(New1Reg)
417 .addReg(AddrReg);
418 BuildMI(StoreBB, MIMD, TII->get(AArch64::CBNZW))
419 .addReg(StatusReg, getKillRegState(StatusDead))
420 .addMBB(LoadCmpBB);
421 BuildMI(StoreBB, MIMD, TII->get(AArch64::B)).addMBB(DoneBB);
422 StoreBB->addSuccessor(LoadCmpBB);
423 StoreBB->addSuccessor(DoneBB);
424
425 // .Lfail:
426 // stlxp wStatus, xDestLo, xDestHi, [xAddr]
427 // cbnz wStatus, .Lloadcmp
428 BuildMI(FailBB, MIMD, TII->get(StxpOp), StatusReg)
429 .addReg(Dest0.getReg())
430 .addReg(Dest1.getReg())
431 .addReg(AddrReg);
432 BuildMI(FailBB, MIMD, TII->get(AArch64::CBNZW))
433 .addReg(StatusReg, getKillRegState(StatusDead))
434 .addMBB(LoadCmpBB);
435 FailBB->addSuccessor(LoadCmpBB);
436 FailBB->addSuccessor(DoneBB);
437
438 DoneBB->splice(DoneBB->end(), &MBB, MI, MBB.end());
439 DoneBB->transferSuccessors(&MBB);
440
441 MBB.addSuccessor(LoadCmpBB);
442
443 NextMBBI = MBB.end();
444 MI.eraseFromParent();
445
446 // Recompute liveness bottom up.
447 LivePhysRegs LiveRegs;
448 computeAndAddLiveIns(LiveRegs, *DoneBB);
449 computeAndAddLiveIns(LiveRegs, *FailBB);
450 computeAndAddLiveIns(LiveRegs, *StoreBB);
451 computeAndAddLiveIns(LiveRegs, *LoadCmpBB);
452
453 // Do an extra pass in the loop to get the loop carried dependencies right.
454 FailBB->clearLiveIns();
455 computeAndAddLiveIns(LiveRegs, *FailBB);
456 StoreBB->clearLiveIns();
457 computeAndAddLiveIns(LiveRegs, *StoreBB);
458 LoadCmpBB->clearLiveIns();
459 computeAndAddLiveIns(LiveRegs, *LoadCmpBB);
460
461 return true;
462}
463
464/// \brief Expand Pseudos to Instructions with destructive operands.
465///
466/// This mechanism uses MOVPRFX instructions for zeroing the false lanes
467/// or for fixing relaxed register allocation conditions to comply with
468/// the instructions register constraints. The latter case may be cheaper
469/// than setting the register constraints in the register allocator,
470/// since that will insert regular MOV instructions rather than MOVPRFX.
471///
472/// Example (after register allocation):
473///
474/// FSUB_ZPZZ_ZERO_B Z0, Pg, Z1, Z0
475///
476/// * The Pseudo FSUB_ZPZZ_ZERO_B maps to FSUB_ZPmZ_B.
477/// * We cannot map directly to FSUB_ZPmZ_B because the register
478/// constraints of the instruction are not met.
479/// * Also the _ZERO specifies the false lanes need to be zeroed.
480///
481/// We first try to see if the destructive operand == result operand,
482/// if not, we try to swap the operands, e.g.
483///
484/// FSUB_ZPmZ_B Z0, Pg/m, Z0, Z1
485///
486/// But because FSUB_ZPmZ is not commutative, this is semantically
487/// different, so we need a reverse instruction:
488///
489/// FSUBR_ZPmZ_B Z0, Pg/m, Z0, Z1
490///
491/// Then we implement the zeroing of the false lanes of Z0 by adding
492/// a zeroing MOVPRFX instruction:
493///
494/// MOVPRFX_ZPzZ_B Z0, Pg/z, Z0
495/// FSUBR_ZPmZ_B Z0, Pg/m, Z0, Z1
496///
497/// Note that this can only be done for _ZERO or _UNDEF variants where
498/// we can guarantee the false lanes to be zeroed (by implementing this)
499/// or that they are undef (don't care / not used), otherwise the
500/// swapping of operands is illegal because the operation is not
501/// (or cannot be emulated to be) fully commutative.
502bool AArch64ExpandPseudoImpl::expand_DestructiveOp(
503 MachineInstr &MI, MachineBasicBlock &MBB,
505 unsigned Opcode = AArch64::getSVEPseudoMap(MI.getOpcode());
506 uint64_t DType = TII->get(Opcode).TSFlags & AArch64::DestructiveInstTypeMask;
507 uint64_t FalseLanes = MI.getDesc().TSFlags & AArch64::FalseLanesMask;
508 bool FalseZero = FalseLanes == AArch64::FalseLanesZero;
509 Register DstReg = MI.getOperand(0).getReg();
510 bool DstIsDead = MI.getOperand(0).isDead();
511 bool UseRev = false;
512 unsigned PredIdx, DOPIdx, SrcIdx, Src2Idx;
513
514 switch (DType) {
517 if (DstReg == MI.getOperand(3).getReg()) {
518 // FSUB Zd, Pg, Zs1, Zd ==> FSUBR Zd, Pg/m, Zd, Zs1
519 std::tie(PredIdx, DOPIdx, SrcIdx) = std::make_tuple(1, 3, 2);
520 UseRev = true;
521 break;
522 }
523 [[fallthrough]];
526 std::tie(PredIdx, DOPIdx, SrcIdx) = std::make_tuple(1, 2, 3);
527 break;
529 std::tie(PredIdx, DOPIdx, SrcIdx) = std::make_tuple(2, 3, 3);
530 break;
532 std::tie(PredIdx, DOPIdx, SrcIdx, Src2Idx) = std::make_tuple(1, 2, 3, 4);
533 if (DstReg == MI.getOperand(3).getReg()) {
534 // FMLA Zd, Pg, Za, Zd, Zm ==> FMAD Zdn, Pg, Zm, Za
535 std::tie(PredIdx, DOPIdx, SrcIdx, Src2Idx) = std::make_tuple(1, 3, 4, 2);
536 UseRev = true;
537 } else if (DstReg == MI.getOperand(4).getReg()) {
538 // FMLA Zd, Pg, Za, Zm, Zd ==> FMAD Zdn, Pg, Zm, Za
539 std::tie(PredIdx, DOPIdx, SrcIdx, Src2Idx) = std::make_tuple(1, 4, 3, 2);
540 UseRev = true;
541 }
542 break;
544 // EXT_ZZI_CONSTRUCTIVE Zd, Zs, Imm
545 // ==> MOVPRFX Zd Zs; EXT_ZZI Zd, Zd, Zs, Imm
546 std::tie(DOPIdx, SrcIdx, Src2Idx) = std::make_tuple(1, 1, 2);
547 break;
549 std::tie(DOPIdx, SrcIdx) = std::make_tuple(1, 2);
550 break;
552 std::tie(DOPIdx, SrcIdx, Src2Idx) = std::make_tuple(1, 2, 3);
553 break;
554 default:
555 llvm_unreachable("Unsupported Destructive Operand type");
556 }
557
558 // MOVPRFX can only be used if the destination operand
559 // is the destructive operand, not as any other operand,
560 // so the Destructive Operand must be unique.
561 bool DOPRegIsUnique = false;
562 switch (DType) {
564 DOPRegIsUnique = DstReg != MI.getOperand(SrcIdx).getReg();
565 break;
568 DOPRegIsUnique =
569 DstReg != MI.getOperand(DOPIdx).getReg() ||
570 MI.getOperand(DOPIdx).getReg() != MI.getOperand(SrcIdx).getReg();
571 break;
577 DOPRegIsUnique = true;
578 break;
580 DOPRegIsUnique =
581 DstReg != MI.getOperand(DOPIdx).getReg() ||
582 (MI.getOperand(DOPIdx).getReg() != MI.getOperand(SrcIdx).getReg() &&
583 MI.getOperand(DOPIdx).getReg() != MI.getOperand(Src2Idx).getReg());
584 break;
585 }
586
587 // Resolve the reverse opcode
588 if (UseRev) {
589 int NewOpcode;
590 // e.g. DIV -> DIVR
591 if ((NewOpcode = AArch64::getSVERevInstr(Opcode)) != -1)
592 Opcode = NewOpcode;
593 // e.g. DIVR -> DIV
594 else if ((NewOpcode = AArch64::getSVENonRevInstr(Opcode)) != -1)
595 Opcode = NewOpcode;
596 }
597
598 // Get the right MOVPRFX
599 uint64_t ElementSize = TII->getElementSizeForOpcode(Opcode);
600 unsigned MovPrfx, LSLZero, MovPrfxZero;
601 switch (ElementSize) {
604 MovPrfx = AArch64::MOVPRFX_ZZ;
605 LSLZero = AArch64::LSL_ZPmI_B;
606 MovPrfxZero = AArch64::MOVPRFX_ZPzZ_B;
607 break;
609 MovPrfx = AArch64::MOVPRFX_ZZ;
610 LSLZero = AArch64::LSL_ZPmI_H;
611 MovPrfxZero = AArch64::MOVPRFX_ZPzZ_H;
612 break;
614 MovPrfx = AArch64::MOVPRFX_ZZ;
615 LSLZero = AArch64::LSL_ZPmI_S;
616 MovPrfxZero = AArch64::MOVPRFX_ZPzZ_S;
617 break;
619 MovPrfx = AArch64::MOVPRFX_ZZ;
620 LSLZero = AArch64::LSL_ZPmI_D;
621 MovPrfxZero = AArch64::MOVPRFX_ZPzZ_D;
622 break;
623 default:
624 llvm_unreachable("Unsupported ElementSize");
625 }
626
627 // Preserve undef state until DOP's reg is defined.
628 RegState DOPRegState = getUndefRegState(MI.getOperand(DOPIdx).isUndef());
629
630 //
631 // Create the destructive operation (if required)
632 //
633 MachineInstrBuilder PRFX, DOP;
634 if (FalseZero) {
635 // If we cannot prefix the requested instruction we'll instead emit a
636 // prefixed_zeroing_mov for DestructiveBinary.
637 assert((DOPRegIsUnique || DType == AArch64::DestructiveBinary ||
640 "The destructive operand should be unique");
641 assert(ElementSize != AArch64::ElementSizeNone &&
642 "This instruction is unpredicated");
643
644 // Merge source operand into destination register
645 PRFX = BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(MovPrfxZero))
646 .addReg(DstReg, RegState::Define)
647 .addReg(MI.getOperand(PredIdx).getReg())
648 .addReg(MI.getOperand(DOPIdx).getReg(), DOPRegState);
649
650 // After the movprfx, the destructive operand is same as Dst
651 DOPIdx = 0;
652 DOPRegState = {};
653
654 // Create the additional LSL to zero the lanes when the DstReg is not
655 // unique. Zeros the lanes in z0 that aren't active in p0 with sequence
656 // movprfx z0.b, p0/z, z0.b; lsl z0.b, p0/m, z0.b, #0;
657 if ((DType == AArch64::DestructiveBinary ||
660 !DOPRegIsUnique) {
661 BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(LSLZero))
662 .addReg(DstReg, RegState::Define)
663 .add(MI.getOperand(PredIdx))
664 .addReg(DstReg)
665 .addImm(0);
666 }
667 } else if (DstReg != MI.getOperand(DOPIdx).getReg()) {
668 assert(DOPRegIsUnique && "The destructive operand should be unique");
669 PRFX = BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(MovPrfx))
670 .addReg(DstReg, RegState::Define)
671 .addReg(MI.getOperand(DOPIdx).getReg(), DOPRegState);
672 DOPIdx = 0;
673 DOPRegState = {};
674 }
675
676 //
677 // Create the destructive operation
678 //
679 DOP = BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(Opcode))
680 .addReg(DstReg, RegState::Define | getDeadRegState(DstIsDead));
681 DOPRegState = DOPRegState | RegState::Kill;
682
683 switch (DType) {
685 DOP.addReg(MI.getOperand(DOPIdx).getReg(), DOPRegState)
686 .add(MI.getOperand(PredIdx))
687 .add(MI.getOperand(SrcIdx));
688 break;
693 DOP.add(MI.getOperand(PredIdx))
694 .addReg(MI.getOperand(DOPIdx).getReg(), DOPRegState)
695 .add(MI.getOperand(SrcIdx));
696 break;
698 DOP.add(MI.getOperand(PredIdx))
699 .addReg(MI.getOperand(DOPIdx).getReg(), DOPRegState)
700 .add(MI.getOperand(SrcIdx))
701 .add(MI.getOperand(Src2Idx));
702 break;
704 DOP.addReg(MI.getOperand(DOPIdx).getReg(), DOPRegState)
705 .add(MI.getOperand(SrcIdx));
706 break;
709 DOP.addReg(MI.getOperand(DOPIdx).getReg(), DOPRegState)
710 .add(MI.getOperand(SrcIdx))
711 .add(MI.getOperand(Src2Idx));
712 break;
713 }
714
715 if (PRFX) {
716 transferImpOps(MI, PRFX, DOP);
718 } else
719 transferImpOps(MI, DOP, DOP);
720
721 MI.eraseFromParent();
722 return true;
723}
724
725bool AArch64ExpandPseudoImpl::expandSVEBitwisePseudo(
726 MachineInstr &MI, MachineBasicBlock &MBB,
728 MachineInstrBuilder PRFX, DOP;
729 const unsigned Opcode = MI.getOpcode();
730 const MachineOperand &Op0 = MI.getOperand(0);
731 const MachineOperand *Op1 = &MI.getOperand(1);
732 const MachineOperand *Op2 = &MI.getOperand(2);
733 const Register DOPReg = Op0.getReg();
734
735 if (DOPReg == Op2->getReg()) {
736 // Commute the operands to allow destroying the second source.
737 std::swap(Op1, Op2);
738 } else if (DOPReg != Op1->getReg()) {
739 // If not in destructive form, emit a MOVPRFX. The input should only be
740 // killed if unused by the subsequent instruction.
741 PRFX = BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::MOVPRFX_ZZ))
743 .addReg(Op1->getReg(),
745 getUndefRegState(Op1->isUndef()) |
746 getKillRegState(Op1->isKill() &&
747 Opcode == AArch64::NAND_ZZZ));
748 }
749
750 assert((DOPReg == Op1->getReg() || PRFX) && "invalid expansion");
751
752 const RegState DOPRegState = getRenamableRegState(Op0.isRenamable()) |
753 getUndefRegState(!PRFX && Op1->isUndef()) |
754 RegState::Kill;
755
756 switch (Opcode) {
757 default:
758 llvm_unreachable("unhandled opcode");
759 case AArch64::EON_ZZZ:
760 DOP = BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::BSL2N_ZZZZ))
761 .add(Op0)
762 .addReg(DOPReg, DOPRegState)
763 .add(*Op1)
764 .add(*Op2);
765 break;
766 case AArch64::NAND_ZZZ:
767 DOP = BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::NBSL_ZZZZ))
768 .add(Op0)
769 .addReg(DOPReg, DOPRegState)
770 .add(*Op2)
771 .add(*Op2);
772 break;
773 case AArch64::NOR_ZZZ:
774 DOP = BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::NBSL_ZZZZ))
775 .add(Op0)
776 .addReg(DOPReg, DOPRegState)
777 .add(*Op2)
778 .add(*Op1);
779 break;
780 }
781
782 if (PRFX) {
783 transferImpOps(MI, PRFX, DOP);
785 } else {
786 transferImpOps(MI, DOP, DOP);
787 }
788
789 MI.eraseFromParent();
790 return true;
791}
792
793bool AArch64ExpandPseudoImpl::expandSetTagLoop(
794 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
795 MachineBasicBlock::iterator &NextMBBI) {
796 MachineInstr &MI = *MBBI;
797 DebugLoc DL = MI.getDebugLoc();
798 Register SizeReg = MI.getOperand(0).getReg();
799 Register AddressReg = MI.getOperand(1).getReg();
800
802
803 bool ZeroData = MI.getOpcode() == AArch64::STZGloop_wback;
804 const unsigned OpCode1 =
805 ZeroData ? AArch64::STZGPostIndex : AArch64::STGPostIndex;
806 const unsigned OpCode2 =
807 ZeroData ? AArch64::STZ2GPostIndex : AArch64::ST2GPostIndex;
808
809 unsigned Size = MI.getOperand(2).getImm();
810 assert(Size > 0 && Size % 16 == 0);
811 if (Size % (16 * 2) != 0) {
812 BuildMI(MBB, MBBI, DL, TII->get(OpCode1), AddressReg)
813 .addReg(AddressReg)
814 .addReg(AddressReg)
815 .addImm(1);
816 Size -= 16;
817 }
819 BuildMI(MBB, MBBI, DL, TII->get(AArch64::MOVi64imm), SizeReg)
820 .addImm(Size);
821 expandMOVImm(MBB, I, 64);
822
823 auto LoopBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
824 auto DoneBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
825
826 MF->insert(++MBB.getIterator(), LoopBB);
827 MF->insert(++LoopBB->getIterator(), DoneBB);
828
829 BuildMI(LoopBB, DL, TII->get(OpCode2))
830 .addDef(AddressReg)
831 .addReg(AddressReg)
832 .addReg(AddressReg)
833 .addImm(2)
835 .setMIFlags(MI.getFlags());
836 BuildMI(LoopBB, DL, TII->get(AArch64::SUBSXri))
837 .addDef(SizeReg)
838 .addReg(SizeReg)
839 .addImm(16 * 2)
840 .addImm(0);
841 BuildMI(LoopBB, DL, TII->get(AArch64::Bcc))
843 .addMBB(LoopBB)
844 .addReg(AArch64::NZCV, RegState::Implicit | RegState::Kill);
845
846 LoopBB->addSuccessor(LoopBB);
847 LoopBB->addSuccessor(DoneBB);
848
849 DoneBB->splice(DoneBB->end(), &MBB, MI, MBB.end());
850 DoneBB->transferSuccessors(&MBB);
851
852 MBB.addSuccessor(LoopBB);
853
854 NextMBBI = MBB.end();
855 MI.eraseFromParent();
856 // Recompute liveness bottom up.
857 LivePhysRegs LiveRegs;
858 computeAndAddLiveIns(LiveRegs, *DoneBB);
859 computeAndAddLiveIns(LiveRegs, *LoopBB);
860 // Do an extra pass in the loop to get the loop carried dependencies right.
861 // FIXME: is this necessary?
862 LoopBB->clearLiveIns();
863 computeAndAddLiveIns(LiveRegs, *LoopBB);
864 DoneBB->clearLiveIns();
865 computeAndAddLiveIns(LiveRegs, *DoneBB);
866
867 return true;
868}
869
870bool AArch64ExpandPseudoImpl::expandSVESpillFill(
871 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, unsigned Opc,
872 unsigned N) {
873 assert((Opc == AArch64::LDR_ZXI || Opc == AArch64::STR_ZXI ||
874 Opc == AArch64::LDR_PXI || Opc == AArch64::STR_PXI) &&
875 "Unexpected opcode");
876 RegState RState =
877 getDefRegState(Opc == AArch64::LDR_ZXI || Opc == AArch64::LDR_PXI);
878 unsigned sub0 = (Opc == AArch64::LDR_ZXI || Opc == AArch64::STR_ZXI)
879 ? AArch64::zsub0
880 : AArch64::psub0;
881 const TargetRegisterInfo *TRI =
883 MachineInstr &MI = *MBBI;
884 for (unsigned Offset = 0; Offset < N; ++Offset) {
885 int ImmOffset = MI.getOperand(2).getImm() + Offset;
886 bool Kill = (Offset + 1 == N) ? MI.getOperand(1).isKill() : false;
887 assert(ImmOffset >= -256 && ImmOffset < 256 &&
888 "Immediate spill offset out of range");
889 BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(Opc))
890 .addReg(TRI->getSubReg(MI.getOperand(0).getReg(), sub0 + Offset),
891 RState)
892 .addReg(MI.getOperand(1).getReg(), getKillRegState(Kill))
893 .addImm(ImmOffset);
894 }
896 return true;
897}
898
899// Create a call with the passed opcode and explicit operands, copying over all
900// the implicit operands from *MBBI, starting at the regmask.
903 const AArch64InstrInfo *TII,
904 unsigned Opcode,
905 ArrayRef<MachineOperand> ExplicitOps,
906 unsigned RegMaskStartIdx) {
907 // Be careful not to duplicate the LR def which the original instruction
908 // already carries.
909 MachineFunction &MF = *MBB.getParent();
911 MF.CreateMachineInstr(TII->get(Opcode), MBBI->getDebugLoc(),
912 /*NoImplicit=*/true);
913 MBB.insert(MBBI, Call);
914 MachineInstrBuilder(MF, Call).add(ExplicitOps);
915
916 // Register arguments are added during ISel, but cannot be added as explicit
917 // operands of the branch as it expects to be B <target> which is only one
918 // operand. Instead they are implicit operands used by the branch.
919 while (!MBBI->getOperand(RegMaskStartIdx).isRegMask()) {
920 const MachineOperand &MOP = MBBI->getOperand(RegMaskStartIdx);
921 assert(MOP.isReg() && "can only add register operands");
923 MOP.getReg(), /*Def=*/false, /*Implicit=*/true, /*isKill=*/false,
924 /*isDead=*/false, /*isUndef=*/MOP.isUndef()));
925 RegMaskStartIdx++;
926 }
927 for (const MachineOperand &MO :
928 llvm::drop_begin(MBBI->operands(), RegMaskStartIdx))
929 Call->addOperand(MO);
930
931 return Call;
932}
933
934// Create a call to CallTarget, copying over all the operands from *MBBI,
935// starting at the regmask.
938 const AArch64InstrInfo *TII,
939 MachineOperand &CallTarget,
940 unsigned RegMaskStartIdx) {
941 unsigned Opc = CallTarget.isGlobal() ? AArch64::BL : AArch64::BLR;
942
943 assert((CallTarget.isGlobal() || CallTarget.isReg()) &&
944 "invalid operand for regular call");
945 return createCallWithOps(MBB, MBBI, TII, Opc, CallTarget, RegMaskStartIdx);
946}
947
948bool AArch64ExpandPseudoImpl::expandCALL_RVMARKER(
949 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI) {
950 // Expand CALL_RVMARKER pseudo to:
951 // - a branch to the call target, followed by
952 // - the special `mov x29, x29` marker, if necessary, and
953 // - another branch, to the runtime function
954 // Mark the sequence as bundle, to avoid passes moving other code in between.
955 MachineInstr &MI = *MBBI;
956 MachineOperand &RVTarget = MI.getOperand(0);
957 bool DoEmitMarker = MI.getOperand(1).getImm();
958 assert(RVTarget.isGlobal() && "invalid operand for attached call");
959
960 MachineInstr *OriginalCall = nullptr;
961
962 if (MI.getOpcode() == AArch64::BLRA_RVMARKER) {
963 // ptrauth call.
964 const MachineOperand &CallTarget = MI.getOperand(2);
965 const MachineOperand &Key = MI.getOperand(3);
966 const MachineOperand &IntDisc = MI.getOperand(4);
967 const MachineOperand &AddrDisc = MI.getOperand(5);
968
969 assert((Key.getImm() == AArch64PACKey::IA ||
970 Key.getImm() == AArch64PACKey::IB) &&
971 "Invalid auth call key");
972
973 MachineOperand Ops[] = {CallTarget, Key, IntDisc, AddrDisc};
974
975 OriginalCall = createCallWithOps(MBB, MBBI, TII, AArch64::BLRA, Ops,
976 /*RegMaskStartIdx=*/6);
977 } else {
978 assert(MI.getOpcode() == AArch64::BLR_RVMARKER && "unknown rvmarker MI");
979 OriginalCall = createCall(MBB, MBBI, TII, MI.getOperand(2),
980 // Regmask starts after the RV and call targets.
981 /*RegMaskStartIdx=*/3);
982 }
983
984 if (DoEmitMarker)
985 BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::ORRXrs))
986 .addReg(AArch64::FP, RegState::Define)
987 .addReg(AArch64::XZR)
988 .addReg(AArch64::FP)
989 .addImm(0);
990
991 auto *RVCall = BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::BL))
992 .add(RVTarget)
993 .getInstr();
994
995 if (MI.shouldUpdateAdditionalCallInfo())
996 MBB.getParent()->moveAdditionalCallInfo(&MI, OriginalCall);
997
998 MI.eraseFromParent();
999 finalizeBundle(MBB, OriginalCall->getIterator(),
1000 std::next(RVCall->getIterator()));
1001 return true;
1002}
1003
1004bool AArch64ExpandPseudoImpl::expandCALL_BTI(MachineBasicBlock &MBB,
1006 // Expand CALL_BTI pseudo to:
1007 // - a branch to the call target
1008 // - a BTI instruction
1009 // Mark the sequence as a bundle, to avoid passes moving other code in
1010 // between.
1011 MachineInstr &MI = *MBBI;
1012 MachineInstr *Call = createCall(MBB, MBBI, TII, MI.getOperand(0),
1013 // Regmask starts after the call target.
1014 /*RegMaskStartIdx=*/1);
1015
1016 Call->setCFIType(*MBB.getParent(), MI.getCFIType());
1017
1018 MachineInstr *BTI =
1019 BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::HINT))
1020 // BTI J so that setjmp can to BR to this.
1021 .addImm(36)
1022 .getInstr();
1023
1024 if (MI.shouldUpdateAdditionalCallInfo())
1026
1027 MI.eraseFromParent();
1028 finalizeBundle(MBB, Call->getIterator(), std::next(BTI->getIterator()));
1029 return true;
1030}
1031
1032bool AArch64ExpandPseudoImpl::expandStoreSwiftAsyncContext(
1033 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI) {
1034 Register CtxReg = MBBI->getOperand(0).getReg();
1035 Register BaseReg = MBBI->getOperand(1).getReg();
1036 int Offset = MBBI->getOperand(2).getImm();
1037 DebugLoc DL(MBBI->getDebugLoc());
1038 auto &STI = MBB.getParent()->getSubtarget<AArch64Subtarget>();
1039
1040 if (STI.getTargetTriple().getArchName() != "arm64e") {
1041 BuildMI(MBB, MBBI, DL, TII->get(AArch64::STRXui))
1042 .addUse(CtxReg)
1043 .addUse(BaseReg)
1044 .addImm(Offset / 8)
1047 return true;
1048 }
1049
1050 // We need to sign the context in an address-discriminated way. 0xc31a is a
1051 // fixed random value, chosen as part of the ABI.
1052 // add x16, xBase, #Offset
1053 // movk x16, #0xc31a, lsl #48
1054 // mov x17, x22/xzr
1055 // pacdb x17, x16
1056 // str x17, [xBase, #Offset]
1057 unsigned Opc = Offset >= 0 ? AArch64::ADDXri : AArch64::SUBXri;
1058 BuildMI(MBB, MBBI, DL, TII->get(Opc), AArch64::X16)
1059 .addUse(BaseReg)
1060 .addImm(abs(Offset))
1061 .addImm(0)
1063 BuildMI(MBB, MBBI, DL, TII->get(AArch64::MOVKXi), AArch64::X16)
1064 .addUse(AArch64::X16)
1065 .addImm(0xc31a)
1066 .addImm(48)
1068 // We're not allowed to clobber X22 (and couldn't clobber XZR if we tried), so
1069 // move it somewhere before signing.
1070 BuildMI(MBB, MBBI, DL, TII->get(AArch64::ORRXrs), AArch64::X17)
1071 .addUse(AArch64::XZR)
1072 .addUse(CtxReg)
1073 .addImm(0)
1075 BuildMI(MBB, MBBI, DL, TII->get(AArch64::PACDB), AArch64::X17)
1076 .addUse(AArch64::X17)
1077 .addUse(AArch64::X16)
1079 BuildMI(MBB, MBBI, DL, TII->get(AArch64::STRXui))
1080 .addUse(AArch64::X17)
1081 .addUse(BaseReg)
1082 .addImm(Offset / 8)
1084
1086 return true;
1087}
1088
1089AArch64ExpandPseudoImpl::ConditionalBlocks
1090AArch64ExpandPseudoImpl::expandConditionalPseudo(
1091 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, DebugLoc DL,
1092 MachineInstrBuilder &Branch) {
1093 assert((std::next(MBBI) != MBB.end() ||
1094 MBB.successors().begin() != MBB.successors().end()) &&
1095 "Unexpected unreachable in block");
1096
1097 // Split MBB and create two new blocks:
1098 // - MBB now contains all instructions before the conditional pseudo.
1099 // - CondBB contains the conditional pseudo instruction only.
1100 // - EndBB contains all instructions after the conditional pseudo.
1101 MachineInstr &PrevMI = *std::prev(MBBI);
1102 MachineBasicBlock *CondBB = MBB.splitAt(PrevMI, /*UpdateLiveIns*/ true);
1103 MachineBasicBlock *EndBB =
1104 std::next(MBBI) == CondBB->end()
1105 ? *CondBB->successors().begin()
1106 : CondBB->splitAt(*MBBI, /*UpdateLiveIns*/ true);
1107
1108 // Add the SMBB label to the branch instruction & create a branch to EndBB.
1109 Branch.addMBB(CondBB);
1110 BuildMI(&MBB, DL, TII->get(AArch64::B))
1111 .addMBB(EndBB);
1112 MBB.addSuccessor(EndBB);
1113
1114 // Create branch from CondBB to EndBB. Users of this helper should insert new
1115 // instructions at CondBB.back() -- i.e. before the branch.
1116 BuildMI(CondBB, DL, TII->get(AArch64::B)).addMBB(EndBB);
1117 return {*CondBB, *EndBB};
1118}
1119
1120MachineBasicBlock *
1121AArch64ExpandPseudoImpl::expandRestoreZASave(MachineBasicBlock &MBB,
1123 MachineInstr &MI = *MBBI;
1124 DebugLoc DL = MI.getDebugLoc();
1125
1126 // Compare TPIDR2_EL0 against 0. Restore ZA if TPIDR2_EL0 is zero.
1127 MachineInstrBuilder Branch =
1128 BuildMI(MBB, MBBI, DL, TII->get(AArch64::CBZX)).add(MI.getOperand(0));
1129
1130 auto [CondBB, EndBB] = expandConditionalPseudo(MBB, MBBI, DL, Branch);
1131 // Replace the pseudo with a call (BL).
1132 MachineInstrBuilder MIB =
1133 BuildMI(CondBB, CondBB.back(), DL, TII->get(AArch64::BL));
1134 // Copy operands (mainly the regmask) from the pseudo.
1135 for (unsigned I = 2; I < MI.getNumOperands(); ++I)
1136 MIB.add(MI.getOperand(I));
1137 // Mark the TPIDR2 block pointer (X0) as an implicit use.
1138 MIB.addReg(MI.getOperand(1).getReg(), RegState::Implicit);
1139
1140 MI.eraseFromParent();
1141 return &EndBB;
1142}
1143
1144static constexpr unsigned ZERO_ALL_ZA_MASK = 0b11111111;
1145
1147AArch64ExpandPseudoImpl::expandCommitZASave(MachineBasicBlock &MBB,
1149 MachineInstr &MI = *MBBI;
1150 DebugLoc DL = MI.getDebugLoc();
1151 [[maybe_unused]] auto *RI = MBB.getParent()->getSubtarget().getRegisterInfo();
1152
1153 // Compare TPIDR2_EL0 against 0. Commit ZA if TPIDR2_EL0 is non-zero.
1154 MachineInstrBuilder Branch =
1155 BuildMI(MBB, MBBI, DL, TII->get(AArch64::CBNZX)).add(MI.getOperand(0));
1156
1157 auto [CondBB, EndBB] = expandConditionalPseudo(MBB, MBBI, DL, Branch);
1158 // Replace the pseudo with a call (BL).
1160 BuildMI(CondBB, CondBB.back(), DL, TII->get(AArch64::BL));
1161 // Copy operands (mainly the regmask) from the pseudo.
1162 for (unsigned I = 3; I < MI.getNumOperands(); ++I)
1163 MIB.add(MI.getOperand(I));
1164 // Clear TPIDR2_EL0.
1165 BuildMI(CondBB, CondBB.back(), DL, TII->get(AArch64::MSR))
1166 .addImm(AArch64SysReg::TPIDR2_EL0)
1167 .addReg(AArch64::XZR);
1168 bool ZeroZA = MI.getOperand(1).getImm() != 0;
1169 bool ZeroZT0 = MI.getOperand(2).getImm() != 0;
1170 if (ZeroZA) {
1171 assert(MI.definesRegister(AArch64::ZAB0, RI) && "should define ZA!");
1172 BuildMI(CondBB, CondBB.back(), DL, TII->get(AArch64::ZERO_M))
1174 .addDef(AArch64::ZAB0, RegState::ImplicitDefine);
1175 }
1176 if (ZeroZT0) {
1177 assert(MI.definesRegister(AArch64::ZT0, RI) && "should define ZT0!");
1178 BuildMI(CondBB, CondBB.back(), DL, TII->get(AArch64::ZERO_T))
1179 .addDef(AArch64::ZT0);
1180 }
1181
1182 MI.eraseFromParent();
1183 return &EndBB;
1184}
1185
1186MachineBasicBlock *
1187AArch64ExpandPseudoImpl::expandCondSMToggle(MachineBasicBlock &MBB,
1189 MachineInstr &MI = *MBBI;
1190 // In the case of a smstart/smstop before a unreachable, just remove the pseudo.
1191 // Exception handling code generated by Clang may introduce unreachables and it
1192 // seems unnecessary to restore pstate.sm when that happens. Note that it is
1193 // not just an optimisation, the code below expects a successor instruction/block
1194 // in order to split the block at MBBI.
1195 if (std::next(MBBI) == MBB.end() &&
1196 MI.getParent()->successors().begin() ==
1197 MI.getParent()->successors().end()) {
1198 MI.eraseFromParent();
1199 return &MBB;
1200 }
1201
1202 // Expand the pseudo into smstart or smstop instruction. The pseudo has the
1203 // following operands:
1204 //
1205 // MSRpstatePseudo <za|sm|both>, <0|1>, condition[, pstate.sm], <regmask>
1206 //
1207 // The pseudo is expanded into a conditional smstart/smstop, with a
1208 // check if pstate.sm (register) equals the expected value, and if not,
1209 // invokes the smstart/smstop.
1210 //
1211 // As an example, the following block contains a normal call from a
1212 // streaming-compatible function:
1213 //
1214 // OrigBB:
1215 // MSRpstatePseudo 3, 0, IfCallerIsStreaming, %0, <regmask> <- Cond SMSTOP
1216 // bl @normal_callee
1217 // MSRpstatePseudo 3, 1, IfCallerIsStreaming, %0, <regmask> <- Cond SMSTART
1218 //
1219 // ...which will be transformed into:
1220 //
1221 // OrigBB:
1222 // TBNZx %0:gpr64, 0, SMBB
1223 // b EndBB
1224 //
1225 // SMBB:
1226 // MSRpstatesvcrImm1 3, 0, <regmask> <- SMSTOP
1227 //
1228 // EndBB:
1229 // bl @normal_callee
1230 // MSRcond_pstatesvcrImm1 3, 1, <regmask> <- SMSTART
1231 //
1232 DebugLoc DL = MI.getDebugLoc();
1233
1234 // Create the conditional branch based on the third operand of the
1235 // instruction, which tells us if we are wrapping a normal or streaming
1236 // function.
1237 // We test the live value of pstate.sm and toggle pstate.sm if this is not the
1238 // expected value for the callee (0 for a normal callee and 1 for a streaming
1239 // callee).
1240 unsigned Opc;
1241 switch (MI.getOperand(2).getImm()) {
1242 case AArch64SME::Always:
1243 llvm_unreachable("Should have matched to instruction directly");
1245 Opc = AArch64::TBNZW;
1246 break;
1248 Opc = AArch64::TBZW;
1249 break;
1250 }
1251 auto PStateSM = MI.getOperand(3).getReg();
1253 unsigned SMReg32 = TRI->getSubReg(PStateSM, AArch64::sub_32);
1254 MachineInstrBuilder Tbx =
1255 BuildMI(MBB, MBBI, DL, TII->get(Opc)).addReg(SMReg32).addImm(0);
1256
1257 auto [CondBB, EndBB] = expandConditionalPseudo(MBB, MBBI, DL, Tbx);
1258 // Create the SMSTART/SMSTOP (MSRpstatesvcrImm1) instruction in SMBB.
1259 MachineInstrBuilder MIB = BuildMI(CondBB, CondBB.back(), MI.getDebugLoc(),
1260 TII->get(AArch64::MSRpstatesvcrImm1));
1261 // Copy all but the second and third operands of MSRcond_pstatesvcrImm1 (as
1262 // these contain the CopyFromReg for the first argument and the flag to
1263 // indicate whether the callee is streaming or normal).
1264 MIB.add(MI.getOperand(0));
1265 MIB.add(MI.getOperand(1));
1266 for (unsigned i = 4; i < MI.getNumOperands(); ++i)
1267 MIB.add(MI.getOperand(i));
1268
1269 MI.eraseFromParent();
1270 return &EndBB;
1271}
1272
1273bool AArch64ExpandPseudoImpl::expandMultiVecPseudo(
1274 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
1275 const TargetRegisterClass &ContiguousClass,
1276 const TargetRegisterClass &StridedClass, unsigned ContiguousOp,
1277 unsigned StridedOpc) {
1278 MachineInstr &MI = *MBBI;
1279 Register Tuple = MI.getOperand(0).getReg();
1280
1281 auto ContiguousRange = ContiguousClass.getRegisters();
1282 auto StridedRange = StridedClass.getRegisters();
1283 unsigned Opc;
1284 if (llvm::is_contained(ContiguousRange, Tuple.asMCReg())) {
1285 Opc = ContiguousOp;
1286 } else if (llvm::is_contained(StridedRange, Tuple.asMCReg())) {
1287 Opc = StridedOpc;
1288 } else
1289 llvm_unreachable("Cannot expand Multi-Vector pseudo");
1290
1291 MachineInstrBuilder MIB = BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(Opc))
1292 .add(MI.getOperand(0))
1293 .add(MI.getOperand(1))
1294 .add(MI.getOperand(2))
1295 .add(MI.getOperand(3));
1296 transferImpOps(MI, MIB, MIB);
1297 MI.eraseFromParent();
1298 return true;
1299}
1300
1301bool AArch64ExpandPseudoImpl::expandCopyIntoTuplePseudo(
1302 MachineInstr &MI, MachineBasicBlock &MBB,
1304 Register Src = MI.getOperand(1).getReg();
1305 Register Dest = MI.getOperand(0).getReg();
1306
1307 if (Src != Dest)
1308 BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::ORR_ZZZ))
1309 .addReg(Dest, RegState::Define)
1310 .addReg(Src)
1311 .addReg(Src);
1312
1313 MI.eraseFromParent();
1314 return true;
1315}
1316
1317/// If MBBI references a pseudo instruction that should be expanded here,
1318/// do the expansion and return true. Otherwise return false.
1319bool AArch64ExpandPseudoImpl::expandMI(MachineBasicBlock &MBB,
1321 MachineBasicBlock::iterator &NextMBBI) {
1322 MachineInstr &MI = *MBBI;
1323 unsigned Opcode = MI.getOpcode();
1324
1325 // Check if we can expand the destructive op
1326 int OrigInstr = AArch64::getSVEPseudoMap(MI.getOpcode());
1327 if (OrigInstr != -1) {
1328 auto &Orig = TII->get(OrigInstr);
1329 if ((Orig.TSFlags & AArch64::DestructiveInstTypeMask) !=
1331 return expand_DestructiveOp(MI, MBB, MBBI);
1332 }
1333 }
1334
1335 switch (Opcode) {
1336 default:
1337 break;
1338
1339 case AArch64::BSPv8i8:
1340 case AArch64::BSPv16i8: {
1341 Register DstReg = MI.getOperand(0).getReg();
1342 if (DstReg == MI.getOperand(3).getReg()) {
1343 // Expand to BIT
1344 auto I = BuildMI(MBB, MBBI, MI.getDebugLoc(),
1345 TII->get(Opcode == AArch64::BSPv8i8 ? AArch64::BITv8i8
1346 : AArch64::BITv16i8))
1347 .add(MI.getOperand(0))
1348 .add(MI.getOperand(3))
1349 .add(MI.getOperand(2))
1350 .add(MI.getOperand(1));
1351 transferImpOps(MI, I, I);
1352 } else if (DstReg == MI.getOperand(2).getReg()) {
1353 // Expand to BIF
1354 auto I = BuildMI(MBB, MBBI, MI.getDebugLoc(),
1355 TII->get(Opcode == AArch64::BSPv8i8 ? AArch64::BIFv8i8
1356 : AArch64::BIFv16i8))
1357 .add(MI.getOperand(0))
1358 .add(MI.getOperand(2))
1359 .add(MI.getOperand(3))
1360 .add(MI.getOperand(1));
1361 transferImpOps(MI, I, I);
1362 } else {
1363 // Expand to BSL, use additional move if required
1364 const auto &ST = MBB.getParent()->getSubtarget<AArch64Subtarget>();
1365 if (DstReg == MI.getOperand(1).getReg()) {
1366 auto I =
1367 BuildMI(MBB, MBBI, MI.getDebugLoc(),
1368 TII->get(Opcode == AArch64::BSPv8i8 ? AArch64::BSLv8i8
1369 : AArch64::BSLv16i8))
1370 .add(MI.getOperand(0))
1371 .add(MI.getOperand(1))
1372 .add(MI.getOperand(2))
1373 .add(MI.getOperand(3));
1374 transferImpOps(MI, I, I);
1375 } else if (Opcode == AArch64::BSPv16i8 &&
1376 ST.isSVEorStreamingSVEAvailable() &&
1377 (ST.hasSVE2() || ST.hasSME())) {
1378 // Expand BSPv16i8 with MOVPRFX + BSL. Don't expand BSPv8i8 as FPR64
1379 // defs are assumed to zero the upper bits.
1380 const TargetRegisterInfo &TRI = TII->getRegisterInfo();
1381 auto getZReg = [&TRI](const MachineOperand &MO) -> Register {
1382 return TRI.getMatchingSuperReg(MO.getReg(), AArch64::zsub,
1383 &AArch64::ZPRRegClass);
1384 };
1385 const MachineOperand &Dst = MI.getOperand(0);
1386 const MachineOperand &Mask = MI.getOperand(1);
1387 const MachineOperand &TVal = MI.getOperand(2);
1388 const MachineOperand &FVal = MI.getOperand(3);
1389 Register DOPReg = getZReg(Dst);
1390 auto PRFX =
1391 BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::MOVPRFX_ZZ))
1392 .addDef(DOPReg, getRenamableRegState(Dst.isRenamable()))
1393 .addReg(getZReg(TVal),
1395 getUndefRegState(TVal.isUndef()) |
1396 getKillRegState(TVal.isKill() &&
1397 TVal.getReg() != Mask.getReg() &&
1398 TVal.getReg() != FVal.getReg()));
1399 auto DOP =
1400 BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::BSL_ZZZZ))
1401 .addDef(DOPReg, getDeadRegState(Dst.isDead()) |
1402 getRenamableRegState(Dst.isRenamable()))
1403 .addReg(DOPReg, RegState::Kill |
1404 getRenamableRegState(Dst.isRenamable()))
1405 .addReg(getZReg(FVal),
1407 getUndefRegState(FVal.isUndef()) |
1408 getKillRegState(FVal.isKill()))
1409 .addReg(getZReg(Mask),
1410 getRenamableRegState(Mask.isRenamable()) |
1411 getUndefRegState(Mask.isUndef()) |
1412 getKillRegState(Mask.isKill()));
1413 transferImpOps(MI, PRFX, DOP);
1415 } else {
1417 getRenamableRegState(MI.getOperand(1).isRenamable()) |
1418 getUndefRegState(MI.getOperand(1).isUndef()) |
1420 MI.getOperand(1).isKill() &&
1421 MI.getOperand(1).getReg() != MI.getOperand(2).getReg() &&
1422 MI.getOperand(1).getReg() != MI.getOperand(3).getReg());
1423 BuildMI(MBB, MBBI, MI.getDebugLoc(),
1424 TII->get(Opcode == AArch64::BSPv8i8 ? AArch64::ORRv8i8
1425 : AArch64::ORRv16i8))
1426 .addReg(DstReg,
1427 RegState::Define |
1428 getRenamableRegState(MI.getOperand(0).isRenamable()))
1429 .addReg(MI.getOperand(1).getReg(), RegState)
1430 .addReg(MI.getOperand(1).getReg(), RegState);
1431 auto I2 =
1432 BuildMI(MBB, MBBI, MI.getDebugLoc(),
1433 TII->get(Opcode == AArch64::BSPv8i8 ? AArch64::BSLv8i8
1434 : AArch64::BSLv16i8))
1435 .add(MI.getOperand(0))
1436 .addReg(DstReg,
1437 RegState::Kill | getRenamableRegState(
1438 MI.getOperand(0).isRenamable()))
1439 .add(MI.getOperand(2))
1440 .add(MI.getOperand(3));
1441 transferImpOps(MI, I2, I2);
1442 }
1443 }
1444 MI.eraseFromParent();
1445 return true;
1446 }
1447
1448 case AArch64::ADDWrr:
1449 case AArch64::SUBWrr:
1450 case AArch64::ADDXrr:
1451 case AArch64::SUBXrr:
1452 case AArch64::ADDSWrr:
1453 case AArch64::SUBSWrr:
1454 case AArch64::ADDSXrr:
1455 case AArch64::SUBSXrr:
1456 case AArch64::ANDWrr:
1457 case AArch64::ANDXrr:
1458 case AArch64::BICWrr:
1459 case AArch64::BICXrr:
1460 case AArch64::ANDSWrr:
1461 case AArch64::ANDSXrr:
1462 case AArch64::BICSWrr:
1463 case AArch64::BICSXrr:
1464 case AArch64::EONWrr:
1465 case AArch64::EONXrr:
1466 case AArch64::EORWrr:
1467 case AArch64::EORXrr:
1468 case AArch64::ORNWrr:
1469 case AArch64::ORNXrr:
1470 case AArch64::ORRWrr:
1471 case AArch64::ORRXrr: {
1472 unsigned Opcode;
1473 switch (MI.getOpcode()) {
1474 default:
1475 return false;
1476 case AArch64::ADDWrr: Opcode = AArch64::ADDWrs; break;
1477 case AArch64::SUBWrr: Opcode = AArch64::SUBWrs; break;
1478 case AArch64::ADDXrr: Opcode = AArch64::ADDXrs; break;
1479 case AArch64::SUBXrr: Opcode = AArch64::SUBXrs; break;
1480 case AArch64::ADDSWrr: Opcode = AArch64::ADDSWrs; break;
1481 case AArch64::SUBSWrr: Opcode = AArch64::SUBSWrs; break;
1482 case AArch64::ADDSXrr: Opcode = AArch64::ADDSXrs; break;
1483 case AArch64::SUBSXrr: Opcode = AArch64::SUBSXrs; break;
1484 case AArch64::ANDWrr: Opcode = AArch64::ANDWrs; break;
1485 case AArch64::ANDXrr: Opcode = AArch64::ANDXrs; break;
1486 case AArch64::BICWrr: Opcode = AArch64::BICWrs; break;
1487 case AArch64::BICXrr: Opcode = AArch64::BICXrs; break;
1488 case AArch64::ANDSWrr: Opcode = AArch64::ANDSWrs; break;
1489 case AArch64::ANDSXrr: Opcode = AArch64::ANDSXrs; break;
1490 case AArch64::BICSWrr: Opcode = AArch64::BICSWrs; break;
1491 case AArch64::BICSXrr: Opcode = AArch64::BICSXrs; break;
1492 case AArch64::EONWrr: Opcode = AArch64::EONWrs; break;
1493 case AArch64::EONXrr: Opcode = AArch64::EONXrs; break;
1494 case AArch64::EORWrr: Opcode = AArch64::EORWrs; break;
1495 case AArch64::EORXrr: Opcode = AArch64::EORXrs; break;
1496 case AArch64::ORNWrr: Opcode = AArch64::ORNWrs; break;
1497 case AArch64::ORNXrr: Opcode = AArch64::ORNXrs; break;
1498 case AArch64::ORRWrr: Opcode = AArch64::ORRWrs; break;
1499 case AArch64::ORRXrr: Opcode = AArch64::ORRXrs; break;
1500 }
1501 MachineFunction &MF = *MBB.getParent();
1502 // Try to create new inst without implicit operands added.
1503 MachineInstr *NewMI = MF.CreateMachineInstr(
1504 TII->get(Opcode), MI.getDebugLoc(), /*NoImplicit=*/true);
1505 MBB.insert(MBBI, NewMI);
1506 MachineInstrBuilder MIB1(MF, NewMI);
1507 MIB1->setPCSections(MF, MI.getPCSections());
1508 MIB1.addReg(MI.getOperand(0).getReg(), RegState::Define)
1509 .add(MI.getOperand(1))
1510 .add(MI.getOperand(2))
1512 transferImpOps(MI, MIB1, MIB1);
1513 if (auto DebugNumber = MI.peekDebugInstrNum())
1514 NewMI->setDebugInstrNum(DebugNumber);
1515 MI.eraseFromParent();
1516 return true;
1517 }
1518
1519 case AArch64::LOADgot: {
1521 Register DstReg = MI.getOperand(0).getReg();
1522 const MachineOperand &MO1 = MI.getOperand(1);
1523 unsigned Flags = MO1.getTargetFlags();
1524
1525 if (MF->getTarget().getCodeModel() == CodeModel::Tiny) {
1526 // Tiny codemodel expand to LDR
1527 MachineInstrBuilder MIB = BuildMI(MBB, MBBI, MI.getDebugLoc(),
1528 TII->get(AArch64::LDRXl), DstReg);
1529
1530 if (MO1.isGlobal()) {
1531 MIB.addGlobalAddress(MO1.getGlobal(), 0, Flags);
1532 } else if (MO1.isSymbol()) {
1533 MIB.addExternalSymbol(MO1.getSymbolName(), Flags);
1534 } else {
1535 assert(MO1.isCPI() &&
1536 "Only expect globals, externalsymbols, or constant pools");
1537 MIB.addConstantPoolIndex(MO1.getIndex(), MO1.getOffset(), Flags);
1538 }
1539 } else {
1540 // Small codemodel expand into ADRP + LDR.
1541 MachineFunction &MF = *MI.getParent()->getParent();
1542 DebugLoc DL = MI.getDebugLoc();
1543 MachineInstrBuilder MIB1 =
1544 BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::ADRP), DstReg);
1545
1546 MachineInstrBuilder MIB2;
1547 if (MF.getSubtarget<AArch64Subtarget>().isTargetILP32()) {
1549 unsigned Reg32 = TRI->getSubReg(DstReg, AArch64::sub_32);
1550 MIB2 = BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::LDRWui))
1551 .addDef(Reg32)
1552 .addReg(DstReg, RegState::Kill)
1553 .addReg(DstReg, RegState::Implicit);
1554 } else {
1555 Register DstReg = MI.getOperand(0).getReg();
1556 MIB2 = BuildMI(MBB, MBBI, DL, TII->get(AArch64::LDRXui))
1557 .add(MI.getOperand(0))
1558 .addUse(DstReg, RegState::Kill);
1559 }
1560
1561 if (MO1.isGlobal()) {
1562 MIB1.addGlobalAddress(MO1.getGlobal(), 0, Flags | AArch64II::MO_PAGE);
1563 MIB2.addGlobalAddress(MO1.getGlobal(), 0,
1565 } else if (MO1.isSymbol()) {
1567 MIB2.addExternalSymbol(MO1.getSymbolName(), Flags |
1570 } else {
1571 assert(MO1.isCPI() &&
1572 "Only expect globals, externalsymbols, or constant pools");
1573 MIB1.addConstantPoolIndex(MO1.getIndex(), MO1.getOffset(),
1574 Flags | AArch64II::MO_PAGE);
1575 MIB2.addConstantPoolIndex(MO1.getIndex(), MO1.getOffset(),
1576 Flags | AArch64II::MO_PAGEOFF |
1578 }
1579
1580 // If the LOADgot instruction has a debug-instr-number, annotate the
1581 // LDRWui instruction that it is expanded to with the same
1582 // debug-instr-number to preserve debug information.
1583 if (MI.peekDebugInstrNum() != 0)
1584 MIB2->setDebugInstrNum(MI.peekDebugInstrNum());
1585 transferImpOps(MI, MIB1, MIB2);
1586 }
1587 MI.eraseFromParent();
1588 return true;
1589 }
1590 case AArch64::MOVaddrBA:
1591 case AArch64::MOVaddr:
1592 case AArch64::MOVaddrJT:
1593 case AArch64::MOVaddrCP:
1594 case AArch64::MOVaddrTLS:
1595 case AArch64::MOVaddrEXT: {
1596 MachineFunction &MF = *MI.getParent()->getParent();
1597 Register DstReg = MI.getOperand(0).getReg();
1598 assert(DstReg != AArch64::XZR);
1599
1600 bool IsTargetMachO = MF.getSubtarget<AArch64Subtarget>().isTargetMachO();
1603 MI.getOpcode(), MI.getOperand(1).getTargetFlags(), IsTargetMachO, Insn);
1604
1605 // Compute the constant pool index, if any.
1606 std::optional<unsigned> CPIdx;
1607 if (Opcode == AArch64::MOVaddrBA && IsTargetMachO) {
1608 // blockaddress expressions have to come from a constant pool because the
1609 // largest addend (and hence offset within a function) allowed for ADRP is
1610 // only 8MB.
1611 const BlockAddress *BA = MI.getOperand(1).getBlockAddress();
1612 assert(MI.getOperand(1).getOffset() == 0 && "unexpected offset");
1613 MachineConstantPool *MCP = MF.getConstantPool();
1614 CPIdx = MCP->getConstantPoolIndex(BA, Align(8));
1615 }
1616
1617 MachineInstrBuilder FirstMIB;
1618 MachineInstrBuilder LastMIB;
1619 for (const auto &I : Insn) {
1620 MachineInstrBuilder MIB;
1621 switch (I.Opcode) {
1622 case AArch64::ADRP:
1623 MIB = BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::ADRP),
1624 DstReg);
1625 if (CPIdx)
1627 else
1628 MIB.add(MI.getOperand(1));
1629 break;
1630 case AArch64::LDRXui:
1631 MIB = BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::LDRXui),
1632 DstReg)
1633 .addUse(DstReg)
1636 break;
1637 case AArch64::MOVKXi: {
1638 // MO_TAGGED on the page indicates a tagged address. Set the tag now.
1639 // We do so by creating a MOVK that sets bits 48-63 of the register to
1640 // (global address + 0x100000000 - PC) >> 48. This assumes that we're in
1641 // the small code model so we can assume a binary size of <= 4GB, which
1642 // makes the untagged PC relative offset positive. The binary must also
1643 // be loaded into address range [0, 2^48). Both of these properties need
1644 // to be ensured at runtime when using tagged addresses.
1645 auto Tag = MI.getOperand(1);
1646 Tag.setTargetFlags(AArch64II::MO_PREL | AArch64II::MO_G3);
1647 Tag.setOffset(0x100000000);
1648 MIB = BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::MOVKXi),
1649 DstReg)
1650 .addReg(DstReg)
1651 .add(Tag)
1652 .addImm(48);
1653 break;
1654 }
1655 case AArch64::ADDXri:
1656 MIB = BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::ADDXri))
1657 .add(MI.getOperand(0))
1658 .addReg(DstReg)
1659 .add(MI.getOperand(2))
1660 .addImm(0);
1661 break;
1662 default:
1663 llvm_unreachable("unexpected opcode in MOVaddr expansion");
1664 }
1665
1666 if (!FirstMIB.getInstr())
1667 FirstMIB = MIB;
1668 LastMIB = MIB;
1669 }
1670
1671 transferImpOps(MI, FirstMIB, LastMIB);
1672 MI.eraseFromParent();
1673 return true;
1674 }
1675 case AArch64::ADDlowTLS:
1676 // Produce a plain ADD
1677 BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::ADDXri))
1678 .add(MI.getOperand(0))
1679 .add(MI.getOperand(1))
1680 .add(MI.getOperand(2))
1681 .addImm(0);
1682 MI.eraseFromParent();
1683 return true;
1684
1685 case AArch64::MOVbaseTLS: {
1686 Register DstReg = MI.getOperand(0).getReg();
1687 auto SysReg = AArch64SysReg::TPIDR_EL0;
1689 if (MF->getSubtarget<AArch64Subtarget>().useEL3ForTP())
1690 SysReg = AArch64SysReg::TPIDR_EL3;
1691 else if (MF->getSubtarget<AArch64Subtarget>().useEL2ForTP())
1692 SysReg = AArch64SysReg::TPIDR_EL2;
1693 else if (MF->getSubtarget<AArch64Subtarget>().useEL1ForTP())
1694 SysReg = AArch64SysReg::TPIDR_EL1;
1695 else if (MF->getSubtarget<AArch64Subtarget>().useROEL0ForTP())
1696 SysReg = AArch64SysReg::TPIDRRO_EL0;
1697 BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::MRS), DstReg)
1698 .addImm(SysReg);
1699 MI.eraseFromParent();
1700 return true;
1701 }
1702
1703 case AArch64::MOVi32imm:
1704 return expandMOVImm(MBB, MBBI, 32);
1705 case AArch64::MOVi64imm:
1706 return expandMOVImm(MBB, MBBI, 64);
1707 case AArch64::RET_ReallyLR: {
1708 // Hiding the LR use with RET_ReallyLR may lead to extra kills in the
1709 // function and missing live-ins. We are fine in practice because callee
1710 // saved register handling ensures the register value is restored before
1711 // RET, but we need the undef flag here to appease the MachineVerifier
1712 // liveness checks.
1713 MachineInstrBuilder MIB =
1714 BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::RET))
1715 .addReg(AArch64::LR, RegState::Undef);
1716 transferImpOps(MI, MIB, MIB);
1717 MI.eraseFromParent();
1718 return true;
1719 }
1720 case AArch64::CMP_SWAP_8:
1721 return expandCMP_SWAP(MBB, MBBI, AArch64::LDAXRB, AArch64::STLXRB,
1722 AArch64::SUBSWrx,
1724 AArch64::WZR, NextMBBI);
1725 case AArch64::CMP_SWAP_16:
1726 return expandCMP_SWAP(MBB, MBBI, AArch64::LDAXRH, AArch64::STLXRH,
1727 AArch64::SUBSWrx,
1729 AArch64::WZR, NextMBBI);
1730 case AArch64::CMP_SWAP_32:
1731 return expandCMP_SWAP(MBB, MBBI, AArch64::LDAXRW, AArch64::STLXRW,
1732 AArch64::SUBSWrs,
1734 AArch64::WZR, NextMBBI);
1735 case AArch64::CMP_SWAP_64:
1736 return expandCMP_SWAP(MBB, MBBI,
1737 AArch64::LDAXRX, AArch64::STLXRX, AArch64::SUBSXrs,
1739 AArch64::XZR, NextMBBI);
1740 case AArch64::CMP_SWAP_128:
1741 case AArch64::CMP_SWAP_128_RELEASE:
1742 case AArch64::CMP_SWAP_128_ACQUIRE:
1743 case AArch64::CMP_SWAP_128_MONOTONIC:
1744 return expandCMP_SWAP_128(MBB, MBBI, NextMBBI);
1745
1746 case AArch64::AESMCrrTied:
1747 case AArch64::AESIMCrrTied: {
1748 MachineInstrBuilder MIB =
1749 BuildMI(MBB, MBBI, MI.getDebugLoc(),
1750 TII->get(Opcode == AArch64::AESMCrrTied ? AArch64::AESMCrr :
1751 AArch64::AESIMCrr))
1752 .add(MI.getOperand(0))
1753 .add(MI.getOperand(1));
1754 transferImpOps(MI, MIB, MIB);
1755 MI.eraseFromParent();
1756 return true;
1757 }
1758 case AArch64::IRGstack: {
1759 MachineFunction &MF = *MBB.getParent();
1760 const AArch64FunctionInfo *AFI = MF.getInfo<AArch64FunctionInfo>();
1761 const AArch64FrameLowering *TFI =
1762 MF.getSubtarget<AArch64Subtarget>().getFrameLowering();
1763
1764 // IRG does not allow immediate offset. getTaggedBasePointerOffset should
1765 // almost always point to SP-after-prologue; if not, emit a longer
1766 // instruction sequence.
1767 int BaseOffset = -AFI->getTaggedBasePointerOffset();
1768 Register FrameReg;
1769 StackOffset FrameRegOffset = TFI->resolveFrameOffsetReference(
1770 MF, BaseOffset, false /*isFixed*/, TargetStackID::Default /*StackID*/,
1771 FrameReg,
1772 /*PreferFP=*/false,
1773 /*ForSimm=*/true);
1774 Register SrcReg = FrameReg;
1775 if (FrameRegOffset) {
1776 // Use output register as temporary.
1777 SrcReg = MI.getOperand(0).getReg();
1778 emitFrameOffset(MBB, &MI, MI.getDebugLoc(), SrcReg, FrameReg,
1779 FrameRegOffset, TII);
1780 }
1781 BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::IRG))
1782 .add(MI.getOperand(0))
1783 .addUse(SrcReg)
1784 .add(MI.getOperand(2));
1785 MI.eraseFromParent();
1786 return true;
1787 }
1788 case AArch64::TAGPstack: {
1789 int64_t Offset = MI.getOperand(2).getImm();
1790 BuildMI(MBB, MBBI, MI.getDebugLoc(),
1791 TII->get(Offset >= 0 ? AArch64::ADDG : AArch64::SUBG))
1792 .add(MI.getOperand(0))
1793 .add(MI.getOperand(1))
1794 .addImm(std::abs(Offset))
1795 .add(MI.getOperand(4));
1796 MI.eraseFromParent();
1797 return true;
1798 }
1799 case AArch64::STGloop_wback:
1800 case AArch64::STZGloop_wback:
1801 return expandSetTagLoop(MBB, MBBI, NextMBBI);
1802 case AArch64::STGloop:
1803 case AArch64::STZGloop:
1805 "Non-writeback variants of STGloop / STZGloop should not "
1806 "survive past PrologEpilogInserter.");
1807 case AArch64::STR_ZZZZXI:
1808 case AArch64::STR_ZZZZXI_STRIDED_CONTIGUOUS:
1809 return expandSVESpillFill(MBB, MBBI, AArch64::STR_ZXI, 4);
1810 case AArch64::STR_ZZZXI:
1811 return expandSVESpillFill(MBB, MBBI, AArch64::STR_ZXI, 3);
1812 case AArch64::STR_ZZXI:
1813 case AArch64::STR_ZZXI_STRIDED_CONTIGUOUS:
1814 return expandSVESpillFill(MBB, MBBI, AArch64::STR_ZXI, 2);
1815 case AArch64::STR_PPXI:
1816 return expandSVESpillFill(MBB, MBBI, AArch64::STR_PXI, 2);
1817 case AArch64::LDR_ZZZZXI:
1818 case AArch64::LDR_ZZZZXI_STRIDED_CONTIGUOUS:
1819 return expandSVESpillFill(MBB, MBBI, AArch64::LDR_ZXI, 4);
1820 case AArch64::LDR_ZZZXI:
1821 return expandSVESpillFill(MBB, MBBI, AArch64::LDR_ZXI, 3);
1822 case AArch64::LDR_ZZXI:
1823 case AArch64::LDR_ZZXI_STRIDED_CONTIGUOUS:
1824 return expandSVESpillFill(MBB, MBBI, AArch64::LDR_ZXI, 2);
1825 case AArch64::LDR_PPXI:
1826 return expandSVESpillFill(MBB, MBBI, AArch64::LDR_PXI, 2);
1827 case AArch64::BLR_RVMARKER:
1828 case AArch64::BLRA_RVMARKER:
1829 return expandCALL_RVMARKER(MBB, MBBI);
1830 case AArch64::BLR_BTI:
1831 return expandCALL_BTI(MBB, MBBI);
1832 case AArch64::StoreSwiftAsyncContext:
1833 return expandStoreSwiftAsyncContext(MBB, MBBI);
1834 case AArch64::RestoreZAPseudo:
1835 case AArch64::CommitZASavePseudo:
1836 case AArch64::MSRpstatePseudo: {
1837 auto *NewMBB = [&] {
1838 switch (Opcode) {
1839 case AArch64::RestoreZAPseudo:
1840 return expandRestoreZASave(MBB, MBBI);
1841 case AArch64::CommitZASavePseudo:
1842 return expandCommitZASave(MBB, MBBI);
1843 case AArch64::MSRpstatePseudo:
1844 return expandCondSMToggle(MBB, MBBI);
1845 default:
1846 llvm_unreachable("Unexpected conditional pseudo!");
1847 }
1848 }();
1849 if (NewMBB != &MBB)
1850 NextMBBI = MBB.end(); // The NextMBBI iterator is invalidated.
1851 return true;
1852 }
1853 case AArch64::InOutZAUsePseudo:
1854 case AArch64::RequiresZASavePseudo:
1855 case AArch64::RequiresZT0SavePseudo:
1856 case AArch64::SMEStateAllocPseudo:
1857 case AArch64::COALESCER_BARRIER_FPR16:
1858 case AArch64::COALESCER_BARRIER_FPR32:
1859 case AArch64::COALESCER_BARRIER_FPR64:
1860 case AArch64::COALESCER_BARRIER_FPR128:
1861 MI.eraseFromParent();
1862 return true;
1863 case AArch64::LD1B_2Z_IMM_PSEUDO:
1864 return expandMultiVecPseudo(
1865 MBB, MBBI, AArch64::ZPR2RegClass, AArch64::ZPR2StridedRegClass,
1866 AArch64::LD1B_2Z_IMM, AArch64::LD1B_2Z_STRIDED_IMM);
1867 case AArch64::LD1H_2Z_IMM_PSEUDO:
1868 return expandMultiVecPseudo(
1869 MBB, MBBI, AArch64::ZPR2RegClass, AArch64::ZPR2StridedRegClass,
1870 AArch64::LD1H_2Z_IMM, AArch64::LD1H_2Z_STRIDED_IMM);
1871 case AArch64::LD1W_2Z_IMM_PSEUDO:
1872 return expandMultiVecPseudo(
1873 MBB, MBBI, AArch64::ZPR2RegClass, AArch64::ZPR2StridedRegClass,
1874 AArch64::LD1W_2Z_IMM, AArch64::LD1W_2Z_STRIDED_IMM);
1875 case AArch64::LD1D_2Z_IMM_PSEUDO:
1876 return expandMultiVecPseudo(
1877 MBB, MBBI, AArch64::ZPR2RegClass, AArch64::ZPR2StridedRegClass,
1878 AArch64::LD1D_2Z_IMM, AArch64::LD1D_2Z_STRIDED_IMM);
1879 case AArch64::LDNT1B_2Z_IMM_PSEUDO:
1880 return expandMultiVecPseudo(
1881 MBB, MBBI, AArch64::ZPR2RegClass, AArch64::ZPR2StridedRegClass,
1882 AArch64::LDNT1B_2Z_IMM, AArch64::LDNT1B_2Z_STRIDED_IMM);
1883 case AArch64::LDNT1H_2Z_IMM_PSEUDO:
1884 return expandMultiVecPseudo(
1885 MBB, MBBI, AArch64::ZPR2RegClass, AArch64::ZPR2StridedRegClass,
1886 AArch64::LDNT1H_2Z_IMM, AArch64::LDNT1H_2Z_STRIDED_IMM);
1887 case AArch64::LDNT1W_2Z_IMM_PSEUDO:
1888 return expandMultiVecPseudo(
1889 MBB, MBBI, AArch64::ZPR2RegClass, AArch64::ZPR2StridedRegClass,
1890 AArch64::LDNT1W_2Z_IMM, AArch64::LDNT1W_2Z_STRIDED_IMM);
1891 case AArch64::LDNT1D_2Z_IMM_PSEUDO:
1892 return expandMultiVecPseudo(
1893 MBB, MBBI, AArch64::ZPR2RegClass, AArch64::ZPR2StridedRegClass,
1894 AArch64::LDNT1D_2Z_IMM, AArch64::LDNT1D_2Z_STRIDED_IMM);
1895 case AArch64::ST1B_2Z_IMM_PSEUDO:
1896 return expandMultiVecPseudo(
1897 MBB, MBBI, AArch64::ZPR2RegClass, AArch64::ZPR2StridedRegClass,
1898 AArch64::ST1B_2Z_IMM, AArch64::ST1B_2Z_STRIDED_IMM);
1899 case AArch64::ST1H_2Z_IMM_PSEUDO:
1900 return expandMultiVecPseudo(
1901 MBB, MBBI, AArch64::ZPR2RegClass, AArch64::ZPR2StridedRegClass,
1902 AArch64::ST1H_2Z_IMM, AArch64::ST1H_2Z_STRIDED_IMM);
1903 case AArch64::ST1W_2Z_IMM_PSEUDO:
1904 return expandMultiVecPseudo(
1905 MBB, MBBI, AArch64::ZPR2RegClass, AArch64::ZPR2StridedRegClass,
1906 AArch64::ST1W_2Z_IMM, AArch64::ST1W_2Z_STRIDED_IMM);
1907 case AArch64::ST1D_2Z_IMM_PSEUDO:
1908 return expandMultiVecPseudo(
1909 MBB, MBBI, AArch64::ZPR2RegClass, AArch64::ZPR2StridedRegClass,
1910 AArch64::ST1D_2Z_IMM, AArch64::ST1D_2Z_STRIDED_IMM);
1911 case AArch64::STNT1B_2Z_IMM_PSEUDO:
1912 return expandMultiVecPseudo(
1913 MBB, MBBI, AArch64::ZPR2RegClass, AArch64::ZPR2StridedRegClass,
1914 AArch64::STNT1B_2Z_IMM, AArch64::STNT1B_2Z_STRIDED_IMM);
1915 case AArch64::STNT1H_2Z_IMM_PSEUDO:
1916 return expandMultiVecPseudo(
1917 MBB, MBBI, AArch64::ZPR2RegClass, AArch64::ZPR2StridedRegClass,
1918 AArch64::STNT1H_2Z_IMM, AArch64::STNT1H_2Z_STRIDED_IMM);
1919 case AArch64::STNT1W_2Z_IMM_PSEUDO:
1920 return expandMultiVecPseudo(
1921 MBB, MBBI, AArch64::ZPR2RegClass, AArch64::ZPR2StridedRegClass,
1922 AArch64::STNT1W_2Z_IMM, AArch64::STNT1W_2Z_STRIDED_IMM);
1923 case AArch64::STNT1D_2Z_IMM_PSEUDO:
1924 return expandMultiVecPseudo(
1925 MBB, MBBI, AArch64::ZPR2RegClass, AArch64::ZPR2StridedRegClass,
1926 AArch64::STNT1D_2Z_IMM, AArch64::STNT1D_2Z_STRIDED_IMM);
1927 case AArch64::LD1B_2Z_PSEUDO:
1928 return expandMultiVecPseudo(MBB, MBBI, AArch64::ZPR2RegClass,
1929 AArch64::ZPR2StridedRegClass, AArch64::LD1B_2Z,
1930 AArch64::LD1B_2Z_STRIDED);
1931 case AArch64::LD1H_2Z_PSEUDO:
1932 return expandMultiVecPseudo(MBB, MBBI, AArch64::ZPR2RegClass,
1933 AArch64::ZPR2StridedRegClass, AArch64::LD1H_2Z,
1934 AArch64::LD1H_2Z_STRIDED);
1935 case AArch64::LD1W_2Z_PSEUDO:
1936 return expandMultiVecPseudo(MBB, MBBI, AArch64::ZPR2RegClass,
1937 AArch64::ZPR2StridedRegClass, AArch64::LD1W_2Z,
1938 AArch64::LD1W_2Z_STRIDED);
1939 case AArch64::LD1D_2Z_PSEUDO:
1940 return expandMultiVecPseudo(MBB, MBBI, AArch64::ZPR2RegClass,
1941 AArch64::ZPR2StridedRegClass, AArch64::LD1D_2Z,
1942 AArch64::LD1D_2Z_STRIDED);
1943 case AArch64::LDNT1B_2Z_PSEUDO:
1944 return expandMultiVecPseudo(MBB, MBBI, AArch64::ZPR2RegClass,
1945 AArch64::ZPR2StridedRegClass,
1946 AArch64::LDNT1B_2Z, AArch64::LDNT1B_2Z_STRIDED);
1947 case AArch64::LDNT1H_2Z_PSEUDO:
1948 return expandMultiVecPseudo(MBB, MBBI, AArch64::ZPR2RegClass,
1949 AArch64::ZPR2StridedRegClass,
1950 AArch64::LDNT1H_2Z, AArch64::LDNT1H_2Z_STRIDED);
1951 case AArch64::LDNT1W_2Z_PSEUDO:
1952 return expandMultiVecPseudo(MBB, MBBI, AArch64::ZPR2RegClass,
1953 AArch64::ZPR2StridedRegClass,
1954 AArch64::LDNT1W_2Z, AArch64::LDNT1W_2Z_STRIDED);
1955 case AArch64::LDNT1D_2Z_PSEUDO:
1956 return expandMultiVecPseudo(MBB, MBBI, AArch64::ZPR2RegClass,
1957 AArch64::ZPR2StridedRegClass,
1958 AArch64::LDNT1D_2Z, AArch64::LDNT1D_2Z_STRIDED);
1959 case AArch64::LD1B_4Z_IMM_PSEUDO:
1960 return expandMultiVecPseudo(
1961 MBB, MBBI, AArch64::ZPR4RegClass, AArch64::ZPR4StridedRegClass,
1962 AArch64::LD1B_4Z_IMM, AArch64::LD1B_4Z_STRIDED_IMM);
1963 case AArch64::LD1H_4Z_IMM_PSEUDO:
1964 return expandMultiVecPseudo(
1965 MBB, MBBI, AArch64::ZPR4RegClass, AArch64::ZPR4StridedRegClass,
1966 AArch64::LD1H_4Z_IMM, AArch64::LD1H_4Z_STRIDED_IMM);
1967 case AArch64::LD1W_4Z_IMM_PSEUDO:
1968 return expandMultiVecPseudo(
1969 MBB, MBBI, AArch64::ZPR4RegClass, AArch64::ZPR4StridedRegClass,
1970 AArch64::LD1W_4Z_IMM, AArch64::LD1W_4Z_STRIDED_IMM);
1971 case AArch64::LD1D_4Z_IMM_PSEUDO:
1972 return expandMultiVecPseudo(
1973 MBB, MBBI, AArch64::ZPR4RegClass, AArch64::ZPR4StridedRegClass,
1974 AArch64::LD1D_4Z_IMM, AArch64::LD1D_4Z_STRIDED_IMM);
1975 case AArch64::LDNT1B_4Z_IMM_PSEUDO:
1976 return expandMultiVecPseudo(
1977 MBB, MBBI, AArch64::ZPR4RegClass, AArch64::ZPR4StridedRegClass,
1978 AArch64::LDNT1B_4Z_IMM, AArch64::LDNT1B_4Z_STRIDED_IMM);
1979 case AArch64::LDNT1H_4Z_IMM_PSEUDO:
1980 return expandMultiVecPseudo(
1981 MBB, MBBI, AArch64::ZPR4RegClass, AArch64::ZPR4StridedRegClass,
1982 AArch64::LDNT1H_4Z_IMM, AArch64::LDNT1H_4Z_STRIDED_IMM);
1983 case AArch64::LDNT1W_4Z_IMM_PSEUDO:
1984 return expandMultiVecPseudo(
1985 MBB, MBBI, AArch64::ZPR4RegClass, AArch64::ZPR4StridedRegClass,
1986 AArch64::LDNT1W_4Z_IMM, AArch64::LDNT1W_4Z_STRIDED_IMM);
1987 case AArch64::LDNT1D_4Z_IMM_PSEUDO:
1988 return expandMultiVecPseudo(
1989 MBB, MBBI, AArch64::ZPR4RegClass, AArch64::ZPR4StridedRegClass,
1990 AArch64::LDNT1D_4Z_IMM, AArch64::LDNT1D_4Z_STRIDED_IMM);
1991 case AArch64::ST1B_4Z_IMM_PSEUDO:
1992 return expandMultiVecPseudo(
1993 MBB, MBBI, AArch64::ZPR4RegClass, AArch64::ZPR4StridedRegClass,
1994 AArch64::ST1B_4Z_IMM, AArch64::ST1B_4Z_STRIDED_IMM);
1995 case AArch64::ST1H_4Z_IMM_PSEUDO:
1996 return expandMultiVecPseudo(
1997 MBB, MBBI, AArch64::ZPR4RegClass, AArch64::ZPR4StridedRegClass,
1998 AArch64::ST1H_4Z_IMM, AArch64::ST1H_4Z_STRIDED_IMM);
1999 case AArch64::ST1W_4Z_IMM_PSEUDO:
2000 return expandMultiVecPseudo(
2001 MBB, MBBI, AArch64::ZPR4RegClass, AArch64::ZPR4StridedRegClass,
2002 AArch64::ST1W_4Z_IMM, AArch64::ST1W_4Z_STRIDED_IMM);
2003 case AArch64::ST1D_4Z_IMM_PSEUDO:
2004 return expandMultiVecPseudo(
2005 MBB, MBBI, AArch64::ZPR4RegClass, AArch64::ZPR4StridedRegClass,
2006 AArch64::ST1D_4Z_IMM, AArch64::ST1D_4Z_STRIDED_IMM);
2007 case AArch64::STNT1B_4Z_IMM_PSEUDO:
2008 return expandMultiVecPseudo(
2009 MBB, MBBI, AArch64::ZPR4RegClass, AArch64::ZPR4StridedRegClass,
2010 AArch64::STNT1B_4Z_IMM, AArch64::STNT1B_4Z_STRIDED_IMM);
2011 case AArch64::STNT1H_4Z_IMM_PSEUDO:
2012 return expandMultiVecPseudo(
2013 MBB, MBBI, AArch64::ZPR4RegClass, AArch64::ZPR4StridedRegClass,
2014 AArch64::STNT1H_4Z_IMM, AArch64::STNT1H_4Z_STRIDED_IMM);
2015 case AArch64::STNT1W_4Z_IMM_PSEUDO:
2016 return expandMultiVecPseudo(
2017 MBB, MBBI, AArch64::ZPR4RegClass, AArch64::ZPR4StridedRegClass,
2018 AArch64::STNT1W_4Z_IMM, AArch64::STNT1W_4Z_STRIDED_IMM);
2019 case AArch64::STNT1D_4Z_IMM_PSEUDO:
2020 return expandMultiVecPseudo(
2021 MBB, MBBI, AArch64::ZPR4RegClass, AArch64::ZPR4StridedRegClass,
2022 AArch64::STNT1D_4Z_IMM, AArch64::STNT1D_4Z_STRIDED_IMM);
2023 case AArch64::LD1B_4Z_PSEUDO:
2024 return expandMultiVecPseudo(MBB, MBBI, AArch64::ZPR4RegClass,
2025 AArch64::ZPR4StridedRegClass, AArch64::LD1B_4Z,
2026 AArch64::LD1B_4Z_STRIDED);
2027 case AArch64::LD1H_4Z_PSEUDO:
2028 return expandMultiVecPseudo(MBB, MBBI, AArch64::ZPR4RegClass,
2029 AArch64::ZPR4StridedRegClass, AArch64::LD1H_4Z,
2030 AArch64::LD1H_4Z_STRIDED);
2031 case AArch64::LD1W_4Z_PSEUDO:
2032 return expandMultiVecPseudo(MBB, MBBI, AArch64::ZPR4RegClass,
2033 AArch64::ZPR4StridedRegClass, AArch64::LD1W_4Z,
2034 AArch64::LD1W_4Z_STRIDED);
2035 case AArch64::LD1D_4Z_PSEUDO:
2036 return expandMultiVecPseudo(MBB, MBBI, AArch64::ZPR4RegClass,
2037 AArch64::ZPR4StridedRegClass, AArch64::LD1D_4Z,
2038 AArch64::LD1D_4Z_STRIDED);
2039 case AArch64::LDNT1B_4Z_PSEUDO:
2040 return expandMultiVecPseudo(MBB, MBBI, AArch64::ZPR4RegClass,
2041 AArch64::ZPR4StridedRegClass,
2042 AArch64::LDNT1B_4Z, AArch64::LDNT1B_4Z_STRIDED);
2043 case AArch64::LDNT1H_4Z_PSEUDO:
2044 return expandMultiVecPseudo(MBB, MBBI, AArch64::ZPR4RegClass,
2045 AArch64::ZPR4StridedRegClass,
2046 AArch64::LDNT1H_4Z, AArch64::LDNT1H_4Z_STRIDED);
2047 case AArch64::LDNT1W_4Z_PSEUDO:
2048 return expandMultiVecPseudo(MBB, MBBI, AArch64::ZPR4RegClass,
2049 AArch64::ZPR4StridedRegClass,
2050 AArch64::LDNT1W_4Z, AArch64::LDNT1W_4Z_STRIDED);
2051 case AArch64::LDNT1D_4Z_PSEUDO:
2052 return expandMultiVecPseudo(MBB, MBBI, AArch64::ZPR4RegClass,
2053 AArch64::ZPR4StridedRegClass,
2054 AArch64::LDNT1D_4Z, AArch64::LDNT1D_4Z_STRIDED);
2055 case AArch64::COPY_INTO_TRANSPOSED_TUPLE:
2056 return expandCopyIntoTuplePseudo(MI, MBB, MBBI);
2057 case AArch64::EON_ZZZ:
2058 case AArch64::NAND_ZZZ:
2059 case AArch64::NOR_ZZZ:
2060 return expandSVEBitwisePseudo(MI, MBB, MBBI);
2061 }
2062 return false;
2063}
2064
2065/// Iterate over the instructions in basic block MBB and expand any
2066/// pseudo instructions. Return true if anything was modified.
2067bool AArch64ExpandPseudoImpl::expandMBB(MachineBasicBlock &MBB) {
2068 bool Modified = false;
2069
2071 while (MBBI != E) {
2072 MachineBasicBlock::iterator NMBBI = std::next(MBBI);
2073 if (MBBI->isPseudo())
2074 Modified |= expandMI(MBB, MBBI, NMBBI);
2075 MBBI = NMBBI;
2076 }
2077
2078 return Modified;
2079}
2080
2081bool AArch64ExpandPseudoImpl::run(MachineFunction &MF) {
2082 TII = MF.getSubtarget<AArch64Subtarget>().getInstrInfo();
2083
2084 bool Modified = false;
2085 for (auto &MBB : MF)
2086 Modified |= expandMBB(MBB);
2087 return Modified;
2088}
2089
2090bool AArch64ExpandPseudoLegacy::runOnMachineFunction(MachineFunction &MF) {
2091 return AArch64ExpandPseudoImpl().run(MF);
2092}
2093
2094/// Returns an instance of the pseudo instruction expansion pass.
2096 return new AArch64ExpandPseudoLegacy();
2097}
2098
2102 const bool Changed = AArch64ExpandPseudoImpl().run(MF);
2103 if (!Changed)
2104 return PreservedAnalyses::all();
2107 return PA;
2108}
#define AARCH64_EXPAND_PSEUDO_NAME
MachineInstrBuilder & UseMI
static MachineInstr * createCallWithOps(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, const AArch64InstrInfo *TII, unsigned Opcode, ArrayRef< MachineOperand > ExplicitOps, unsigned RegMaskStartIdx)
static constexpr unsigned ZERO_ALL_ZA_MASK
static MachineInstr * createCall(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, const AArch64InstrInfo *TII, MachineOperand &CallTarget, unsigned RegMaskStartIdx)
MachineInstrBuilder MachineInstrBuilder & DefMI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
uint64_t uint64_t
uint64_t Imm
MachineBasicBlock & MBB
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
MachineBasicBlock MachineBasicBlock::iterator MBBI
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
This file implements the LivePhysRegs utility for tracking liveness of physical registers.
#define I(x, y, z)
Definition MD5.cpp:57
This file declares the MachineConstantPool class which is an abstract constant pool to keep track of ...
Register const TargetRegisterInfo * TRI
Promote Memory to Register
Definition Mem2Reg.cpp:110
static MCRegister getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
static void transferImpOps(const MachineInstr &OldMI, MachineInstrBuilder &MI)
Transfer implicit operands on the pseudo instruction to the instructions created from the expansion.
PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
Represent the analysis usage information of a pass.
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
Represents analyses that only rely on functions' control flow.
Definition Analysis.h:73
A debug info location.
Definition DebugLoc.h:126
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:312
const HexagonRegisterInfo & getRegisterInfo() const
Describe properties that are true of each instruction in the target description file.
ArrayRef< MCPhysReg > getRegisters() const
LLVM_ABI instr_iterator insert(instr_iterator I, MachineInstr *M)
Insert MI into the instruction list before I, possibly inside a bundle.
const BasicBlock * getBasicBlock() const
Return the LLVM basic block that this instance corresponded to originally.
LLVM_ABI void addSuccessor(MachineBasicBlock *Succ, BranchProbability Prob=BranchProbability::getUnknown())
Add Succ as a successor of this MachineBasicBlock.
LLVM_ABI MachineBasicBlock * splitAt(MachineInstr &SplitInst, bool UpdateLiveIns=true, LiveIntervals *LIS=nullptr)
Split a basic block into 2 pieces at SplitPoint.
LLVM_ABI void eraseFromParent()
This method unlinks 'this' from the containing function and deletes it.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
iterator_range< succ_iterator > successors()
MachineInstrBundleIterator< MachineInstr > iterator
LLVM_ABI unsigned getConstantPoolIndex(const Constant *C, Align Alignment)
getConstantPoolIndex - Create a new entry in the constant pool or return an existing one.
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.
void moveAdditionalCallInfo(const MachineInstr *Old, const MachineInstr *New)
Move the call site info from Old to \New call site info.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
MachineConstantPool * getConstantPool()
getConstantPool - Return the constant pool object for the current function.
MachineBasicBlock * CreateMachineBasicBlock(const BasicBlock *BB=nullptr, std::optional< UniqueBBID > BBID=std::nullopt)
CreateMachineInstr - Allocate a new MachineInstr.
void insert(iterator MBBI, MachineBasicBlock *MBB)
const TargetMachine & getTarget() const
getTarget - Return the target machine this machine code is compiled with
const MachineInstrBuilder & addExternalSymbol(const char *FnName, unsigned TargetFlags=0) const
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 & setMIFlag(MachineInstr::MIFlag Flag) const
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & add(const MachineOperand &MO) const
const MachineInstrBuilder & addConstantPoolIndex(unsigned Idx, int Offset=0, unsigned TargetFlags=0) const
const MachineInstrBuilder & addGlobalAddress(const GlobalValue *GV, int64_t Offset=0, unsigned TargetFlags=0) const
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
const MachineInstrBuilder & addDef(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register definition operand.
const MachineInstrBuilder & cloneMemRefs(const MachineInstr &OtherMI) const
const MachineInstrBuilder & setMIFlags(unsigned Flags) const
MachineInstr * getInstr() const
If conversion operators fail, use this method to get the MachineInstr explicitly.
Representation of each machine instruction.
void setDebugInstrNum(unsigned Num)
Set instruction number of this MachineInstr.
const DebugLoc & getDebugLoc() const
Returns the debug location id of this MachineInstr.
MachineOperand class - Representation of each machine instruction operand.
const GlobalValue * getGlobal() const
bool isReg() const
isReg - Tests if this is a MO_Register operand.
bool isCPI() const
isCPI - Tests if this is a MO_ConstantPoolIndex operand.
bool isSymbol() const
isSymbol - Tests if this is a MO_ExternalSymbol operand.
LLVM_ABI bool isRenamable() const
isRenamable - Returns true if this register may be renamed, i.e.
unsigned getTargetFlags() const
bool isGlobal() const
isGlobal - Tests if this is a MO_GlobalAddress operand.
const char * getSymbolName() const
Register getReg() const
getReg - Returns the register number.
static MachineOperand CreateReg(Register Reg, bool isDef, bool isImp=false, bool isKill=false, bool isDead=false, bool isUndef=false, bool isEarlyClobber=false, unsigned SubReg=0, bool isDebug=false, bool isInternalRead=false, bool isRenamable=false)
int64_t getOffset() const
Return the offset from the symbol in this operand.
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
void push_back(const T &Elt)
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
CodeModel::Model getCodeModel() const
Returns the code model.
virtual const TargetRegisterInfo * getRegisterInfo() const =0
Return the target's register information.
self_iterator getIterator()
Definition ilist_node.h:123
IteratorT end() const
IteratorT begin() const
CallInst * Call
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ MO_NC
MO_NC - Indicates whether the linker is expected to check the symbol reference for overflow.
@ MO_PAGEOFF
MO_PAGEOFF - A symbol operand with this flag represents the offset of that symbol within a 4K page.
@ MO_PREL
MO_PREL - Indicates that the bits of the symbol operand represented by MO_G0 etc are PC relative.
@ MO_PAGE
MO_PAGE - A symbol operand with this flag represents the pc-relative offset of the 4K page containing...
@ MO_G3
MO_G3 - A symbol operand with this flag (granule 3) represents the high 16-bits of a 64-bit address,...
static unsigned getArithExtendImm(AArch64_AM::ShiftExtendType ET, unsigned Imm)
getArithExtendImm - Encode the extend type and shift amount for an arithmetic instruction: imm: 3-bit...
static unsigned getShifterImm(AArch64_AM::ShiftExtendType ST, unsigned Imm)
getShifterImm - Encode the shift type and amount: imm: 6-bit shift amount shifter: 000 ==> lsl 001 ==...
void expandMOVAddr(unsigned Opcode, unsigned TargetFlags, bool IsTargetMachO, SmallVectorImpl< AddrInsnModel > &Insn)
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...
int32_t getSVERevInstr(uint32_t Opcode)
int32_t getSVENonRevInstr(uint32_t Opcode)
int32_t getSVEPseudoMap(uint32_t Opcode)
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
BaseReg
Stack frame base register. Bit 0 of FREInfo.Info.
Definition SFrame.h:77
This is an optimization pass for GlobalISel generic memory operations.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
Definition STLExtras.h:316
@ Offset
Definition DWP.cpp:577
LLVM_ABI void finalizeBundle(MachineBasicBlock &MBB, MachineBasicBlock::instr_iterator FirstMI, MachineBasicBlock::instr_iterator LastMI)
finalizeBundle - Finalize a machine instruction bundle which includes a sequence of instructions star...
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
RegState
Flags to represent properties of register accesses.
@ Kill
The last use of a register.
constexpr RegState getKillRegState(bool B)
APFloat abs(APFloat X)
Returns the absolute value of the argument.
Definition APFloat.h:1721
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
constexpr RegState getDeadRegState(bool B)
Op::Description Desc
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
FunctionPass * createAArch64ExpandPseudoLegacyPass()
Returns an instance of the pseudo instruction expansion pass.
constexpr RegState getRenamableRegState(bool B)
void emitFrameOffset(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, const DebugLoc &DL, unsigned DestReg, unsigned SrcReg, StackOffset Offset, const TargetInstrInfo *TII, MachineInstr::MIFlag=MachineInstr::NoFlags, bool SetNZCV=false, bool NeedsWinCFI=false, bool *HasWinCFI=nullptr, bool EmitCFAOffset=false, StackOffset InitialOffset={}, unsigned FrameReg=AArch64::SP)
emitFrameOffset - Emit instructions as needed to set DestReg to SrcReg plus Offset.
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:163
constexpr RegState getDefRegState(bool B)
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
LLVM_ATTRIBUTE_VISIBILITY_DEFAULT AnalysisKey InnerAnalysisManagerProxy< AnalysisManagerT, IRUnitT, ExtraArgTs... >::Key
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Definition STLExtras.h:1963
LLVM_ABI void computeAndAddLiveIns(LivePhysRegs &LiveRegs, MachineBasicBlock &MBB)
Convenience function combining computeLiveIns() and addLiveIns().
constexpr RegState getUndefRegState(bool B)
MCRegisterClass TargetRegisterClass
Definition FastISel.h:58
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Definition BitVector.h:880
#define N