[llvm] 38104cf - [LLVM][SVE] Add MachineInst pass to coalesce PTRUE instructions. (#204820)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Jul 17 06:17:16 PDT 2026
Author: Paul Walker
Date: 2026-07-17T14:17:10+01:00
New Revision: 38104cf836c3903647c917a5b251e938f4eadbb9
URL: https://github.com/llvm/llvm-project/commit/38104cf836c3903647c917a5b251e938f4eadbb9
DIFF: https://github.com/llvm/llvm-project/commit/38104cf836c3903647c917a5b251e938f4eadbb9.diff
LOG: [LLVM][SVE] Add MachineInst pass to coalesce PTRUE instructions. (#204820)
SVE predicate registers contain a bit for each byte of a data register.
When operating on bigger element types the overlaping predicate bits are
grouped together but typically only the least-significant-bit is read as
part of the operation. This means the value of the other bits does not
affect the operation, making it possible to use the result of PTRUE for
a larger element typed operation, assuming the predicate patterns are
equivalent. For example:
ADD_S (PTRUE_H 31), Z0, Z1 == ADD_S (PTRUE_S 31), Z0, Z1
AArch64PTrueCoalescingPass uses this fact to reduce the number of PTRUE
instructions in a function, with the general trend towards needing a
single PTRUE based on the smallest element type in use.
NOTE: The pass will be enabled by default using a dedicated PR to make
it easier to revert if something goes wrong.
Added:
llvm/lib/Target/AArch64/AArch64PTrueCoalescing.cpp
llvm/test/CodeGen/AArch64/sve-ptrue-coalesce.mir
Modified:
llvm/lib/Target/AArch64/AArch64.h
llvm/lib/Target/AArch64/AArch64PassRegistry.def
llvm/lib/Target/AArch64/AArch64TargetMachine.cpp
llvm/lib/Target/AArch64/CMakeLists.txt
llvm/test/CodeGen/AArch64/O3-pipeline.ll
Removed:
################################################################################
diff --git a/llvm/lib/Target/AArch64/AArch64.h b/llvm/lib/Target/AArch64/AArch64.h
index 55cfdc1bceb72..86a6635a37497 100644
--- a/llvm/lib/Target/AArch64/AArch64.h
+++ b/llvm/lib/Target/AArch64/AArch64.h
@@ -71,7 +71,7 @@ FunctionPass *createAArch64BranchTargetsPass();
FunctionPass *createAArch64CodeLayoutOptPass();
FunctionPass *createAArch64MIPeepholeOptLegacyPass();
FunctionPass *createAArch64PostCoalescerPass();
-
+FunctionPass *createAArch64PTrueCoalescingLegacyPass();
FunctionPass *createAArch64CleanupLocalDynamicTLSPass();
FunctionPass *createAArch64CollectLOHPass();
@@ -181,6 +181,7 @@ void initializeAArch64LoadStoreOptLegacyPass(PassRegistry &);
void initializeAArch64LowerHomogeneousPrologEpilogLegacyPass(PassRegistry &);
void initializeAArch64CodeLayoutOptPass(PassRegistry &);
void initializeAArch64MIPeepholeOptLegacyPass(PassRegistry &);
+void initializeAArch64PTrueCoalescingLegacyPass(PassRegistry &);
void initializeAArch64O0PreLegalizerCombinerLegacyPass(PassRegistry &);
void initializeAArch64PostCoalescerLegacyPass(PassRegistry &);
void initializeAArch64PostLegalizerCombinerLegacyPass(PassRegistry &);
@@ -306,6 +307,13 @@ class AArch64MIPeepholeOptPass
MachineFunctionAnalysisManager &MFAM);
};
+class AArch64PTrueCoalescingPass
+ : public OptionalPassInfoMixin<AArch64PTrueCoalescingPass> {
+public:
+ PreservedAnalyses run(MachineFunction &MF,
+ MachineFunctionAnalysisManager &MFAM);
+};
+
class AArch64ConditionOptimizerPass
: public OptionalPassInfoMixin<AArch64ConditionOptimizerPass> {
public:
diff --git a/llvm/lib/Target/AArch64/AArch64PTrueCoalescing.cpp b/llvm/lib/Target/AArch64/AArch64PTrueCoalescing.cpp
new file mode 100644
index 0000000000000..825b8821141ff
--- /dev/null
+++ b/llvm/lib/Target/AArch64/AArch64PTrueCoalescing.cpp
@@ -0,0 +1,270 @@
+//===- AArch64PTrueCoalescing.cpp - Coalesce SVE PTRUEs ---------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This pass coalesces compatible all-active SVE PTRUE instructions.
+//
+// Consider two all-active PTRUE instructions X and Y with element sizes XSize
+// and YSize. If X dominates Y and XSize <= YSize, then every predicate bit that
+// Y sets is also set by X. In that case, uses of Y can be redirected to X as
+// long as each user of Y only reads predicate bits at YSize granularity or
+// larger.
+//
+// If the dominating PTRUE has a larger element size, we can coalesce the pair
+// by changing the dominating PTRUE to the smaller element size, provided that
+// all of its existing users are also safe with that granularity.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AArch64.h"
+#include "AArch64InstrInfo.h"
+#include "AArch64Subtarget.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/CodeGen/MachineDominators.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineInstr.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/InitializePasses.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "aarch64-ptrue-coalesce"
+
+static cl::opt<bool> EnablePTrueCoalescing(
+ "aarch64-enable-ptrue-coalescing", cl::init(false), cl::Hidden,
+ cl::desc("Enable coalescing of compatible AArch64 SVE PTRUE instructions"));
+
+namespace {
+
+class AArch64PTrueCoalescingImpl {
+ const AArch64InstrInfo *TII = nullptr;
+ MachineRegisterInfo *MRI = nullptr;
+ MachineDominatorTree *MDT = nullptr;
+
+public:
+ explicit AArch64PTrueCoalescingImpl(MachineDominatorTree &MDT) : MDT(&MDT) {}
+
+ bool run(MachineFunction &MF);
+
+private:
+ struct PredicateInfo {
+ // Instruction that created the predicate.
+ MachineInstr *MI = nullptr;
+ // Element size of the MI.
+ unsigned ElementSize = AArch64::ElementSizeNone;
+ // Smallest element size of all instructions that use the predicate.
+ unsigned SmallestUsedElementSize = AArch64::ElementSizeNone;
+
+ bool isValid() const {
+ assert(ElementSize != AArch64::ElementSizeNone &&
+ "PTRUE missing element size!");
+ return MI && SmallestUsedElementSize != AArch64::ElementSizeNone;
+ }
+
+ void invalidate() {
+ assert(isValid());
+ MI = nullptr;
+ }
+ };
+
+ std::optional<PredicateInfo> createPredicateInfo(MachineInstr &MI) const {
+ // TODO: Extend support beyond "PTRUE all"?
+ if (!isPTrueOpcode(MI.getOpcode()) || MI.getOperand(1).getImm() != 31)
+ return std::nullopt;
+
+ Register Pred = MI.getOperand(0).getReg();
+ unsigned SmallestUsedElementSize = getSmallestElementSizeInUse(Pred);
+ unsigned ElementSize = TII->getElementSizeForOpcode(MI.getOpcode());
+ assert(ElementSize != AArch64::ElementSizeNone &&
+ "PTRUE missing element size!");
+
+ if (SmallestUsedElementSize == AArch64::ElementSizeNone)
+ return std::nullopt;
+
+ return PredicateInfo{&MI, ElementSize, SmallestUsedElementSize};
+ }
+
+ // Return the smallest element size of all instructions that use Reg, or
+ // AArch64::ElementSizeNone when unknown.
+ unsigned getSmallestElementSizeInUse(Register Reg) const;
+
+ // Try to replace uses of CanPred with DomPred. In some cases that means
+ // modifying DomPred to support smaller element types.
+ bool tryCoalesce(PredicateInfo &DomPred, PredicateInfo &CanPred) const;
+};
+
+class AArch64PTrueCoalescingLegacy : public MachineFunctionPass {
+public:
+ static char ID;
+
+ AArch64PTrueCoalescingLegacy() : MachineFunctionPass(ID) {}
+
+ bool runOnMachineFunction(MachineFunction &MF) override;
+
+ StringRef getPassName() const override { return "AArch64 PTRUE Coalescing"; }
+
+ void getAnalysisUsage(AnalysisUsage &AU) const override {
+ AU.setPreservesCFG();
+ AU.addRequired<MachineDominatorTreeWrapperPass>();
+ AU.addPreserved<MachineDominatorTreeWrapperPass>();
+ MachineFunctionPass::getAnalysisUsage(AU);
+ }
+};
+
+char AArch64PTrueCoalescingLegacy::ID = 0;
+
+} // end anonymous namespace
+
+INITIALIZE_PASS_BEGIN(AArch64PTrueCoalescingLegacy, DEBUG_TYPE,
+ "AArch64 PTRUE Coalescing", false, false)
+INITIALIZE_PASS_DEPENDENCY(MachineDominatorTreeWrapperPass)
+INITIALIZE_PASS_END(AArch64PTrueCoalescingLegacy, DEBUG_TYPE,
+ "AArch64 PTRUE Coalescing", false, false)
+
+unsigned
+AArch64PTrueCoalescingImpl::getSmallestElementSizeInUse(Register Reg) const {
+ // SSA form only applies to virtual registers.
+ if (!Reg.isVirtual())
+ return AArch64::ElementSizeNone;
+
+ unsigned SmallestElementSize = AArch64::ElementSizeNone;
+
+ for (MachineOperand &UseMO : MRI->use_nodbg_operands(Reg)) {
+ assert(UseMO.getSubReg() == 0 && "Unexpected SubReg!");
+ MachineInstr *UseMI = UseMO.getParent();
+
+ unsigned ElementSize = TII->getElementSizeForOpcode(UseMI->getOpcode());
+ if (ElementSize == AArch64::ElementSizeNone)
+ return AArch64::ElementSizeNone;
+
+ if (SmallestElementSize == AArch64::ElementSizeNone ||
+ SmallestElementSize > ElementSize)
+ SmallestElementSize = ElementSize;
+ }
+
+ return SmallestElementSize;
+}
+
+bool AArch64PTrueCoalescingImpl::tryCoalesce(PredicateInfo &DomPI,
+ PredicateInfo &CanPI) const {
+ assert(DomPI.isValid() && CanPI.isValid());
+ MachineInstr *DomMI = DomPI.MI;
+ MachineInstr *CanMI = CanPI.MI;
+
+ if (DomMI == CanMI || !MDT->dominates(DomMI, CanMI))
+ return false;
+
+ // A predicate's observable shape is the larger of the element size of the
+ // instruction writing the predicate and the one reading it. First check if
+ // DomPI can replace CanPI as-is for CanPI's users. If not, try changing DomPI
+ // to CanPI's element size, but only if DomPI's existing users would observe
+ // the same shape after that change.
+
+ bool MutateDomPTrue = false;
+ if (std::max(CanPI.ElementSize, CanPI.SmallestUsedElementSize) !=
+ std::max(DomPI.ElementSize, CanPI.SmallestUsedElementSize)) {
+ if (std::max(CanPI.ElementSize, DomPI.SmallestUsedElementSize) !=
+ std::max(DomPI.ElementSize, DomPI.SmallestUsedElementSize))
+ return false;
+
+ MutateDomPTrue = true;
+ }
+
+ Register DomReg = DomMI->getOperand(0).getReg();
+ Register CanReg = CanMI->getOperand(0).getReg();
+ if (!MRI->constrainRegClass(DomReg, MRI->getRegClass(CanReg)))
+ return false;
+
+ LLVM_DEBUG(dbgs() << "Coalescing PTRUE: " << CanMI);
+ LLVM_DEBUG(dbgs() << " with: " << DomMI);
+
+ if (MutateDomPTrue) {
+ LLVM_DEBUG(dbgs() << " updated: " << DomMI);
+ DomMI->setDesc(TII->get(CanMI->getOpcode()));
+ DomPI.ElementSize = CanPI.ElementSize;
+ LLVM_DEBUG(dbgs() << " to: " << DomMI);
+ }
+
+ MRI->replaceRegWith(CanReg, DomReg);
+ MRI->clearKillFlags(DomReg);
+ CanMI->eraseFromParent();
+
+ // Update DomPI based on uses inherited from CanPI.
+ if (CanPI.SmallestUsedElementSize < DomPI.SmallestUsedElementSize)
+ DomPI.SmallestUsedElementSize = CanPI.SmallestUsedElementSize;
+ CanPI.invalidate();
+ return true;
+}
+
+bool AArch64PTrueCoalescingImpl::run(MachineFunction &MF) {
+ if (!EnablePTrueCoalescing ||
+ !MF.getSubtarget<AArch64Subtarget>().isSVEorStreamingSVEAvailable())
+ return false;
+
+ TII = static_cast<const AArch64InstrInfo *>(MF.getSubtarget().getInstrInfo());
+ MRI = &MF.getRegInfo();
+
+ assert(MRI->isSSA() && "Expected to be run on SSA form!");
+
+ // TODO: Until we prove candidates share the same VG definition, do not
+ // coalesce in functions that define VG.
+ if (!MRI->def_empty(AArch64::VG))
+ return false;
+
+ // A list of predicate setting instructions with some usage information.
+ SmallVector<PredicateInfo, 8> PIs;
+
+ // Build a list of predicates whose uses all have a known size.
+ for (MachineBasicBlock &MBB : MF)
+ for (MachineInstr &MI : MBB)
+ if (auto PI = createPredicateInfo(MI))
+ PIs.push_back(*PI);
+
+ LLVM_DEBUG(dbgs() << "Coalescable PTRUE candidates: " << PIs.size() << "\n");
+ bool Changed = false;
+
+ for (PredicateInfo &DominantPI : PIs) {
+ if (!DominantPI.isValid())
+ continue;
+
+ for (PredicateInfo &CandidatePI : PIs) {
+ if (!CandidatePI.isValid())
+ continue;
+
+ Changed |= tryCoalesce(DominantPI, CandidatePI);
+ }
+ }
+
+ return Changed;
+}
+
+bool AArch64PTrueCoalescingLegacy::runOnMachineFunction(MachineFunction &MF) {
+ MachineDominatorTree &MDT =
+ getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();
+ return AArch64PTrueCoalescingImpl(MDT).run(MF);
+}
+
+FunctionPass *llvm::createAArch64PTrueCoalescingLegacyPass() {
+ return new AArch64PTrueCoalescingLegacy();
+}
+
+PreservedAnalyses
+AArch64PTrueCoalescingPass::run(MachineFunction &MF,
+ MachineFunctionAnalysisManager &MFAM) {
+ MachineDominatorTree &MDT = MFAM.getResult<MachineDominatorTreeAnalysis>(MF);
+ const bool Changed = AArch64PTrueCoalescingImpl(MDT).run(MF);
+ if (!Changed)
+ return PreservedAnalyses::all();
+
+ auto PA = getMachineFunctionPassPreservedAnalyses();
+ PA.preserve<MachineDominatorTreeAnalysis>();
+ PA.preserveSet<CFGAnalyses>();
+ return PA;
+}
diff --git a/llvm/lib/Target/AArch64/AArch64PassRegistry.def b/llvm/lib/Target/AArch64/AArch64PassRegistry.def
index bdfa9bca299b1..1a44a6289efbf 100644
--- a/llvm/lib/Target/AArch64/AArch64PassRegistry.def
+++ b/llvm/lib/Target/AArch64/AArch64PassRegistry.def
@@ -46,6 +46,7 @@ MACHINE_FUNCTION_PASS("aarch64-isel", AArch64DAGToDAGISelPass(*this))
MACHINE_FUNCTION_PASS("aarch64-jump-tables", AArch64CompressJumpTablesPass())
MACHINE_FUNCTION_PASS("aarch64-ldst-opt", AArch64LoadStoreOptPass())
MACHINE_FUNCTION_PASS("aarch64-mi-peephole-opt", AArch64MIPeepholeOptPass())
+MACHINE_FUNCTION_PASS("aarch64-ptrue-coalesce", AArch64PTrueCoalescingPass())
MACHINE_FUNCTION_PASS("aarch64-post-coalescer", AArch64PostCoalescerPass())
MACHINE_FUNCTION_PASS("aarch64-post-select-optimize",
AArch64PostSelectOptimizePass())
diff --git a/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp b/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp
index 0841f50c2a424..d4801e68b9812 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp
+++ b/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp
@@ -259,6 +259,7 @@ LLVMInitializeAArch64Target() {
initializeAArch64ExpandPseudoLegacyPass(PR);
initializeAArch64LoadStoreOptLegacyPass(PR);
initializeAArch64MIPeepholeOptLegacyPass(PR);
+ initializeAArch64PTrueCoalescingLegacyPass(PR);
initializeAArch64SIMDInstrOptLegacyPass(PR);
initializeAArch64O0PreLegalizerCombinerLegacyPass(PR);
initializeAArch64PreLegalizerCombinerLegacyPass(PR);
@@ -830,8 +831,10 @@ void AArch64PassConfig::addMachineSSAOptimization() {
// Run default MachineSSAOptimization first.
TargetPassConfig::addMachineSSAOptimization();
- if (TM->getOptLevel() != CodeGenOptLevel::None)
+ if (TM->getOptLevel() != CodeGenOptLevel::None) {
addPass(createAArch64MIPeepholeOptLegacyPass());
+ addPass(createAArch64PTrueCoalescingLegacyPass());
+ }
}
bool AArch64PassConfig::addILPOpts() {
diff --git a/llvm/lib/Target/AArch64/CMakeLists.txt b/llvm/lib/Target/AArch64/CMakeLists.txt
index e3f7f697b69d5..fadf5ce60907c 100644
--- a/llvm/lib/Target/AArch64/CMakeLists.txt
+++ b/llvm/lib/Target/AArch64/CMakeLists.txt
@@ -77,6 +77,7 @@ add_llvm_target(AArch64CodeGen
AArch64PointerAuth.cpp
AArch64PostCoalescerPass.cpp
AArch64PromoteConstant.cpp
+ AArch64PTrueCoalescing.cpp
AArch64PBQPRegAlloc.cpp
AArch64RegisterInfo.cpp
AArch64SMEAttributes.cpp
diff --git a/llvm/test/CodeGen/AArch64/O3-pipeline.ll b/llvm/test/CodeGen/AArch64/O3-pipeline.ll
index 08d3b94530d14..213559d8e24e8 100644
--- a/llvm/test/CodeGen/AArch64/O3-pipeline.ll
+++ b/llvm/test/CodeGen/AArch64/O3-pipeline.ll
@@ -172,6 +172,8 @@
; CHECK-NEXT: Peephole Optimizations
; CHECK-NEXT: Remove dead machine instructions
; CHECK-NEXT: AArch64 MI Peephole Optimization pass
+; CHECK-NEXT: MachineDominator Tree Construction
+; CHECK-NEXT: AArch64 PTRUE Coalescing
; CHECK-NEXT: AArch64 Dead register definitions
; CHECK-NEXT: Detect Dead Lanes
; CHECK-NEXT: Init Undef Pass
@@ -180,7 +182,6 @@
; CHECK-NEXT: Live Variable Analysis
; CHECK-NEXT: Eliminate PHI nodes for register allocation
; CHECK-NEXT: Two-Address instruction pass
-; CHECK-NEXT: MachineDominator Tree Construction
; CHECK-NEXT: Slot index numbering
; CHECK-NEXT: Live Interval Analysis
; CHECK-NEXT: Register Coalescer
diff --git a/llvm/test/CodeGen/AArch64/sve-ptrue-coalesce.mir b/llvm/test/CodeGen/AArch64/sve-ptrue-coalesce.mir
new file mode 100644
index 0000000000000..bd24623900ff6
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/sve-ptrue-coalesce.mir
@@ -0,0 +1,593 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
+# RUN: llc -mtriple=aarch64 -mattr=+sve,+sme -run-pass=aarch64-ptrue-coalesce -aarch64-enable-ptrue-coalescing -verify-machineinstrs -o - %s | FileCheck %s --check-prefixes=CHECK,ENABLED
+# RUN: llc -mtriple=aarch64 -mattr=+sve,+sme -passes=aarch64-ptrue-coalesce -aarch64-enable-ptrue-coalescing -o - %s | FileCheck %s --check-prefixes=CHECK,ENABLED
+# RUN: llc -mtriple=aarch64 -mattr=+sve,+sme -passes=aarch64-ptrue-coalesce -aarch64-enable-ptrue-coalescing=false -verify-machineinstrs -o - %s | FileCheck %s --check-prefixes=CHECK,DISABLED
+
+---
+name: ptrue_b_replaces_ptrue_h_for_h_user
+alignment: 2
+tracksRegLiveness: true
+registers:
+ - { id: 0, class: ppr_3b }
+ - { id: 1, class: ppr_3b }
+ - { id: 2, class: zpr }
+ - { id: 3, class: zpr }
+ - { id: 4, class: ppr }
+ - { id: 5, class: ppr }
+liveins:
+ - { reg: '$z0', virtual-reg: '%2' }
+ - { reg: '$z1', virtual-reg: '%3' }
+body: |
+ bb.0:
+ liveins: $z0, $z1
+
+ ; ENABLED-LABEL: name: ptrue_b_replaces_ptrue_h_for_h_user
+ ; ENABLED: liveins: $z0, $z1
+ ; ENABLED-NEXT: {{ $}}
+ ; ENABLED-NEXT: [[COPY:%[0-9]+]]:zpr = COPY $z0
+ ; ENABLED-NEXT: [[COPY1:%[0-9]+]]:zpr = COPY $z1
+ ; ENABLED-NEXT: [[PTRUE_B:%[0-9]+]]:ppr_3b = PTRUE_B 31, implicit $vg
+ ; ENABLED-NEXT: [[CMPEQ_PPzZZ_H:%[0-9]+]]:ppr = CMPEQ_PPzZZ_H [[PTRUE_B]], [[COPY]], [[COPY1]], implicit-def dead $nzcv
+ ; ENABLED-NEXT: [[CMPEQ_PPzZZ_B:%[0-9]+]]:ppr = CMPEQ_PPzZZ_B [[PTRUE_B]], [[COPY]], [[COPY1]], implicit-def dead $nzcv
+ ; ENABLED-NEXT: RET_ReallyLR
+ ;
+ ; DISABLED-LABEL: name: ptrue_b_replaces_ptrue_h_for_h_user
+ ; DISABLED: liveins: $z0, $z1
+ ; DISABLED-NEXT: {{ $}}
+ ; DISABLED-NEXT: [[COPY:%[0-9]+]]:zpr = COPY $z0
+ ; DISABLED-NEXT: [[COPY1:%[0-9]+]]:zpr = COPY $z1
+ ; DISABLED-NEXT: [[PTRUE_B:%[0-9]+]]:ppr_3b = PTRUE_B 31, implicit $vg
+ ; DISABLED-NEXT: [[PTRUE_H:%[0-9]+]]:ppr_3b = PTRUE_H 31, implicit $vg
+ ; DISABLED-NEXT: [[CMPEQ_PPzZZ_H:%[0-9]+]]:ppr = CMPEQ_PPzZZ_H [[PTRUE_H]], [[COPY]], [[COPY1]], implicit-def dead $nzcv
+ ; DISABLED-NEXT: [[CMPEQ_PPzZZ_B:%[0-9]+]]:ppr = CMPEQ_PPzZZ_B [[PTRUE_B]], [[COPY]], [[COPY1]], implicit-def dead $nzcv
+ ; DISABLED-NEXT: RET_ReallyLR
+ %2:zpr = COPY $z0
+ %3:zpr = COPY $z1
+ %0:ppr_3b = PTRUE_B 31, implicit $vg
+ %1:ppr_3b = PTRUE_H 31, implicit $vg
+ %4:ppr = CMPEQ_PPzZZ_H %1, %2, %3, implicit-def dead $nzcv
+ %5:ppr = CMPEQ_PPzZZ_B %0, %2, %3, implicit-def dead $nzcv
+ RET_ReallyLR
+
+...
+---
+name: keep_ptrue_h_for_b_user
+alignment: 2
+tracksRegLiveness: true
+registers:
+ - { id: 0, class: ppr_3b }
+ - { id: 1, class: ppr_3b }
+ - { id: 2, class: zpr }
+ - { id: 3, class: zpr }
+ - { id: 4, class: ppr }
+ - { id: 5, class: ppr }
+liveins:
+ - { reg: '$z0', virtual-reg: '%2' }
+ - { reg: '$z1', virtual-reg: '%3' }
+body: |
+ bb.0:
+ liveins: $z0, $z1
+
+ ; ENABLED-LABEL: name: keep_ptrue_h_for_b_user
+ ; ENABLED: liveins: $z0, $z1
+ ; ENABLED-NEXT: {{ $}}
+ ; ENABLED-NEXT: [[COPY:%[0-9]+]]:zpr = COPY $z0
+ ; ENABLED-NEXT: [[COPY1:%[0-9]+]]:zpr = COPY $z1
+ ; ENABLED-NEXT: [[PTRUE_H:%[0-9]+]]:ppr_3b = PTRUE_H 31, implicit $vg
+ ; ENABLED-NEXT: [[CMPEQ_PPzZZ_B:%[0-9]+]]:ppr = CMPEQ_PPzZZ_B [[PTRUE_H]], [[COPY]], [[COPY1]], implicit-def dead $nzcv
+ ; ENABLED-NEXT: [[CMPEQ_PPzZZ_H:%[0-9]+]]:ppr = CMPEQ_PPzZZ_H [[PTRUE_H]], [[COPY]], [[COPY1]], implicit-def dead $nzcv
+ ; ENABLED-NEXT: RET_ReallyLR
+ ;
+ ; DISABLED-LABEL: name: keep_ptrue_h_for_b_user
+ ; DISABLED: liveins: $z0, $z1
+ ; DISABLED-NEXT: {{ $}}
+ ; DISABLED-NEXT: [[COPY:%[0-9]+]]:zpr = COPY $z0
+ ; DISABLED-NEXT: [[COPY1:%[0-9]+]]:zpr = COPY $z1
+ ; DISABLED-NEXT: [[PTRUE_B:%[0-9]+]]:ppr_3b = PTRUE_B 31, implicit $vg
+ ; DISABLED-NEXT: [[PTRUE_H:%[0-9]+]]:ppr_3b = PTRUE_H 31, implicit $vg
+ ; DISABLED-NEXT: [[CMPEQ_PPzZZ_B:%[0-9]+]]:ppr = CMPEQ_PPzZZ_B [[PTRUE_H]], [[COPY]], [[COPY1]], implicit-def dead $nzcv
+ ; DISABLED-NEXT: [[CMPEQ_PPzZZ_H:%[0-9]+]]:ppr = CMPEQ_PPzZZ_H [[PTRUE_B]], [[COPY]], [[COPY1]], implicit-def dead $nzcv
+ ; DISABLED-NEXT: RET_ReallyLR
+ %2:zpr = COPY $z0
+ %3:zpr = COPY $z1
+ %0:ppr_3b = PTRUE_B 31, implicit $vg
+ %1:ppr_3b = PTRUE_H 31, implicit $vg
+ %4:ppr = CMPEQ_PPzZZ_B %1, %2, %3, implicit-def dead $nzcv
+ %5:ppr = CMPEQ_PPzZZ_H %0, %2, %3, implicit-def dead $nzcv
+ RET_ReallyLR
+
+...
+---
+name: ptrue_b_replaces_and_updates_ptrue_h
+alignment: 2
+tracksRegLiveness: true
+registers:
+ - { id: 0, class: ppr_3b }
+ - { id: 1, class: ppr_3b }
+ - { id: 2, class: zpr }
+ - { id: 3, class: zpr }
+ - { id: 4, class: ppr }
+ - { id: 5, class: ppr }
+liveins:
+ - { reg: '$z0', virtual-reg: '%2' }
+ - { reg: '$z1', virtual-reg: '%3' }
+body: |
+ bb.0:
+ liveins: $z0, $z1
+
+ ; ENABLED-LABEL: name: ptrue_b_replaces_and_updates_ptrue_h
+ ; ENABLED: liveins: $z0, $z1
+ ; ENABLED-NEXT: {{ $}}
+ ; ENABLED-NEXT: [[COPY:%[0-9]+]]:zpr = COPY $z0
+ ; ENABLED-NEXT: [[COPY1:%[0-9]+]]:zpr = COPY $z1
+ ; ENABLED-NEXT: [[PTRUE_B:%[0-9]+]]:ppr_3b = PTRUE_B 31, implicit $vg
+ ; ENABLED-NEXT: [[CMPEQ_PPzZZ_H:%[0-9]+]]:ppr = CMPEQ_PPzZZ_H [[PTRUE_B]], [[COPY]], [[COPY1]], implicit-def dead $nzcv
+ ; ENABLED-NEXT: [[CMPEQ_PPzZZ_B:%[0-9]+]]:ppr = CMPEQ_PPzZZ_B [[PTRUE_B]], [[COPY]], [[COPY1]], implicit-def dead $nzcv
+ ; ENABLED-NEXT: RET_ReallyLR
+ ;
+ ; DISABLED-LABEL: name: ptrue_b_replaces_and_updates_ptrue_h
+ ; DISABLED: liveins: $z0, $z1
+ ; DISABLED-NEXT: {{ $}}
+ ; DISABLED-NEXT: [[COPY:%[0-9]+]]:zpr = COPY $z0
+ ; DISABLED-NEXT: [[COPY1:%[0-9]+]]:zpr = COPY $z1
+ ; DISABLED-NEXT: [[PTRUE_H:%[0-9]+]]:ppr_3b = PTRUE_H 31, implicit $vg
+ ; DISABLED-NEXT: [[CMPEQ_PPzZZ_H:%[0-9]+]]:ppr = CMPEQ_PPzZZ_H [[PTRUE_H]], [[COPY]], [[COPY1]], implicit-def dead $nzcv
+ ; DISABLED-NEXT: [[PTRUE_B:%[0-9]+]]:ppr_3b = PTRUE_B 31, implicit $vg
+ ; DISABLED-NEXT: [[CMPEQ_PPzZZ_B:%[0-9]+]]:ppr = CMPEQ_PPzZZ_B [[PTRUE_B]], [[COPY]], [[COPY1]], implicit-def dead $nzcv
+ ; DISABLED-NEXT: RET_ReallyLR
+ %2:zpr = COPY $z0
+ %3:zpr = COPY $z1
+ %0:ppr_3b = PTRUE_H 31, implicit $vg
+ %4:ppr = CMPEQ_PPzZZ_H %0, %2, %3, implicit-def dead $nzcv
+ %1:ppr_3b = PTRUE_B 31, implicit $vg
+ %5:ppr = CMPEQ_PPzZZ_B %1, %2, %3, implicit-def dead $nzcv
+ RET_ReallyLR
+
+...
+---
+name: ptrue_b_replaces_ptrue_h_in_dominated_block
+alignment: 2
+tracksRegLiveness: true
+registers:
+ - { id: 0, class: ppr_3b }
+ - { id: 1, class: ppr_3b }
+ - { id: 2, class: zpr }
+ - { id: 3, class: zpr }
+ - { id: 4, class: ppr }
+ - { id: 5, class: ppr }
+liveins:
+ - { reg: '$z0', virtual-reg: '%2' }
+ - { reg: '$z1', virtual-reg: '%3' }
+body: |
+ ; ENABLED-LABEL: name: ptrue_b_replaces_ptrue_h_in_dominated_block
+ ; ENABLED: bb.0:
+ ; ENABLED-NEXT: successors: %bb.1(0x80000000)
+ ; ENABLED-NEXT: liveins: $z0, $z1
+ ; ENABLED-NEXT: {{ $}}
+ ; ENABLED-NEXT: [[COPY:%[0-9]+]]:zpr = COPY $z0
+ ; ENABLED-NEXT: [[COPY1:%[0-9]+]]:zpr = COPY $z1
+ ; ENABLED-NEXT: [[PTRUE_B:%[0-9]+]]:ppr_3b = PTRUE_B 31, implicit $vg
+ ; ENABLED-NEXT: [[CMPEQ_PPzZZ_B:%[0-9]+]]:ppr = CMPEQ_PPzZZ_B [[PTRUE_B]], [[COPY]], [[COPY1]], implicit-def dead $nzcv
+ ; ENABLED-NEXT: B %bb.1
+ ; ENABLED-NEXT: {{ $}}
+ ; ENABLED-NEXT: bb.1:
+ ; ENABLED-NEXT: [[CMPEQ_PPzZZ_H:%[0-9]+]]:ppr = CMPEQ_PPzZZ_H [[PTRUE_B]], [[COPY]], [[COPY1]], implicit-def dead $nzcv
+ ; ENABLED-NEXT: RET_ReallyLR
+ ;
+ ; DISABLED-LABEL: name: ptrue_b_replaces_ptrue_h_in_dominated_block
+ ; DISABLED: bb.0:
+ ; DISABLED-NEXT: successors: %bb.1(0x80000000)
+ ; DISABLED-NEXT: liveins: $z0, $z1
+ ; DISABLED-NEXT: {{ $}}
+ ; DISABLED-NEXT: [[COPY:%[0-9]+]]:zpr = COPY $z0
+ ; DISABLED-NEXT: [[COPY1:%[0-9]+]]:zpr = COPY $z1
+ ; DISABLED-NEXT: [[PTRUE_B:%[0-9]+]]:ppr_3b = PTRUE_B 31, implicit $vg
+ ; DISABLED-NEXT: [[CMPEQ_PPzZZ_B:%[0-9]+]]:ppr = CMPEQ_PPzZZ_B [[PTRUE_B]], [[COPY]], [[COPY1]], implicit-def dead $nzcv
+ ; DISABLED-NEXT: B %bb.1
+ ; DISABLED-NEXT: {{ $}}
+ ; DISABLED-NEXT: bb.1:
+ ; DISABLED-NEXT: [[PTRUE_H:%[0-9]+]]:ppr_3b = PTRUE_H 31, implicit $vg
+ ; DISABLED-NEXT: [[CMPEQ_PPzZZ_H:%[0-9]+]]:ppr = CMPEQ_PPzZZ_H [[PTRUE_H]], [[COPY]], [[COPY1]], implicit-def dead $nzcv
+ ; DISABLED-NEXT: RET_ReallyLR
+ bb.0:
+ successors: %bb.1
+ liveins: $z0, $z1
+
+ %2:zpr = COPY $z0
+ %3:zpr = COPY $z1
+ %0:ppr_3b = PTRUE_B 31, implicit $vg
+ %5:ppr = CMPEQ_PPzZZ_B %0, %2, %3, implicit-def dead $nzcv
+ B %bb.1
+
+ bb.1:
+ %1:ppr_3b = PTRUE_H 31, implicit $vg
+ %4:ppr = CMPEQ_PPzZZ_H %1, %2, %3, implicit-def dead $nzcv
+ RET_ReallyLR
+
+...
+
+---
+name: keep_ptrue_h_when_b_user_would_observe_extra_lanes
+alignment: 2
+tracksRegLiveness: true
+registers:
+ - { id: 0, class: ppr_3b }
+ - { id: 1, class: ppr_3b }
+ - { id: 2, class: zpr }
+ - { id: 3, class: zpr }
+ - { id: 4, class: ppr }
+ - { id: 5, class: ppr }
+liveins:
+ - { reg: '$z0', virtual-reg: '%2' }
+ - { reg: '$z1', virtual-reg: '%3' }
+body: |
+ bb.0:
+ liveins: $z0, $z1
+
+ ; CHECK-LABEL: name: keep_ptrue_h_when_b_user_would_observe_extra_lanes
+ ; CHECK: liveins: $z0, $z1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:zpr = COPY $z0
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:zpr = COPY $z1
+ ; CHECK-NEXT: [[PTRUE_B:%[0-9]+]]:ppr_3b = PTRUE_B 31, implicit $vg
+ ; CHECK-NEXT: [[CMPEQ_PPzZZ_B:%[0-9]+]]:ppr = CMPEQ_PPzZZ_B [[PTRUE_B]], [[COPY]], [[COPY1]], implicit-def dead $nzcv
+ ; CHECK-NEXT: [[PTRUE_H:%[0-9]+]]:ppr_3b = PTRUE_H 31, implicit $vg
+ ; CHECK-NEXT: [[CMPEQ_PPzZZ_B1:%[0-9]+]]:ppr = CMPEQ_PPzZZ_B [[PTRUE_H]], [[COPY]], [[COPY1]], implicit-def dead $nzcv
+ ; CHECK-NEXT: RET_ReallyLR
+ %2:zpr = COPY $z0
+ %3:zpr = COPY $z1
+ %0:ppr_3b = PTRUE_B 31, implicit $vg
+ %4:ppr = CMPEQ_PPzZZ_B %0, %2, %3, implicit-def dead $nzcv
+ %1:ppr_3b = PTRUE_H 31, implicit $vg
+ %5:ppr = CMPEQ_PPzZZ_B %1, %2, %3, implicit-def dead $nzcv
+ RET_ReallyLR
+
+...
+---
+name: keep_ptrue_s_when_d_user_cannot_be_narrowed
+alignment: 2
+tracksRegLiveness: true
+registers:
+ - { id: 0, class: ppr_3b }
+ - { id: 1, class: ppr_3b }
+ - { id: 2, class: zpr }
+ - { id: 3, class: zpr }
+ - { id: 4, class: ppr }
+ - { id: 5, class: ppr }
+ - { id: 6, class: zpr }
+liveins:
+ - { reg: '$z0', virtual-reg: '%2' }
+ - { reg: '$z1', virtual-reg: '%3' }
+body: |
+ bb.0:
+ liveins: $z0, $z1
+
+ ; CHECK-LABEL: name: keep_ptrue_s_when_d_user_cannot_be_narrowed
+ ; CHECK: liveins: $z0, $z1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:zpr = COPY $z0
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:zpr = COPY $z1
+ ; CHECK-NEXT: [[PTRUE_D:%[0-9]+]]:ppr_3b = PTRUE_D 31, implicit $vg
+ ; CHECK-NEXT: [[CMPEQ_PPzZZ_H:%[0-9]+]]:ppr = CMPEQ_PPzZZ_H [[PTRUE_D]], [[COPY]], [[COPY1]], implicit-def dead $nzcv
+ ; CHECK-NEXT: [[PTRUE_S:%[0-9]+]]:ppr_3b = PTRUE_S 31, implicit $vg
+ ; CHECK-NEXT: [[DEF:%[0-9]+]]:zpr = IMPLICIT_DEF
+ ; CHECK-NEXT: [[CMPEQ_PPzZZ_S:%[0-9]+]]:ppr = CMPEQ_PPzZZ_S [[PTRUE_S]], [[DEF]], [[COPY]], implicit-def dead $nzcv
+ ; CHECK-NEXT: RET_ReallyLR
+ %2:zpr = COPY $z0
+ %3:zpr = COPY $z1
+ %0:ppr_3b = PTRUE_D 31, implicit $vg
+ %4:ppr = CMPEQ_PPzZZ_H %0, %2, %3, implicit-def dead $nzcv
+ %1:ppr_3b = PTRUE_S 31, implicit $vg
+ %6:zpr = IMPLICIT_DEF
+ %5:ppr = CMPEQ_PPzZZ_S %1, %6, %2, implicit-def dead $nzcv
+ RET_ReallyLR
+
+...
+---
+name: keep_ptrue_h_when_candidate_does_not_dominate
+alignment: 2
+tracksRegLiveness: true
+registers:
+ - { id: 0, class: ppr_3b }
+ - { id: 1, class: ppr_3b }
+ - { id: 2, class: zpr }
+ - { id: 3, class: zpr }
+ - { id: 4, class: ppr }
+ - { id: 5, class: ppr }
+ - { id: 6, class: gpr32 }
+liveins:
+ - { reg: '$z0', virtual-reg: '%2' }
+ - { reg: '$z1', virtual-reg: '%3' }
+ - { reg: '$w0', virtual-reg: '%6' }
+body: |
+ ; CHECK-LABEL: name: keep_ptrue_h_when_candidate_does_not_dominate
+ ; CHECK: bb.0:
+ ; CHECK-NEXT: successors: %bb.2(0x40000000), %bb.1(0x40000000)
+ ; CHECK-NEXT: liveins: $z0, $z1, $w0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:zpr = COPY $z0
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:zpr = COPY $z1
+ ; CHECK-NEXT: [[COPY2:%[0-9]+]]:gpr32 = COPY $w0
+ ; CHECK-NEXT: CBZW [[COPY2]], %bb.2
+ ; CHECK-NEXT: B %bb.1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: bb.1:
+ ; CHECK-NEXT: successors: %bb.2(0x80000000)
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[PTRUE_B:%[0-9]+]]:ppr_3b = PTRUE_B 31, implicit $vg
+ ; CHECK-NEXT: [[CMPEQ_PPzZZ_B:%[0-9]+]]:ppr = CMPEQ_PPzZZ_B [[PTRUE_B]], [[COPY]], [[COPY1]], implicit-def dead $nzcv
+ ; CHECK-NEXT: B %bb.2
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: bb.2:
+ ; CHECK-NEXT: [[PTRUE_H:%[0-9]+]]:ppr_3b = PTRUE_H 31, implicit $vg
+ ; CHECK-NEXT: [[CMPEQ_PPzZZ_H:%[0-9]+]]:ppr = CMPEQ_PPzZZ_H [[PTRUE_H]], [[COPY]], [[COPY1]], implicit-def dead $nzcv
+ ; CHECK-NEXT: RET_ReallyLR
+ bb.0:
+ successors: %bb.2, %bb.1
+ liveins: $z0, $z1, $w0
+
+ %2:zpr = COPY $z0
+ %3:zpr = COPY $z1
+ %6:gpr32 = COPY $w0
+ CBZW %6, %bb.2
+ B %bb.1
+
+ bb.1:
+ successors: %bb.2
+
+ %0:ppr_3b = PTRUE_B 31, implicit $vg
+ %5:ppr = CMPEQ_PPzZZ_B %0, %2, %3, implicit-def dead $nzcv
+ B %bb.2
+
+ bb.2:
+ %1:ppr_3b = PTRUE_H 31, implicit $vg
+ %4:ppr = CMPEQ_PPzZZ_H %1, %2, %3, implicit-def dead $nzcv
+ RET_ReallyLR
+
+...
+---
+name: ptrue_s_replaces_ptrue_d_for_d_user
+alignment: 2
+tracksRegLiveness: true
+registers:
+ - { id: 0, class: ppr_3b }
+ - { id: 1, class: ppr_3b }
+ - { id: 2, class: zpr }
+ - { id: 3, class: zpr }
+ - { id: 4, class: ppr }
+ - { id: 5, class: ppr }
+liveins:
+ - { reg: '$z0', virtual-reg: '%2' }
+ - { reg: '$z1', virtual-reg: '%3' }
+body: |
+ bb.0:
+ liveins: $z0, $z1
+
+ ; ENABLED-LABEL: name: ptrue_s_replaces_ptrue_d_for_d_user
+ ; ENABLED: liveins: $z0, $z1
+ ; ENABLED-NEXT: {{ $}}
+ ; ENABLED-NEXT: [[COPY:%[0-9]+]]:zpr = COPY $z0
+ ; ENABLED-NEXT: [[COPY1:%[0-9]+]]:zpr = COPY $z1
+ ; ENABLED-NEXT: [[PTRUE_S:%[0-9]+]]:ppr_3b = PTRUE_S 31, implicit $vg
+ ; ENABLED-NEXT: [[CMPEQ_PPzZZ_D:%[0-9]+]]:ppr = CMPEQ_PPzZZ_D [[PTRUE_S]], [[COPY]], [[COPY1]], implicit-def dead $nzcv
+ ; ENABLED-NEXT: [[CMPEQ_PPzZZ_S:%[0-9]+]]:ppr = CMPEQ_PPzZZ_S [[PTRUE_S]], [[COPY]], [[COPY1]], implicit-def dead $nzcv
+ ; ENABLED-NEXT: RET_ReallyLR
+ ;
+ ; DISABLED-LABEL: name: ptrue_s_replaces_ptrue_d_for_d_user
+ ; DISABLED: liveins: $z0, $z1
+ ; DISABLED-NEXT: {{ $}}
+ ; DISABLED-NEXT: [[COPY:%[0-9]+]]:zpr = COPY $z0
+ ; DISABLED-NEXT: [[COPY1:%[0-9]+]]:zpr = COPY $z1
+ ; DISABLED-NEXT: [[PTRUE_S:%[0-9]+]]:ppr_3b = PTRUE_S 31, implicit $vg
+ ; DISABLED-NEXT: [[PTRUE_D:%[0-9]+]]:ppr_3b = PTRUE_D 31, implicit $vg
+ ; DISABLED-NEXT: [[CMPEQ_PPzZZ_D:%[0-9]+]]:ppr = CMPEQ_PPzZZ_D [[PTRUE_D]], [[COPY]], [[COPY1]], implicit-def dead $nzcv
+ ; DISABLED-NEXT: [[CMPEQ_PPzZZ_S:%[0-9]+]]:ppr = CMPEQ_PPzZZ_S [[PTRUE_S]], [[COPY]], [[COPY1]], implicit-def dead $nzcv
+ ; DISABLED-NEXT: RET_ReallyLR
+ %2:zpr = COPY $z0
+ %3:zpr = COPY $z1
+ %0:ppr_3b = PTRUE_S 31, implicit $vg
+ %1:ppr_3b = PTRUE_D 31, implicit $vg
+ %4:ppr = CMPEQ_PPzZZ_D %1, %2, %3, implicit-def dead $nzcv
+ %5:ppr = CMPEQ_PPzZZ_S %0, %2, %3, implicit-def dead $nzcv
+ RET_ReallyLR
+
+...
+---
+name: keep_non_all_ptrue
+alignment: 2
+tracksRegLiveness: true
+registers:
+ - { id: 0, class: ppr_3b }
+ - { id: 1, class: ppr_3b }
+ - { id: 2, class: zpr }
+ - { id: 3, class: zpr }
+ - { id: 4, class: ppr }
+ - { id: 5, class: ppr }
+liveins:
+ - { reg: '$z0', virtual-reg: '%2' }
+ - { reg: '$z1', virtual-reg: '%3' }
+body: |
+ bb.0:
+ liveins: $z0, $z1
+
+ ; CHECK-LABEL: name: keep_non_all_ptrue
+ ; CHECK: liveins: $z0, $z1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:zpr = COPY $z0
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:zpr = COPY $z1
+ ; CHECK-NEXT: [[PTRUE_B:%[0-9]+]]:ppr_3b = PTRUE_B 1, implicit $vg
+ ; CHECK-NEXT: [[PTRUE_H:%[0-9]+]]:ppr_3b = PTRUE_H 31, implicit $vg
+ ; CHECK-NEXT: [[CMPEQ_PPzZZ_B:%[0-9]+]]:ppr = CMPEQ_PPzZZ_B [[PTRUE_B]], [[COPY]], [[COPY1]], implicit-def dead $nzcv
+ ; CHECK-NEXT: [[CMPEQ_PPzZZ_H:%[0-9]+]]:ppr = CMPEQ_PPzZZ_H [[PTRUE_H]], [[COPY]], [[COPY1]], implicit-def dead $nzcv
+ ; CHECK-NEXT: RET_ReallyLR
+ %2:zpr = COPY $z0
+ %3:zpr = COPY $z1
+ %0:ppr_3b = PTRUE_B 1, implicit $vg
+ %1:ppr_3b = PTRUE_H 31, implicit $vg
+ %4:ppr = CMPEQ_PPzZZ_B %0, %2, %3, implicit-def dead $nzcv
+ %5:ppr = CMPEQ_PPzZZ_H %1, %2, %3, implicit-def dead $nzcv
+ RET_ReallyLR
+
+...
+---
+name: keep_ptrue_s_when_existing_b_user_would_observe_extra_lanes
+alignment: 2
+tracksRegLiveness: true
+registers:
+ - { id: 0, class: ppr_3b }
+ - { id: 1, class: ppr_3b }
+ - { id: 2, class: zpr }
+ - { id: 3, class: zpr }
+ - { id: 4, class: zpr }
+ - { id: 5, class: ppr }
+liveins:
+ - { reg: '$z0', virtual-reg: '%2' }
+ - { reg: '$z1', virtual-reg: '%3' }
+body: |
+ bb.0:
+ liveins: $z0, $z1
+
+ ; CHECK-LABEL: name: keep_ptrue_s_when_existing_b_user_would_observe_extra_lanes
+ ; CHECK: liveins: $z0, $z1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:zpr = COPY $z0
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:zpr = COPY $z1
+ ; CHECK-NEXT: [[PTRUE_S:%[0-9]+]]:ppr_3b = PTRUE_S 31, implicit $vg
+ ; CHECK-NEXT: [[ADD_ZPmZ_B:%[0-9]+]]:zpr = ADD_ZPmZ_B [[PTRUE_S]], [[COPY]], [[COPY1]]
+ ; CHECK-NEXT: [[PTRUE_B:%[0-9]+]]:ppr_3b = PTRUE_B 31, implicit $vg
+ ; CHECK-NEXT: [[CMPEQ_PPzZZ_B:%[0-9]+]]:ppr = CMPEQ_PPzZZ_B [[PTRUE_B]], [[ADD_ZPmZ_B]], [[COPY1]], implicit-def dead $nzcv
+ ; CHECK-NEXT: RET_ReallyLR
+ %2:zpr = COPY $z0
+ %3:zpr = COPY $z1
+ %0:ppr_3b = PTRUE_S 31, implicit $vg
+ %4:zpr = ADD_ZPmZ_B %0, %2, %3
+ %1:ppr_3b = PTRUE_B 31, implicit $vg
+ %5:ppr = CMPEQ_PPzZZ_B %1, %4, %3, implicit-def dead $nzcv
+ RET_ReallyLR
+
+...
+---
+name: do_notcoalesce_across_vg_definitions
+alignment: 2
+tracksRegLiveness: true
+registers:
+ - { id: 0, class: ppr_3b }
+ - { id: 1, class: ppr_3b }
+ - { id: 2, class: zpr }
+ - { id: 3, class: zpr }
+ - { id: 4, class: ppr }
+ - { id: 5, class: ppr }
+liveins:
+ - { reg: '$z0', virtual-reg: '%2' }
+ - { reg: '$z1', virtual-reg: '%3' }
+body: |
+ bb.0:
+ liveins: $z0, $z1
+
+ ; CHECK-LABEL: name: do_notcoalesce_across_vg_definitions
+ ; CHECK: liveins: $z0, $z1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:zpr = COPY $z0
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:zpr = COPY $z1
+ ; CHECK-NEXT: [[PTRUE_B:%[0-9]+]]:ppr_3b = PTRUE_B 31, implicit $vg
+ ; CHECK-NEXT: [[CMPEQ_PPzZZ_B:%[0-9]+]]:ppr = CMPEQ_PPzZZ_B [[PTRUE_B]], [[COPY]], [[COPY1]], implicit-def dead $nzcv
+ ; CHECK-NEXT: MSRpstatesvcrImm1 1, 1, csr_aarch64_smstartstop, implicit-def dead $nzcv, implicit $vg, implicit-def $vg
+ ; CHECK-NEXT: [[PTRUE_H:%[0-9]+]]:ppr_3b = PTRUE_H 31, implicit $vg
+ ; CHECK-NEXT: [[CMPEQ_PPzZZ_H:%[0-9]+]]:ppr = CMPEQ_PPzZZ_H [[PTRUE_H]], [[COPY]], [[COPY1]], implicit-def dead $nzcv
+ ; CHECK-NEXT: RET_ReallyLR
+ %2:zpr = COPY $z0
+ %3:zpr = COPY $z1
+ %0:ppr_3b = PTRUE_B 31, implicit $vg
+ %5:ppr = CMPEQ_PPzZZ_B %0, %2, %3, implicit-def dead $nzcv
+ MSRpstatesvcrImm1 1, 1, csr_aarch64_smstartstop, implicit-def dead $nzcv, implicit $vg, implicit-def $vg
+ %1:ppr_3b = PTRUE_H 31, implicit $vg
+ %4:ppr = CMPEQ_PPzZZ_H %1, %2, %3, implicit-def dead $nzcv
+ RET_ReallyLR
+
+...
+---
+name: constrained_ptrue_b_replaces_ptrue_h_for_h_user
+alignment: 2
+tracksRegLiveness: true
+registers:
+ - { id: 0, class: ppr }
+ - { id: 1, class: ppr_3b }
+ - { id: 2, class: zpr }
+ - { id: 3, class: zpr }
+ - { id: 4, class: ppr }
+ - { id: 5, class: ppr }
+ - { id: 6, class: ppr }
+liveins:
+ - { reg: '$z0', virtual-reg: '%2' }
+ - { reg: '$z1', virtual-reg: '%3' }
+body: |
+ bb.0:
+ liveins: $z0, $z1
+
+ ; ENABLED-LABEL: name: constrained_ptrue_b_replaces_ptrue_h_for_h_user
+ ; ENABLED: liveins: $z0, $z1
+ ; ENABLED-NEXT: {{ $}}
+ ; ENABLED-NEXT: [[COPY:%[0-9]+]]:zpr = COPY $z0
+ ; ENABLED-NEXT: [[COPY1:%[0-9]+]]:zpr = COPY $z1
+ ; ENABLED-NEXT: [[PTRUE_B:%[0-9]+]]:ppr_3b = PTRUE_B 31, implicit $vg
+ ; ENABLED-NEXT: [[BRKN_PPzP:%[0-9]+]]:ppr = BRKN_PPzP [[PTRUE_B]], [[PTRUE_B]], [[PTRUE_B]]
+ ; ENABLED-NEXT: [[CMPEQ_PPzZZ_H:%[0-9]+]]:ppr = CMPEQ_PPzZZ_H [[PTRUE_B]], [[COPY]], [[COPY1]], implicit-def dead $nzcv
+ ; ENABLED-NEXT: RET_ReallyLR
+ ;
+ ; DISABLED-LABEL: name: constrained_ptrue_b_replaces_ptrue_h_for_h_user
+ ; DISABLED: liveins: $z0, $z1
+ ; DISABLED-NEXT: {{ $}}
+ ; DISABLED-NEXT: [[COPY:%[0-9]+]]:zpr = COPY $z0
+ ; DISABLED-NEXT: [[COPY1:%[0-9]+]]:zpr = COPY $z1
+ ; DISABLED-NEXT: [[PTRUE_B:%[0-9]+]]:ppr = PTRUE_B 31, implicit $vg
+ ; DISABLED-NEXT: [[BRKN_PPzP:%[0-9]+]]:ppr = BRKN_PPzP [[PTRUE_B]], [[PTRUE_B]], [[PTRUE_B]]
+ ; DISABLED-NEXT: [[PTRUE_H:%[0-9]+]]:ppr_3b = PTRUE_H 31, implicit $vg
+ ; DISABLED-NEXT: [[CMPEQ_PPzZZ_H:%[0-9]+]]:ppr = CMPEQ_PPzZZ_H [[PTRUE_H]], [[COPY]], [[COPY1]], implicit-def dead $nzcv
+ ; DISABLED-NEXT: RET_ReallyLR
+ %2:zpr = COPY $z0
+ %3:zpr = COPY $z1
+ %0:ppr = PTRUE_B 31, implicit $vg
+ %6:ppr = BRKN_PPzP %0, %0, %0
+ %1:ppr_3b = PTRUE_H 31, implicit $vg
+ %4:ppr = CMPEQ_PPzZZ_H %1, %2, %3, implicit-def dead $nzcv
+ RET_ReallyLR
+
+...
+---
+name: keep_ptrue_when_constrain_regclass_fails
+alignment: 2
+tracksRegLiveness: true
+registers:
+ - { id: 0, class: ppr_p8to15 }
+ - { id: 1, class: ppr_3b }
+ - { id: 2, class: zpr }
+ - { id: 3, class: zpr }
+ - { id: 4, class: ppr }
+ - { id: 5, class: ppr }
+ - { id: 6, class: ppr }
+liveins:
+ - { reg: '$z0', virtual-reg: '%2' }
+ - { reg: '$z1', virtual-reg: '%3' }
+body: |
+ bb.0:
+ liveins: $z0, $z1
+
+ ; CHECK-LABEL: name: keep_ptrue_when_constrain_regclass_fails
+ ; CHECK: liveins: $z0, $z1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:zpr = COPY $z0
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:zpr = COPY $z1
+ ; CHECK-NEXT: [[PTRUE_B:%[0-9]+]]:ppr_p8to15 = PTRUE_B 31, implicit $vg
+ ; CHECK-NEXT: [[BRKN_PPzP:%[0-9]+]]:ppr = BRKN_PPzP [[PTRUE_B]], [[PTRUE_B]], [[PTRUE_B]]
+ ; CHECK-NEXT: [[PTRUE_H:%[0-9]+]]:ppr_3b = PTRUE_H 31, implicit $vg
+ ; CHECK-NEXT: [[CMPEQ_PPzZZ_H:%[0-9]+]]:ppr = CMPEQ_PPzZZ_H [[PTRUE_H]], [[COPY]], [[COPY1]], implicit-def dead $nzcv
+ ; CHECK-NEXT: RET_ReallyLR
+ %2:zpr = COPY $z0
+ %3:zpr = COPY $z1
+ %0:ppr_p8to15 = PTRUE_B 31, implicit $vg
+ %6:ppr = BRKN_PPzP %0, %0, %0
+ %1:ppr_3b = PTRUE_H 31, implicit $vg
+ %4:ppr = CMPEQ_PPzZZ_H %1, %2, %3, implicit-def dead $nzcv
+ RET_ReallyLR
+
+...
More information about the llvm-commits
mailing list