LLVM 22.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 AArch64ExpandPseudo : public MachineFunctionPass {
48public:
49 const AArch64InstrInfo *TII;
50
51 static char ID;
52
53 AArch64ExpandPseudo() : MachineFunctionPass(ID) {}
54
55 bool runOnMachineFunction(MachineFunction &Fn) override;
56
57 StringRef getPassName() const override { return AARCH64_EXPAND_PSEUDO_NAME; }
58
59private:
60 bool expandMBB(MachineBasicBlock &MBB);
63 bool expandMultiVecPseudo(MachineBasicBlock &MBB,
65 TargetRegisterClass ContiguousClass,
66 TargetRegisterClass StridedClass,
67 unsigned ContiguousOpc, unsigned StridedOpc);
68 bool expandFormTuplePseudo(MachineBasicBlock &MBB,
71 unsigned Size);
73 unsigned BitSize);
74
75 bool expand_DestructiveOp(MachineInstr &MI, MachineBasicBlock &MBB,
78 unsigned LdarOp, unsigned StlrOp, unsigned CmpOp,
79 unsigned ExtendImm, unsigned ZeroReg,
81 bool expandCMP_SWAP_128(MachineBasicBlock &MBB,
84 bool expandSetTagLoop(MachineBasicBlock &MBB,
87 bool expandSVESpillFill(MachineBasicBlock &MBB,
89 unsigned N);
90 bool expandCALL_RVMARKER(MachineBasicBlock &MBB,
93 bool expandStoreSwiftAsyncContext(MachineBasicBlock &MBB,
95 struct ConditionalBlocks {
96 MachineBasicBlock &CondBB;
97 MachineBasicBlock &EndBB;
98 };
99 ConditionalBlocks expandConditionalPseudo(MachineBasicBlock &MBB,
101 DebugLoc DL,
102 MachineInstrBuilder &Branch);
103 MachineBasicBlock *expandRestoreZASave(MachineBasicBlock &MBB,
105 MachineBasicBlock *expandCommitZASave(MachineBasicBlock &MBB,
107 MachineBasicBlock *expandCondSMToggle(MachineBasicBlock &MBB,
109};
110
111} // end anonymous namespace
112
113char AArch64ExpandPseudo::ID = 0;
114
115INITIALIZE_PASS(AArch64ExpandPseudo, "aarch64-expand-pseudo",
116 AARCH64_EXPAND_PSEUDO_NAME, false, false)
117
118/// Transfer implicit operands on the pseudo instruction to the
119/// instructions created from the expansion.
120static void transferImpOps(MachineInstr &OldMI, MachineInstrBuilder &UseMI,
122 const MCInstrDesc &Desc = OldMI.getDesc();
123 for (const MachineOperand &MO :
124 llvm::drop_begin(OldMI.operands(), Desc.getNumOperands())) {
125 assert(MO.isReg() && MO.getReg());
126 if (MO.isUse())
127 UseMI.add(MO);
128 else
129 DefMI.add(MO);
130 }
131}
132
133/// Expand a MOVi32imm or MOVi64imm pseudo instruction to one or more
134/// real move-immediate instructions to synthesize the immediate.
135bool AArch64ExpandPseudo::expandMOVImm(MachineBasicBlock &MBB,
137 unsigned BitSize) {
138 MachineInstr &MI = *MBBI;
139 Register DstReg = MI.getOperand(0).getReg();
140 uint64_t RenamableState =
141 MI.getOperand(0).isRenamable() ? RegState::Renamable : 0;
142 uint64_t Imm = MI.getOperand(1).getImm();
143
144 if (DstReg == AArch64::XZR || DstReg == AArch64::WZR) {
145 // Useless def, and we don't want to risk creating an invalid ORR (which
146 // would really write to sp).
147 MI.eraseFromParent();
148 return true;
149 }
150
152 AArch64_IMM::expandMOVImm(Imm, BitSize, Insn);
153 assert(Insn.size() != 0);
154
155 SmallVector<MachineInstrBuilder, 4> MIBS;
156 for (auto I = Insn.begin(), E = Insn.end(); I != E; ++I) {
157 bool LastItem = std::next(I) == E;
158 switch (I->Opcode)
159 {
160 default: llvm_unreachable("unhandled!"); break;
161
162 case AArch64::ORRWri:
163 case AArch64::ORRXri:
164 if (I->Op1 == 0) {
165 MIBS.push_back(BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(I->Opcode))
166 .add(MI.getOperand(0))
167 .addReg(BitSize == 32 ? AArch64::WZR : AArch64::XZR)
168 .addImm(I->Op2));
169 } else {
170 Register DstReg = MI.getOperand(0).getReg();
171 bool DstIsDead = MI.getOperand(0).isDead();
172 MIBS.push_back(
173 BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(I->Opcode))
174 .addReg(DstReg, RegState::Define |
175 getDeadRegState(DstIsDead && LastItem) |
176 RenamableState)
177 .addReg(DstReg)
178 .addImm(I->Op2));
179 }
180 break;
181 case AArch64::ORRWrs:
182 case AArch64::ORRXrs: {
183 Register DstReg = MI.getOperand(0).getReg();
184 bool DstIsDead = MI.getOperand(0).isDead();
185 MIBS.push_back(
186 BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(I->Opcode))
187 .addReg(DstReg, RegState::Define |
188 getDeadRegState(DstIsDead && LastItem) |
189 RenamableState)
190 .addReg(DstReg)
191 .addReg(DstReg)
192 .addImm(I->Op2));
193 } break;
194 case AArch64::ANDXri:
195 case AArch64::EORXri:
196 if (I->Op1 == 0) {
197 MIBS.push_back(BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(I->Opcode))
198 .add(MI.getOperand(0))
199 .addReg(BitSize == 32 ? AArch64::WZR : AArch64::XZR)
200 .addImm(I->Op2));
201 } else {
202 Register DstReg = MI.getOperand(0).getReg();
203 bool DstIsDead = MI.getOperand(0).isDead();
204 MIBS.push_back(
205 BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(I->Opcode))
206 .addReg(DstReg, RegState::Define |
207 getDeadRegState(DstIsDead && LastItem) |
208 RenamableState)
209 .addReg(DstReg)
210 .addImm(I->Op2));
211 }
212 break;
213 case AArch64::MOVNWi:
214 case AArch64::MOVNXi:
215 case AArch64::MOVZWi:
216 case AArch64::MOVZXi: {
217 bool DstIsDead = MI.getOperand(0).isDead();
218 MIBS.push_back(BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(I->Opcode))
219 .addReg(DstReg, RegState::Define |
220 getDeadRegState(DstIsDead && LastItem) |
221 RenamableState)
222 .addImm(I->Op1)
223 .addImm(I->Op2));
224 } break;
225 case AArch64::MOVKWi:
226 case AArch64::MOVKXi: {
227 Register DstReg = MI.getOperand(0).getReg();
228 bool DstIsDead = MI.getOperand(0).isDead();
229 MIBS.push_back(BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(I->Opcode))
230 .addReg(DstReg,
232 getDeadRegState(DstIsDead && LastItem) |
233 RenamableState)
234 .addReg(DstReg)
235 .addImm(I->Op1)
236 .addImm(I->Op2));
237 } break;
238 }
239 }
240 transferImpOps(MI, MIBS.front(), MIBS.back());
241 MI.eraseFromParent();
242 return true;
243}
244
245bool AArch64ExpandPseudo::expandCMP_SWAP(
246 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, unsigned LdarOp,
247 unsigned StlrOp, unsigned CmpOp, unsigned ExtendImm, unsigned ZeroReg,
248 MachineBasicBlock::iterator &NextMBBI) {
249 MachineInstr &MI = *MBBI;
250 MIMetadata MIMD(MI);
251 const MachineOperand &Dest = MI.getOperand(0);
252 Register StatusReg = MI.getOperand(1).getReg();
253 bool StatusDead = MI.getOperand(1).isDead();
254 // Duplicating undef operands into 2 instructions does not guarantee the same
255 // value on both; However undef should be replaced by xzr anyway.
256 assert(!MI.getOperand(2).isUndef() && "cannot handle undef");
257 Register AddrReg = MI.getOperand(2).getReg();
258 Register DesiredReg = MI.getOperand(3).getReg();
259 Register NewReg = MI.getOperand(4).getReg();
260
261 MachineFunction *MF = MBB.getParent();
262 auto LoadCmpBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
263 auto StoreBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
264 auto DoneBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
265
266 MF->insert(++MBB.getIterator(), LoadCmpBB);
267 MF->insert(++LoadCmpBB->getIterator(), StoreBB);
268 MF->insert(++StoreBB->getIterator(), DoneBB);
269
270 // .Lloadcmp:
271 // mov wStatus, 0
272 // ldaxr xDest, [xAddr]
273 // cmp xDest, xDesired
274 // b.ne .Ldone
275 if (!StatusDead)
276 BuildMI(LoadCmpBB, MIMD, TII->get(AArch64::MOVZWi), StatusReg)
277 .addImm(0).addImm(0);
278 BuildMI(LoadCmpBB, MIMD, TII->get(LdarOp), Dest.getReg())
279 .addReg(AddrReg);
280 BuildMI(LoadCmpBB, MIMD, TII->get(CmpOp), ZeroReg)
281 .addReg(Dest.getReg(), getKillRegState(Dest.isDead()))
282 .addReg(DesiredReg)
283 .addImm(ExtendImm);
284 BuildMI(LoadCmpBB, MIMD, TII->get(AArch64::Bcc))
286 .addMBB(DoneBB)
287 .addReg(AArch64::NZCV, RegState::Implicit | RegState::Kill);
288 LoadCmpBB->addSuccessor(DoneBB);
289 LoadCmpBB->addSuccessor(StoreBB);
290
291 // .Lstore:
292 // stlxr wStatus, xNew, [xAddr]
293 // cbnz wStatus, .Lloadcmp
294 BuildMI(StoreBB, MIMD, TII->get(StlrOp), StatusReg)
295 .addReg(NewReg)
296 .addReg(AddrReg);
297 BuildMI(StoreBB, MIMD, TII->get(AArch64::CBNZW))
298 .addReg(StatusReg, getKillRegState(StatusDead))
299 .addMBB(LoadCmpBB);
300 StoreBB->addSuccessor(LoadCmpBB);
301 StoreBB->addSuccessor(DoneBB);
302
303 DoneBB->splice(DoneBB->end(), &MBB, MI, MBB.end());
304 DoneBB->transferSuccessors(&MBB);
305
306 MBB.addSuccessor(LoadCmpBB);
307
308 NextMBBI = MBB.end();
309 MI.eraseFromParent();
310
311 // Recompute livein lists.
312 LivePhysRegs LiveRegs;
313 computeAndAddLiveIns(LiveRegs, *DoneBB);
314 computeAndAddLiveIns(LiveRegs, *StoreBB);
315 computeAndAddLiveIns(LiveRegs, *LoadCmpBB);
316 // Do an extra pass around the loop to get loop carried registers right.
317 StoreBB->clearLiveIns();
318 computeAndAddLiveIns(LiveRegs, *StoreBB);
319 LoadCmpBB->clearLiveIns();
320 computeAndAddLiveIns(LiveRegs, *LoadCmpBB);
321
322 return true;
323}
324
325bool AArch64ExpandPseudo::expandCMP_SWAP_128(
326 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
327 MachineBasicBlock::iterator &NextMBBI) {
328 MachineInstr &MI = *MBBI;
329 MIMetadata MIMD(MI);
330 MachineOperand &DestLo = MI.getOperand(0);
331 MachineOperand &DestHi = MI.getOperand(1);
332 Register StatusReg = MI.getOperand(2).getReg();
333 bool StatusDead = MI.getOperand(2).isDead();
334 // Duplicating undef operands into 2 instructions does not guarantee the same
335 // value on both; However undef should be replaced by xzr anyway.
336 assert(!MI.getOperand(3).isUndef() && "cannot handle undef");
337 Register AddrReg = MI.getOperand(3).getReg();
338 Register DesiredLoReg = MI.getOperand(4).getReg();
339 Register DesiredHiReg = MI.getOperand(5).getReg();
340 Register NewLoReg = MI.getOperand(6).getReg();
341 Register NewHiReg = MI.getOperand(7).getReg();
342
343 unsigned LdxpOp, StxpOp;
344
345 switch (MI.getOpcode()) {
346 case AArch64::CMP_SWAP_128_MONOTONIC:
347 LdxpOp = AArch64::LDXPX;
348 StxpOp = AArch64::STXPX;
349 break;
350 case AArch64::CMP_SWAP_128_RELEASE:
351 LdxpOp = AArch64::LDXPX;
352 StxpOp = AArch64::STLXPX;
353 break;
354 case AArch64::CMP_SWAP_128_ACQUIRE:
355 LdxpOp = AArch64::LDAXPX;
356 StxpOp = AArch64::STXPX;
357 break;
358 case AArch64::CMP_SWAP_128:
359 LdxpOp = AArch64::LDAXPX;
360 StxpOp = AArch64::STLXPX;
361 break;
362 default:
363 llvm_unreachable("Unexpected opcode");
364 }
365
366 MachineFunction *MF = MBB.getParent();
367 auto LoadCmpBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
368 auto StoreBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
369 auto FailBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
370 auto DoneBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
371
372 MF->insert(++MBB.getIterator(), LoadCmpBB);
373 MF->insert(++LoadCmpBB->getIterator(), StoreBB);
374 MF->insert(++StoreBB->getIterator(), FailBB);
375 MF->insert(++FailBB->getIterator(), DoneBB);
376
377 // .Lloadcmp:
378 // ldaxp xDestLo, xDestHi, [xAddr]
379 // cmp xDestLo, xDesiredLo
380 // sbcs xDestHi, xDesiredHi
381 // b.ne .Ldone
382 BuildMI(LoadCmpBB, MIMD, TII->get(LdxpOp))
383 .addReg(DestLo.getReg(), RegState::Define)
384 .addReg(DestHi.getReg(), RegState::Define)
385 .addReg(AddrReg);
386 BuildMI(LoadCmpBB, MIMD, TII->get(AArch64::SUBSXrs), AArch64::XZR)
387 .addReg(DestLo.getReg(), getKillRegState(DestLo.isDead()))
388 .addReg(DesiredLoReg)
389 .addImm(0);
390 BuildMI(LoadCmpBB, MIMD, TII->get(AArch64::CSINCWr), StatusReg)
391 .addUse(AArch64::WZR)
392 .addUse(AArch64::WZR)
394 BuildMI(LoadCmpBB, MIMD, TII->get(AArch64::SUBSXrs), AArch64::XZR)
395 .addReg(DestHi.getReg(), getKillRegState(DestHi.isDead()))
396 .addReg(DesiredHiReg)
397 .addImm(0);
398 BuildMI(LoadCmpBB, MIMD, TII->get(AArch64::CSINCWr), StatusReg)
399 .addUse(StatusReg, RegState::Kill)
400 .addUse(StatusReg, RegState::Kill)
402 BuildMI(LoadCmpBB, MIMD, TII->get(AArch64::CBNZW))
403 .addUse(StatusReg, getKillRegState(StatusDead))
404 .addMBB(FailBB);
405 LoadCmpBB->addSuccessor(FailBB);
406 LoadCmpBB->addSuccessor(StoreBB);
407
408 // .Lstore:
409 // stlxp wStatus, xNewLo, xNewHi, [xAddr]
410 // cbnz wStatus, .Lloadcmp
411 BuildMI(StoreBB, MIMD, TII->get(StxpOp), StatusReg)
412 .addReg(NewLoReg)
413 .addReg(NewHiReg)
414 .addReg(AddrReg);
415 BuildMI(StoreBB, MIMD, TII->get(AArch64::CBNZW))
416 .addReg(StatusReg, getKillRegState(StatusDead))
417 .addMBB(LoadCmpBB);
418 BuildMI(StoreBB, MIMD, TII->get(AArch64::B)).addMBB(DoneBB);
419 StoreBB->addSuccessor(LoadCmpBB);
420 StoreBB->addSuccessor(DoneBB);
421
422 // .Lfail:
423 // stlxp wStatus, xDestLo, xDestHi, [xAddr]
424 // cbnz wStatus, .Lloadcmp
425 BuildMI(FailBB, MIMD, TII->get(StxpOp), StatusReg)
426 .addReg(DestLo.getReg())
427 .addReg(DestHi.getReg())
428 .addReg(AddrReg);
429 BuildMI(FailBB, MIMD, TII->get(AArch64::CBNZW))
430 .addReg(StatusReg, getKillRegState(StatusDead))
431 .addMBB(LoadCmpBB);
432 FailBB->addSuccessor(LoadCmpBB);
433 FailBB->addSuccessor(DoneBB);
434
435 DoneBB->splice(DoneBB->end(), &MBB, MI, MBB.end());
436 DoneBB->transferSuccessors(&MBB);
437
438 MBB.addSuccessor(LoadCmpBB);
439
440 NextMBBI = MBB.end();
441 MI.eraseFromParent();
442
443 // Recompute liveness bottom up.
444 LivePhysRegs LiveRegs;
445 computeAndAddLiveIns(LiveRegs, *DoneBB);
446 computeAndAddLiveIns(LiveRegs, *FailBB);
447 computeAndAddLiveIns(LiveRegs, *StoreBB);
448 computeAndAddLiveIns(LiveRegs, *LoadCmpBB);
449
450 // Do an extra pass in the loop to get the loop carried dependencies right.
451 FailBB->clearLiveIns();
452 computeAndAddLiveIns(LiveRegs, *FailBB);
453 StoreBB->clearLiveIns();
454 computeAndAddLiveIns(LiveRegs, *StoreBB);
455 LoadCmpBB->clearLiveIns();
456 computeAndAddLiveIns(LiveRegs, *LoadCmpBB);
457
458 return true;
459}
460
461/// \brief Expand Pseudos to Instructions with destructive operands.
462///
463/// This mechanism uses MOVPRFX instructions for zeroing the false lanes
464/// or for fixing relaxed register allocation conditions to comply with
465/// the instructions register constraints. The latter case may be cheaper
466/// than setting the register constraints in the register allocator,
467/// since that will insert regular MOV instructions rather than MOVPRFX.
468///
469/// Example (after register allocation):
470///
471/// FSUB_ZPZZ_ZERO_B Z0, Pg, Z1, Z0
472///
473/// * The Pseudo FSUB_ZPZZ_ZERO_B maps to FSUB_ZPmZ_B.
474/// * We cannot map directly to FSUB_ZPmZ_B because the register
475/// constraints of the instruction are not met.
476/// * Also the _ZERO specifies the false lanes need to be zeroed.
477///
478/// We first try to see if the destructive operand == result operand,
479/// if not, we try to swap the operands, e.g.
480///
481/// FSUB_ZPmZ_B Z0, Pg/m, Z0, Z1
482///
483/// But because FSUB_ZPmZ is not commutative, this is semantically
484/// different, so we need a reverse instruction:
485///
486/// FSUBR_ZPmZ_B Z0, Pg/m, Z0, Z1
487///
488/// Then we implement the zeroing of the false lanes of Z0 by adding
489/// a zeroing MOVPRFX instruction:
490///
491/// MOVPRFX_ZPzZ_B Z0, Pg/z, Z0
492/// FSUBR_ZPmZ_B Z0, Pg/m, Z0, Z1
493///
494/// Note that this can only be done for _ZERO or _UNDEF variants where
495/// we can guarantee the false lanes to be zeroed (by implementing this)
496/// or that they are undef (don't care / not used), otherwise the
497/// swapping of operands is illegal because the operation is not
498/// (or cannot be emulated to be) fully commutative.
499bool AArch64ExpandPseudo::expand_DestructiveOp(
500 MachineInstr &MI,
501 MachineBasicBlock &MBB,
503 unsigned Opcode = AArch64::getSVEPseudoMap(MI.getOpcode());
504 uint64_t DType = TII->get(Opcode).TSFlags & AArch64::DestructiveInstTypeMask;
505 uint64_t FalseLanes = MI.getDesc().TSFlags & AArch64::FalseLanesMask;
506 bool FalseZero = FalseLanes == AArch64::FalseLanesZero;
507 Register DstReg = MI.getOperand(0).getReg();
508 bool DstIsDead = MI.getOperand(0).isDead();
509 bool UseRev = false;
510 unsigned PredIdx, DOPIdx, SrcIdx, Src2Idx;
511
512 switch (DType) {
515 if (DstReg == MI.getOperand(3).getReg()) {
516 // FSUB Zd, Pg, Zs1, Zd ==> FSUBR Zd, Pg/m, Zd, Zs1
517 std::tie(PredIdx, DOPIdx, SrcIdx) = std::make_tuple(1, 3, 2);
518 UseRev = true;
519 break;
520 }
521 [[fallthrough]];
524 std::tie(PredIdx, DOPIdx, SrcIdx) = std::make_tuple(1, 2, 3);
525 break;
527 std::tie(PredIdx, DOPIdx, SrcIdx) = std::make_tuple(2, 3, 3);
528 break;
530 std::tie(PredIdx, DOPIdx, SrcIdx, Src2Idx) = std::make_tuple(1, 2, 3, 4);
531 if (DstReg == MI.getOperand(3).getReg()) {
532 // FMLA Zd, Pg, Za, Zd, Zm ==> FMAD Zdn, Pg, Zm, Za
533 std::tie(PredIdx, DOPIdx, SrcIdx, Src2Idx) = std::make_tuple(1, 3, 4, 2);
534 UseRev = true;
535 } else if (DstReg == MI.getOperand(4).getReg()) {
536 // FMLA Zd, Pg, Za, Zm, Zd ==> FMAD Zdn, Pg, Zm, Za
537 std::tie(PredIdx, DOPIdx, SrcIdx, Src2Idx) = std::make_tuple(1, 4, 3, 2);
538 UseRev = true;
539 }
540 break;
542 // EXT_ZZI_CONSTRUCTIVE Zd, Zs, Imm
543 // ==> MOVPRFX Zd Zs; EXT_ZZI Zd, Zd, Zs, Imm
544 std::tie(DOPIdx, SrcIdx, Src2Idx) = std::make_tuple(1, 1, 2);
545 break;
546 default:
547 llvm_unreachable("Unsupported Destructive Operand type");
548 }
549
550 // MOVPRFX can only be used if the destination operand
551 // is the destructive operand, not as any other operand,
552 // so the Destructive Operand must be unique.
553 bool DOPRegIsUnique = false;
554 switch (DType) {
556 DOPRegIsUnique = DstReg != MI.getOperand(SrcIdx).getReg();
557 break;
560 DOPRegIsUnique =
561 DstReg != MI.getOperand(DOPIdx).getReg() ||
562 MI.getOperand(DOPIdx).getReg() != MI.getOperand(SrcIdx).getReg();
563 break;
567 DOPRegIsUnique = true;
568 break;
570 DOPRegIsUnique =
571 DstReg != MI.getOperand(DOPIdx).getReg() ||
572 (MI.getOperand(DOPIdx).getReg() != MI.getOperand(SrcIdx).getReg() &&
573 MI.getOperand(DOPIdx).getReg() != MI.getOperand(Src2Idx).getReg());
574 break;
575 }
576
577 // Resolve the reverse opcode
578 if (UseRev) {
579 int NewOpcode;
580 // e.g. DIV -> DIVR
581 if ((NewOpcode = AArch64::getSVERevInstr(Opcode)) != -1)
582 Opcode = NewOpcode;
583 // e.g. DIVR -> DIV
584 else if ((NewOpcode = AArch64::getSVENonRevInstr(Opcode)) != -1)
585 Opcode = NewOpcode;
586 }
587
588 // Get the right MOVPRFX
589 uint64_t ElementSize = TII->getElementSizeForOpcode(Opcode);
590 unsigned MovPrfx, LSLZero, MovPrfxZero;
591 switch (ElementSize) {
594 MovPrfx = AArch64::MOVPRFX_ZZ;
595 LSLZero = AArch64::LSL_ZPmI_B;
596 MovPrfxZero = AArch64::MOVPRFX_ZPzZ_B;
597 break;
599 MovPrfx = AArch64::MOVPRFX_ZZ;
600 LSLZero = AArch64::LSL_ZPmI_H;
601 MovPrfxZero = AArch64::MOVPRFX_ZPzZ_H;
602 break;
604 MovPrfx = AArch64::MOVPRFX_ZZ;
605 LSLZero = AArch64::LSL_ZPmI_S;
606 MovPrfxZero = AArch64::MOVPRFX_ZPzZ_S;
607 break;
609 MovPrfx = AArch64::MOVPRFX_ZZ;
610 LSLZero = AArch64::LSL_ZPmI_D;
611 MovPrfxZero = AArch64::MOVPRFX_ZPzZ_D;
612 break;
613 default:
614 llvm_unreachable("Unsupported ElementSize");
615 }
616
617 // Preserve undef state until DOP's reg is defined.
618 unsigned DOPRegState = MI.getOperand(DOPIdx).isUndef() ? RegState::Undef : 0;
619
620 //
621 // Create the destructive operation (if required)
622 //
623 MachineInstrBuilder PRFX, DOP;
624 if (FalseZero) {
625 // If we cannot prefix the requested instruction we'll instead emit a
626 // prefixed_zeroing_mov for DestructiveBinary.
627 assert((DOPRegIsUnique || DType == AArch64::DestructiveBinary ||
630 "The destructive operand should be unique");
631 assert(ElementSize != AArch64::ElementSizeNone &&
632 "This instruction is unpredicated");
633
634 // Merge source operand into destination register
635 PRFX = BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(MovPrfxZero))
636 .addReg(DstReg, RegState::Define)
637 .addReg(MI.getOperand(PredIdx).getReg())
638 .addReg(MI.getOperand(DOPIdx).getReg(), DOPRegState);
639
640 // After the movprfx, the destructive operand is same as Dst
641 DOPIdx = 0;
642 DOPRegState = 0;
643
644 // Create the additional LSL to zero the lanes when the DstReg is not
645 // unique. Zeros the lanes in z0 that aren't active in p0 with sequence
646 // movprfx z0.b, p0/z, z0.b; lsl z0.b, p0/m, z0.b, #0;
647 if ((DType == AArch64::DestructiveBinary ||
650 !DOPRegIsUnique) {
651 BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(LSLZero))
652 .addReg(DstReg, RegState::Define)
653 .add(MI.getOperand(PredIdx))
654 .addReg(DstReg)
655 .addImm(0);
656 }
657 } else if (DstReg != MI.getOperand(DOPIdx).getReg()) {
658 assert(DOPRegIsUnique && "The destructive operand should be unique");
659 PRFX = BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(MovPrfx))
660 .addReg(DstReg, RegState::Define)
661 .addReg(MI.getOperand(DOPIdx).getReg(), DOPRegState);
662 DOPIdx = 0;
663 DOPRegState = 0;
664 }
665
666 //
667 // Create the destructive operation
668 //
669 DOP = BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(Opcode))
670 .addReg(DstReg, RegState::Define | getDeadRegState(DstIsDead));
671 DOPRegState = DOPRegState | RegState::Kill;
672
673 switch (DType) {
675 DOP.addReg(MI.getOperand(DOPIdx).getReg(), DOPRegState)
676 .add(MI.getOperand(PredIdx))
677 .add(MI.getOperand(SrcIdx));
678 break;
683 DOP.add(MI.getOperand(PredIdx))
684 .addReg(MI.getOperand(DOPIdx).getReg(), DOPRegState)
685 .add(MI.getOperand(SrcIdx));
686 break;
688 DOP.add(MI.getOperand(PredIdx))
689 .addReg(MI.getOperand(DOPIdx).getReg(), DOPRegState)
690 .add(MI.getOperand(SrcIdx))
691 .add(MI.getOperand(Src2Idx));
692 break;
694 DOP.addReg(MI.getOperand(DOPIdx).getReg(), DOPRegState)
695 .add(MI.getOperand(SrcIdx))
696 .add(MI.getOperand(Src2Idx));
697 break;
698 }
699
700 if (PRFX) {
701 transferImpOps(MI, PRFX, DOP);
703 } else
704 transferImpOps(MI, DOP, DOP);
705
706 MI.eraseFromParent();
707 return true;
708}
709
710bool AArch64ExpandPseudo::expandSetTagLoop(
711 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
712 MachineBasicBlock::iterator &NextMBBI) {
713 MachineInstr &MI = *MBBI;
714 DebugLoc DL = MI.getDebugLoc();
715 Register SizeReg = MI.getOperand(0).getReg();
716 Register AddressReg = MI.getOperand(1).getReg();
717
718 MachineFunction *MF = MBB.getParent();
719
720 bool ZeroData = MI.getOpcode() == AArch64::STZGloop_wback;
721 const unsigned OpCode1 =
722 ZeroData ? AArch64::STZGPostIndex : AArch64::STGPostIndex;
723 const unsigned OpCode2 =
724 ZeroData ? AArch64::STZ2GPostIndex : AArch64::ST2GPostIndex;
725
726 unsigned Size = MI.getOperand(2).getImm();
727 assert(Size > 0 && Size % 16 == 0);
728 if (Size % (16 * 2) != 0) {
729 BuildMI(MBB, MBBI, DL, TII->get(OpCode1), AddressReg)
730 .addReg(AddressReg)
731 .addReg(AddressReg)
732 .addImm(1);
733 Size -= 16;
734 }
736 BuildMI(MBB, MBBI, DL, TII->get(AArch64::MOVi64imm), SizeReg)
737 .addImm(Size);
738 expandMOVImm(MBB, I, 64);
739
740 auto LoopBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
741 auto DoneBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
742
743 MF->insert(++MBB.getIterator(), LoopBB);
744 MF->insert(++LoopBB->getIterator(), DoneBB);
745
746 BuildMI(LoopBB, DL, TII->get(OpCode2))
747 .addDef(AddressReg)
748 .addReg(AddressReg)
749 .addReg(AddressReg)
750 .addImm(2)
752 .setMIFlags(MI.getFlags());
753 BuildMI(LoopBB, DL, TII->get(AArch64::SUBSXri))
754 .addDef(SizeReg)
755 .addReg(SizeReg)
756 .addImm(16 * 2)
757 .addImm(0);
758 BuildMI(LoopBB, DL, TII->get(AArch64::Bcc))
760 .addMBB(LoopBB)
761 .addReg(AArch64::NZCV, RegState::Implicit | RegState::Kill);
762
763 LoopBB->addSuccessor(LoopBB);
764 LoopBB->addSuccessor(DoneBB);
765
766 DoneBB->splice(DoneBB->end(), &MBB, MI, MBB.end());
767 DoneBB->transferSuccessors(&MBB);
768
769 MBB.addSuccessor(LoopBB);
770
771 NextMBBI = MBB.end();
772 MI.eraseFromParent();
773 // Recompute liveness bottom up.
774 LivePhysRegs LiveRegs;
775 computeAndAddLiveIns(LiveRegs, *DoneBB);
776 computeAndAddLiveIns(LiveRegs, *LoopBB);
777 // Do an extra pass in the loop to get the loop carried dependencies right.
778 // FIXME: is this necessary?
779 LoopBB->clearLiveIns();
780 computeAndAddLiveIns(LiveRegs, *LoopBB);
781 DoneBB->clearLiveIns();
782 computeAndAddLiveIns(LiveRegs, *DoneBB);
783
784 return true;
785}
786
787bool AArch64ExpandPseudo::expandSVESpillFill(MachineBasicBlock &MBB,
789 unsigned Opc, unsigned N) {
790 assert((Opc == AArch64::LDR_ZXI || Opc == AArch64::STR_ZXI ||
791 Opc == AArch64::LDR_PXI || Opc == AArch64::STR_PXI) &&
792 "Unexpected opcode");
793 unsigned RState = (Opc == AArch64::LDR_ZXI || Opc == AArch64::LDR_PXI)
795 : 0;
796 unsigned sub0 = (Opc == AArch64::LDR_ZXI || Opc == AArch64::STR_ZXI)
797 ? AArch64::zsub0
798 : AArch64::psub0;
799 const TargetRegisterInfo *TRI =
801 MachineInstr &MI = *MBBI;
802 for (unsigned Offset = 0; Offset < N; ++Offset) {
803 int ImmOffset = MI.getOperand(2).getImm() + Offset;
804 bool Kill = (Offset + 1 == N) ? MI.getOperand(1).isKill() : false;
805 assert(ImmOffset >= -256 && ImmOffset < 256 &&
806 "Immediate spill offset out of range");
807 BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(Opc))
808 .addReg(TRI->getSubReg(MI.getOperand(0).getReg(), sub0 + Offset),
809 RState)
810 .addReg(MI.getOperand(1).getReg(), getKillRegState(Kill))
811 .addImm(ImmOffset);
812 }
813 MI.eraseFromParent();
814 return true;
815}
816
817// Create a call with the passed opcode and explicit operands, copying over all
818// the implicit operands from *MBBI, starting at the regmask.
821 const AArch64InstrInfo *TII,
822 unsigned Opcode,
823 ArrayRef<MachineOperand> ExplicitOps,
824 unsigned RegMaskStartIdx) {
825 // Build the MI, with explicit operands first (including the call target).
826 MachineInstr *Call = BuildMI(MBB, MBBI, MBBI->getDebugLoc(), TII->get(Opcode))
827 .add(ExplicitOps)
828 .getInstr();
829
830 // Register arguments are added during ISel, but cannot be added as explicit
831 // operands of the branch as it expects to be B <target> which is only one
832 // operand. Instead they are implicit operands used by the branch.
833 while (!MBBI->getOperand(RegMaskStartIdx).isRegMask()) {
834 const MachineOperand &MOP = MBBI->getOperand(RegMaskStartIdx);
835 assert(MOP.isReg() && "can only add register operands");
837 MOP.getReg(), /*Def=*/false, /*Implicit=*/true, /*isKill=*/false,
838 /*isDead=*/false, /*isUndef=*/MOP.isUndef()));
839 RegMaskStartIdx++;
840 }
841 for (const MachineOperand &MO :
842 llvm::drop_begin(MBBI->operands(), RegMaskStartIdx))
843 Call->addOperand(MO);
844
845 return Call;
846}
847
848// Create a call to CallTarget, copying over all the operands from *MBBI,
849// starting at the regmask.
852 const AArch64InstrInfo *TII,
853 MachineOperand &CallTarget,
854 unsigned RegMaskStartIdx) {
855 unsigned Opc = CallTarget.isGlobal() ? AArch64::BL : AArch64::BLR;
856
857 assert((CallTarget.isGlobal() || CallTarget.isReg()) &&
858 "invalid operand for regular call");
859 return createCallWithOps(MBB, MBBI, TII, Opc, CallTarget, RegMaskStartIdx);
860}
861
862bool AArch64ExpandPseudo::expandCALL_RVMARKER(
863 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI) {
864 // Expand CALL_RVMARKER pseudo to:
865 // - a branch to the call target, followed by
866 // - the special `mov x29, x29` marker, if necessary, and
867 // - another branch, to the runtime function
868 // Mark the sequence as bundle, to avoid passes moving other code in between.
869 MachineInstr &MI = *MBBI;
870 MachineOperand &RVTarget = MI.getOperand(0);
871 bool DoEmitMarker = MI.getOperand(1).getImm();
872 assert(RVTarget.isGlobal() && "invalid operand for attached call");
873
874 MachineInstr *OriginalCall = nullptr;
875
876 if (MI.getOpcode() == AArch64::BLRA_RVMARKER) {
877 // ptrauth call.
878 const MachineOperand &CallTarget = MI.getOperand(2);
879 const MachineOperand &Key = MI.getOperand(3);
880 const MachineOperand &IntDisc = MI.getOperand(4);
881 const MachineOperand &AddrDisc = MI.getOperand(5);
882
883 assert((Key.getImm() == AArch64PACKey::IA ||
884 Key.getImm() == AArch64PACKey::IB) &&
885 "Invalid auth call key");
886
887 MachineOperand Ops[] = {CallTarget, Key, IntDisc, AddrDisc};
888
889 OriginalCall = createCallWithOps(MBB, MBBI, TII, AArch64::BLRA, Ops,
890 /*RegMaskStartIdx=*/6);
891 } else {
892 assert(MI.getOpcode() == AArch64::BLR_RVMARKER && "unknown rvmarker MI");
893 OriginalCall = createCall(MBB, MBBI, TII, MI.getOperand(2),
894 // Regmask starts after the RV and call targets.
895 /*RegMaskStartIdx=*/3);
896 }
897
898 if (DoEmitMarker)
899 BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::ORRXrs))
900 .addReg(AArch64::FP, RegState::Define)
901 .addReg(AArch64::XZR)
902 .addReg(AArch64::FP)
903 .addImm(0);
904
905 auto *RVCall = BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::BL))
906 .add(RVTarget)
907 .getInstr();
908
909 if (MI.shouldUpdateAdditionalCallInfo())
910 MBB.getParent()->moveAdditionalCallInfo(&MI, OriginalCall);
911
912 MI.eraseFromParent();
913 finalizeBundle(MBB, OriginalCall->getIterator(),
914 std::next(RVCall->getIterator()));
915 return true;
916}
917
918bool AArch64ExpandPseudo::expandCALL_BTI(MachineBasicBlock &MBB,
920 // Expand CALL_BTI pseudo to:
921 // - a branch to the call target
922 // - a BTI instruction
923 // Mark the sequence as a bundle, to avoid passes moving other code in
924 // between.
925 MachineInstr &MI = *MBBI;
926 MachineInstr *Call = createCall(MBB, MBBI, TII, MI.getOperand(0),
927 // Regmask starts after the call target.
928 /*RegMaskStartIdx=*/1);
929
930 Call->setCFIType(*MBB.getParent(), MI.getCFIType());
931
932 MachineInstr *BTI =
933 BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::HINT))
934 // BTI J so that setjmp can to BR to this.
935 .addImm(36)
936 .getInstr();
937
938 if (MI.shouldUpdateAdditionalCallInfo())
940
941 MI.eraseFromParent();
942 finalizeBundle(MBB, Call->getIterator(), std::next(BTI->getIterator()));
943 return true;
944}
945
946bool AArch64ExpandPseudo::expandStoreSwiftAsyncContext(
947 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI) {
948 Register CtxReg = MBBI->getOperand(0).getReg();
949 Register BaseReg = MBBI->getOperand(1).getReg();
950 int Offset = MBBI->getOperand(2).getImm();
951 DebugLoc DL(MBBI->getDebugLoc());
952 auto &STI = MBB.getParent()->getSubtarget<AArch64Subtarget>();
953
954 if (STI.getTargetTriple().getArchName() != "arm64e") {
955 BuildMI(MBB, MBBI, DL, TII->get(AArch64::STRXui))
956 .addUse(CtxReg)
957 .addUse(BaseReg)
958 .addImm(Offset / 8)
961 return true;
962 }
963
964 // We need to sign the context in an address-discriminated way. 0xc31a is a
965 // fixed random value, chosen as part of the ABI.
966 // add x16, xBase, #Offset
967 // movk x16, #0xc31a, lsl #48
968 // mov x17, x22/xzr
969 // pacdb x17, x16
970 // str x17, [xBase, #Offset]
971 unsigned Opc = Offset >= 0 ? AArch64::ADDXri : AArch64::SUBXri;
972 BuildMI(MBB, MBBI, DL, TII->get(Opc), AArch64::X16)
973 .addUse(BaseReg)
974 .addImm(abs(Offset))
975 .addImm(0)
977 BuildMI(MBB, MBBI, DL, TII->get(AArch64::MOVKXi), AArch64::X16)
978 .addUse(AArch64::X16)
979 .addImm(0xc31a)
980 .addImm(48)
982 // We're not allowed to clobber X22 (and couldn't clobber XZR if we tried), so
983 // move it somewhere before signing.
984 BuildMI(MBB, MBBI, DL, TII->get(AArch64::ORRXrs), AArch64::X17)
985 .addUse(AArch64::XZR)
986 .addUse(CtxReg)
987 .addImm(0)
989 BuildMI(MBB, MBBI, DL, TII->get(AArch64::PACDB), AArch64::X17)
990 .addUse(AArch64::X17)
991 .addUse(AArch64::X16)
993 BuildMI(MBB, MBBI, DL, TII->get(AArch64::STRXui))
994 .addUse(AArch64::X17)
995 .addUse(BaseReg)
996 .addImm(Offset / 8)
998
1000 return true;
1001}
1002
1003AArch64ExpandPseudo::ConditionalBlocks
1004AArch64ExpandPseudo::expandConditionalPseudo(MachineBasicBlock &MBB,
1006 DebugLoc DL,
1007 MachineInstrBuilder &Branch) {
1008 assert((std::next(MBBI) != MBB.end() ||
1009 MBB.successors().begin() != MBB.successors().end()) &&
1010 "Unexpected unreachable in block");
1011
1012 // Split MBB and create two new blocks:
1013 // - MBB now contains all instructions before the conditional pseudo.
1014 // - CondBB contains the conditional pseudo instruction only.
1015 // - EndBB contains all instructions after the conditional pseudo.
1016 MachineInstr &PrevMI = *std::prev(MBBI);
1017 MachineBasicBlock *CondBB = MBB.splitAt(PrevMI, /*UpdateLiveIns*/ true);
1018 MachineBasicBlock *EndBB =
1019 std::next(MBBI) == CondBB->end()
1020 ? *CondBB->successors().begin()
1021 : CondBB->splitAt(*MBBI, /*UpdateLiveIns*/ true);
1022
1023 // Add the SMBB label to the branch instruction & create a branch to EndBB.
1024 Branch.addMBB(CondBB);
1025 BuildMI(&MBB, DL, TII->get(AArch64::B))
1026 .addMBB(EndBB);
1027 MBB.addSuccessor(EndBB);
1028
1029 // Create branch from CondBB to EndBB. Users of this helper should insert new
1030 // instructions at CondBB.back() -- i.e. before the branch.
1031 BuildMI(CondBB, DL, TII->get(AArch64::B)).addMBB(EndBB);
1032 return {*CondBB, *EndBB};
1033}
1034
1035MachineBasicBlock *
1036AArch64ExpandPseudo::expandRestoreZASave(MachineBasicBlock &MBB,
1038 MachineInstr &MI = *MBBI;
1039 DebugLoc DL = MI.getDebugLoc();
1040
1041 // Compare TPIDR2_EL0 against 0. Restore ZA if TPIDR2_EL0 is zero.
1042 MachineInstrBuilder Branch =
1043 BuildMI(MBB, MBBI, DL, TII->get(AArch64::CBZX)).add(MI.getOperand(0));
1044
1045 auto [CondBB, EndBB] = expandConditionalPseudo(MBB, MBBI, DL, Branch);
1046 // Replace the pseudo with a call (BL).
1047 MachineInstrBuilder MIB =
1048 BuildMI(CondBB, CondBB.back(), DL, TII->get(AArch64::BL));
1049 // Copy operands (mainly the regmask) from the pseudo.
1050 for (unsigned I = 2; I < MI.getNumOperands(); ++I)
1051 MIB.add(MI.getOperand(I));
1052 // Mark the TPIDR2 block pointer (X0) as an implicit use.
1053 MIB.addReg(MI.getOperand(1).getReg(), RegState::Implicit);
1054
1055 MI.eraseFromParent();
1056 return &EndBB;
1057}
1058
1059static constexpr unsigned ZERO_ALL_ZA_MASK = 0b11111111;
1060
1062AArch64ExpandPseudo::expandCommitZASave(MachineBasicBlock &MBB,
1064 MachineInstr &MI = *MBBI;
1065 DebugLoc DL = MI.getDebugLoc();
1066
1067 // Compare TPIDR2_EL0 against 0. Commit ZA if TPIDR2_EL0 is non-zero.
1068 MachineInstrBuilder Branch =
1069 BuildMI(MBB, MBBI, DL, TII->get(AArch64::CBNZX)).add(MI.getOperand(0));
1070
1071 auto [CondBB, EndBB] = expandConditionalPseudo(MBB, MBBI, DL, Branch);
1072 // Replace the pseudo with a call (BL).
1074 BuildMI(CondBB, CondBB.back(), DL, TII->get(AArch64::BL));
1075 // Copy operands (mainly the regmask) from the pseudo.
1076 for (unsigned I = 2; I < MI.getNumOperands(); ++I)
1077 MIB.add(MI.getOperand(I));
1078 // Clear TPIDR2_EL0.
1079 BuildMI(CondBB, CondBB.back(), DL, TII->get(AArch64::MSR))
1080 .addImm(AArch64SysReg::TPIDR2_EL0)
1081 .addReg(AArch64::XZR);
1082 bool ZeroZA = MI.getOperand(1).getImm() != 0;
1083 if (ZeroZA) {
1084 [[maybe_unused]] auto *TRI =
1085 MBB.getParent()->getSubtarget().getRegisterInfo();
1086 assert(MI.definesRegister(AArch64::ZAB0, TRI) && "should define ZA!");
1087 BuildMI(CondBB, CondBB.back(), DL, TII->get(AArch64::ZERO_M))
1089 .addDef(AArch64::ZAB0, RegState::ImplicitDefine);
1090 }
1091
1092 MI.eraseFromParent();
1093 return &EndBB;
1094}
1095
1096MachineBasicBlock *
1097AArch64ExpandPseudo::expandCondSMToggle(MachineBasicBlock &MBB,
1099 MachineInstr &MI = *MBBI;
1100 // In the case of a smstart/smstop before a unreachable, just remove the pseudo.
1101 // Exception handling code generated by Clang may introduce unreachables and it
1102 // seems unnecessary to restore pstate.sm when that happens. Note that it is
1103 // not just an optimisation, the code below expects a successor instruction/block
1104 // in order to split the block at MBBI.
1105 if (std::next(MBBI) == MBB.end() &&
1106 MI.getParent()->successors().begin() ==
1107 MI.getParent()->successors().end()) {
1108 MI.eraseFromParent();
1109 return &MBB;
1110 }
1111
1112 // Expand the pseudo into smstart or smstop instruction. The pseudo has the
1113 // following operands:
1114 //
1115 // MSRpstatePseudo <za|sm|both>, <0|1>, condition[, pstate.sm], <regmask>
1116 //
1117 // The pseudo is expanded into a conditional smstart/smstop, with a
1118 // check if pstate.sm (register) equals the expected value, and if not,
1119 // invokes the smstart/smstop.
1120 //
1121 // As an example, the following block contains a normal call from a
1122 // streaming-compatible function:
1123 //
1124 // OrigBB:
1125 // MSRpstatePseudo 3, 0, IfCallerIsStreaming, %0, <regmask> <- Cond SMSTOP
1126 // bl @normal_callee
1127 // MSRpstatePseudo 3, 1, IfCallerIsStreaming, %0, <regmask> <- Cond SMSTART
1128 //
1129 // ...which will be transformed into:
1130 //
1131 // OrigBB:
1132 // TBNZx %0:gpr64, 0, SMBB
1133 // b EndBB
1134 //
1135 // SMBB:
1136 // MSRpstatesvcrImm1 3, 0, <regmask> <- SMSTOP
1137 //
1138 // EndBB:
1139 // bl @normal_callee
1140 // MSRcond_pstatesvcrImm1 3, 1, <regmask> <- SMSTART
1141 //
1142 DebugLoc DL = MI.getDebugLoc();
1143
1144 // Create the conditional branch based on the third operand of the
1145 // instruction, which tells us if we are wrapping a normal or streaming
1146 // function.
1147 // We test the live value of pstate.sm and toggle pstate.sm if this is not the
1148 // expected value for the callee (0 for a normal callee and 1 for a streaming
1149 // callee).
1150 unsigned Opc;
1151 switch (MI.getOperand(2).getImm()) {
1152 case AArch64SME::Always:
1153 llvm_unreachable("Should have matched to instruction directly");
1155 Opc = AArch64::TBNZW;
1156 break;
1158 Opc = AArch64::TBZW;
1159 break;
1160 }
1161 auto PStateSM = MI.getOperand(3).getReg();
1163 unsigned SMReg32 = TRI->getSubReg(PStateSM, AArch64::sub_32);
1164 MachineInstrBuilder Tbx =
1165 BuildMI(MBB, MBBI, DL, TII->get(Opc)).addReg(SMReg32).addImm(0);
1166
1167 auto [CondBB, EndBB] = expandConditionalPseudo(MBB, MBBI, DL, Tbx);
1168 // Create the SMSTART/SMSTOP (MSRpstatesvcrImm1) instruction in SMBB.
1169 MachineInstrBuilder MIB = BuildMI(CondBB, CondBB.back(), MI.getDebugLoc(),
1170 TII->get(AArch64::MSRpstatesvcrImm1));
1171 // Copy all but the second and third operands of MSRcond_pstatesvcrImm1 (as
1172 // these contain the CopyFromReg for the first argument and the flag to
1173 // indicate whether the callee is streaming or normal).
1174 MIB.add(MI.getOperand(0));
1175 MIB.add(MI.getOperand(1));
1176 for (unsigned i = 4; i < MI.getNumOperands(); ++i)
1177 MIB.add(MI.getOperand(i));
1178
1179 MI.eraseFromParent();
1180 return &EndBB;
1181}
1182
1183bool AArch64ExpandPseudo::expandMultiVecPseudo(
1184 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
1185 TargetRegisterClass ContiguousClass, TargetRegisterClass StridedClass,
1186 unsigned ContiguousOp, unsigned StridedOpc) {
1187 MachineInstr &MI = *MBBI;
1188 Register Tuple = MI.getOperand(0).getReg();
1189
1190 auto ContiguousRange = ContiguousClass.getRegisters();
1191 auto StridedRange = StridedClass.getRegisters();
1192 unsigned Opc;
1193 if (llvm::is_contained(ContiguousRange, Tuple.asMCReg())) {
1194 Opc = ContiguousOp;
1195 } else if (llvm::is_contained(StridedRange, Tuple.asMCReg())) {
1196 Opc = StridedOpc;
1197 } else
1198 llvm_unreachable("Cannot expand Multi-Vector pseudo");
1199
1200 MachineInstrBuilder MIB = BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(Opc))
1201 .add(MI.getOperand(0))
1202 .add(MI.getOperand(1))
1203 .add(MI.getOperand(2))
1204 .add(MI.getOperand(3));
1205 transferImpOps(MI, MIB, MIB);
1206 MI.eraseFromParent();
1207 return true;
1208}
1209
1210bool AArch64ExpandPseudo::expandFormTuplePseudo(
1211 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
1212 MachineBasicBlock::iterator &NextMBBI, unsigned Size) {
1213 assert((Size == 2 || Size == 4) && "Invalid Tuple Size");
1214 MachineInstr &MI = *MBBI;
1215 Register ReturnTuple = MI.getOperand(0).getReg();
1216
1217 const TargetRegisterInfo *TRI =
1219 for (unsigned I = 0; I < Size; ++I) {
1220 Register FormTupleOpReg = MI.getOperand(I + 1).getReg();
1221 Register ReturnTupleSubReg =
1222 TRI->getSubReg(ReturnTuple, AArch64::zsub0 + I);
1223 // Add copies to ensure the subregisters remain in the correct order
1224 // for any contigious operation they are used by.
1225 if (FormTupleOpReg != ReturnTupleSubReg)
1226 BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::ORR_ZZZ))
1227 .addReg(ReturnTupleSubReg, RegState::Define)
1228 .addReg(FormTupleOpReg)
1229 .addReg(FormTupleOpReg);
1230 }
1231
1232 MI.eraseFromParent();
1233 return true;
1234}
1235
1236/// If MBBI references a pseudo instruction that should be expanded here,
1237/// do the expansion and return true. Otherwise return false.
1238bool AArch64ExpandPseudo::expandMI(MachineBasicBlock &MBB,
1240 MachineBasicBlock::iterator &NextMBBI) {
1241 MachineInstr &MI = *MBBI;
1242 unsigned Opcode = MI.getOpcode();
1243
1244 // Check if we can expand the destructive op
1245 int OrigInstr = AArch64::getSVEPseudoMap(MI.getOpcode());
1246 if (OrigInstr != -1) {
1247 auto &Orig = TII->get(OrigInstr);
1248 if ((Orig.TSFlags & AArch64::DestructiveInstTypeMask) !=
1250 return expand_DestructiveOp(MI, MBB, MBBI);
1251 }
1252 }
1253
1254 switch (Opcode) {
1255 default:
1256 break;
1257
1258 case AArch64::BSPv8i8:
1259 case AArch64::BSPv16i8: {
1260 Register DstReg = MI.getOperand(0).getReg();
1261 if (DstReg == MI.getOperand(3).getReg()) {
1262 // Expand to BIT
1263 auto I = BuildMI(MBB, MBBI, MI.getDebugLoc(),
1264 TII->get(Opcode == AArch64::BSPv8i8 ? AArch64::BITv8i8
1265 : AArch64::BITv16i8))
1266 .add(MI.getOperand(0))
1267 .add(MI.getOperand(3))
1268 .add(MI.getOperand(2))
1269 .add(MI.getOperand(1));
1270 transferImpOps(MI, I, I);
1271 } else if (DstReg == MI.getOperand(2).getReg()) {
1272 // Expand to BIF
1273 auto I = BuildMI(MBB, MBBI, MI.getDebugLoc(),
1274 TII->get(Opcode == AArch64::BSPv8i8 ? AArch64::BIFv8i8
1275 : AArch64::BIFv16i8))
1276 .add(MI.getOperand(0))
1277 .add(MI.getOperand(2))
1278 .add(MI.getOperand(3))
1279 .add(MI.getOperand(1));
1280 transferImpOps(MI, I, I);
1281 } else {
1282 // Expand to BSL, use additional move if required
1283 if (DstReg == MI.getOperand(1).getReg()) {
1284 auto I =
1285 BuildMI(MBB, MBBI, MI.getDebugLoc(),
1286 TII->get(Opcode == AArch64::BSPv8i8 ? AArch64::BSLv8i8
1287 : AArch64::BSLv16i8))
1288 .add(MI.getOperand(0))
1289 .add(MI.getOperand(1))
1290 .add(MI.getOperand(2))
1291 .add(MI.getOperand(3));
1292 transferImpOps(MI, I, I);
1293 } else {
1294 unsigned RegState =
1295 getRenamableRegState(MI.getOperand(1).isRenamable()) |
1297 MI.getOperand(1).isKill() &&
1298 MI.getOperand(1).getReg() != MI.getOperand(2).getReg() &&
1299 MI.getOperand(1).getReg() != MI.getOperand(3).getReg());
1300 BuildMI(MBB, MBBI, MI.getDebugLoc(),
1301 TII->get(Opcode == AArch64::BSPv8i8 ? AArch64::ORRv8i8
1302 : AArch64::ORRv16i8))
1303 .addReg(DstReg,
1305 getRenamableRegState(MI.getOperand(0).isRenamable()))
1306 .addReg(MI.getOperand(1).getReg(), RegState)
1307 .addReg(MI.getOperand(1).getReg(), RegState);
1308 auto I2 =
1309 BuildMI(MBB, MBBI, MI.getDebugLoc(),
1310 TII->get(Opcode == AArch64::BSPv8i8 ? AArch64::BSLv8i8
1311 : AArch64::BSLv16i8))
1312 .add(MI.getOperand(0))
1313 .addReg(DstReg,
1315 MI.getOperand(0).isRenamable()))
1316 .add(MI.getOperand(2))
1317 .add(MI.getOperand(3));
1318 transferImpOps(MI, I2, I2);
1319 }
1320 }
1321 MI.eraseFromParent();
1322 return true;
1323 }
1324
1325 case AArch64::ADDWrr:
1326 case AArch64::SUBWrr:
1327 case AArch64::ADDXrr:
1328 case AArch64::SUBXrr:
1329 case AArch64::ADDSWrr:
1330 case AArch64::SUBSWrr:
1331 case AArch64::ADDSXrr:
1332 case AArch64::SUBSXrr:
1333 case AArch64::ANDWrr:
1334 case AArch64::ANDXrr:
1335 case AArch64::BICWrr:
1336 case AArch64::BICXrr:
1337 case AArch64::ANDSWrr:
1338 case AArch64::ANDSXrr:
1339 case AArch64::BICSWrr:
1340 case AArch64::BICSXrr:
1341 case AArch64::EONWrr:
1342 case AArch64::EONXrr:
1343 case AArch64::EORWrr:
1344 case AArch64::EORXrr:
1345 case AArch64::ORNWrr:
1346 case AArch64::ORNXrr:
1347 case AArch64::ORRWrr:
1348 case AArch64::ORRXrr: {
1349 unsigned Opcode;
1350 switch (MI.getOpcode()) {
1351 default:
1352 return false;
1353 case AArch64::ADDWrr: Opcode = AArch64::ADDWrs; break;
1354 case AArch64::SUBWrr: Opcode = AArch64::SUBWrs; break;
1355 case AArch64::ADDXrr: Opcode = AArch64::ADDXrs; break;
1356 case AArch64::SUBXrr: Opcode = AArch64::SUBXrs; break;
1357 case AArch64::ADDSWrr: Opcode = AArch64::ADDSWrs; break;
1358 case AArch64::SUBSWrr: Opcode = AArch64::SUBSWrs; break;
1359 case AArch64::ADDSXrr: Opcode = AArch64::ADDSXrs; break;
1360 case AArch64::SUBSXrr: Opcode = AArch64::SUBSXrs; break;
1361 case AArch64::ANDWrr: Opcode = AArch64::ANDWrs; break;
1362 case AArch64::ANDXrr: Opcode = AArch64::ANDXrs; break;
1363 case AArch64::BICWrr: Opcode = AArch64::BICWrs; break;
1364 case AArch64::BICXrr: Opcode = AArch64::BICXrs; break;
1365 case AArch64::ANDSWrr: Opcode = AArch64::ANDSWrs; break;
1366 case AArch64::ANDSXrr: Opcode = AArch64::ANDSXrs; break;
1367 case AArch64::BICSWrr: Opcode = AArch64::BICSWrs; break;
1368 case AArch64::BICSXrr: Opcode = AArch64::BICSXrs; break;
1369 case AArch64::EONWrr: Opcode = AArch64::EONWrs; break;
1370 case AArch64::EONXrr: Opcode = AArch64::EONXrs; break;
1371 case AArch64::EORWrr: Opcode = AArch64::EORWrs; break;
1372 case AArch64::EORXrr: Opcode = AArch64::EORXrs; break;
1373 case AArch64::ORNWrr: Opcode = AArch64::ORNWrs; break;
1374 case AArch64::ORNXrr: Opcode = AArch64::ORNXrs; break;
1375 case AArch64::ORRWrr: Opcode = AArch64::ORRWrs; break;
1376 case AArch64::ORRXrr: Opcode = AArch64::ORRXrs; break;
1377 }
1378 MachineFunction &MF = *MBB.getParent();
1379 // Try to create new inst without implicit operands added.
1380 MachineInstr *NewMI = MF.CreateMachineInstr(
1381 TII->get(Opcode), MI.getDebugLoc(), /*NoImplicit=*/true);
1382 MBB.insert(MBBI, NewMI);
1383 MachineInstrBuilder MIB1(MF, NewMI);
1384 MIB1->setPCSections(MF, MI.getPCSections());
1385 MIB1.addReg(MI.getOperand(0).getReg(), RegState::Define)
1386 .add(MI.getOperand(1))
1387 .add(MI.getOperand(2))
1389 transferImpOps(MI, MIB1, MIB1);
1390 if (auto DebugNumber = MI.peekDebugInstrNum())
1391 NewMI->setDebugInstrNum(DebugNumber);
1392 MI.eraseFromParent();
1393 return true;
1394 }
1395
1396 case AArch64::LOADgot: {
1397 MachineFunction *MF = MBB.getParent();
1398 Register DstReg = MI.getOperand(0).getReg();
1399 const MachineOperand &MO1 = MI.getOperand(1);
1400 unsigned Flags = MO1.getTargetFlags();
1401
1402 if (MF->getTarget().getCodeModel() == CodeModel::Tiny) {
1403 // Tiny codemodel expand to LDR
1404 MachineInstrBuilder MIB = BuildMI(MBB, MBBI, MI.getDebugLoc(),
1405 TII->get(AArch64::LDRXl), DstReg);
1406
1407 if (MO1.isGlobal()) {
1408 MIB.addGlobalAddress(MO1.getGlobal(), 0, Flags);
1409 } else if (MO1.isSymbol()) {
1410 MIB.addExternalSymbol(MO1.getSymbolName(), Flags);
1411 } else {
1412 assert(MO1.isCPI() &&
1413 "Only expect globals, externalsymbols, or constant pools");
1414 MIB.addConstantPoolIndex(MO1.getIndex(), MO1.getOffset(), Flags);
1415 }
1416 } else {
1417 // Small codemodel expand into ADRP + LDR.
1418 MachineFunction &MF = *MI.getParent()->getParent();
1419 DebugLoc DL = MI.getDebugLoc();
1420 MachineInstrBuilder MIB1 =
1421 BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::ADRP), DstReg);
1422
1423 MachineInstrBuilder MIB2;
1424 if (MF.getSubtarget<AArch64Subtarget>().isTargetILP32()) {
1426 unsigned Reg32 = TRI->getSubReg(DstReg, AArch64::sub_32);
1427 unsigned DstFlags = MI.getOperand(0).getTargetFlags();
1428 MIB2 = BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::LDRWui))
1429 .addDef(Reg32)
1430 .addReg(DstReg, RegState::Kill)
1431 .addReg(DstReg, DstFlags | RegState::Implicit);
1432 } else {
1433 Register DstReg = MI.getOperand(0).getReg();
1434 MIB2 = BuildMI(MBB, MBBI, DL, TII->get(AArch64::LDRXui))
1435 .add(MI.getOperand(0))
1436 .addUse(DstReg, RegState::Kill);
1437 }
1438
1439 if (MO1.isGlobal()) {
1440 MIB1.addGlobalAddress(MO1.getGlobal(), 0, Flags | AArch64II::MO_PAGE);
1441 MIB2.addGlobalAddress(MO1.getGlobal(), 0,
1443 } else if (MO1.isSymbol()) {
1445 MIB2.addExternalSymbol(MO1.getSymbolName(), Flags |
1448 } else {
1449 assert(MO1.isCPI() &&
1450 "Only expect globals, externalsymbols, or constant pools");
1451 MIB1.addConstantPoolIndex(MO1.getIndex(), MO1.getOffset(),
1452 Flags | AArch64II::MO_PAGE);
1453 MIB2.addConstantPoolIndex(MO1.getIndex(), MO1.getOffset(),
1454 Flags | AArch64II::MO_PAGEOFF |
1456 }
1457
1458 // If the LOADgot instruction has a debug-instr-number, annotate the
1459 // LDRWui instruction that it is expanded to with the same
1460 // debug-instr-number to preserve debug information.
1461 if (MI.peekDebugInstrNum() != 0)
1462 MIB2->setDebugInstrNum(MI.peekDebugInstrNum());
1463 transferImpOps(MI, MIB1, MIB2);
1464 }
1465 MI.eraseFromParent();
1466 return true;
1467 }
1468 case AArch64::MOVaddrBA: {
1469 MachineFunction &MF = *MI.getParent()->getParent();
1470 if (MF.getSubtarget<AArch64Subtarget>().isTargetMachO()) {
1471 // blockaddress expressions have to come from a constant pool because the
1472 // largest addend (and hence offset within a function) allowed for ADRP is
1473 // only 8MB.
1474 const BlockAddress *BA = MI.getOperand(1).getBlockAddress();
1475 assert(MI.getOperand(1).getOffset() == 0 && "unexpected offset");
1476
1477 MachineConstantPool *MCP = MF.getConstantPool();
1478 unsigned CPIdx = MCP->getConstantPoolIndex(BA, Align(8));
1479
1480 Register DstReg = MI.getOperand(0).getReg();
1481 auto MIB1 =
1482 BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::ADRP), DstReg)
1484 auto MIB2 = BuildMI(MBB, MBBI, MI.getDebugLoc(),
1485 TII->get(AArch64::LDRXui), DstReg)
1486 .addUse(DstReg)
1489 transferImpOps(MI, MIB1, MIB2);
1490 MI.eraseFromParent();
1491 return true;
1492 }
1493 }
1494 [[fallthrough]];
1495 case AArch64::MOVaddr:
1496 case AArch64::MOVaddrJT:
1497 case AArch64::MOVaddrCP:
1498 case AArch64::MOVaddrTLS:
1499 case AArch64::MOVaddrEXT: {
1500 // Expand into ADRP + ADD.
1501 Register DstReg = MI.getOperand(0).getReg();
1502 assert(DstReg != AArch64::XZR);
1503 MachineInstrBuilder MIB1 =
1504 BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::ADRP), DstReg)
1505 .add(MI.getOperand(1));
1506
1507 if (MI.getOperand(1).getTargetFlags() & AArch64II::MO_TAGGED) {
1508 // MO_TAGGED on the page indicates a tagged address. Set the tag now.
1509 // We do so by creating a MOVK that sets bits 48-63 of the register to
1510 // (global address + 0x100000000 - PC) >> 48. This assumes that we're in
1511 // the small code model so we can assume a binary size of <= 4GB, which
1512 // makes the untagged PC relative offset positive. The binary must also be
1513 // loaded into address range [0, 2^48). Both of these properties need to
1514 // be ensured at runtime when using tagged addresses.
1515 auto Tag = MI.getOperand(1);
1516 Tag.setTargetFlags(AArch64II::MO_PREL | AArch64II::MO_G3);
1517 Tag.setOffset(0x100000000);
1518 BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::MOVKXi), DstReg)
1519 .addReg(DstReg)
1520 .add(Tag)
1521 .addImm(48);
1522 }
1523
1524 MachineInstrBuilder MIB2 =
1525 BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::ADDXri))
1526 .add(MI.getOperand(0))
1527 .addReg(DstReg)
1528 .add(MI.getOperand(2))
1529 .addImm(0);
1530
1531 transferImpOps(MI, MIB1, MIB2);
1532 MI.eraseFromParent();
1533 return true;
1534 }
1535 case AArch64::ADDlowTLS:
1536 // Produce a plain ADD
1537 BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::ADDXri))
1538 .add(MI.getOperand(0))
1539 .add(MI.getOperand(1))
1540 .add(MI.getOperand(2))
1541 .addImm(0);
1542 MI.eraseFromParent();
1543 return true;
1544
1545 case AArch64::MOVbaseTLS: {
1546 Register DstReg = MI.getOperand(0).getReg();
1547 auto SysReg = AArch64SysReg::TPIDR_EL0;
1548 MachineFunction *MF = MBB.getParent();
1549 if (MF->getSubtarget<AArch64Subtarget>().useEL3ForTP())
1550 SysReg = AArch64SysReg::TPIDR_EL3;
1551 else if (MF->getSubtarget<AArch64Subtarget>().useEL2ForTP())
1552 SysReg = AArch64SysReg::TPIDR_EL2;
1553 else if (MF->getSubtarget<AArch64Subtarget>().useEL1ForTP())
1554 SysReg = AArch64SysReg::TPIDR_EL1;
1555 else if (MF->getSubtarget<AArch64Subtarget>().useROEL0ForTP())
1556 SysReg = AArch64SysReg::TPIDRRO_EL0;
1557 BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::MRS), DstReg)
1558 .addImm(SysReg);
1559 MI.eraseFromParent();
1560 return true;
1561 }
1562
1563 case AArch64::MOVi32imm:
1564 return expandMOVImm(MBB, MBBI, 32);
1565 case AArch64::MOVi64imm:
1566 return expandMOVImm(MBB, MBBI, 64);
1567 case AArch64::RET_ReallyLR: {
1568 // Hiding the LR use with RET_ReallyLR may lead to extra kills in the
1569 // function and missing live-ins. We are fine in practice because callee
1570 // saved register handling ensures the register value is restored before
1571 // RET, but we need the undef flag here to appease the MachineVerifier
1572 // liveness checks.
1573 MachineInstrBuilder MIB =
1574 BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::RET))
1575 .addReg(AArch64::LR, RegState::Undef);
1576 transferImpOps(MI, MIB, MIB);
1577 MI.eraseFromParent();
1578 return true;
1579 }
1580 case AArch64::CMP_SWAP_8:
1581 return expandCMP_SWAP(MBB, MBBI, AArch64::LDAXRB, AArch64::STLXRB,
1582 AArch64::SUBSWrx,
1584 AArch64::WZR, NextMBBI);
1585 case AArch64::CMP_SWAP_16:
1586 return expandCMP_SWAP(MBB, MBBI, AArch64::LDAXRH, AArch64::STLXRH,
1587 AArch64::SUBSWrx,
1589 AArch64::WZR, NextMBBI);
1590 case AArch64::CMP_SWAP_32:
1591 return expandCMP_SWAP(MBB, MBBI, AArch64::LDAXRW, AArch64::STLXRW,
1592 AArch64::SUBSWrs,
1594 AArch64::WZR, NextMBBI);
1595 case AArch64::CMP_SWAP_64:
1596 return expandCMP_SWAP(MBB, MBBI,
1597 AArch64::LDAXRX, AArch64::STLXRX, AArch64::SUBSXrs,
1599 AArch64::XZR, NextMBBI);
1600 case AArch64::CMP_SWAP_128:
1601 case AArch64::CMP_SWAP_128_RELEASE:
1602 case AArch64::CMP_SWAP_128_ACQUIRE:
1603 case AArch64::CMP_SWAP_128_MONOTONIC:
1604 return expandCMP_SWAP_128(MBB, MBBI, NextMBBI);
1605
1606 case AArch64::AESMCrrTied:
1607 case AArch64::AESIMCrrTied: {
1608 MachineInstrBuilder MIB =
1609 BuildMI(MBB, MBBI, MI.getDebugLoc(),
1610 TII->get(Opcode == AArch64::AESMCrrTied ? AArch64::AESMCrr :
1611 AArch64::AESIMCrr))
1612 .add(MI.getOperand(0))
1613 .add(MI.getOperand(1));
1614 transferImpOps(MI, MIB, MIB);
1615 MI.eraseFromParent();
1616 return true;
1617 }
1618 case AArch64::IRGstack: {
1619 MachineFunction &MF = *MBB.getParent();
1620 const AArch64FunctionInfo *AFI = MF.getInfo<AArch64FunctionInfo>();
1621 const AArch64FrameLowering *TFI =
1622 MF.getSubtarget<AArch64Subtarget>().getFrameLowering();
1623
1624 // IRG does not allow immediate offset. getTaggedBasePointerOffset should
1625 // almost always point to SP-after-prologue; if not, emit a longer
1626 // instruction sequence.
1627 int BaseOffset = -AFI->getTaggedBasePointerOffset();
1628 Register FrameReg;
1629 StackOffset FrameRegOffset = TFI->resolveFrameOffsetReference(
1630 MF, BaseOffset, false /*isFixed*/, TargetStackID::Default /*StackID*/,
1631 FrameReg,
1632 /*PreferFP=*/false,
1633 /*ForSimm=*/true);
1634 Register SrcReg = FrameReg;
1635 if (FrameRegOffset) {
1636 // Use output register as temporary.
1637 SrcReg = MI.getOperand(0).getReg();
1638 emitFrameOffset(MBB, &MI, MI.getDebugLoc(), SrcReg, FrameReg,
1639 FrameRegOffset, TII);
1640 }
1641 BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::IRG))
1642 .add(MI.getOperand(0))
1643 .addUse(SrcReg)
1644 .add(MI.getOperand(2));
1645 MI.eraseFromParent();
1646 return true;
1647 }
1648 case AArch64::TAGPstack: {
1649 int64_t Offset = MI.getOperand(2).getImm();
1650 BuildMI(MBB, MBBI, MI.getDebugLoc(),
1651 TII->get(Offset >= 0 ? AArch64::ADDG : AArch64::SUBG))
1652 .add(MI.getOperand(0))
1653 .add(MI.getOperand(1))
1654 .addImm(std::abs(Offset))
1655 .add(MI.getOperand(4));
1656 MI.eraseFromParent();
1657 return true;
1658 }
1659 case AArch64::STGloop_wback:
1660 case AArch64::STZGloop_wback:
1661 return expandSetTagLoop(MBB, MBBI, NextMBBI);
1662 case AArch64::STGloop:
1663 case AArch64::STZGloop:
1665 "Non-writeback variants of STGloop / STZGloop should not "
1666 "survive past PrologEpilogInserter.");
1667 case AArch64::STR_ZZZZXI:
1668 case AArch64::STR_ZZZZXI_STRIDED_CONTIGUOUS:
1669 return expandSVESpillFill(MBB, MBBI, AArch64::STR_ZXI, 4);
1670 case AArch64::STR_ZZZXI:
1671 return expandSVESpillFill(MBB, MBBI, AArch64::STR_ZXI, 3);
1672 case AArch64::STR_ZZXI:
1673 case AArch64::STR_ZZXI_STRIDED_CONTIGUOUS:
1674 return expandSVESpillFill(MBB, MBBI, AArch64::STR_ZXI, 2);
1675 case AArch64::STR_PPXI:
1676 return expandSVESpillFill(MBB, MBBI, AArch64::STR_PXI, 2);
1677 case AArch64::LDR_ZZZZXI:
1678 case AArch64::LDR_ZZZZXI_STRIDED_CONTIGUOUS:
1679 return expandSVESpillFill(MBB, MBBI, AArch64::LDR_ZXI, 4);
1680 case AArch64::LDR_ZZZXI:
1681 return expandSVESpillFill(MBB, MBBI, AArch64::LDR_ZXI, 3);
1682 case AArch64::LDR_ZZXI:
1683 case AArch64::LDR_ZZXI_STRIDED_CONTIGUOUS:
1684 return expandSVESpillFill(MBB, MBBI, AArch64::LDR_ZXI, 2);
1685 case AArch64::LDR_PPXI:
1686 return expandSVESpillFill(MBB, MBBI, AArch64::LDR_PXI, 2);
1687 case AArch64::BLR_RVMARKER:
1688 case AArch64::BLRA_RVMARKER:
1689 return expandCALL_RVMARKER(MBB, MBBI);
1690 case AArch64::BLR_BTI:
1691 return expandCALL_BTI(MBB, MBBI);
1692 case AArch64::StoreSwiftAsyncContext:
1693 return expandStoreSwiftAsyncContext(MBB, MBBI);
1694 case AArch64::RestoreZAPseudo:
1695 case AArch64::CommitZASavePseudo:
1696 case AArch64::MSRpstatePseudo: {
1697 auto *NewMBB = [&] {
1698 switch (Opcode) {
1699 case AArch64::RestoreZAPseudo:
1700 return expandRestoreZASave(MBB, MBBI);
1701 case AArch64::CommitZASavePseudo:
1702 return expandCommitZASave(MBB, MBBI);
1703 case AArch64::MSRpstatePseudo:
1704 return expandCondSMToggle(MBB, MBBI);
1705 default:
1706 llvm_unreachable("Unexpected conditional pseudo!");
1707 }
1708 }();
1709 if (NewMBB != &MBB)
1710 NextMBBI = MBB.end(); // The NextMBBI iterator is invalidated.
1711 return true;
1712 }
1713 case AArch64::InOutZAUsePseudo:
1714 case AArch64::RequiresZASavePseudo:
1715 case AArch64::SMEStateAllocPseudo:
1716 case AArch64::COALESCER_BARRIER_FPR16:
1717 case AArch64::COALESCER_BARRIER_FPR32:
1718 case AArch64::COALESCER_BARRIER_FPR64:
1719 case AArch64::COALESCER_BARRIER_FPR128:
1720 MI.eraseFromParent();
1721 return true;
1722 case AArch64::LD1B_2Z_IMM_PSEUDO:
1723 return expandMultiVecPseudo(
1724 MBB, MBBI, AArch64::ZPR2RegClass, AArch64::ZPR2StridedRegClass,
1725 AArch64::LD1B_2Z_IMM, AArch64::LD1B_2Z_STRIDED_IMM);
1726 case AArch64::LD1H_2Z_IMM_PSEUDO:
1727 return expandMultiVecPseudo(
1728 MBB, MBBI, AArch64::ZPR2RegClass, AArch64::ZPR2StridedRegClass,
1729 AArch64::LD1H_2Z_IMM, AArch64::LD1H_2Z_STRIDED_IMM);
1730 case AArch64::LD1W_2Z_IMM_PSEUDO:
1731 return expandMultiVecPseudo(
1732 MBB, MBBI, AArch64::ZPR2RegClass, AArch64::ZPR2StridedRegClass,
1733 AArch64::LD1W_2Z_IMM, AArch64::LD1W_2Z_STRIDED_IMM);
1734 case AArch64::LD1D_2Z_IMM_PSEUDO:
1735 return expandMultiVecPseudo(
1736 MBB, MBBI, AArch64::ZPR2RegClass, AArch64::ZPR2StridedRegClass,
1737 AArch64::LD1D_2Z_IMM, AArch64::LD1D_2Z_STRIDED_IMM);
1738 case AArch64::LDNT1B_2Z_IMM_PSEUDO:
1739 return expandMultiVecPseudo(
1740 MBB, MBBI, AArch64::ZPR2RegClass, AArch64::ZPR2StridedRegClass,
1741 AArch64::LDNT1B_2Z_IMM, AArch64::LDNT1B_2Z_STRIDED_IMM);
1742 case AArch64::LDNT1H_2Z_IMM_PSEUDO:
1743 return expandMultiVecPseudo(
1744 MBB, MBBI, AArch64::ZPR2RegClass, AArch64::ZPR2StridedRegClass,
1745 AArch64::LDNT1H_2Z_IMM, AArch64::LDNT1H_2Z_STRIDED_IMM);
1746 case AArch64::LDNT1W_2Z_IMM_PSEUDO:
1747 return expandMultiVecPseudo(
1748 MBB, MBBI, AArch64::ZPR2RegClass, AArch64::ZPR2StridedRegClass,
1749 AArch64::LDNT1W_2Z_IMM, AArch64::LDNT1W_2Z_STRIDED_IMM);
1750 case AArch64::LDNT1D_2Z_IMM_PSEUDO:
1751 return expandMultiVecPseudo(
1752 MBB, MBBI, AArch64::ZPR2RegClass, AArch64::ZPR2StridedRegClass,
1753 AArch64::LDNT1D_2Z_IMM, AArch64::LDNT1D_2Z_STRIDED_IMM);
1754 case AArch64::LD1B_2Z_PSEUDO:
1755 return expandMultiVecPseudo(MBB, MBBI, AArch64::ZPR2RegClass,
1756 AArch64::ZPR2StridedRegClass, AArch64::LD1B_2Z,
1757 AArch64::LD1B_2Z_STRIDED);
1758 case AArch64::LD1H_2Z_PSEUDO:
1759 return expandMultiVecPseudo(MBB, MBBI, AArch64::ZPR2RegClass,
1760 AArch64::ZPR2StridedRegClass, AArch64::LD1H_2Z,
1761 AArch64::LD1H_2Z_STRIDED);
1762 case AArch64::LD1W_2Z_PSEUDO:
1763 return expandMultiVecPseudo(MBB, MBBI, AArch64::ZPR2RegClass,
1764 AArch64::ZPR2StridedRegClass, AArch64::LD1W_2Z,
1765 AArch64::LD1W_2Z_STRIDED);
1766 case AArch64::LD1D_2Z_PSEUDO:
1767 return expandMultiVecPseudo(MBB, MBBI, AArch64::ZPR2RegClass,
1768 AArch64::ZPR2StridedRegClass, AArch64::LD1D_2Z,
1769 AArch64::LD1D_2Z_STRIDED);
1770 case AArch64::LDNT1B_2Z_PSEUDO:
1771 return expandMultiVecPseudo(
1772 MBB, MBBI, AArch64::ZPR2RegClass, AArch64::ZPR2StridedRegClass,
1773 AArch64::LDNT1B_2Z, AArch64::LDNT1B_2Z_STRIDED);
1774 case AArch64::LDNT1H_2Z_PSEUDO:
1775 return expandMultiVecPseudo(
1776 MBB, MBBI, AArch64::ZPR2RegClass, AArch64::ZPR2StridedRegClass,
1777 AArch64::LDNT1H_2Z, AArch64::LDNT1H_2Z_STRIDED);
1778 case AArch64::LDNT1W_2Z_PSEUDO:
1779 return expandMultiVecPseudo(
1780 MBB, MBBI, AArch64::ZPR2RegClass, AArch64::ZPR2StridedRegClass,
1781 AArch64::LDNT1W_2Z, AArch64::LDNT1W_2Z_STRIDED);
1782 case AArch64::LDNT1D_2Z_PSEUDO:
1783 return expandMultiVecPseudo(
1784 MBB, MBBI, AArch64::ZPR2RegClass, AArch64::ZPR2StridedRegClass,
1785 AArch64::LDNT1D_2Z, AArch64::LDNT1D_2Z_STRIDED);
1786 case AArch64::LD1B_4Z_IMM_PSEUDO:
1787 return expandMultiVecPseudo(
1788 MBB, MBBI, AArch64::ZPR4RegClass, AArch64::ZPR4StridedRegClass,
1789 AArch64::LD1B_4Z_IMM, AArch64::LD1B_4Z_STRIDED_IMM);
1790 case AArch64::LD1H_4Z_IMM_PSEUDO:
1791 return expandMultiVecPseudo(
1792 MBB, MBBI, AArch64::ZPR4RegClass, AArch64::ZPR4StridedRegClass,
1793 AArch64::LD1H_4Z_IMM, AArch64::LD1H_4Z_STRIDED_IMM);
1794 case AArch64::LD1W_4Z_IMM_PSEUDO:
1795 return expandMultiVecPseudo(
1796 MBB, MBBI, AArch64::ZPR4RegClass, AArch64::ZPR4StridedRegClass,
1797 AArch64::LD1W_4Z_IMM, AArch64::LD1W_4Z_STRIDED_IMM);
1798 case AArch64::LD1D_4Z_IMM_PSEUDO:
1799 return expandMultiVecPseudo(
1800 MBB, MBBI, AArch64::ZPR4RegClass, AArch64::ZPR4StridedRegClass,
1801 AArch64::LD1D_4Z_IMM, AArch64::LD1D_4Z_STRIDED_IMM);
1802 case AArch64::LDNT1B_4Z_IMM_PSEUDO:
1803 return expandMultiVecPseudo(
1804 MBB, MBBI, AArch64::ZPR4RegClass, AArch64::ZPR4StridedRegClass,
1805 AArch64::LDNT1B_4Z_IMM, AArch64::LDNT1B_4Z_STRIDED_IMM);
1806 case AArch64::LDNT1H_4Z_IMM_PSEUDO:
1807 return expandMultiVecPseudo(
1808 MBB, MBBI, AArch64::ZPR4RegClass, AArch64::ZPR4StridedRegClass,
1809 AArch64::LDNT1H_4Z_IMM, AArch64::LDNT1H_4Z_STRIDED_IMM);
1810 case AArch64::LDNT1W_4Z_IMM_PSEUDO:
1811 return expandMultiVecPseudo(
1812 MBB, MBBI, AArch64::ZPR4RegClass, AArch64::ZPR4StridedRegClass,
1813 AArch64::LDNT1W_4Z_IMM, AArch64::LDNT1W_4Z_STRIDED_IMM);
1814 case AArch64::LDNT1D_4Z_IMM_PSEUDO:
1815 return expandMultiVecPseudo(
1816 MBB, MBBI, AArch64::ZPR4RegClass, AArch64::ZPR4StridedRegClass,
1817 AArch64::LDNT1D_4Z_IMM, AArch64::LDNT1D_4Z_STRIDED_IMM);
1818 case AArch64::LD1B_4Z_PSEUDO:
1819 return expandMultiVecPseudo(MBB, MBBI, AArch64::ZPR4RegClass,
1820 AArch64::ZPR4StridedRegClass, AArch64::LD1B_4Z,
1821 AArch64::LD1B_4Z_STRIDED);
1822 case AArch64::LD1H_4Z_PSEUDO:
1823 return expandMultiVecPseudo(MBB, MBBI, AArch64::ZPR4RegClass,
1824 AArch64::ZPR4StridedRegClass, AArch64::LD1H_4Z,
1825 AArch64::LD1H_4Z_STRIDED);
1826 case AArch64::LD1W_4Z_PSEUDO:
1827 return expandMultiVecPseudo(MBB, MBBI, AArch64::ZPR4RegClass,
1828 AArch64::ZPR4StridedRegClass, AArch64::LD1W_4Z,
1829 AArch64::LD1W_4Z_STRIDED);
1830 case AArch64::LD1D_4Z_PSEUDO:
1831 return expandMultiVecPseudo(MBB, MBBI, AArch64::ZPR4RegClass,
1832 AArch64::ZPR4StridedRegClass, AArch64::LD1D_4Z,
1833 AArch64::LD1D_4Z_STRIDED);
1834 case AArch64::LDNT1B_4Z_PSEUDO:
1835 return expandMultiVecPseudo(
1836 MBB, MBBI, AArch64::ZPR4RegClass, AArch64::ZPR4StridedRegClass,
1837 AArch64::LDNT1B_4Z, AArch64::LDNT1B_4Z_STRIDED);
1838 case AArch64::LDNT1H_4Z_PSEUDO:
1839 return expandMultiVecPseudo(
1840 MBB, MBBI, AArch64::ZPR4RegClass, AArch64::ZPR4StridedRegClass,
1841 AArch64::LDNT1H_4Z, AArch64::LDNT1H_4Z_STRIDED);
1842 case AArch64::LDNT1W_4Z_PSEUDO:
1843 return expandMultiVecPseudo(
1844 MBB, MBBI, AArch64::ZPR4RegClass, AArch64::ZPR4StridedRegClass,
1845 AArch64::LDNT1W_4Z, AArch64::LDNT1W_4Z_STRIDED);
1846 case AArch64::LDNT1D_4Z_PSEUDO:
1847 return expandMultiVecPseudo(
1848 MBB, MBBI, AArch64::ZPR4RegClass, AArch64::ZPR4StridedRegClass,
1849 AArch64::LDNT1D_4Z, AArch64::LDNT1D_4Z_STRIDED);
1850 case AArch64::FORM_TRANSPOSED_REG_TUPLE_X2_PSEUDO:
1851 return expandFormTuplePseudo(MBB, MBBI, NextMBBI, 2);
1852 case AArch64::FORM_TRANSPOSED_REG_TUPLE_X4_PSEUDO:
1853 return expandFormTuplePseudo(MBB, MBBI, NextMBBI, 4);
1854 }
1855 return false;
1856}
1857
1858/// Iterate over the instructions in basic block MBB and expand any
1859/// pseudo instructions. Return true if anything was modified.
1860bool AArch64ExpandPseudo::expandMBB(MachineBasicBlock &MBB) {
1861 bool Modified = false;
1862
1864 while (MBBI != E) {
1865 MachineBasicBlock::iterator NMBBI = std::next(MBBI);
1866 Modified |= expandMI(MBB, MBBI, NMBBI);
1867 MBBI = NMBBI;
1868 }
1869
1870 return Modified;
1871}
1872
1873bool AArch64ExpandPseudo::runOnMachineFunction(MachineFunction &MF) {
1874 TII = static_cast<const AArch64InstrInfo *>(MF.getSubtarget().getInstrInfo());
1875
1876 bool Modified = false;
1877 for (auto &MBB : MF)
1878 Modified |= expandMBB(MBB);
1879 return Modified;
1880}
1881
1882/// Returns an instance of the pseudo instruction expansion pass.
1884 return new AArch64ExpandPseudo();
1885}
#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!")
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:58
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 unsigned getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:41
A debug info location.
Definition DebugLoc.h:124
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:314
Describe properties that are true of each instruction in the target description file.
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
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 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 & 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 & addReg(Register RegNo, unsigned flags=0, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
const MachineInstrBuilder & cloneMemRefs(const MachineInstr &OtherMI) const
const MachineInstrBuilder & addUse(Register RegNo, unsigned Flags=0, unsigned SubReg=0) const
Add a virtual register use operand.
const MachineInstrBuilder & setMIFlags(unsigned Flags) const
MachineInstr * getInstr() const
If conversion operators fail, use this method to get the MachineInstr explicitly.
const MachineInstrBuilder & addDef(Register RegNo, unsigned Flags=0, unsigned SubReg=0) const
Add a virtual register definition operand.
Representation of each machine instruction.
void setDebugInstrNum(unsigned Num)
Set instruction number 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.
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.
MCRegister asMCReg() const
Utility to check-convert this value to a MCRegister.
Definition Register.h:102
void push_back(const T &Elt)
StringRef - Represent a constant reference to a string, i.e.
Definition StringRef.h:55
CodeModel::Model getCodeModel() const
Returns the code model.
ArrayRef< MCPhysReg > getRegisters() const
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_TAGGED
MO_TAGGED - With MO_PAGE, indicates that the page includes a memory tag in bits 56-63.
@ 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 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...
int getSVERevInstr(uint16_t Opcode)
int getSVEPseudoMap(uint16_t Opcode)
int getSVENonRevInstr(uint16_t Opcode)
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
@ Implicit
Not emitted register (e.g. carry, or temporary result).
@ Renamable
Register that may be renamed.
@ Define
Register definition.
@ Kill
The last use of a register.
@ Undef
Value of the register doesn't matter.
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:318
@ Offset
Definition DWP.cpp:477
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.
APFloat abs(APFloat X)
Returns the absolute value of the argument.
Definition APFloat.h:1563
unsigned getDeadRegState(bool B)
Op::Description Desc
FunctionPass * createAArch64ExpandPseudoPass()
Returns an instance of the pseudo instruction expansion pass.
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:167
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
unsigned getKillRegState(bool B)
unsigned getRenamableRegState(bool B)
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Definition STLExtras.h:1899
void computeAndAddLiveIns(LivePhysRegs &LiveRegs, MachineBasicBlock &MBB)
Convenience function combining computeLiveIns() and addLiveIns().
#define N