[llvm] Aarch64 extract movz movk only subtarget feature (PR #216166)
Tomer Shafir via llvm-commits
llvm-commits at lists.llvm.org
Thu Aug 13 13:05:56 PDT 2026
https://github.com/tomershafir created https://github.com/llvm/llvm-project/pull/216166
Depends on https://github.com/llvm/llvm-project/pull/214849. The first 5 commits are from the base PR.
>From 9a1c1c68f4c3284498fced1767500160f579a6e0 Mon Sep 17 00:00:00 2001
From: tomershafir <tomer.shafir8 at gmail.com>
Date: Fri, 7 Aug 2026 09:56:26 +0300
Subject: [PATCH 1/5] [AArch64] Restrict FP imm ISel by accurate subtarget
macro-fusion
This patch improves the accuracy of FP immediate lowering for runtime performance builds. Until now we relaxed the instruction count limit from 2 to 4 merely based on the satisfaction of `ST.hasFuseLiterals`, but this could be wrong for example false-positive for `MOVN` instructions which would relax the limit but are not macro fused. Here we check exactly if immediate materialization parts can be macro fus
ed using a new subtarget helper which is shared with macro-fusion.
---
.../Target/AArch64/AArch64ISelLowering.cpp | 22 +-
.../lib/Target/AArch64/AArch64MacroFusion.cpp | 28 +-
llvm/lib/Target/AArch64/AArch64Subtarget.cpp | 47 ++
llvm/lib/Target/AArch64/AArch64Subtarget.h | 11 +
.../fpimm-legal-expand-fuse-literals.ll | 589 ++++++++++++++++++
.../AArch64/fpimm-legal-expand-optsize.ll | 117 ++++
6 files changed, 787 insertions(+), 27 deletions(-)
create mode 100644 llvm/test/CodeGen/AArch64/fpimm-legal-expand-fuse-literals.ll
create mode 100644 llvm/test/CodeGen/AArch64/fpimm-legal-expand-optsize.ll
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 51be0e66b19b0..be3d337358d53 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -13756,7 +13756,6 @@ bool AArch64TargetLowering::isFPImmLegalAsFMov(const APFloat &Imm,
bool AArch64TargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT,
bool OptForSize) const {
bool IsLegal = isFPImmLegalAsFMov(Imm, VT);
- const APInt ImmInt = Imm.bitcastToAPInt();
// If we can not materialize in immediate field for fmov, check if the
// value can be encoded as the immediate operand of a logical instruction.
@@ -13771,15 +13770,32 @@ bool AArch64TargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT,
// movw+movk is fused). So by default we limit up to 2 instructions
// or 4 with hasFuseLiterals.
SmallVector<AArch64_IMM::ImmInsnModel, 4> Insn;
+ const APInt ImmInt = Imm.bitcastToAPInt();
AArch64_IMM::expandMOVImm(ImmInt.getZExtValue(), VT.getSizeInBits(), Insn);
assert(Insn.size() <= 4 &&
"Should be able to build any value with at most 4 moves");
- unsigned Limit = (OptForSize ? 1 : (Subtarget->hasFuseLiterals() ? 4 : 2));
+
+ unsigned Limit = OptForSize ? 1 : 2;
+
+ if (!OptForSize && Insn.size() > Limit && Subtarget->hasFuseLiterals()) {
+ // Relax the limit based on subtarget fusion capabilites
+ for (unsigned i = 0; i + 1 < Insn.size(); ++i) {
+ if (Subtarget->fusesMOVImmPair(Insn[i].Opcode, Insn[i].Op2,
+ Insn[i + 1].Opcode, Insn[i + 1].Op2)) {
+ ++Limit;
+ // An instruction can only be fused once, so the 2nd one of the pair
+ // cannot start another pair and is skipped.
+ ++i;
+ }
+ }
+ }
+
IsLegal = Insn.size() <= Limit;
}
LLVM_DEBUG(dbgs() << (IsLegal ? "Legal " : "Illegal ") << VT
- << " imm value: "; Imm.dump(););
+ << " imm value: ";
+ Imm.dump(););
return IsLegal;
}
diff --git a/llvm/lib/Target/AArch64/AArch64MacroFusion.cpp b/llvm/lib/Target/AArch64/AArch64MacroFusion.cpp
index c367b65cd28f9..d5c669c14b296 100644
--- a/llvm/lib/Target/AArch64/AArch64MacroFusion.cpp
+++ b/llvm/lib/Target/AArch64/AArch64MacroFusion.cpp
@@ -224,30 +224,10 @@ static bool isAdrpAddPair(const MachineInstr *FirstMI,
}
/// Literal generation.
-static bool isLiteralsPair(const MachineInstr *FirstMI,
+static bool isLiteralsPair(const AArch64Subtarget &ST,
+ const MachineInstr *FirstMI,
const MachineInstr &SecondMI) {
- // Assume the 1st instr to be a wildcard if it is unspecified.
- // 32 bit immediate.
- if ((FirstMI == nullptr || FirstMI->getOpcode() == AArch64::MOVZWi) &&
- (SecondMI.getOpcode() == AArch64::MOVKWi &&
- SecondMI.getOperand(3).getImm() == 16))
- return true;
-
- // Lower half of 64 bit immediate.
- if((FirstMI == nullptr || FirstMI->getOpcode() == AArch64::MOVZXi) &&
- (SecondMI.getOpcode() == AArch64::MOVKXi &&
- SecondMI.getOperand(3).getImm() == 16))
- return true;
-
- // Upper half of 64 bit immediate.
- if ((FirstMI == nullptr ||
- (FirstMI->getOpcode() == AArch64::MOVKXi &&
- FirstMI->getOperand(3).getImm() == 32)) &&
- (SecondMI.getOpcode() == AArch64::MOVKXi &&
- SecondMI.getOperand(3).getImm() == 48))
- return true;
-
- return false;
+ return ST.fusesMOVImmPair(FirstMI, SecondMI);
}
/// Fuse address generation and loads or stores.
@@ -714,7 +694,7 @@ static bool shouldScheduleAdjacent(const TargetInstrInfo &TII,
++NumFusedAdrpAdd;
return true;
}
- if (ST.hasFuseLiterals() && isLiteralsPair(FirstMI, SecondMI)) {
+ if (ST.hasFuseLiterals() && isLiteralsPair(ST, FirstMI, SecondMI)) {
++NumFusedLiterals;
return true;
}
diff --git a/llvm/lib/Target/AArch64/AArch64Subtarget.cpp b/llvm/lib/Target/AArch64/AArch64Subtarget.cpp
index 9ee3d0cc9e0ea..4fef12ab37ad8 100644
--- a/llvm/lib/Target/AArch64/AArch64Subtarget.cpp
+++ b/llvm/lib/Target/AArch64/AArch64Subtarget.cpp
@@ -651,3 +651,50 @@ bool AArch64Subtarget::isX16X17Safer() const {
bool AArch64Subtarget::enableMachinePipeliner() const {
return getSchedModel().hasInstrSchedModel();
}
+
+/// Returns a MOVK's shifter operand, or 0 otherwise.
+static unsigned getMOVKShiftImm(const MachineInstr &MI) {
+ unsigned Opc = MI.getOpcode();
+ if (Opc != AArch64::MOVKWi && Opc != AArch64::MOVKXi)
+ return 0;
+ return MI.getOperand(3).getImm();
+}
+
+/// \p HasFirst is false when the 1st instruction is a wildcard.
+static bool fusesMOVImmPairImpl(const AArch64Subtarget &ST, bool HasFirst,
+ unsigned FirstOpc, unsigned FirstShift,
+ unsigned SecondOpc, unsigned SecondShift) {
+ assert(ST.hasFuseLiterals() && "the subtarget doesn't fuse move immediate");
+
+ // 32 bit immediate.
+ if ((!HasFirst || FirstOpc == AArch64::MOVZWi) &&
+ SecondOpc == AArch64::MOVKWi && SecondShift == 16)
+ return true;
+
+ // Lower half of 64 bit immediate.
+ if ((!HasFirst || FirstOpc == AArch64::MOVZXi) &&
+ SecondOpc == AArch64::MOVKXi && SecondShift == 16)
+ return true;
+
+ // Upper half of 64 bit immediate.
+ if ((!HasFirst || (FirstOpc == AArch64::MOVKXi && FirstShift == 32)) &&
+ SecondOpc == AArch64::MOVKXi && SecondShift == 48)
+ return true;
+
+ return false;
+}
+
+bool AArch64Subtarget::fusesMOVImmPair(unsigned FirstOpc, unsigned FirstShift,
+ unsigned SecondOpc,
+ unsigned SecondShift) const {
+ return fusesMOVImmPairImpl(*this, /*HasFirst=*/true, FirstOpc, FirstShift,
+ SecondOpc, SecondShift);
+}
+
+bool AArch64Subtarget::fusesMOVImmPair(const MachineInstr *FirstMI,
+ const MachineInstr &SecondMI) const {
+ return fusesMOVImmPairImpl(*this, FirstMI != nullptr,
+ FirstMI ? FirstMI->getOpcode() : 0,
+ FirstMI ? getMOVKShiftImm(*FirstMI) : 0,
+ SecondMI.getOpcode(), getMOVKShiftImm(SecondMI));
+}
diff --git a/llvm/lib/Target/AArch64/AArch64Subtarget.h b/llvm/lib/Target/AArch64/AArch64Subtarget.h
index 380c3e11fcbf2..98cc97ae0a695 100644
--- a/llvm/lib/Target/AArch64/AArch64Subtarget.h
+++ b/llvm/lib/Target/AArch64/AArch64Subtarget.h
@@ -268,6 +268,17 @@ class AArch64Subtarget final : public AArch64GenSubtargetInfo {
hasFuseLiterals() || hasFuseAppleSMECompute() || hasFuseFMinFMax();
}
+ /// Return true if the subtarget fuses this pair of move immediate
+ /// instructions.
+ bool fusesMOVImmPair(unsigned FirstOpc, unsigned FirstShift,
+ unsigned SecondOpc, unsigned SecondShift) const;
+
+ /// Return true if the subtarget fuses this pair of move immediate
+ /// instructions. The 1st instruction is a wildcard when it is nullptr, which
+ /// tells whether the 2nd one can be fused at all.
+ bool fusesMOVImmPair(const MachineInstr *FirstMI,
+ const MachineInstr &SecondMI) const;
+
unsigned getEpilogueVectorizationMinVF() const {
return EpilogueVectorizationMinVF;
}
diff --git a/llvm/test/CodeGen/AArch64/fpimm-legal-expand-fuse-literals.ll b/llvm/test/CodeGen/AArch64/fpimm-legal-expand-fuse-literals.ll
new file mode 100644
index 0000000000000..3afc99254976c
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/fpimm-legal-expand-fuse-literals.ll
@@ -0,0 +1,589 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc %s -o - -mtriple=aarch64-unknown -mattr=+fuse-literals | FileCheck %s --check-prefixes=CHECK,FUSE
+; RUN: llc %s -o - -mtriple=aarch64-unknown -mattr=-fuse-literals | FileCheck %s --check-prefixes=CHECK,NOFUSE
+
+define double @movz() {
+; CHECK-LABEL: movz:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #4660 // =0x1234
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0x0000000000001234
+}
+
+define double @movz16() {
+; CHECK-LABEL: movz16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #305397760 // =0x12340000
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0x0000000012340000
+}
+
+define double @movz32() {
+; CHECK-LABEL: movz32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #20014547599360 // =0x123400000000
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0x0000123400000000
+}
+
+define double @movz48() {
+; CHECK-LABEL: movz48:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #1311673391471656960 // =0x1234000000000000
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0x1234000000000000
+}
+
+define double @movn() {
+; CHECK-LABEL: movn:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #-60876 // =0xffffffffffff1234
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0xFFFFFFFFFFFF1234
+}
+
+define double @movn16() {
+; CHECK-LABEL: movn16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #-3989504001 // =0xffffffff1234ffff
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0xFFFFFFFF1234FFFF
+}
+
+define double @movn32() {
+; CHECK-LABEL: movn32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #-261456134144001 // =0xffff1234ffffffff
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0xFFFF1234FFFFFFFF
+}
+
+define double @movn48() {
+; CHECK-LABEL: movn48:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #1311954866448367615 // =0x1234ffffffffffff
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0x1234FFFFFFFFFFFF
+}
+
+define double @orr() {
+; CHECK-LABEL: orr:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #281479271743489 // =0x1000100010001
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0x0001000100010001
+}
+
+define double @movz_movk16() {
+; CHECK-LABEL: movz_movk16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #4660 // =0x1234
+; CHECK-NEXT: movk x8, #22136, lsl #16
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0x0000000056781234
+}
+
+define double @movz_movk32() {
+; CHECK-LABEL: movz_movk32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #4660 // =0x1234
+; CHECK-NEXT: movk x8, #22136, lsl #32
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0x0000567800001234
+}
+
+define double @movz_movk48() {
+; CHECK-LABEL: movz_movk48:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #4660 // =0x1234
+; CHECK-NEXT: movk x8, #22136, lsl #48
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0x5678000000001234
+}
+
+define double @movz16_movk32() {
+; CHECK-LABEL: movz16_movk32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #305397760 // =0x12340000
+; CHECK-NEXT: movk x8, #22136, lsl #32
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0x0000567812340000
+}
+
+define double @movz16_movk48() {
+; CHECK-LABEL: movz16_movk48:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #305397760 // =0x12340000
+; CHECK-NEXT: movk x8, #22136, lsl #48
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0x5678000012340000
+}
+
+define double @movz32_movk48() {
+; CHECK-LABEL: movz32_movk48:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #20014547599360 // =0x123400000000
+; CHECK-NEXT: movk x8, #22136, lsl #48
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0x5678123400000000
+}
+
+define double @movn_movk16() {
+; CHECK-LABEL: movn_movk16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #-60876 // =0xffffffffffff1234
+; CHECK-NEXT: movk x8, #22136, lsl #16
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0xFFFFFFFF56781234
+}
+
+define double @movn_movk32() {
+; CHECK-LABEL: movn_movk32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #-60876 // =0xffffffffffff1234
+; CHECK-NEXT: movk x8, #22136, lsl #32
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0xFFFF5678FFFF1234
+}
+
+define double @movn_movk48() {
+; CHECK-LABEL: movn_movk48:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #-60876 // =0xffffffffffff1234
+; CHECK-NEXT: movk x8, #22136, lsl #48
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0x5678FFFFFFFF1234
+}
+
+define double @movn16_movk32() {
+; CHECK-LABEL: movn16_movk32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #-3989504001 // =0xffffffff1234ffff
+; CHECK-NEXT: movk x8, #22136, lsl #32
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0xFFFF56781234FFFF
+}
+
+define double @movn16_movk48() {
+; CHECK-LABEL: movn16_movk48:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #-3989504001 // =0xffffffff1234ffff
+; CHECK-NEXT: movk x8, #22136, lsl #48
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0x5678FFFF1234FFFF
+}
+
+define double @movn32_movk48() {
+; CHECK-LABEL: movn32_movk48:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #-261456134144001 // =0xffff1234ffffffff
+; CHECK-NEXT: movk x8, #22136, lsl #48
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0x56781234FFFFFFFF
+}
+
+define double @movn_eors() {
+; CHECK-LABEL: movn_eors:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #-4661 // =0xffffffffffffedcb
+; CHECK-NEXT: eor x8, x8, x8, lsl #32
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0x00001234FFFFEDCB
+}
+
+define double @movn_eons() {
+; CHECK-LABEL: movn_eons:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #-4661 // =0xffffffffffffedcb
+; CHECK-NEXT: eon x8, x8, x8, lsl #32
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0xFFFFEDCB00001234
+}
+
+define double @orr_eor() {
+; CHECK-LABEL: orr_eor:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #562945658585087 // =0x1ffff0001ffff
+; CHECK-NEXT: eor x8, x8, #0x3fffe
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0x0001FFFF00020001
+}
+
+define double @orr_movk0() {
+; CHECK-LABEL: orr_movk0:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #281479271743489 // =0x1000100010001
+; CHECK-NEXT: movk x8, #4660
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0x0001000100011234
+}
+
+define double @orr_movk16() {
+; CHECK-LABEL: orr_movk16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #281479271743489 // =0x1000100010001
+; CHECK-NEXT: movk x8, #4660, lsl #16
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0x0001000112340001
+}
+
+define double @orr_movk32() {
+; CHECK-LABEL: orr_movk32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #281479271743489 // =0x1000100010001
+; CHECK-NEXT: movk x8, #4660, lsl #32
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0x0001123400010001
+}
+
+define double @orr_movk48() {
+; CHECK-LABEL: orr_movk48:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #281479271743489 // =0x1000100010001
+; CHECK-NEXT: movk x8, #4660, lsl #48
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0x1234000100010001
+}
+
+define double @orr_orr() {
+; CHECK-LABEL: orr_orr:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #1125917086973956 // =0x4000400040004
+; CHECK-NEXT: orr x8, x8, #0x1000100010001
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0x0005000500050005
+}
+
+define double @orr_and() {
+; CHECK-LABEL: orr_and:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #6148914691236517205 // =0x5555555555555555
+; CHECK-NEXT: and x8, x8, #0xff00ff00ff00ff
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0x0055005500550055
+}
+
+define double @movz_movk16_movk32() {
+; FUSE-LABEL: movz_movk16_movk32:
+; FUSE: // %bb.0:
+; FUSE-NEXT: mov x8, #4660 // =0x1234
+; FUSE-NEXT: movk x8, #22136, lsl #16
+; FUSE-NEXT: movk x8, #39612, lsl #32
+; FUSE-NEXT: fmov d0, x8
+; FUSE-NEXT: ret
+;
+; NOFUSE-LABEL: movz_movk16_movk32:
+; NOFUSE: // %bb.0:
+; NOFUSE-NEXT: adrp x8, .LCPI30_0
+; NOFUSE-NEXT: ldr d0, [x8, :lo12:.LCPI30_0]
+; NOFUSE-NEXT: ret
+ ret double 0x00009ABC56781234
+}
+
+define double @movz_movk16_movk48() {
+; FUSE-LABEL: movz_movk16_movk48:
+; FUSE: // %bb.0:
+; FUSE-NEXT: mov x8, #4660 // =0x1234
+; FUSE-NEXT: movk x8, #22136, lsl #16
+; FUSE-NEXT: movk x8, #39612, lsl #48
+; FUSE-NEXT: fmov d0, x8
+; FUSE-NEXT: ret
+;
+; NOFUSE-LABEL: movz_movk16_movk48:
+; NOFUSE: // %bb.0:
+; NOFUSE-NEXT: adrp x8, .LCPI31_0
+; NOFUSE-NEXT: ldr d0, [x8, :lo12:.LCPI31_0]
+; NOFUSE-NEXT: ret
+ ret double 0x9ABC000056781234
+}
+
+define double @movz_movk16_orrs() {
+; FUSE-LABEL: movz_movk16_orrs:
+; FUSE: // %bb.0:
+; FUSE-NEXT: mov x8, #4660 // =0x1234
+; FUSE-NEXT: movk x8, #4660, lsl #16
+; FUSE-NEXT: orr x8, x8, x8, lsl #32
+; FUSE-NEXT: fmov d0, x8
+; FUSE-NEXT: ret
+;
+; NOFUSE-LABEL: movz_movk16_orrs:
+; NOFUSE: // %bb.0:
+; NOFUSE-NEXT: adrp x8, .LCPI32_0
+; NOFUSE-NEXT: ldr d0, [x8, :lo12:.LCPI32_0]
+; NOFUSE-NEXT: ret
+ ret double 0x1234123412341234
+}
+
+define double @movz_movk32_movk48() {
+; FUSE-LABEL: movz_movk32_movk48:
+; FUSE: // %bb.0:
+; FUSE-NEXT: mov x8, #4660 // =0x1234
+; FUSE-NEXT: movk x8, #22136, lsl #32
+; FUSE-NEXT: movk x8, #39612, lsl #48
+; FUSE-NEXT: fmov d0, x8
+; FUSE-NEXT: ret
+;
+; NOFUSE-LABEL: movz_movk32_movk48:
+; NOFUSE: // %bb.0:
+; NOFUSE-NEXT: adrp x8, .LCPI33_0
+; NOFUSE-NEXT: ldr d0, [x8, :lo12:.LCPI33_0]
+; NOFUSE-NEXT: ret
+ ret double 0x9ABC567800001234
+}
+
+define double @movz16_movk32_movk48() {
+; FUSE-LABEL: movz16_movk32_movk48:
+; FUSE: // %bb.0:
+; FUSE-NEXT: mov x8, #305397760 // =0x12340000
+; FUSE-NEXT: movk x8, #22136, lsl #32
+; FUSE-NEXT: movk x8, #39612, lsl #48
+; FUSE-NEXT: fmov d0, x8
+; FUSE-NEXT: ret
+;
+; NOFUSE-LABEL: movz16_movk32_movk48:
+; NOFUSE: // %bb.0:
+; NOFUSE-NEXT: adrp x8, .LCPI34_0
+; NOFUSE-NEXT: ldr d0, [x8, :lo12:.LCPI34_0]
+; NOFUSE-NEXT: ret
+ ret double 0x9ABC567812340000
+}
+
+define double @movn_movk16_eors() {
+; CHECK-LABEL: movn_movk16_eors:
+; CHECK: // %bb.0:
+; CHECK-NEXT: adrp x8, .LCPI35_0
+; CHECK-NEXT: ldr d0, [x8, :lo12:.LCPI35_0]
+; CHECK-NEXT: ret
+ ret double 0xA987EDCB56781234
+}
+
+define double @movn_movk16_movk32() {
+; CHECK-LABEL: movn_movk16_movk32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: adrp x8, .LCPI36_0
+; CHECK-NEXT: ldr d0, [x8, :lo12:.LCPI36_0]
+; CHECK-NEXT: ret
+ ret double 0xFFFF9ABC56781234
+}
+
+define double @movn_movk16_movk48() {
+; CHECK-LABEL: movn_movk16_movk48:
+; CHECK: // %bb.0:
+; CHECK-NEXT: adrp x8, .LCPI37_0
+; CHECK-NEXT: ldr d0, [x8, :lo12:.LCPI37_0]
+; CHECK-NEXT: ret
+ ret double 0x9ABCFFFF56781234
+}
+
+define double @movn_movk32_movk48() {
+; FUSE-LABEL: movn_movk32_movk48:
+; FUSE: // %bb.0:
+; FUSE-NEXT: mov x8, #-60876 // =0xffffffffffff1234
+; FUSE-NEXT: movk x8, #22136, lsl #32
+; FUSE-NEXT: movk x8, #39612, lsl #48
+; FUSE-NEXT: fmov d0, x8
+; FUSE-NEXT: ret
+;
+; NOFUSE-LABEL: movn_movk32_movk48:
+; NOFUSE: // %bb.0:
+; NOFUSE-NEXT: adrp x8, .LCPI38_0
+; NOFUSE-NEXT: ldr d0, [x8, :lo12:.LCPI38_0]
+; NOFUSE-NEXT: ret
+ ret double 0x9ABC5678FFFF1234
+}
+
+define double @movn16_movk32_movk48() {
+; FUSE-LABEL: movn16_movk32_movk48:
+; FUSE: // %bb.0:
+; FUSE-NEXT: mov x8, #-3989504001 // =0xffffffff1234ffff
+; FUSE-NEXT: movk x8, #22136, lsl #32
+; FUSE-NEXT: movk x8, #39612, lsl #48
+; FUSE-NEXT: fmov d0, x8
+; FUSE-NEXT: ret
+;
+; NOFUSE-LABEL: movn16_movk32_movk48:
+; NOFUSE: // %bb.0:
+; NOFUSE-NEXT: adrp x8, .LCPI39_0
+; NOFUSE-NEXT: ldr d0, [x8, :lo12:.LCPI39_0]
+; NOFUSE-NEXT: ret
+ ret double 0x9ABC56781234FFFF
+}
+
+define double @orr_movk0_movk16() {
+; CHECK-LABEL: orr_movk0_movk16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: adrp x8, .LCPI40_0
+; CHECK-NEXT: ldr d0, [x8, :lo12:.LCPI40_0]
+; CHECK-NEXT: ret
+ ret double 0x0001000156781234
+}
+
+define double @orr_movk0_movk32() {
+; CHECK-LABEL: orr_movk0_movk32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: adrp x8, .LCPI41_0
+; CHECK-NEXT: ldr d0, [x8, :lo12:.LCPI41_0]
+; CHECK-NEXT: ret
+ ret double 0x0001567800011234
+}
+
+define double @orr_movk0_movk48() {
+; CHECK-LABEL: orr_movk0_movk48:
+; CHECK: // %bb.0:
+; CHECK-NEXT: adrp x8, .LCPI42_0
+; CHECK-NEXT: ldr d0, [x8, :lo12:.LCPI42_0]
+; CHECK-NEXT: ret
+ ret double 0x5678000100011234
+}
+
+define double @orr_movk16_movk32() {
+; CHECK-LABEL: orr_movk16_movk32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: adrp x8, .LCPI43_0
+; CHECK-NEXT: ldr d0, [x8, :lo12:.LCPI43_0]
+; CHECK-NEXT: ret
+ ret double 0x0001567812340001
+}
+
+define double @orr_movk16_movk48() {
+; CHECK-LABEL: orr_movk16_movk48:
+; CHECK: // %bb.0:
+; CHECK-NEXT: adrp x8, .LCPI44_0
+; CHECK-NEXT: ldr d0, [x8, :lo12:.LCPI44_0]
+; CHECK-NEXT: ret
+ ret double 0x5678000112340001
+}
+
+define double @orr_movk32_movk48() {
+; FUSE-LABEL: orr_movk32_movk48:
+; FUSE: // %bb.0:
+; FUSE-NEXT: mov x8, #281479271743489 // =0x1000100010001
+; FUSE-NEXT: movk x8, #4660, lsl #32
+; FUSE-NEXT: movk x8, #22136, lsl #48
+; FUSE-NEXT: fmov d0, x8
+; FUSE-NEXT: ret
+;
+; NOFUSE-LABEL: orr_movk32_movk48:
+; NOFUSE: // %bb.0:
+; NOFUSE-NEXT: adrp x8, .LCPI45_0
+; NOFUSE-NEXT: ldr d0, [x8, :lo12:.LCPI45_0]
+; NOFUSE-NEXT: ret
+ ret double 0x5678123400010001
+}
+
+define double @movn_movk16_eons() {
+; CHECK-LABEL: movn_movk16_eons:
+; CHECK: // %bb.0:
+; CHECK-NEXT: adrp x8, .LCPI46_0
+; CHECK-NEXT: ldr d0, [x8, :lo12:.LCPI46_0]
+; CHECK-NEXT: ret
+ ret double 0xFFF567818AC7EDCB
+}
+
+define double @movz_movk16_movk32_movk48() {
+; FUSE-LABEL: movz_movk16_movk32_movk48:
+; FUSE: // %bb.0:
+; FUSE-NEXT: mov x8, #4660 // =0x1234
+; FUSE-NEXT: movk x8, #22136, lsl #16
+; FUSE-NEXT: movk x8, #39612, lsl #32
+; FUSE-NEXT: movk x8, #43981, lsl #48
+; FUSE-NEXT: fmov d0, x8
+; FUSE-NEXT: ret
+;
+; NOFUSE-LABEL: movz_movk16_movk32_movk48:
+; NOFUSE: // %bb.0:
+; NOFUSE-NEXT: adrp x8, .LCPI47_0
+; NOFUSE-NEXT: ldr d0, [x8, :lo12:.LCPI47_0]
+; NOFUSE-NEXT: ret
+ ret double 0xABCD9ABC56781234
+}
+
+;; 32 bit FP immediate expansion shouldnt be affected by the limit,
+;; because we can always materialize it using up to 2 instructions - as
+;; `AArch64ExpandImm.cpp` asserts, which is already the default limit
+;; for non-optsize functions.
+
+define float @f32_movz() {
+; CHECK-LABEL: f32_movz:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov w8, #4660 // =0x1234
+; CHECK-NEXT: fmov s0, w8
+; CHECK-NEXT: ret
+ ret float bitcast (i32 4660 to float)
+}
+
+define float @f32_movz16() {
+; CHECK-LABEL: f32_movz16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov w8, #305397760 // =0x12340000
+; CHECK-NEXT: fmov s0, w8
+; CHECK-NEXT: ret
+ ret float bitcast (i32 305397760 to float)
+}
+
+define float @f32_movn() {
+; CHECK-LABEL: f32_movn:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov w8, #-60876 // =0xffff1234
+; CHECK-NEXT: fmov s0, w8
+; CHECK-NEXT: ret
+ ret float bitcast (i32 -60876 to float)
+}
+
+define float @f32_movn16() {
+; CHECK-LABEL: f32_movn16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov w8, #305463295 // =0x1234ffff
+; CHECK-NEXT: fmov s0, w8
+; CHECK-NEXT: ret
+ ret float bitcast (i32 305463295 to float)
+}
+
+define float @f32_orr() {
+; CHECK-LABEL: f32_orr:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov w8, #16843009 // =0x1010101
+; CHECK-NEXT: fmov s0, w8
+; CHECK-NEXT: ret
+ ret float bitcast (i32 16843009 to float)
+}
+
+define float @f32_movz_movk16() {
+; CHECK-LABEL: f32_movz_movk16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov w8, #4660 // =0x1234
+; CHECK-NEXT: movk w8, #3855, lsl #16
+; CHECK-NEXT: fmov s0, w8
+; CHECK-NEXT: ret
+ ret float bitcast (i32 252645940 to float)
+}
diff --git a/llvm/test/CodeGen/AArch64/fpimm-legal-expand-optsize.ll b/llvm/test/CodeGen/AArch64/fpimm-legal-expand-optsize.ll
new file mode 100644
index 0000000000000..61604b5a13e27
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/fpimm-legal-expand-optsize.ll
@@ -0,0 +1,117 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc %s -o - -mtriple=aarch64-unknown -mattr=+fuse-literals | FileCheck %s
+; RUN: llc %s -o - -mtriple=aarch64-unknown -mattr=-fuse-literals | FileCheck %s
+
+;; Representative tests for each class of FP immediate expansion that shouldn't apply
+;; when optimizing for size.
+
+define double @movz_optsize() #0 {
+; CHECK-LABEL: movz_optsize:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #4660 // =0x1234
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0x0000000000001234
+}
+
+define double @movz_minsize() #1 {
+; CHECK-LABEL: movz_minsize:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #4660 // =0x1234
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0x0000000000001234
+}
+
+define double @movz_movk16_optsize() #0 {
+; CHECK-LABEL: movz_movk16_optsize:
+; CHECK: // %bb.0:
+; CHECK-NEXT: adrp x8, .LCPI2_0
+; CHECK-NEXT: ldr d0, [x8, :lo12:.LCPI2_0]
+; CHECK-NEXT: ret
+ ret double 0x0000000056781234
+}
+
+define double @movz_movk16_minsize() #1 {
+; CHECK-LABEL: movz_movk16_minsize:
+; CHECK: // %bb.0:
+; CHECK-NEXT: adrp x8, .LCPI3_0
+; CHECK-NEXT: ldr d0, [x8, :lo12:.LCPI3_0]
+; CHECK-NEXT: ret
+ ret double 0x0000000056781234
+}
+
+define double @movz_movk16_movk32_optsize() #0 {
+; CHECK-LABEL: movz_movk16_movk32_optsize:
+; CHECK: // %bb.0:
+; CHECK-NEXT: adrp x8, .LCPI4_0
+; CHECK-NEXT: ldr d0, [x8, :lo12:.LCPI4_0]
+; CHECK-NEXT: ret
+ ret double 0x00009ABC56781234
+}
+
+define double @movz_movk16_movk32_minsize() #1 {
+; CHECK-LABEL: movz_movk16_movk32_minsize:
+; CHECK: // %bb.0:
+; CHECK-NEXT: adrp x8, .LCPI5_0
+; CHECK-NEXT: ldr d0, [x8, :lo12:.LCPI5_0]
+; CHECK-NEXT: ret
+ ret double 0x00009ABC56781234
+}
+
+define double @movz_movk16_movk32_movk48_optsize() #0 {
+; CHECK-LABEL: movz_movk16_movk32_movk48_optsize:
+; CHECK: // %bb.0:
+; CHECK-NEXT: adrp x8, .LCPI6_0
+; CHECK-NEXT: ldr d0, [x8, :lo12:.LCPI6_0]
+; CHECK-NEXT: ret
+ ret double 0xABCD9ABC56781234
+}
+
+define double @movz_movk16_movk32_movk48_minsize() #1 {
+; CHECK-LABEL: movz_movk16_movk32_movk48_minsize:
+; CHECK: // %bb.0:
+; CHECK-NEXT: adrp x8, .LCPI7_0
+; CHECK-NEXT: ldr d0, [x8, :lo12:.LCPI7_0]
+; CHECK-NEXT: ret
+ ret double 0xABCD9ABC56781234
+}
+
+define float @f32_movz_optsize() #0 {
+; CHECK-LABEL: f32_movz_optsize:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov w8, #4660 // =0x1234
+; CHECK-NEXT: fmov s0, w8
+; CHECK-NEXT: ret
+ ret float bitcast (i32 4660 to float)
+}
+
+define float @f32_movz_minsize() #1 {
+; CHECK-LABEL: f32_movz_minsize:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov w8, #4660 // =0x1234
+; CHECK-NEXT: fmov s0, w8
+; CHECK-NEXT: ret
+ ret float bitcast (i32 4660 to float)
+}
+
+define float @f32_movz_movk16_optsize() #0 {
+; CHECK-LABEL: f32_movz_movk16_optsize:
+; CHECK: // %bb.0:
+; CHECK-NEXT: adrp x8, .LCPI10_0
+; CHECK-NEXT: ldr s0, [x8, :lo12:.LCPI10_0]
+; CHECK-NEXT: ret
+ ret float bitcast (i32 252645940 to float)
+}
+
+define float @f32_movz_movk16_minsize() #1 {
+; CHECK-LABEL: f32_movz_movk16_minsize:
+; CHECK: // %bb.0:
+; CHECK-NEXT: adrp x8, .LCPI11_0
+; CHECK-NEXT: ldr s0, [x8, :lo12:.LCPI11_0]
+; CHECK-NEXT: ret
+ ret float bitcast (i32 252645940 to float)
+}
+
+attributes #0 = { optsize }
+attributes #1 = { minsize optsize }
>From c378332621c18439e22244d64c1eaa402112a0bf Mon Sep 17 00:00:00 2001
From: Tomer Shafir <tomer.shafir8 at gmail.com>
Date: Tue, 11 Aug 2026 21:12:41 +0300
Subject: [PATCH 2/5] Apply suggestion from @jroelofs
Co-authored-by: Jon Roelofs <jroelofs at gmail.com>
---
llvm/test/CodeGen/AArch64/fpimm-legal-expand-fuse-literals.ll | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/test/CodeGen/AArch64/fpimm-legal-expand-fuse-literals.ll b/llvm/test/CodeGen/AArch64/fpimm-legal-expand-fuse-literals.ll
index 3afc99254976c..d38d7ac299921 100644
--- a/llvm/test/CodeGen/AArch64/fpimm-legal-expand-fuse-literals.ll
+++ b/llvm/test/CodeGen/AArch64/fpimm-legal-expand-fuse-literals.ll
@@ -528,7 +528,7 @@ define double @movz_movk16_movk32_movk48() {
ret double 0xABCD9ABC56781234
}
-;; 32 bit FP immediate expansion shouldnt be affected by the limit,
+;; 32 bit FP immediate expansion shouldn't be affected by the limit,
;; because we can always materialize it using up to 2 instructions - as
;; `AArch64ExpandImm.cpp` asserts, which is already the default limit
;; for non-optsize functions.
>From 6ac05bb5cdc376d436a9f85d814267443b23d9b4 Mon Sep 17 00:00:00 2001
From: tomershafir <tomer.shafir8 at gmail.com>
Date: Tue, 11 Aug 2026 21:12:06 +0300
Subject: [PATCH 3/5] inline isLiteralsPair
---
llvm/lib/Target/AArch64/AArch64MacroFusion.cpp | 9 +--------
1 file changed, 1 insertion(+), 8 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64MacroFusion.cpp b/llvm/lib/Target/AArch64/AArch64MacroFusion.cpp
index d5c669c14b296..b914945043495 100644
--- a/llvm/lib/Target/AArch64/AArch64MacroFusion.cpp
+++ b/llvm/lib/Target/AArch64/AArch64MacroFusion.cpp
@@ -223,13 +223,6 @@ static bool isAdrpAddPair(const MachineInstr *FirstMI,
return false;
}
-/// Literal generation.
-static bool isLiteralsPair(const AArch64Subtarget &ST,
- const MachineInstr *FirstMI,
- const MachineInstr &SecondMI) {
- return ST.fusesMOVImmPair(FirstMI, SecondMI);
-}
-
/// Fuse address generation and loads or stores.
static bool isAddressLdStPair(const MachineInstr *FirstMI,
const MachineInstr &SecondMI) {
@@ -694,7 +687,7 @@ static bool shouldScheduleAdjacent(const TargetInstrInfo &TII,
++NumFusedAdrpAdd;
return true;
}
- if (ST.hasFuseLiterals() && isLiteralsPair(ST, FirstMI, SecondMI)) {
+ if (ST.hasFuseLiterals() && ST.fusesMOVImmPair(FirstMI, SecondMI)) {
++NumFusedLiterals;
return true;
}
>From 4a5ad58c7530108c4d93ccc8f62b3eb8702bfed9 Mon Sep 17 00:00:00 2001
From: tomershafir <tomer.shafir8 at gmail.com>
Date: Wed, 12 Aug 2026 11:14:08 +0300
Subject: [PATCH 4/5] hoist pair defs and fix loop var name
---
llvm/lib/Target/AArch64/AArch64ISelLowering.cpp | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index be3d337358d53..e59af42784fa7 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -13779,13 +13779,15 @@ bool AArch64TargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT,
if (!OptForSize && Insn.size() > Limit && Subtarget->hasFuseLiterals()) {
// Relax the limit based on subtarget fusion capabilites
- for (unsigned i = 0; i + 1 < Insn.size(); ++i) {
- if (Subtarget->fusesMOVImmPair(Insn[i].Opcode, Insn[i].Op2,
- Insn[i + 1].Opcode, Insn[i + 1].Op2)) {
+ for (unsigned I = 0; I + 1 < Insn.size(); ++I) {
+ const AArch64_IMM::ImmInsnModel &First = Insn[I];
+ const AArch64_IMM::ImmInsnModel &Second = Insn[I + 1];
+ if (Subtarget->fusesMOVImmPair(First.Opcode, First.Op2, Second.Opcode,
+ Second.Op2)) {
++Limit;
// An instruction can only be fused once, so the 2nd one of the pair
// cannot start another pair and is skipped.
- ++i;
+ ++I;
}
}
}
>From 9d462f8007be8796186566b7a3f58e60dc298dda Mon Sep 17 00:00:00 2001
From: tomershafir <tomer.shafir8 at gmail.com>
Date: Thu, 13 Aug 2026 23:02:57 +0300
Subject: [PATCH 5/5] [AArch64] Extract MOVZ+MOVK only clustering
This patch extracts a subtarget feature out of wider `FuseLiterals` that controls scheduling MOVZ+MOVK instructions only back to back. Enabled on Apple CPU.
---
llvm/lib/Target/AArch64/AArch64Features.td | 5 +
.../Target/AArch64/AArch64ISelLowering.cpp | 16 +-
.../lib/Target/AArch64/AArch64MacroFusion.cpp | 23 +
llvm/lib/Target/AArch64/AArch64Processors.td | 2 +-
llvm/lib/Target/AArch64/AArch64Subtarget.cpp | 34 +
llvm/lib/Target/AArch64/AArch64Subtarget.h | 19 +-
.../fpimm-legal-expand-fuse-movz-movk.ll | 556 ++++++++
.../AArch64/fpimm-legal-expand-optsize.ll | 2 +
.../AArch64/literal_pools_float_apple.ll | 10 +-
.../misched-fusion-movz-movk-post-ra.mir | 1124 +++++++++++++++++
.../misched-fusion-movz-movk-pre-ra.mir | 584 +++++++++
.../AArch64/misched-fusion-movz-movk.ll | 60 +
.../TableGen/aarch64-apple-tuning-features.td | 12 +-
13 files changed, 2430 insertions(+), 17 deletions(-)
create mode 100644 llvm/test/CodeGen/AArch64/fpimm-legal-expand-fuse-movz-movk.ll
create mode 100644 llvm/test/CodeGen/AArch64/misched-fusion-movz-movk-post-ra.mir
create mode 100644 llvm/test/CodeGen/AArch64/misched-fusion-movz-movk-pre-ra.mir
create mode 100644 llvm/test/CodeGen/AArch64/misched-fusion-movz-movk.ll
diff --git a/llvm/lib/Target/AArch64/AArch64Features.td b/llvm/lib/Target/AArch64/AArch64Features.td
index 6eea064b257f6..6c36b881f72d3 100644
--- a/llvm/lib/Target/AArch64/AArch64Features.td
+++ b/llvm/lib/Target/AArch64/AArch64Features.td
@@ -853,6 +853,11 @@ def FeatureFuseLiterals : SubtargetFeature<
"CPU fuses literal generation operations",
[], InlineIgnore>;
+def FeatureFuseMovzMovk : SubtargetFeature<
+ "fuse-movz-movk", "HasFuseMovzMovk", "true",
+ "CPU fuses MOVZ and MOVK operations",
+ [], InlineIgnore>;
+
def FeatureFuseAddSub2RegAndConstOne : SubtargetFeature<
"fuse-addsub-2reg-const1", "HasFuseAddSub2RegAndConstOne", "true",
"CPU fuses (a + b + 1) and (a - b - 1)",
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 64e09f6962d29..02a74a3636771 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -13862,13 +13862,21 @@ bool AArch64TargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT,
unsigned Limit = OptForSize ? 1 : 2;
- if (!OptForSize && Insn.size() > Limit && Subtarget->hasFuseLiterals()) {
- // Relax the limit based on subtarget fusion capabilites
+ if (!OptForSize && Insn.size() > Limit) {
+ // Relax the limit based on subtarget fusion capabilites.
+ //
+ // The dependencies that macro-fusion requires hold by construction here.
+ // AArch64ExpandPseudoInsts writes the pseudo's dest throughout the
+ // expansion, which gives WAW, and the 2nd instruction of a fused pair is
+ // always a MOVK, whose source is tied to its dest, which gives RAW.
for (unsigned I = 0; I + 1 < Insn.size(); ++I) {
const AArch64_IMM::ImmInsnModel &First = Insn[I];
const AArch64_IMM::ImmInsnModel &Second = Insn[I + 1];
- if (Subtarget->fusesMOVImmPair(First.Opcode, First.Op2, Second.Opcode,
- Second.Op2)) {
+ if ((Subtarget->hasFuseLiterals() &&
+ Subtarget->fusesMOVImmPair(First.Opcode, First.Op2, Second.Opcode,
+ Second.Op2)) ||
+ (Subtarget->hasFuseMovzMovk() &&
+ Subtarget->fusesMovzMovkPair(First.Opcode, Second.Opcode))) {
++Limit;
// An instruction can only be fused once, so the 2nd one of the pair
// cannot start another pair and is skipped.
diff --git a/llvm/lib/Target/AArch64/AArch64MacroFusion.cpp b/llvm/lib/Target/AArch64/AArch64MacroFusion.cpp
index 276855beb6aa8..09d6f952093f4 100644
--- a/llvm/lib/Target/AArch64/AArch64MacroFusion.cpp
+++ b/llvm/lib/Target/AArch64/AArch64MacroFusion.cpp
@@ -27,6 +27,7 @@ STATISTIC(NumFusedAES, "Number of AES fusions");
STATISTIC(NumFusedCryptoEOR, "Number of crypto-EOR fusions");
STATISTIC(NumFusedAdrpAdd, "Number of ADRP-ADD fusions");
STATISTIC(NumFusedLiterals, "Number of literal-generation fusions");
+STATISTIC(NumFusedMovzMovk, "Number of MOVZ-MOVK fusions");
STATISTIC(NumFusedAddress, "Number of address-generation load/store fusions");
STATISTIC(NumFusedCmpCSel, "Number of compare-CSEL fusions");
STATISTIC(NumFusedFCmpFCSel, "Number of FP-compare-FCSEL fusions");
@@ -643,6 +644,24 @@ static bool isFMinFMaxPair(const MachineInstr *FirstMI,
return mayHaveWAWDependency(*FirstMI, SecondMI, TRI);
}
+// MOVZ + MOVK.
+static bool isMovzMovkPair(const MachineInstr *FirstMI,
+ const MachineInstr &SecondMI,
+ const TargetRegisterInfo *TRI,
+ const AArch64Subtarget &ST) {
+ if (!ST.fusesMovzMovkPair(FirstMI, SecondMI))
+ return false;
+
+ // The opcode check above only establishes the shape of the pair. MOVZ+MOVK
+ // should be clustered only when both write the same register. Architecturally
+ // a RAW dependency between MOVZ and MOVK would already imply WAW, because
+ // both have a single register operand.
+ assert(
+ (FirstMI == nullptr || mayHaveWAWDependency(*FirstMI, SecondMI, TRI)) &&
+ "read-after-write should have implied write-after-write for MOVZ+MOVK");
+ return true;
+}
+
/// \brief Check if the instr pair, FirstMI and SecondMI, should be fused
/// together. Given SecondMI, when FirstMI is unspecified, then check if
/// SecondMI may be part of a fused pair at all.
@@ -695,6 +714,10 @@ static bool shouldScheduleAdjacent(const TargetInstrInfo &TII,
++NumFusedLiterals;
return true;
}
+ if (ST.hasFuseMovzMovk() && isMovzMovkPair(FirstMI, SecondMI, TRI, ST)) {
+ ++NumFusedMovzMovk;
+ return true;
+ }
if (ST.hasFuseAddress() && isAddressLdStPair(FirstMI, SecondMI)) {
++NumFusedAddress;
return true;
diff --git a/llvm/lib/Target/AArch64/AArch64Processors.td b/llvm/lib/Target/AArch64/AArch64Processors.td
index 68efd16459ada..9eb058922e317 100644
--- a/llvm/lib/Target/AArch64/AArch64Processors.td
+++ b/llvm/lib/Target/AArch64/AArch64Processors.td
@@ -427,7 +427,7 @@ def TuneAppleA14 : SubtargetFeature<"apple-a14", "ARMProcFamily", "AppleA14",
FeatureFuseAddress,
FeatureFuseArithmeticLogic,
FeatureFuseCmpCSel,
- FeatureFuseLiterals,
+ FeatureFuseMovzMovk,
FeatureMaxInterleaveFactor4])>;
def TuneAppleA15 : SubtargetFeature<"apple-a15", "ARMProcFamily", "AppleA15",
diff --git a/llvm/lib/Target/AArch64/AArch64Subtarget.cpp b/llvm/lib/Target/AArch64/AArch64Subtarget.cpp
index 4fef12ab37ad8..c55624b93b3ca 100644
--- a/llvm/lib/Target/AArch64/AArch64Subtarget.cpp
+++ b/llvm/lib/Target/AArch64/AArch64Subtarget.cpp
@@ -698,3 +698,37 @@ bool AArch64Subtarget::fusesMOVImmPair(const MachineInstr *FirstMI,
FirstMI ? getMOVKShiftImm(*FirstMI) : 0,
SecondMI.getOpcode(), getMOVKShiftImm(SecondMI));
}
+
+/// \p HasFirst is false when the 1st instruction is a wildcard.
+static bool fusesMovzMovkPairImpl(const AArch64Subtarget &ST, bool HasFirst,
+ unsigned FirstOpc, unsigned SecondOpc) {
+ assert(ST.hasFuseMovzMovk() && "the subtarget doesn't fuse MOVZ+MOVK");
+
+ switch (SecondOpc) {
+ case AArch64::MOVKWi:
+ case AArch64::MOVKXi:
+ // Assume the 1st instr to be a wildcard if it is unspecified.
+ if (!HasFirst)
+ return true;
+
+ switch (FirstOpc) {
+ case AArch64::MOVZWi:
+ case AArch64::MOVZXi:
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool AArch64Subtarget::fusesMovzMovkPair(unsigned FirstOpc,
+ unsigned SecondOpc) const {
+ return fusesMovzMovkPairImpl(*this, /*HasFirst=*/true, FirstOpc, SecondOpc);
+}
+
+bool AArch64Subtarget::fusesMovzMovkPair(const MachineInstr *FirstMI,
+ const MachineInstr &SecondMI) const {
+ return fusesMovzMovkPairImpl(*this, FirstMI != nullptr,
+ FirstMI ? FirstMI->getOpcode() : 0,
+ SecondMI.getOpcode());
+}
diff --git a/llvm/lib/Target/AArch64/AArch64Subtarget.h b/llvm/lib/Target/AArch64/AArch64Subtarget.h
index 98cc97ae0a695..8ab2da51b6903 100644
--- a/llvm/lib/Target/AArch64/AArch64Subtarget.h
+++ b/llvm/lib/Target/AArch64/AArch64Subtarget.h
@@ -265,7 +265,8 @@ class AArch64Subtarget final : public AArch64GenSubtargetInfo {
return hasArithmeticBccFusion() || hasArithmeticCbzFusion() ||
hasFuseAES() || hasFuseArithmeticLogic() || hasFuseCmpCSel() ||
hasFuseFCmpFCSel() || hasFuseCmpCSet() || hasFuseAdrpAdd() ||
- hasFuseLiterals() || hasFuseAppleSMECompute() || hasFuseFMinFMax();
+ hasFuseLiterals() || hasFuseMovzMovk() || hasFuseAppleSMECompute() ||
+ hasFuseFMinFMax();
}
/// Return true if the subtarget fuses this pair of move immediate
@@ -279,6 +280,22 @@ class AArch64Subtarget final : public AArch64GenSubtargetInfo {
bool fusesMOVImmPair(const MachineInstr *FirstMI,
const MachineInstr &SecondMI) const;
+ /// Return true if the subtarget fuses this opcode pair as MOVZ+MOVK
+ /// instructions.
+ ///
+ /// This checks the opcode shape only. The caller is
+ /// responsible for establishing that the pair writes the same register.
+ bool fusesMovzMovkPair(unsigned FirstOpc, unsigned SecondOpc) const;
+
+ /// Return true if the subtarget fuses this pair as MOVZ+MOVK
+ /// instructions. The 1st instruction is a wildcard when it is nullptr, which
+ /// tells whether the 2nd one can be fused at all.
+ ///
+ /// This checks the opcode shape only. The caller is
+ /// responsible for establishing that the pair writes the same register.
+ bool fusesMovzMovkPair(const MachineInstr *FirstMI,
+ const MachineInstr &SecondMI) const;
+
unsigned getEpilogueVectorizationMinVF() const {
return EpilogueVectorizationMinVF;
}
diff --git a/llvm/test/CodeGen/AArch64/fpimm-legal-expand-fuse-movz-movk.ll b/llvm/test/CodeGen/AArch64/fpimm-legal-expand-fuse-movz-movk.ll
new file mode 100644
index 0000000000000..e4c5389a1467f
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/fpimm-legal-expand-fuse-movz-movk.ll
@@ -0,0 +1,556 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc %s -o - -mtriple=aarch64-unknown -mattr=+fuse-movz-movk | FileCheck %s --check-prefixes=CHECK,FUSE
+; RUN: llc %s -o - -mtriple=aarch64-unknown -mattr=-fuse-movz-movk | FileCheck %s --check-prefixes=CHECK,NOFUSE
+
+define double @movz() {
+; CHECK-LABEL: movz:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #4660 // =0x1234
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0x0000000000001234
+}
+
+define double @movz16() {
+; CHECK-LABEL: movz16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #305397760 // =0x12340000
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0x0000000012340000
+}
+
+define double @movz32() {
+; CHECK-LABEL: movz32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #20014547599360 // =0x123400000000
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0x0000123400000000
+}
+
+define double @movz48() {
+; CHECK-LABEL: movz48:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #1311673391471656960 // =0x1234000000000000
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0x1234000000000000
+}
+
+define double @movn() {
+; CHECK-LABEL: movn:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #-60876 // =0xffffffffffff1234
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0xFFFFFFFFFFFF1234
+}
+
+define double @movn16() {
+; CHECK-LABEL: movn16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #-3989504001 // =0xffffffff1234ffff
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0xFFFFFFFF1234FFFF
+}
+
+define double @movn32() {
+; CHECK-LABEL: movn32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #-261456134144001 // =0xffff1234ffffffff
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0xFFFF1234FFFFFFFF
+}
+
+define double @movn48() {
+; CHECK-LABEL: movn48:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #1311954866448367615 // =0x1234ffffffffffff
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0x1234FFFFFFFFFFFF
+}
+
+define double @orr() {
+; CHECK-LABEL: orr:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #281479271743489 // =0x1000100010001
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0x0001000100010001
+}
+
+define double @movz_movk16() {
+; CHECK-LABEL: movz_movk16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #4660 // =0x1234
+; CHECK-NEXT: movk x8, #22136, lsl #16
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0x0000000056781234
+}
+
+define double @movz_movk32() {
+; CHECK-LABEL: movz_movk32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #4660 // =0x1234
+; CHECK-NEXT: movk x8, #22136, lsl #32
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0x0000567800001234
+}
+
+define double @movz_movk48() {
+; CHECK-LABEL: movz_movk48:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #4660 // =0x1234
+; CHECK-NEXT: movk x8, #22136, lsl #48
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0x5678000000001234
+}
+
+define double @movz16_movk32() {
+; CHECK-LABEL: movz16_movk32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #305397760 // =0x12340000
+; CHECK-NEXT: movk x8, #22136, lsl #32
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0x0000567812340000
+}
+
+define double @movz16_movk48() {
+; CHECK-LABEL: movz16_movk48:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #305397760 // =0x12340000
+; CHECK-NEXT: movk x8, #22136, lsl #48
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0x5678000012340000
+}
+
+define double @movz32_movk48() {
+; CHECK-LABEL: movz32_movk48:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #20014547599360 // =0x123400000000
+; CHECK-NEXT: movk x8, #22136, lsl #48
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0x5678123400000000
+}
+
+define double @movn_movk16() {
+; CHECK-LABEL: movn_movk16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #-60876 // =0xffffffffffff1234
+; CHECK-NEXT: movk x8, #22136, lsl #16
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0xFFFFFFFF56781234
+}
+
+define double @movn_movk32() {
+; CHECK-LABEL: movn_movk32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #-60876 // =0xffffffffffff1234
+; CHECK-NEXT: movk x8, #22136, lsl #32
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0xFFFF5678FFFF1234
+}
+
+define double @movn_movk48() {
+; CHECK-LABEL: movn_movk48:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #-60876 // =0xffffffffffff1234
+; CHECK-NEXT: movk x8, #22136, lsl #48
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0x5678FFFFFFFF1234
+}
+
+define double @movn16_movk32() {
+; CHECK-LABEL: movn16_movk32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #-3989504001 // =0xffffffff1234ffff
+; CHECK-NEXT: movk x8, #22136, lsl #32
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0xFFFF56781234FFFF
+}
+
+define double @movn16_movk48() {
+; CHECK-LABEL: movn16_movk48:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #-3989504001 // =0xffffffff1234ffff
+; CHECK-NEXT: movk x8, #22136, lsl #48
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0x5678FFFF1234FFFF
+}
+
+define double @movn32_movk48() {
+; CHECK-LABEL: movn32_movk48:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #-261456134144001 // =0xffff1234ffffffff
+; CHECK-NEXT: movk x8, #22136, lsl #48
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0x56781234FFFFFFFF
+}
+
+define double @movn_eors() {
+; CHECK-LABEL: movn_eors:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #-4661 // =0xffffffffffffedcb
+; CHECK-NEXT: eor x8, x8, x8, lsl #32
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0x00001234FFFFEDCB
+}
+
+define double @movn_eons() {
+; CHECK-LABEL: movn_eons:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #-4661 // =0xffffffffffffedcb
+; CHECK-NEXT: eon x8, x8, x8, lsl #32
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0xFFFFEDCB00001234
+}
+
+define double @orr_eor() {
+; CHECK-LABEL: orr_eor:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #562945658585087 // =0x1ffff0001ffff
+; CHECK-NEXT: eor x8, x8, #0x3fffe
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0x0001FFFF00020001
+}
+
+define double @orr_movk0() {
+; CHECK-LABEL: orr_movk0:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #281479271743489 // =0x1000100010001
+; CHECK-NEXT: movk x8, #4660
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0x0001000100011234
+}
+
+define double @orr_movk16() {
+; CHECK-LABEL: orr_movk16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #281479271743489 // =0x1000100010001
+; CHECK-NEXT: movk x8, #4660, lsl #16
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0x0001000112340001
+}
+
+define double @orr_movk32() {
+; CHECK-LABEL: orr_movk32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #281479271743489 // =0x1000100010001
+; CHECK-NEXT: movk x8, #4660, lsl #32
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0x0001123400010001
+}
+
+define double @orr_movk48() {
+; CHECK-LABEL: orr_movk48:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #281479271743489 // =0x1000100010001
+; CHECK-NEXT: movk x8, #4660, lsl #48
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0x1234000100010001
+}
+
+define double @orr_orr() {
+; CHECK-LABEL: orr_orr:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #1125917086973956 // =0x4000400040004
+; CHECK-NEXT: orr x8, x8, #0x1000100010001
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0x0005000500050005
+}
+
+define double @orr_and() {
+; CHECK-LABEL: orr_and:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov x8, #6148914691236517205 // =0x5555555555555555
+; CHECK-NEXT: and x8, x8, #0xff00ff00ff00ff
+; CHECK-NEXT: fmov d0, x8
+; CHECK-NEXT: ret
+ ret double 0x0055005500550055
+}
+
+define double @movz_movk16_movk32() {
+; FUSE-LABEL: movz_movk16_movk32:
+; FUSE: // %bb.0:
+; FUSE-NEXT: mov x8, #4660 // =0x1234
+; FUSE-NEXT: movk x8, #22136, lsl #16
+; FUSE-NEXT: movk x8, #39612, lsl #32
+; FUSE-NEXT: fmov d0, x8
+; FUSE-NEXT: ret
+;
+; NOFUSE-LABEL: movz_movk16_movk32:
+; NOFUSE: // %bb.0:
+; NOFUSE-NEXT: adrp x8, .LCPI30_0
+; NOFUSE-NEXT: ldr d0, [x8, :lo12:.LCPI30_0]
+; NOFUSE-NEXT: ret
+ ret double 0x00009ABC56781234
+}
+
+define double @movz_movk16_movk48() {
+; FUSE-LABEL: movz_movk16_movk48:
+; FUSE: // %bb.0:
+; FUSE-NEXT: mov x8, #4660 // =0x1234
+; FUSE-NEXT: movk x8, #22136, lsl #16
+; FUSE-NEXT: movk x8, #39612, lsl #48
+; FUSE-NEXT: fmov d0, x8
+; FUSE-NEXT: ret
+;
+; NOFUSE-LABEL: movz_movk16_movk48:
+; NOFUSE: // %bb.0:
+; NOFUSE-NEXT: adrp x8, .LCPI31_0
+; NOFUSE-NEXT: ldr d0, [x8, :lo12:.LCPI31_0]
+; NOFUSE-NEXT: ret
+ ret double 0x9ABC000056781234
+}
+
+define double @movz_movk16_orrs() {
+; FUSE-LABEL: movz_movk16_orrs:
+; FUSE: // %bb.0:
+; FUSE-NEXT: mov x8, #4660 // =0x1234
+; FUSE-NEXT: movk x8, #4660, lsl #16
+; FUSE-NEXT: orr x8, x8, x8, lsl #32
+; FUSE-NEXT: fmov d0, x8
+; FUSE-NEXT: ret
+;
+; NOFUSE-LABEL: movz_movk16_orrs:
+; NOFUSE: // %bb.0:
+; NOFUSE-NEXT: adrp x8, .LCPI32_0
+; NOFUSE-NEXT: ldr d0, [x8, :lo12:.LCPI32_0]
+; NOFUSE-NEXT: ret
+ ret double 0x1234123412341234
+}
+
+define double @movz_movk32_movk48() {
+; FUSE-LABEL: movz_movk32_movk48:
+; FUSE: // %bb.0:
+; FUSE-NEXT: mov x8, #4660 // =0x1234
+; FUSE-NEXT: movk x8, #22136, lsl #32
+; FUSE-NEXT: movk x8, #39612, lsl #48
+; FUSE-NEXT: fmov d0, x8
+; FUSE-NEXT: ret
+;
+; NOFUSE-LABEL: movz_movk32_movk48:
+; NOFUSE: // %bb.0:
+; NOFUSE-NEXT: adrp x8, .LCPI33_0
+; NOFUSE-NEXT: ldr d0, [x8, :lo12:.LCPI33_0]
+; NOFUSE-NEXT: ret
+ ret double 0x9ABC567800001234
+}
+
+define double @movz16_movk32_movk48() {
+; FUSE-LABEL: movz16_movk32_movk48:
+; FUSE: // %bb.0:
+; FUSE-NEXT: mov x8, #305397760 // =0x12340000
+; FUSE-NEXT: movk x8, #22136, lsl #32
+; FUSE-NEXT: movk x8, #39612, lsl #48
+; FUSE-NEXT: fmov d0, x8
+; FUSE-NEXT: ret
+;
+; NOFUSE-LABEL: movz16_movk32_movk48:
+; NOFUSE: // %bb.0:
+; NOFUSE-NEXT: adrp x8, .LCPI34_0
+; NOFUSE-NEXT: ldr d0, [x8, :lo12:.LCPI34_0]
+; NOFUSE-NEXT: ret
+ ret double 0x9ABC567812340000
+}
+
+define double @movn_movk16_eors() {
+; CHECK-LABEL: movn_movk16_eors:
+; CHECK: // %bb.0:
+; CHECK-NEXT: adrp x8, .LCPI35_0
+; CHECK-NEXT: ldr d0, [x8, :lo12:.LCPI35_0]
+; CHECK-NEXT: ret
+ ret double 0xA987EDCB56781234
+}
+
+define double @movn_movk16_movk32() {
+; CHECK-LABEL: movn_movk16_movk32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: adrp x8, .LCPI36_0
+; CHECK-NEXT: ldr d0, [x8, :lo12:.LCPI36_0]
+; CHECK-NEXT: ret
+ ret double 0xFFFF9ABC56781234
+}
+
+define double @movn_movk16_movk48() {
+; CHECK-LABEL: movn_movk16_movk48:
+; CHECK: // %bb.0:
+; CHECK-NEXT: adrp x8, .LCPI37_0
+; CHECK-NEXT: ldr d0, [x8, :lo12:.LCPI37_0]
+; CHECK-NEXT: ret
+ ret double 0x9ABCFFFF56781234
+}
+
+define double @movn_movk32_movk48() {
+; CHECK-LABEL: movn_movk32_movk48:
+; CHECK: // %bb.0:
+; CHECK-NEXT: adrp x8, .LCPI38_0
+; CHECK-NEXT: ldr d0, [x8, :lo12:.LCPI38_0]
+; CHECK-NEXT: ret
+ ret double 0x9ABC5678FFFF1234
+}
+
+define double @movn16_movk32_movk48() {
+; CHECK-LABEL: movn16_movk32_movk48:
+; CHECK: // %bb.0:
+; CHECK-NEXT: adrp x8, .LCPI39_0
+; CHECK-NEXT: ldr d0, [x8, :lo12:.LCPI39_0]
+; CHECK-NEXT: ret
+ ret double 0x9ABC56781234FFFF
+}
+
+define double @orr_movk0_movk16() {
+; CHECK-LABEL: orr_movk0_movk16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: adrp x8, .LCPI40_0
+; CHECK-NEXT: ldr d0, [x8, :lo12:.LCPI40_0]
+; CHECK-NEXT: ret
+ ret double 0x0001000156781234
+}
+
+define double @orr_movk0_movk32() {
+; CHECK-LABEL: orr_movk0_movk32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: adrp x8, .LCPI41_0
+; CHECK-NEXT: ldr d0, [x8, :lo12:.LCPI41_0]
+; CHECK-NEXT: ret
+ ret double 0x0001567800011234
+}
+
+define double @orr_movk0_movk48() {
+; CHECK-LABEL: orr_movk0_movk48:
+; CHECK: // %bb.0:
+; CHECK-NEXT: adrp x8, .LCPI42_0
+; CHECK-NEXT: ldr d0, [x8, :lo12:.LCPI42_0]
+; CHECK-NEXT: ret
+ ret double 0x5678000100011234
+}
+
+define double @orr_movk16_movk32() {
+; CHECK-LABEL: orr_movk16_movk32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: adrp x8, .LCPI43_0
+; CHECK-NEXT: ldr d0, [x8, :lo12:.LCPI43_0]
+; CHECK-NEXT: ret
+ ret double 0x0001567812340001
+}
+
+define double @orr_movk16_movk48() {
+; CHECK-LABEL: orr_movk16_movk48:
+; CHECK: // %bb.0:
+; CHECK-NEXT: adrp x8, .LCPI44_0
+; CHECK-NEXT: ldr d0, [x8, :lo12:.LCPI44_0]
+; CHECK-NEXT: ret
+ ret double 0x5678000112340001
+}
+
+define double @orr_movk32_movk48() {
+; CHECK-LABEL: orr_movk32_movk48:
+; CHECK: // %bb.0:
+; CHECK-NEXT: adrp x8, .LCPI45_0
+; CHECK-NEXT: ldr d0, [x8, :lo12:.LCPI45_0]
+; CHECK-NEXT: ret
+ ret double 0x5678123400010001
+}
+
+define double @movn_movk16_eons() {
+; CHECK-LABEL: movn_movk16_eons:
+; CHECK: // %bb.0:
+; CHECK-NEXT: adrp x8, .LCPI46_0
+; CHECK-NEXT: ldr d0, [x8, :lo12:.LCPI46_0]
+; CHECK-NEXT: ret
+ ret double 0xFFF567818AC7EDCB
+}
+
+define double @movz_movk16_movk32_movk48() {
+; CHECK-LABEL: movz_movk16_movk32_movk48:
+; CHECK: // %bb.0:
+; CHECK-NEXT: adrp x8, .LCPI47_0
+; CHECK-NEXT: ldr d0, [x8, :lo12:.LCPI47_0]
+; CHECK-NEXT: ret
+ ret double 0xABCD9ABC56781234
+}
+
+;; 32 bit FP immediate expansion shouldn't be affected by the limit,
+;; because we can always materialize it using up to 2 instructions - as
+;; `AArch64ExpandImm.cpp` asserts, which is already the default limit
+;; for non-optsize functions.
+
+define float @f32_movz() {
+; CHECK-LABEL: f32_movz:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov w8, #4660 // =0x1234
+; CHECK-NEXT: fmov s0, w8
+; CHECK-NEXT: ret
+ ret float bitcast (i32 4660 to float)
+}
+
+define float @f32_movz16() {
+; CHECK-LABEL: f32_movz16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov w8, #305397760 // =0x12340000
+; CHECK-NEXT: fmov s0, w8
+; CHECK-NEXT: ret
+ ret float bitcast (i32 305397760 to float)
+}
+
+define float @f32_movn() {
+; CHECK-LABEL: f32_movn:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov w8, #-60876 // =0xffff1234
+; CHECK-NEXT: fmov s0, w8
+; CHECK-NEXT: ret
+ ret float bitcast (i32 -60876 to float)
+}
+
+define float @f32_movn16() {
+; CHECK-LABEL: f32_movn16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov w8, #305463295 // =0x1234ffff
+; CHECK-NEXT: fmov s0, w8
+; CHECK-NEXT: ret
+ ret float bitcast (i32 305463295 to float)
+}
+
+define float @f32_orr() {
+; CHECK-LABEL: f32_orr:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov w8, #16843009 // =0x1010101
+; CHECK-NEXT: fmov s0, w8
+; CHECK-NEXT: ret
+ ret float bitcast (i32 16843009 to float)
+}
+
+define float @f32_movz_movk16() {
+; CHECK-LABEL: f32_movz_movk16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov w8, #4660 // =0x1234
+; CHECK-NEXT: movk w8, #3855, lsl #16
+; CHECK-NEXT: fmov s0, w8
+; CHECK-NEXT: ret
+ ret float bitcast (i32 252645940 to float)
+}
diff --git a/llvm/test/CodeGen/AArch64/fpimm-legal-expand-optsize.ll b/llvm/test/CodeGen/AArch64/fpimm-legal-expand-optsize.ll
index 61604b5a13e27..07668ffadc368 100644
--- a/llvm/test/CodeGen/AArch64/fpimm-legal-expand-optsize.ll
+++ b/llvm/test/CodeGen/AArch64/fpimm-legal-expand-optsize.ll
@@ -1,6 +1,8 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
; RUN: llc %s -o - -mtriple=aarch64-unknown -mattr=+fuse-literals | FileCheck %s
; RUN: llc %s -o - -mtriple=aarch64-unknown -mattr=-fuse-literals | FileCheck %s
+; RUN: llc %s -o - -mtriple=aarch64-unknown -mattr=+fuse-movz-movk | FileCheck %s
+; RUN: llc %s -o - -mtriple=aarch64-unknown -mattr=-fuse-movz-movk | FileCheck %s
;; Representative tests for each class of FP immediate expansion that shouldn't apply
;; when optimizing for size.
diff --git a/llvm/test/CodeGen/AArch64/literal_pools_float_apple.ll b/llvm/test/CodeGen/AArch64/literal_pools_float_apple.ll
index 138d885679fb8..68a2f43e8e51a 100644
--- a/llvm/test/CodeGen/AArch64/literal_pools_float_apple.ll
+++ b/llvm/test/CodeGen/AArch64/literal_pools_float_apple.ll
@@ -118,11 +118,11 @@ define double @double_4mov() {
;
; APPLE-LABEL: double_4mov:
; APPLE: ; %bb.0:
-; APPLE-NEXT: mov x8, #4096 ; =0x1000
-; APPLE-NEXT: movk x8, #8192, lsl #16
-; APPLE-NEXT: movk x8, #12288, lsl #32
-; APPLE-NEXT: movk x8, #16384, lsl #48
-; APPLE-NEXT: fmov d0, x8
+; APPLE-NEXT: Lloh0:
+; APPLE-NEXT: adrp x8, lCPI7_0 at PAGE
+; APPLE-NEXT: Lloh1:
+; APPLE-NEXT: ldr d0, [x8, lCPI7_0 at PAGEOFF]
; APPLE-NEXT: ret
+; APPLE-NEXT: .loh AdrpLdr Lloh0, Lloh1
ret double 0x4000300020001000
}
diff --git a/llvm/test/CodeGen/AArch64/misched-fusion-movz-movk-post-ra.mir b/llvm/test/CodeGen/AArch64/misched-fusion-movz-movk-post-ra.mir
new file mode 100644
index 0000000000000..a4be1c0682a06
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/misched-fusion-movz-movk-post-ra.mir
@@ -0,0 +1,1124 @@
+# REQUIRES: asserts
+
+# RUN: llc -filetype=null %s -mtriple=aarch64-linux-gnu -mattr=+fuse-movz-movk -passes=machine-scheduler -misched-print-dags 2>&1 | FileCheck %s --check-prefixes=CHECK,FUSE
+# RUN: llc -filetype=null %s -mtriple=arm64-apple-macosx -mcpu=apple-a14 -passes=machine-scheduler -misched-print-dags 2>&1 | FileCheck %s --check-prefixes=CHECK,FUSE
+# RUN: llc -filetype=null %s -mtriple=arm64-apple-macosx -mcpu=apple-m5 -passes=machine-scheduler -misched-print-dags 2>&1 | FileCheck %s --check-prefixes=CHECK,FUSE
+
+# RUN: llc -filetype=null %s -mtriple=aarch64-linux-gnu -passes=machine-scheduler -misched-print-dags 2>&1 | FileCheck %s --check-prefixes=CHECK,NOFUSE
+# RUN: llc -filetype=null %s -mtriple=arm64-apple-macosx -mcpu=apple-m5 -mattr=-fuse-movz-movk -passes=machine-scheduler -misched-print-dags 2>&1 | FileCheck %s --check-prefixes=CHECK,NOFUSE
+
+---
+name: movzw0_movkw0_waw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzw0_movkw0_waw
+ ; CHECK: SU(0): $w0 = MOVZWi 1, 0
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): $w0 = MOVKWi $w0(tied-def 0), 2, 0
+ $w0 = MOVZWi 1, 0
+ $w9 = MOVZWi 9, 0
+ $w0 = MOVKWi $w0, 2, 0
+...
+
+---
+name: movzw0_movkw0_nowaw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $w0
+ ; CHECK-LABEL: movzw0_movkw0_nowaw
+ ; CHECK: SU(0): $w1 = MOVZWi 1, 0
+ ; CHECK-NOT: Cluster
+ ; CHECK: SU(2): $w0 = MOVKWi $w0(tied-def 0), 2, 0
+ $w1 = MOVZWi 1, 0
+ $w9 = MOVZWi 9, 0
+ $w0 = MOVKWi $w0, 2, 0
+...
+
+---
+name: movzw0_movkw16_waw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzw0_movkw16_waw
+ ; CHECK: SU(0): $w0 = MOVZWi 1, 0
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): $w0 = MOVKWi $w0(tied-def 0), 2, 16
+ $w0 = MOVZWi 1, 0
+ $w9 = MOVZWi 9, 0
+ $w0 = MOVKWi $w0, 2, 16
+...
+
+---
+name: movzw0_movkw16_nowaw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $w0
+ ; CHECK-LABEL: movzw0_movkw16_nowaw
+ ; CHECK: SU(0): $w1 = MOVZWi 1, 0
+ ; CHECK-NOT: Cluster
+ ; CHECK: SU(2): $w0 = MOVKWi $w0(tied-def 0), 2, 16
+ $w1 = MOVZWi 1, 0
+ $w9 = MOVZWi 9, 0
+ $w0 = MOVKWi $w0, 2, 16
+...
+
+---
+name: movzw0_movkx0_waw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzw0_movkx0_waw
+ ; CHECK: SU(0): $w0 = MOVZWi 1, 0
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): $x0 = MOVKXi $x0(tied-def 0), 2, 0
+ $w0 = MOVZWi 1, 0
+ $w9 = MOVZWi 9, 0
+ $x0 = MOVKXi $x0, 2, 0
+...
+
+---
+name: movzw0_movkx0_nowaw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $x0
+ ; CHECK-LABEL: movzw0_movkx0_nowaw
+ ; CHECK: SU(0): $w1 = MOVZWi 1, 0
+ ; CHECK-NOT: Cluster
+ ; CHECK: SU(2): $x0 = MOVKXi $x0(tied-def 0), 2, 0
+ $w1 = MOVZWi 1, 0
+ $w9 = MOVZWi 9, 0
+ $x0 = MOVKXi $x0, 2, 0
+...
+
+---
+name: movzw0_movkx16_waw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzw0_movkx16_waw
+ ; CHECK: SU(0): $w0 = MOVZWi 1, 0
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): $x0 = MOVKXi $x0(tied-def 0), 2, 16
+ $w0 = MOVZWi 1, 0
+ $w9 = MOVZWi 9, 0
+ $x0 = MOVKXi $x0, 2, 16
+...
+
+---
+name: movzw0_movkx16_nowaw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $x0
+ ; CHECK-LABEL: movzw0_movkx16_nowaw
+ ; CHECK: SU(0): $w1 = MOVZWi 1, 0
+ ; CHECK-NOT: Cluster
+ ; CHECK: SU(2): $x0 = MOVKXi $x0(tied-def 0), 2, 16
+ $w1 = MOVZWi 1, 0
+ $w9 = MOVZWi 9, 0
+ $x0 = MOVKXi $x0, 2, 16
+...
+
+---
+name: movzw0_movkx32_waw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzw0_movkx32_waw
+ ; CHECK: SU(0): $w0 = MOVZWi 1, 0
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): $x0 = MOVKXi $x0(tied-def 0), 2, 32
+ $w0 = MOVZWi 1, 0
+ $w9 = MOVZWi 9, 0
+ $x0 = MOVKXi $x0, 2, 32
+...
+
+---
+name: movzw0_movkx32_nowaw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $x0
+ ; CHECK-LABEL: movzw0_movkx32_nowaw
+ ; CHECK: SU(0): $w1 = MOVZWi 1, 0
+ ; CHECK-NOT: Cluster
+ ; CHECK: SU(2): $x0 = MOVKXi $x0(tied-def 0), 2, 32
+ $w1 = MOVZWi 1, 0
+ $w9 = MOVZWi 9, 0
+ $x0 = MOVKXi $x0, 2, 32
+...
+
+---
+name: movzw0_movkx48_waw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzw0_movkx48_waw
+ ; CHECK: SU(0): $w0 = MOVZWi 1, 0
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): $x0 = MOVKXi $x0(tied-def 0), 2, 48
+ $w0 = MOVZWi 1, 0
+ $w9 = MOVZWi 9, 0
+ $x0 = MOVKXi $x0, 2, 48
+...
+
+---
+name: movzw0_movkx48_nowaw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $x0
+ ; CHECK-LABEL: movzw0_movkx48_nowaw
+ ; CHECK: SU(0): $w1 = MOVZWi 1, 0
+ ; CHECK-NOT: Cluster
+ ; CHECK: SU(2): $x0 = MOVKXi $x0(tied-def 0), 2, 48
+ $w1 = MOVZWi 1, 0
+ $w9 = MOVZWi 9, 0
+ $x0 = MOVKXi $x0, 2, 48
+...
+
+---
+name: movzw16_movkw0_waw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzw16_movkw0_waw
+ ; CHECK: SU(0): $w0 = MOVZWi 1, 16
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): $w0 = MOVKWi $w0(tied-def 0), 2, 0
+ $w0 = MOVZWi 1, 16
+ $w9 = MOVZWi 9, 0
+ $w0 = MOVKWi $w0, 2, 0
+...
+
+---
+name: movzw16_movkw0_nowaw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $w0
+ ; CHECK-LABEL: movzw16_movkw0_nowaw
+ ; CHECK: SU(0): $w1 = MOVZWi 1, 16
+ ; CHECK-NOT: Cluster
+ ; CHECK: SU(2): $w0 = MOVKWi $w0(tied-def 0), 2, 0
+ $w1 = MOVZWi 1, 16
+ $w9 = MOVZWi 9, 0
+ $w0 = MOVKWi $w0, 2, 0
+...
+
+---
+name: movzw16_movkw16_waw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzw16_movkw16_waw
+ ; CHECK: SU(0): $w0 = MOVZWi 1, 16
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): $w0 = MOVKWi $w0(tied-def 0), 2, 16
+ $w0 = MOVZWi 1, 16
+ $w9 = MOVZWi 9, 0
+ $w0 = MOVKWi $w0, 2, 16
+...
+
+---
+name: movzw16_movkw16_nowaw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $w0
+ ; CHECK-LABEL: movzw16_movkw16_nowaw
+ ; CHECK: SU(0): $w1 = MOVZWi 1, 16
+ ; CHECK-NOT: Cluster
+ ; CHECK: SU(2): $w0 = MOVKWi $w0(tied-def 0), 2, 16
+ $w1 = MOVZWi 1, 16
+ $w9 = MOVZWi 9, 0
+ $w0 = MOVKWi $w0, 2, 16
+...
+
+---
+name: movzw16_movkx0_waw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzw16_movkx0_waw
+ ; CHECK: SU(0): $w0 = MOVZWi 1, 16
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): $x0 = MOVKXi $x0(tied-def 0), 2, 0
+ $w0 = MOVZWi 1, 16
+ $w9 = MOVZWi 9, 0
+ $x0 = MOVKXi $x0, 2, 0
+...
+
+---
+name: movzw16_movkx0_nowaw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $x0
+ ; CHECK-LABEL: movzw16_movkx0_nowaw
+ ; CHECK: SU(0): $w1 = MOVZWi 1, 16
+ ; CHECK-NOT: Cluster
+ ; CHECK: SU(2): $x0 = MOVKXi $x0(tied-def 0), 2, 0
+ $w1 = MOVZWi 1, 16
+ $w9 = MOVZWi 9, 0
+ $x0 = MOVKXi $x0, 2, 0
+...
+
+---
+name: movzw16_movkx16_waw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzw16_movkx16_waw
+ ; CHECK: SU(0): $w0 = MOVZWi 1, 16
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): $x0 = MOVKXi $x0(tied-def 0), 2, 16
+ $w0 = MOVZWi 1, 16
+ $w9 = MOVZWi 9, 0
+ $x0 = MOVKXi $x0, 2, 16
+...
+
+---
+name: movzw16_movkx16_nowaw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $x0
+ ; CHECK-LABEL: movzw16_movkx16_nowaw
+ ; CHECK: SU(0): $w1 = MOVZWi 1, 16
+ ; CHECK-NOT: Cluster
+ ; CHECK: SU(2): $x0 = MOVKXi $x0(tied-def 0), 2, 16
+ $w1 = MOVZWi 1, 16
+ $w9 = MOVZWi 9, 0
+ $x0 = MOVKXi $x0, 2, 16
+...
+
+---
+name: movzw16_movkx32_waw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzw16_movkx32_waw
+ ; CHECK: SU(0): $w0 = MOVZWi 1, 16
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): $x0 = MOVKXi $x0(tied-def 0), 2, 32
+ $w0 = MOVZWi 1, 16
+ $w9 = MOVZWi 9, 0
+ $x0 = MOVKXi $x0, 2, 32
+...
+
+---
+name: movzw16_movkx32_nowaw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $x0
+ ; CHECK-LABEL: movzw16_movkx32_nowaw
+ ; CHECK: SU(0): $w1 = MOVZWi 1, 16
+ ; CHECK-NOT: Cluster
+ ; CHECK: SU(2): $x0 = MOVKXi $x0(tied-def 0), 2, 32
+ $w1 = MOVZWi 1, 16
+ $w9 = MOVZWi 9, 0
+ $x0 = MOVKXi $x0, 2, 32
+...
+
+---
+name: movzw16_movkx48_waw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzw16_movkx48_waw
+ ; CHECK: SU(0): $w0 = MOVZWi 1, 16
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): $x0 = MOVKXi $x0(tied-def 0), 2, 48
+ $w0 = MOVZWi 1, 16
+ $w9 = MOVZWi 9, 0
+ $x0 = MOVKXi $x0, 2, 48
+...
+
+---
+name: movzw16_movkx48_nowaw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $x0
+ ; CHECK-LABEL: movzw16_movkx48_nowaw
+ ; CHECK: SU(0): $w1 = MOVZWi 1, 16
+ ; CHECK-NOT: Cluster
+ ; CHECK: SU(2): $x0 = MOVKXi $x0(tied-def 0), 2, 48
+ $w1 = MOVZWi 1, 16
+ $w9 = MOVZWi 9, 0
+ $x0 = MOVKXi $x0, 2, 48
+...
+
+---
+name: movzx0_movkw0_waw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzx0_movkw0_waw
+ ; CHECK: SU(0): $x0 = MOVZXi 1, 0
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): $w0 = MOVKWi $w0(tied-def 0), 2, 0
+ $x0 = MOVZXi 1, 0
+ $w9 = MOVZWi 9, 0
+ $w0 = MOVKWi $w0, 2, 0
+...
+
+---
+name: movzx0_movkw0_nowaw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $w0
+ ; CHECK-LABEL: movzx0_movkw0_nowaw
+ ; CHECK: SU(0): $x1 = MOVZXi 1, 0
+ ; CHECK-NOT: Cluster
+ ; CHECK: SU(2): $w0 = MOVKWi $w0(tied-def 0), 2, 0
+ $x1 = MOVZXi 1, 0
+ $w9 = MOVZWi 9, 0
+ $w0 = MOVKWi $w0, 2, 0
+...
+
+---
+name: movzx0_movkw16_waw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzx0_movkw16_waw
+ ; CHECK: SU(0): $x0 = MOVZXi 1, 0
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): $w0 = MOVKWi $w0(tied-def 0), 2, 16
+ $x0 = MOVZXi 1, 0
+ $w9 = MOVZWi 9, 0
+ $w0 = MOVKWi $w0, 2, 16
+...
+
+---
+name: movzx0_movkw16_nowaw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $w0
+ ; CHECK-LABEL: movzx0_movkw16_nowaw
+ ; CHECK: SU(0): $x1 = MOVZXi 1, 0
+ ; CHECK-NOT: Cluster
+ ; CHECK: SU(2): $w0 = MOVKWi $w0(tied-def 0), 2, 16
+ $x1 = MOVZXi 1, 0
+ $w9 = MOVZWi 9, 0
+ $w0 = MOVKWi $w0, 2, 16
+...
+
+---
+name: movzx0_movkx0_waw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzx0_movkx0_waw
+ ; CHECK: SU(0): $x0 = MOVZXi 1, 0
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): $x0 = MOVKXi $x0(tied-def 0), 2, 0
+ $x0 = MOVZXi 1, 0
+ $w9 = MOVZWi 9, 0
+ $x0 = MOVKXi $x0, 2, 0
+...
+
+---
+name: movzx0_movkx0_nowaw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $x0
+ ; CHECK-LABEL: movzx0_movkx0_nowaw
+ ; CHECK: SU(0): $x1 = MOVZXi 1, 0
+ ; CHECK-NOT: Cluster
+ ; CHECK: SU(2): $x0 = MOVKXi $x0(tied-def 0), 2, 0
+ $x1 = MOVZXi 1, 0
+ $w9 = MOVZWi 9, 0
+ $x0 = MOVKXi $x0, 2, 0
+...
+
+---
+name: movzx0_movkx16_waw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzx0_movkx16_waw
+ ; CHECK: SU(0): $x0 = MOVZXi 1, 0
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): $x0 = MOVKXi $x0(tied-def 0), 2, 16
+ $x0 = MOVZXi 1, 0
+ $w9 = MOVZWi 9, 0
+ $x0 = MOVKXi $x0, 2, 16
+...
+
+---
+name: movzx0_movkx16_nowaw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $x0
+ ; CHECK-LABEL: movzx0_movkx16_nowaw
+ ; CHECK: SU(0): $x1 = MOVZXi 1, 0
+ ; CHECK-NOT: Cluster
+ ; CHECK: SU(2): $x0 = MOVKXi $x0(tied-def 0), 2, 16
+ $x1 = MOVZXi 1, 0
+ $w9 = MOVZWi 9, 0
+ $x0 = MOVKXi $x0, 2, 16
+...
+
+---
+name: movzx0_movkx32_waw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzx0_movkx32_waw
+ ; CHECK: SU(0): $x0 = MOVZXi 1, 0
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): $x0 = MOVKXi $x0(tied-def 0), 2, 32
+ $x0 = MOVZXi 1, 0
+ $w9 = MOVZWi 9, 0
+ $x0 = MOVKXi $x0, 2, 32
+...
+
+---
+name: movzx0_movkx32_nowaw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $x0
+ ; CHECK-LABEL: movzx0_movkx32_nowaw
+ ; CHECK: SU(0): $x1 = MOVZXi 1, 0
+ ; CHECK-NOT: Cluster
+ ; CHECK: SU(2): $x0 = MOVKXi $x0(tied-def 0), 2, 32
+ $x1 = MOVZXi 1, 0
+ $w9 = MOVZWi 9, 0
+ $x0 = MOVKXi $x0, 2, 32
+...
+
+---
+name: movzx0_movkx48_waw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzx0_movkx48_waw
+ ; CHECK: SU(0): $x0 = MOVZXi 1, 0
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): $x0 = MOVKXi $x0(tied-def 0), 2, 48
+ $x0 = MOVZXi 1, 0
+ $w9 = MOVZWi 9, 0
+ $x0 = MOVKXi $x0, 2, 48
+...
+
+---
+name: movzx0_movkx48_nowaw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $x0
+ ; CHECK-LABEL: movzx0_movkx48_nowaw
+ ; CHECK: SU(0): $x1 = MOVZXi 1, 0
+ ; CHECK-NOT: Cluster
+ ; CHECK: SU(2): $x0 = MOVKXi $x0(tied-def 0), 2, 48
+ $x1 = MOVZXi 1, 0
+ $w9 = MOVZWi 9, 0
+ $x0 = MOVKXi $x0, 2, 48
+...
+
+---
+name: movzx16_movkw0_waw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzx16_movkw0_waw
+ ; CHECK: SU(0): $x0 = MOVZXi 1, 16
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): $w0 = MOVKWi $w0(tied-def 0), 2, 0
+ $x0 = MOVZXi 1, 16
+ $w9 = MOVZWi 9, 0
+ $w0 = MOVKWi $w0, 2, 0
+...
+
+---
+name: movzx16_movkw0_nowaw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $w0
+ ; CHECK-LABEL: movzx16_movkw0_nowaw
+ ; CHECK: SU(0): $x1 = MOVZXi 1, 16
+ ; CHECK-NOT: Cluster
+ ; CHECK: SU(2): $w0 = MOVKWi $w0(tied-def 0), 2, 0
+ $x1 = MOVZXi 1, 16
+ $w9 = MOVZWi 9, 0
+ $w0 = MOVKWi $w0, 2, 0
+...
+
+---
+name: movzx16_movkw16_waw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzx16_movkw16_waw
+ ; CHECK: SU(0): $x0 = MOVZXi 1, 16
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): $w0 = MOVKWi $w0(tied-def 0), 2, 16
+ $x0 = MOVZXi 1, 16
+ $w9 = MOVZWi 9, 0
+ $w0 = MOVKWi $w0, 2, 16
+...
+
+---
+name: movzx16_movkw16_nowaw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $w0
+ ; CHECK-LABEL: movzx16_movkw16_nowaw
+ ; CHECK: SU(0): $x1 = MOVZXi 1, 16
+ ; CHECK-NOT: Cluster
+ ; CHECK: SU(2): $w0 = MOVKWi $w0(tied-def 0), 2, 16
+ $x1 = MOVZXi 1, 16
+ $w9 = MOVZWi 9, 0
+ $w0 = MOVKWi $w0, 2, 16
+...
+
+---
+name: movzx16_movkx0_waw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzx16_movkx0_waw
+ ; CHECK: SU(0): $x0 = MOVZXi 1, 16
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): $x0 = MOVKXi $x0(tied-def 0), 2, 0
+ $x0 = MOVZXi 1, 16
+ $w9 = MOVZWi 9, 0
+ $x0 = MOVKXi $x0, 2, 0
+...
+
+---
+name: movzx16_movkx0_nowaw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $x0
+ ; CHECK-LABEL: movzx16_movkx0_nowaw
+ ; CHECK: SU(0): $x1 = MOVZXi 1, 16
+ ; CHECK-NOT: Cluster
+ ; CHECK: SU(2): $x0 = MOVKXi $x0(tied-def 0), 2, 0
+ $x1 = MOVZXi 1, 16
+ $w9 = MOVZWi 9, 0
+ $x0 = MOVKXi $x0, 2, 0
+...
+
+---
+name: movzx16_movkx16_waw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzx16_movkx16_waw
+ ; CHECK: SU(0): $x0 = MOVZXi 1, 16
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): $x0 = MOVKXi $x0(tied-def 0), 2, 16
+ $x0 = MOVZXi 1, 16
+ $w9 = MOVZWi 9, 0
+ $x0 = MOVKXi $x0, 2, 16
+...
+
+---
+name: movzx16_movkx16_nowaw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $x0
+ ; CHECK-LABEL: movzx16_movkx16_nowaw
+ ; CHECK: SU(0): $x1 = MOVZXi 1, 16
+ ; CHECK-NOT: Cluster
+ ; CHECK: SU(2): $x0 = MOVKXi $x0(tied-def 0), 2, 16
+ $x1 = MOVZXi 1, 16
+ $w9 = MOVZWi 9, 0
+ $x0 = MOVKXi $x0, 2, 16
+...
+
+---
+name: movzx16_movkx32_waw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzx16_movkx32_waw
+ ; CHECK: SU(0): $x0 = MOVZXi 1, 16
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): $x0 = MOVKXi $x0(tied-def 0), 2, 32
+ $x0 = MOVZXi 1, 16
+ $w9 = MOVZWi 9, 0
+ $x0 = MOVKXi $x0, 2, 32
+...
+
+---
+name: movzx16_movkx32_nowaw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $x0
+ ; CHECK-LABEL: movzx16_movkx32_nowaw
+ ; CHECK: SU(0): $x1 = MOVZXi 1, 16
+ ; CHECK-NOT: Cluster
+ ; CHECK: SU(2): $x0 = MOVKXi $x0(tied-def 0), 2, 32
+ $x1 = MOVZXi 1, 16
+ $w9 = MOVZWi 9, 0
+ $x0 = MOVKXi $x0, 2, 32
+...
+
+---
+name: movzx16_movkx48_waw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzx16_movkx48_waw
+ ; CHECK: SU(0): $x0 = MOVZXi 1, 16
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): $x0 = MOVKXi $x0(tied-def 0), 2, 48
+ $x0 = MOVZXi 1, 16
+ $w9 = MOVZWi 9, 0
+ $x0 = MOVKXi $x0, 2, 48
+...
+
+---
+name: movzx16_movkx48_nowaw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $x0
+ ; CHECK-LABEL: movzx16_movkx48_nowaw
+ ; CHECK: SU(0): $x1 = MOVZXi 1, 16
+ ; CHECK-NOT: Cluster
+ ; CHECK: SU(2): $x0 = MOVKXi $x0(tied-def 0), 2, 48
+ $x1 = MOVZXi 1, 16
+ $w9 = MOVZWi 9, 0
+ $x0 = MOVKXi $x0, 2, 48
+...
+
+---
+name: movzx32_movkw0_waw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzx32_movkw0_waw
+ ; CHECK: SU(0): $x0 = MOVZXi 1, 32
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): $w0 = MOVKWi $w0(tied-def 0), 2, 0
+ $x0 = MOVZXi 1, 32
+ $w9 = MOVZWi 9, 0
+ $w0 = MOVKWi $w0, 2, 0
+...
+
+---
+name: movzx32_movkw0_nowaw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $w0
+ ; CHECK-LABEL: movzx32_movkw0_nowaw
+ ; CHECK: SU(0): $x1 = MOVZXi 1, 32
+ ; CHECK-NOT: Cluster
+ ; CHECK: SU(2): $w0 = MOVKWi $w0(tied-def 0), 2, 0
+ $x1 = MOVZXi 1, 32
+ $w9 = MOVZWi 9, 0
+ $w0 = MOVKWi $w0, 2, 0
+...
+
+---
+name: movzx32_movkw16_waw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzx32_movkw16_waw
+ ; CHECK: SU(0): $x0 = MOVZXi 1, 32
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): $w0 = MOVKWi $w0(tied-def 0), 2, 16
+ $x0 = MOVZXi 1, 32
+ $w9 = MOVZWi 9, 0
+ $w0 = MOVKWi $w0, 2, 16
+...
+
+---
+name: movzx32_movkw16_nowaw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $w0
+ ; CHECK-LABEL: movzx32_movkw16_nowaw
+ ; CHECK: SU(0): $x1 = MOVZXi 1, 32
+ ; CHECK-NOT: Cluster
+ ; CHECK: SU(2): $w0 = MOVKWi $w0(tied-def 0), 2, 16
+ $x1 = MOVZXi 1, 32
+ $w9 = MOVZWi 9, 0
+ $w0 = MOVKWi $w0, 2, 16
+...
+
+---
+name: movzx32_movkx0_waw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzx32_movkx0_waw
+ ; CHECK: SU(0): $x0 = MOVZXi 1, 32
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): $x0 = MOVKXi $x0(tied-def 0), 2, 0
+ $x0 = MOVZXi 1, 32
+ $w9 = MOVZWi 9, 0
+ $x0 = MOVKXi $x0, 2, 0
+...
+
+---
+name: movzx32_movkx0_nowaw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $x0
+ ; CHECK-LABEL: movzx32_movkx0_nowaw
+ ; CHECK: SU(0): $x1 = MOVZXi 1, 32
+ ; CHECK-NOT: Cluster
+ ; CHECK: SU(2): $x0 = MOVKXi $x0(tied-def 0), 2, 0
+ $x1 = MOVZXi 1, 32
+ $w9 = MOVZWi 9, 0
+ $x0 = MOVKXi $x0, 2, 0
+...
+
+---
+name: movzx32_movkx16_waw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzx32_movkx16_waw
+ ; CHECK: SU(0): $x0 = MOVZXi 1, 32
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): $x0 = MOVKXi $x0(tied-def 0), 2, 16
+ $x0 = MOVZXi 1, 32
+ $w9 = MOVZWi 9, 0
+ $x0 = MOVKXi $x0, 2, 16
+...
+
+---
+name: movzx32_movkx16_nowaw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $x0
+ ; CHECK-LABEL: movzx32_movkx16_nowaw
+ ; CHECK: SU(0): $x1 = MOVZXi 1, 32
+ ; CHECK-NOT: Cluster
+ ; CHECK: SU(2): $x0 = MOVKXi $x0(tied-def 0), 2, 16
+ $x1 = MOVZXi 1, 32
+ $w9 = MOVZWi 9, 0
+ $x0 = MOVKXi $x0, 2, 16
+...
+
+---
+name: movzx32_movkx32_waw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzx32_movkx32_waw
+ ; CHECK: SU(0): $x0 = MOVZXi 1, 32
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): $x0 = MOVKXi $x0(tied-def 0), 2, 32
+ $x0 = MOVZXi 1, 32
+ $w9 = MOVZWi 9, 0
+ $x0 = MOVKXi $x0, 2, 32
+...
+
+---
+name: movzx32_movkx32_nowaw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $x0
+ ; CHECK-LABEL: movzx32_movkx32_nowaw
+ ; CHECK: SU(0): $x1 = MOVZXi 1, 32
+ ; CHECK-NOT: Cluster
+ ; CHECK: SU(2): $x0 = MOVKXi $x0(tied-def 0), 2, 32
+ $x1 = MOVZXi 1, 32
+ $w9 = MOVZWi 9, 0
+ $x0 = MOVKXi $x0, 2, 32
+...
+
+---
+name: movzx32_movkx48_waw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzx32_movkx48_waw
+ ; CHECK: SU(0): $x0 = MOVZXi 1, 32
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): $x0 = MOVKXi $x0(tied-def 0), 2, 48
+ $x0 = MOVZXi 1, 32
+ $w9 = MOVZWi 9, 0
+ $x0 = MOVKXi $x0, 2, 48
+...
+
+---
+name: movzx32_movkx48_nowaw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $x0
+ ; CHECK-LABEL: movzx32_movkx48_nowaw
+ ; CHECK: SU(0): $x1 = MOVZXi 1, 32
+ ; CHECK-NOT: Cluster
+ ; CHECK: SU(2): $x0 = MOVKXi $x0(tied-def 0), 2, 48
+ $x1 = MOVZXi 1, 32
+ $w9 = MOVZWi 9, 0
+ $x0 = MOVKXi $x0, 2, 48
+...
+
+---
+name: movzx48_movkw0_waw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzx48_movkw0_waw
+ ; CHECK: SU(0): $x0 = MOVZXi 1, 48
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): $w0 = MOVKWi $w0(tied-def 0), 2, 0
+ $x0 = MOVZXi 1, 48
+ $w9 = MOVZWi 9, 0
+ $w0 = MOVKWi $w0, 2, 0
+...
+
+---
+name: movzx48_movkw0_nowaw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $w0
+ ; CHECK-LABEL: movzx48_movkw0_nowaw
+ ; CHECK: SU(0): $x1 = MOVZXi 1, 48
+ ; CHECK-NOT: Cluster
+ ; CHECK: SU(2): $w0 = MOVKWi $w0(tied-def 0), 2, 0
+ $x1 = MOVZXi 1, 48
+ $w9 = MOVZWi 9, 0
+ $w0 = MOVKWi $w0, 2, 0
+...
+
+---
+name: movzx48_movkw16_waw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzx48_movkw16_waw
+ ; CHECK: SU(0): $x0 = MOVZXi 1, 48
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): $w0 = MOVKWi $w0(tied-def 0), 2, 16
+ $x0 = MOVZXi 1, 48
+ $w9 = MOVZWi 9, 0
+ $w0 = MOVKWi $w0, 2, 16
+...
+
+---
+name: movzx48_movkw16_nowaw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $w0
+ ; CHECK-LABEL: movzx48_movkw16_nowaw
+ ; CHECK: SU(0): $x1 = MOVZXi 1, 48
+ ; CHECK-NOT: Cluster
+ ; CHECK: SU(2): $w0 = MOVKWi $w0(tied-def 0), 2, 16
+ $x1 = MOVZXi 1, 48
+ $w9 = MOVZWi 9, 0
+ $w0 = MOVKWi $w0, 2, 16
+...
+
+---
+name: movzx48_movkx0_waw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzx48_movkx0_waw
+ ; CHECK: SU(0): $x0 = MOVZXi 1, 48
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): $x0 = MOVKXi $x0(tied-def 0), 2, 0
+ $x0 = MOVZXi 1, 48
+ $w9 = MOVZWi 9, 0
+ $x0 = MOVKXi $x0, 2, 0
+...
+
+---
+name: movzx48_movkx0_nowaw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $x0
+ ; CHECK-LABEL: movzx48_movkx0_nowaw
+ ; CHECK: SU(0): $x1 = MOVZXi 1, 48
+ ; CHECK-NOT: Cluster
+ ; CHECK: SU(2): $x0 = MOVKXi $x0(tied-def 0), 2, 0
+ $x1 = MOVZXi 1, 48
+ $w9 = MOVZWi 9, 0
+ $x0 = MOVKXi $x0, 2, 0
+...
+
+---
+name: movzx48_movkx16_waw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzx48_movkx16_waw
+ ; CHECK: SU(0): $x0 = MOVZXi 1, 48
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): $x0 = MOVKXi $x0(tied-def 0), 2, 16
+ $x0 = MOVZXi 1, 48
+ $w9 = MOVZWi 9, 0
+ $x0 = MOVKXi $x0, 2, 16
+...
+
+---
+name: movzx48_movkx16_nowaw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $x0
+ ; CHECK-LABEL: movzx48_movkx16_nowaw
+ ; CHECK: SU(0): $x1 = MOVZXi 1, 48
+ ; CHECK-NOT: Cluster
+ ; CHECK: SU(2): $x0 = MOVKXi $x0(tied-def 0), 2, 16
+ $x1 = MOVZXi 1, 48
+ $w9 = MOVZWi 9, 0
+ $x0 = MOVKXi $x0, 2, 16
+...
+
+---
+name: movzx48_movkx32_waw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzx48_movkx32_waw
+ ; CHECK: SU(0): $x0 = MOVZXi 1, 48
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): $x0 = MOVKXi $x0(tied-def 0), 2, 32
+ $x0 = MOVZXi 1, 48
+ $w9 = MOVZWi 9, 0
+ $x0 = MOVKXi $x0, 2, 32
+...
+
+---
+name: movzx48_movkx32_nowaw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $x0
+ ; CHECK-LABEL: movzx48_movkx32_nowaw
+ ; CHECK: SU(0): $x1 = MOVZXi 1, 48
+ ; CHECK-NOT: Cluster
+ ; CHECK: SU(2): $x0 = MOVKXi $x0(tied-def 0), 2, 32
+ $x1 = MOVZXi 1, 48
+ $w9 = MOVZWi 9, 0
+ $x0 = MOVKXi $x0, 2, 32
+...
+
+---
+name: movzx48_movkx48_waw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzx48_movkx48_waw
+ ; CHECK: SU(0): $x0 = MOVZXi 1, 48
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): $x0 = MOVKXi $x0(tied-def 0), 2, 48
+ $x0 = MOVZXi 1, 48
+ $w9 = MOVZWi 9, 0
+ $x0 = MOVKXi $x0, 2, 48
+...
+
+---
+name: movzx48_movkx48_nowaw
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $x0
+ ; CHECK-LABEL: movzx48_movkx48_nowaw
+ ; CHECK: SU(0): $x1 = MOVZXi 1, 48
+ ; CHECK-NOT: Cluster
+ ; CHECK: SU(2): $x0 = MOVKXi $x0(tied-def 0), 2, 48
+ $x1 = MOVZXi 1, 48
+ $w9 = MOVZWi 9, 0
+ $x0 = MOVKXi $x0, 2, 48
+...
diff --git a/llvm/test/CodeGen/AArch64/misched-fusion-movz-movk-pre-ra.mir b/llvm/test/CodeGen/AArch64/misched-fusion-movz-movk-pre-ra.mir
new file mode 100644
index 0000000000000..d80aa4980ce4d
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/misched-fusion-movz-movk-pre-ra.mir
@@ -0,0 +1,584 @@
+# REQUIRES: asserts
+
+# RUN: llc -filetype=null %s -mtriple=aarch64-unknown -mattr=+fuse-movz-movk -passes=machine-scheduler -misched-print-dags 2>&1 | FileCheck %s --check-prefixes=CHECK,FUSE
+# RUN: llc -filetype=null %s -mtriple=arm64-apple-macosx -mcpu=apple-a14 -passes=machine-scheduler -misched-print-dags 2>&1 | FileCheck %s --check-prefixes=CHECK,FUSE
+# RUN: llc -filetype=null %s -mtriple=arm64-apple-macosx -mcpu=apple-m5 -passes=machine-scheduler -misched-print-dags 2>&1 | FileCheck %s --check-prefixes=CHECK,FUSE
+
+# RUN: llc -filetype=null %s -mtriple=aarch64-unknown -passes=machine-scheduler -misched-print-dags 2>&1 | FileCheck %s --check-prefixes=CHECK,NOFUSE
+# RUN: llc -filetype=null %s -mtriple=arm64-apple-macosx -mcpu=apple-m5 -mattr=-fuse-movz-movk -passes=machine-scheduler -misched-print-dags 2>&1 | FileCheck %s --check-prefixes=CHECK,NOFUSE
+
+---
+name: movzw0_movkw0
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzw0_movkw0
+ ; CHECK: SU(0): %0:gpr32 = MOVZWi 1, 0
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): dead %0:gpr32 = MOVKWi %0:gpr32(tied-def 0), 2, 0
+ %0:gpr32 = MOVZWi 1, 0
+ %1:gpr32 = MOVZWi 9, 0
+ %0:gpr32 = MOVKWi %0, 2, 0
+...
+
+---
+name: movzw0_movkw16
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzw0_movkw16
+ ; CHECK: SU(0): %0:gpr32 = MOVZWi 1, 0
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): dead %0:gpr32 = MOVKWi %0:gpr32(tied-def 0), 2, 16
+ %0:gpr32 = MOVZWi 1, 0
+ %1:gpr32 = MOVZWi 9, 0
+ %0:gpr32 = MOVKWi %0, 2, 16
+...
+
+---
+name: movzw0_movkx0
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzw0_movkx0
+ ; CHECK: SU(0): undef %0.sub_32:gpr64 = MOVZWi 1, 0
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): dead %0:gpr64 = MOVKXi %0:gpr64(tied-def 0), 2, 0
+ undef %0.sub_32:gpr64 = MOVZWi 1, 0
+ %1:gpr32 = MOVZWi 9, 0
+ %0:gpr64 = MOVKXi %0, 2, 0
+...
+
+---
+name: movzw0_movkx16
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzw0_movkx16
+ ; CHECK: SU(0): undef %0.sub_32:gpr64 = MOVZWi 1, 0
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): dead %0:gpr64 = MOVKXi %0:gpr64(tied-def 0), 2, 16
+ undef %0.sub_32:gpr64 = MOVZWi 1, 0
+ %1:gpr32 = MOVZWi 9, 0
+ %0:gpr64 = MOVKXi %0, 2, 16
+...
+
+---
+name: movzw0_movkx32
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzw0_movkx32
+ ; CHECK: SU(0): undef %0.sub_32:gpr64 = MOVZWi 1, 0
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): dead %0:gpr64 = MOVKXi %0:gpr64(tied-def 0), 2, 32
+ undef %0.sub_32:gpr64 = MOVZWi 1, 0
+ %1:gpr32 = MOVZWi 9, 0
+ %0:gpr64 = MOVKXi %0, 2, 32
+...
+
+---
+name: movzw0_movkx48
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzw0_movkx48
+ ; CHECK: SU(0): undef %0.sub_32:gpr64 = MOVZWi 1, 0
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): dead %0:gpr64 = MOVKXi %0:gpr64(tied-def 0), 2, 48
+ undef %0.sub_32:gpr64 = MOVZWi 1, 0
+ %1:gpr32 = MOVZWi 9, 0
+ %0:gpr64 = MOVKXi %0, 2, 48
+...
+
+---
+name: movzw16_movkw0
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzw16_movkw0
+ ; CHECK: SU(0): %0:gpr32 = MOVZWi 1, 16
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): dead %0:gpr32 = MOVKWi %0:gpr32(tied-def 0), 2, 0
+ %0:gpr32 = MOVZWi 1, 16
+ %1:gpr32 = MOVZWi 9, 0
+ %0:gpr32 = MOVKWi %0, 2, 0
+...
+
+---
+name: movzw16_movkw16
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzw16_movkw16
+ ; CHECK: SU(0): %0:gpr32 = MOVZWi 1, 16
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): dead %0:gpr32 = MOVKWi %0:gpr32(tied-def 0), 2, 16
+ %0:gpr32 = MOVZWi 1, 16
+ %1:gpr32 = MOVZWi 9, 0
+ %0:gpr32 = MOVKWi %0, 2, 16
+...
+
+---
+name: movzw16_movkx0
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzw16_movkx0
+ ; CHECK: SU(0): undef %0.sub_32:gpr64 = MOVZWi 1, 16
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): dead %0:gpr64 = MOVKXi %0:gpr64(tied-def 0), 2, 0
+ undef %0.sub_32:gpr64 = MOVZWi 1, 16
+ %1:gpr32 = MOVZWi 9, 0
+ %0:gpr64 = MOVKXi %0, 2, 0
+...
+
+---
+name: movzw16_movkx16
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzw16_movkx16
+ ; CHECK: SU(0): undef %0.sub_32:gpr64 = MOVZWi 1, 16
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): dead %0:gpr64 = MOVKXi %0:gpr64(tied-def 0), 2, 16
+ undef %0.sub_32:gpr64 = MOVZWi 1, 16
+ %1:gpr32 = MOVZWi 9, 0
+ %0:gpr64 = MOVKXi %0, 2, 16
+...
+
+---
+name: movzw16_movkx32
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzw16_movkx32
+ ; CHECK: SU(0): undef %0.sub_32:gpr64 = MOVZWi 1, 16
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): dead %0:gpr64 = MOVKXi %0:gpr64(tied-def 0), 2, 32
+ undef %0.sub_32:gpr64 = MOVZWi 1, 16
+ %1:gpr32 = MOVZWi 9, 0
+ %0:gpr64 = MOVKXi %0, 2, 32
+...
+
+---
+name: movzw16_movkx48
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzw16_movkx48
+ ; CHECK: SU(0): undef %0.sub_32:gpr64 = MOVZWi 1, 16
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): dead %0:gpr64 = MOVKXi %0:gpr64(tied-def 0), 2, 48
+ undef %0.sub_32:gpr64 = MOVZWi 1, 16
+ %1:gpr32 = MOVZWi 9, 0
+ %0:gpr64 = MOVKXi %0, 2, 48
+...
+
+---
+name: movzx0_movkw0
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzx0_movkw0
+ ; CHECK: SU(0): %0:gpr64 = MOVZXi 1, 0
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): dead %0.sub_32:gpr64 = MOVKWi %0.sub_32:gpr64(tied-def 0), 2, 0
+ %0:gpr64 = MOVZXi 1, 0
+ %1:gpr32 = MOVZWi 9, 0
+ %0.sub_32:gpr64 = MOVKWi %0.sub_32, 2, 0
+...
+
+---
+name: movzx0_movkw16
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzx0_movkw16
+ ; CHECK: SU(0): %0:gpr64 = MOVZXi 1, 0
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): dead %0.sub_32:gpr64 = MOVKWi %0.sub_32:gpr64(tied-def 0), 2, 16
+ %0:gpr64 = MOVZXi 1, 0
+ %1:gpr32 = MOVZWi 9, 0
+ %0.sub_32:gpr64 = MOVKWi %0.sub_32, 2, 16
+...
+
+---
+name: movzx0_movkx0
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzx0_movkx0
+ ; CHECK: SU(0): %0:gpr64 = MOVZXi 1, 0
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): dead %0:gpr64 = MOVKXi %0:gpr64(tied-def 0), 2, 0
+ %0:gpr64 = MOVZXi 1, 0
+ %1:gpr32 = MOVZWi 9, 0
+ %0:gpr64 = MOVKXi %0, 2, 0
+...
+
+---
+name: movzx0_movkx16
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzx0_movkx16
+ ; CHECK: SU(0): %0:gpr64 = MOVZXi 1, 0
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): dead %0:gpr64 = MOVKXi %0:gpr64(tied-def 0), 2, 16
+ %0:gpr64 = MOVZXi 1, 0
+ %1:gpr32 = MOVZWi 9, 0
+ %0:gpr64 = MOVKXi %0, 2, 16
+...
+
+---
+name: movzx0_movkx32
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzx0_movkx32
+ ; CHECK: SU(0): %0:gpr64 = MOVZXi 1, 0
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): dead %0:gpr64 = MOVKXi %0:gpr64(tied-def 0), 2, 32
+ %0:gpr64 = MOVZXi 1, 0
+ %1:gpr32 = MOVZWi 9, 0
+ %0:gpr64 = MOVKXi %0, 2, 32
+...
+
+---
+name: movzx0_movkx48
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzx0_movkx48
+ ; CHECK: SU(0): %0:gpr64 = MOVZXi 1, 0
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): dead %0:gpr64 = MOVKXi %0:gpr64(tied-def 0), 2, 48
+ %0:gpr64 = MOVZXi 1, 0
+ %1:gpr32 = MOVZWi 9, 0
+ %0:gpr64 = MOVKXi %0, 2, 48
+...
+
+---
+name: movzx16_movkw0
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzx16_movkw0
+ ; CHECK: SU(0): %0:gpr64 = MOVZXi 1, 16
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): dead %0.sub_32:gpr64 = MOVKWi %0.sub_32:gpr64(tied-def 0), 2, 0
+ %0:gpr64 = MOVZXi 1, 16
+ %1:gpr32 = MOVZWi 9, 0
+ %0.sub_32:gpr64 = MOVKWi %0.sub_32, 2, 0
+...
+
+---
+name: movzx16_movkw16
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzx16_movkw16
+ ; CHECK: SU(0): %0:gpr64 = MOVZXi 1, 16
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): dead %0.sub_32:gpr64 = MOVKWi %0.sub_32:gpr64(tied-def 0), 2, 16
+ %0:gpr64 = MOVZXi 1, 16
+ %1:gpr32 = MOVZWi 9, 0
+ %0.sub_32:gpr64 = MOVKWi %0.sub_32, 2, 16
+...
+
+---
+name: movzx16_movkx0
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzx16_movkx0
+ ; CHECK: SU(0): %0:gpr64 = MOVZXi 1, 16
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): dead %0:gpr64 = MOVKXi %0:gpr64(tied-def 0), 2, 0
+ %0:gpr64 = MOVZXi 1, 16
+ %1:gpr32 = MOVZWi 9, 0
+ %0:gpr64 = MOVKXi %0, 2, 0
+...
+
+---
+name: movzx16_movkx16
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzx16_movkx16
+ ; CHECK: SU(0): %0:gpr64 = MOVZXi 1, 16
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): dead %0:gpr64 = MOVKXi %0:gpr64(tied-def 0), 2, 16
+ %0:gpr64 = MOVZXi 1, 16
+ %1:gpr32 = MOVZWi 9, 0
+ %0:gpr64 = MOVKXi %0, 2, 16
+...
+
+---
+name: movzx16_movkx32
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzx16_movkx32
+ ; CHECK: SU(0): %0:gpr64 = MOVZXi 1, 16
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): dead %0:gpr64 = MOVKXi %0:gpr64(tied-def 0), 2, 32
+ %0:gpr64 = MOVZXi 1, 16
+ %1:gpr32 = MOVZWi 9, 0
+ %0:gpr64 = MOVKXi %0, 2, 32
+...
+
+---
+name: movzx16_movkx48
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzx16_movkx48
+ ; CHECK: SU(0): %0:gpr64 = MOVZXi 1, 16
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): dead %0:gpr64 = MOVKXi %0:gpr64(tied-def 0), 2, 48
+ %0:gpr64 = MOVZXi 1, 16
+ %1:gpr32 = MOVZWi 9, 0
+ %0:gpr64 = MOVKXi %0, 2, 48
+...
+
+---
+name: movzx32_movkw0
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzx32_movkw0
+ ; CHECK: SU(0): %0:gpr64 = MOVZXi 1, 32
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): dead %0.sub_32:gpr64 = MOVKWi %0.sub_32:gpr64(tied-def 0), 2, 0
+ %0:gpr64 = MOVZXi 1, 32
+ %1:gpr32 = MOVZWi 9, 0
+ %0.sub_32:gpr64 = MOVKWi %0.sub_32, 2, 0
+...
+
+---
+name: movzx32_movkw16
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzx32_movkw16
+ ; CHECK: SU(0): %0:gpr64 = MOVZXi 1, 32
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): dead %0.sub_32:gpr64 = MOVKWi %0.sub_32:gpr64(tied-def 0), 2, 16
+ %0:gpr64 = MOVZXi 1, 32
+ %1:gpr32 = MOVZWi 9, 0
+ %0.sub_32:gpr64 = MOVKWi %0.sub_32, 2, 16
+...
+
+---
+name: movzx32_movkx0
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzx32_movkx0
+ ; CHECK: SU(0): %0:gpr64 = MOVZXi 1, 32
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): dead %0:gpr64 = MOVKXi %0:gpr64(tied-def 0), 2, 0
+ %0:gpr64 = MOVZXi 1, 32
+ %1:gpr32 = MOVZWi 9, 0
+ %0:gpr64 = MOVKXi %0, 2, 0
+...
+
+---
+name: movzx32_movkx16
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzx32_movkx16
+ ; CHECK: SU(0): %0:gpr64 = MOVZXi 1, 32
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): dead %0:gpr64 = MOVKXi %0:gpr64(tied-def 0), 2, 16
+ %0:gpr64 = MOVZXi 1, 32
+ %1:gpr32 = MOVZWi 9, 0
+ %0:gpr64 = MOVKXi %0, 2, 16
+...
+
+---
+name: movzx32_movkx32
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzx32_movkx32
+ ; CHECK: SU(0): %0:gpr64 = MOVZXi 1, 32
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): dead %0:gpr64 = MOVKXi %0:gpr64(tied-def 0), 2, 32
+ %0:gpr64 = MOVZXi 1, 32
+ %1:gpr32 = MOVZWi 9, 0
+ %0:gpr64 = MOVKXi %0, 2, 32
+...
+
+---
+name: movzx32_movkx48
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzx32_movkx48
+ ; CHECK: SU(0): %0:gpr64 = MOVZXi 1, 32
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): dead %0:gpr64 = MOVKXi %0:gpr64(tied-def 0), 2, 48
+ %0:gpr64 = MOVZXi 1, 32
+ %1:gpr32 = MOVZWi 9, 0
+ %0:gpr64 = MOVKXi %0, 2, 48
+...
+
+---
+name: movzx48_movkw0
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzx48_movkw0
+ ; CHECK: SU(0): %0:gpr64 = MOVZXi 1, 48
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): dead %0.sub_32:gpr64 = MOVKWi %0.sub_32:gpr64(tied-def 0), 2, 0
+ %0:gpr64 = MOVZXi 1, 48
+ %1:gpr32 = MOVZWi 9, 0
+ %0.sub_32:gpr64 = MOVKWi %0.sub_32, 2, 0
+...
+
+---
+name: movzx48_movkw16
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzx48_movkw16
+ ; CHECK: SU(0): %0:gpr64 = MOVZXi 1, 48
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): dead %0.sub_32:gpr64 = MOVKWi %0.sub_32:gpr64(tied-def 0), 2, 16
+ %0:gpr64 = MOVZXi 1, 48
+ %1:gpr32 = MOVZWi 9, 0
+ %0.sub_32:gpr64 = MOVKWi %0.sub_32, 2, 16
+...
+
+---
+name: movzx48_movkx0
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzx48_movkx0
+ ; CHECK: SU(0): %0:gpr64 = MOVZXi 1, 48
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): dead %0:gpr64 = MOVKXi %0:gpr64(tied-def 0), 2, 0
+ %0:gpr64 = MOVZXi 1, 48
+ %1:gpr32 = MOVZWi 9, 0
+ %0:gpr64 = MOVKXi %0, 2, 0
+...
+
+---
+name: movzx48_movkx16
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzx48_movkx16
+ ; CHECK: SU(0): %0:gpr64 = MOVZXi 1, 48
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): dead %0:gpr64 = MOVKXi %0:gpr64(tied-def 0), 2, 16
+ %0:gpr64 = MOVZXi 1, 48
+ %1:gpr32 = MOVZWi 9, 0
+ %0:gpr64 = MOVKXi %0, 2, 16
+...
+
+---
+name: movzx48_movkx32
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzx48_movkx32
+ ; CHECK: SU(0): %0:gpr64 = MOVZXi 1, 48
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): dead %0:gpr64 = MOVKXi %0:gpr64(tied-def 0), 2, 32
+ %0:gpr64 = MOVZXi 1, 48
+ %1:gpr32 = MOVZWi 9, 0
+ %0:gpr64 = MOVKXi %0, 2, 32
+...
+
+---
+name: movzx48_movkx48
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: movzx48_movkx48
+ ; CHECK: SU(0): %0:gpr64 = MOVZXi 1, 48
+ ; CHECK: Successors:
+ ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster
+ ; CHECK: SU(2): dead %0:gpr64 = MOVKXi %0:gpr64(tied-def 0), 2, 48
+ %0:gpr64 = MOVZXi 1, 48
+ %1:gpr32 = MOVZWi 9, 0
+ %0:gpr64 = MOVKXi %0, 2, 48
+...
diff --git a/llvm/test/CodeGen/AArch64/misched-fusion-movz-movk.ll b/llvm/test/CodeGen/AArch64/misched-fusion-movz-movk.ll
new file mode 100644
index 0000000000000..3428faa13db9d
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/misched-fusion-movz-movk.ll
@@ -0,0 +1,60 @@
+; RUN: llc %s -o - -mtriple=aarch64-unknown -mattr=+fuse-movz-movk,+use-postra-scheduler | FileCheck %s --check-prefixes=CHECK
+
+;; Lack post-RA scheduling, but should behave the same by plain pseudo-expansion
+; RUN: llc %s -o - -mtriple=arm64-apple-macosx -mcpu=apple-a13 -mattr=+fuse-movz-movk | FileCheck %s --check-prefixes=CHECK
+; RUN: llc %s -o - -mtriple=arm64-apple-macosx -mcpu=apple-a14 | FileCheck %s --check-prefixes=CHECK
+; RUN: llc %s -o - -mtriple=arm64-apple-macosx -mcpu=apple-m5 | FileCheck %s --check-prefixes=CHECK
+
+; CHECK-LABEL: movz_movk16_w:
+; CHECK: mov [[R:w[0-9]+]], #48879
+; CHECK-NEXT: movk [[R]], #61536, lsl #16
+define i32 @movz_movk16_w(i32 %a, i32 %b) {
+ %c = add i32 %a, -262095121
+ %r = add i32 %c, %b
+ ret i32 %r
+}
+
+; CHECK-LABEL: movz_movk32_x:
+; CHECK: mov [[R:x[0-9]+]], #4660
+; CHECK-NEXT: movk [[R]], #22136, lsl #32
+define i64 @movz_movk32_x(i64 %a, i64 %b) {
+ %c = add i64 %a, 95073396068916
+ %r = add i64 %c, %b
+ ret i64 %r
+}
+
+; CHECK-LABEL: movz_movk48_x:
+; CHECK: mov [[R:x[0-9]+]], #4660
+; CHECK-NEXT: movk [[R]], #22136, lsl #48
+define i64 @movz_movk48_x(i64 %a, i64 %b) {
+ %c = add i64 %a, 6230730084467085876
+ %r = add i64 %c, %b
+ ret i64 %r
+}
+
+; CHECK-LABEL: movz16_movk32_x:
+; CHECK: mov [[R:x[0-9]+]], #305397760
+; CHECK-NEXT: movk [[R]], #22136, lsl #32
+define i64 @movz16_movk32_x(i64 %a, i64 %b) {
+ %c = add i64 %a, 95073701462016
+ %r = add i64 %c, %b
+ ret i64 %r
+}
+
+; CHECK-LABEL: movz16_movk48_x:
+; CHECK: mov [[R:x[0-9]+]], #305397760
+; CHECK-NEXT: movk [[R]], #22136, lsl #48
+define i64 @movz16_movk48_x(i64 %a, i64 %b) {
+ %c = add i64 %a, 6230730084772478976
+ %r = add i64 %c, %b
+ ret i64 %r
+}
+
+; CHECK-LABEL: movz32_movk48_x:
+; CHECK: mov [[R:x[0-9]+]], #20014547599360
+; CHECK-NEXT: movk [[R]], #22136, lsl #48
+define i64 @movz32_movk48_x(i64 %a, i64 %b) {
+ %c = add i64 %a, 6230750099014680576
+ %r = add i64 %c, %b
+ ret i64 %r
+}
diff --git a/llvm/test/TableGen/aarch64-apple-tuning-features.td b/llvm/test/TableGen/aarch64-apple-tuning-features.td
index 43ef5df90af39..dbea30e3cb4e3 100644
--- a/llvm/test/TableGen/aarch64-apple-tuning-features.td
+++ b/llvm/test/TableGen/aarch64-apple-tuning-features.td
@@ -108,7 +108,7 @@
// CHECK-NEXT: FeatureFuseArithmeticLogic,
// CHECK-NEXT: FeatureFuseCryptoEOR,
// CHECK-NEXT: FeatureFuseCmpCSel,
-// CHECK-NEXT: FeatureFuseLiterals,
+// CHECK-NEXT: FeatureFuseMovzMovk,
// CHECK-NEXT: FeatureMaxInterleaveFactor4,
// CHECK-NEXT: FeatureNoZCZeroingFPR64,
// CHECK-NEXT: FeatureStorePairSuppress,
@@ -137,7 +137,7 @@
// CHECK-NEXT: FeatureFuseArithmeticLogic,
// CHECK-NEXT: FeatureFuseCryptoEOR,
// CHECK-NEXT: FeatureFuseCmpCSel,
-// CHECK-NEXT: FeatureFuseLiterals,
+// CHECK-NEXT: FeatureFuseMovzMovk,
// CHECK-NEXT: FeatureMaxInterleaveFactor4,
// CHECK-NEXT: FeatureNoZCZeroingFPR64,
// CHECK-NEXT: FeatureStorePairSuppress,
@@ -167,7 +167,7 @@
// CHECK-NEXT: FeatureFuseCryptoEOR,
// CHECK-NEXT: FeatureFuseCmpCSel,
// CHECK-NEXT: FeatureFuseFCmpFCSel,
-// CHECK-NEXT: FeatureFuseLiterals,
+// CHECK-NEXT: FeatureFuseMovzMovk,
// CHECK-NEXT: FeatureMaxInterleaveFactor4,
// CHECK-NEXT: FeatureNoZCZeroingFPR64,
// CHECK-NEXT: FeatureStorePairSuppress,
@@ -197,7 +197,7 @@
// CHECK-NEXT: FeatureFuseCryptoEOR,
// CHECK-NEXT: FeatureFuseCmpCSel,
// CHECK-NEXT: FeatureFuseFCmpFCSel,
-// CHECK-NEXT: FeatureFuseLiterals,
+// CHECK-NEXT: FeatureFuseMovzMovk,
// CHECK-NEXT: FeatureMaxInterleaveFactor4,
// CHECK-NEXT: FeatureNoZCZeroingFPR64,
// CHECK-NEXT: FeatureStorePairSuppress,
@@ -250,7 +250,7 @@
// CHECK-NEXT: FeatureFuseCryptoEOR,
// CHECK-NEXT: FeatureFuseCmpCSel,
// CHECK-NEXT: FeatureFuseFCmpFCSel,
-// CHECK-NEXT: FeatureFuseLiterals,
+// CHECK-NEXT: FeatureFuseMovzMovk,
// CHECK-NEXT: FeatureMaxInterleaveFactor4,
// CHECK-NEXT: FeatureNoZCZeroingFPR64,
// CHECK-NEXT: FeatureZCRegMoveFPR128,
@@ -281,7 +281,7 @@
// CHECK-NEXT: FeatureFuseCmpCSel,
// CHECK-NEXT: FeatureFuseFCmpFCSel,
// CHECK-NEXT: FeatureFuseFMinFMax,
-// CHECK-NEXT: FeatureFuseLiterals,
+// CHECK-NEXT: FeatureFuseMovzMovk,
// CHECK-NEXT: FeatureMaxInterleaveFactor4,
// CHECK-NEXT: FeatureNoZCZeroingFPR64,
// CHECK-NEXT: FeatureZCRegMoveFPR128,
More information about the llvm-commits
mailing list