Index: include/llvm/Target/TargetRegisterInfo.h =================================================================== --- include/llvm/Target/TargetRegisterInfo.h +++ include/llvm/Target/TargetRegisterInfo.h @@ -495,6 +495,10 @@ /// used by register scavenger to determine what registers are free. virtual BitVector getReservedRegs(const MachineFunction &MF) const = 0; + /// Returns true if PhysReg is unallocatable and constant throughout the + /// function. Used by MachineRegisterInfo::isConstantPhysReg(). + virtual bool isConstantPhysReg(unsigned PhysReg) const { return false; } + /// Prior to adding the live-out mask to a stackmap or patchpoint /// instruction, provide the target the opportunity to adjust it (mainly to /// remove pseudo-registers that should be ignored). Index: lib/CodeGen/MachineRegisterInfo.cpp =================================================================== --- lib/CodeGen/MachineRegisterInfo.cpp +++ lib/CodeGen/MachineRegisterInfo.cpp @@ -468,9 +468,13 @@ const MachineFunction &MF) const { assert(TargetRegisterInfo::isPhysicalRegister(PhysReg)); + const TargetRegisterInfo *TRI = getTargetRegisterInfo(); + if (TRI->isConstantPhysReg(PhysReg)) + return true; + // Check if any overlapping register is modified, or allocatable so it may be // used later. - for (MCRegAliasIterator AI(PhysReg, getTargetRegisterInfo(), true); + for (MCRegAliasIterator AI(PhysReg, TRI, true); AI.isValid(); ++AI) if (!def_empty(*AI) || isAllocatable(*AI)) return false; Index: lib/Target/AArch64/AArch64RegisterInfo.h =================================================================== --- lib/Target/AArch64/AArch64RegisterInfo.h +++ lib/Target/AArch64/AArch64RegisterInfo.h @@ -62,6 +62,7 @@ CallingConv::ID) const; BitVector getReservedRegs(const MachineFunction &MF) const override; + bool isConstantPhysReg(unsigned PhysReg) const override; const TargetRegisterClass * getPointerRegClass(const MachineFunction &MF, unsigned Kind = 0) const override; Index: lib/Target/AArch64/AArch64RegisterInfo.cpp =================================================================== --- lib/Target/AArch64/AArch64RegisterInfo.cpp +++ lib/Target/AArch64/AArch64RegisterInfo.cpp @@ -167,6 +167,10 @@ return false; } +bool AArch64RegisterInfo::isConstantPhysReg(unsigned PhysReg) const { + return PhysReg == AArch64::WZR || PhysReg == AArch64::XZR; +} + const TargetRegisterClass * AArch64RegisterInfo::getPointerRegClass(const MachineFunction &MF, unsigned Kind) const { Index: test/CodeGen/MIR/AArch64/machine-sink-zr.mir =================================================================== --- /dev/null +++ test/CodeGen/MIR/AArch64/machine-sink-zr.mir @@ -0,0 +1,71 @@ +# RUN: llc -mtriple=aarch64-none-linux-gnu -run-pass machine-sink -o - %s | FileCheck %s +--- | + ; Function Attrs: nounwind + define void @sinkwzr(i32 %N) { + entry: + %cmp3 = icmp eq i32 %N, 0 + br i1 %cmp3, label %for.cond.cleanup, label %for.body.preheader + + for.body.preheader: + br label %for.body + + for.body: + %lsr.iv = phi i32 [ %N, %for.body.preheader ], [ %lsr.iv.next, %for.body ] + %lsr.iv.next = add i32 %lsr.iv, -1 + %exitcond = icmp eq i32 %lsr.iv.next, 0 + br i1 %exitcond, label %for.cond.cleanup, label %for.body + + for.cond.cleanup: + ret void + } +... +--- +name: sinkwzr +alignment: 2 +exposesReturnsTwice: false +legalized: false +regBankSelected: false +selected: false +tracksRegLiveness: true +registers: + - { id: 0, class: gpr32sp } + - { id: 1, class: gpr32all } + - { id: 2, class: gpr32 } + - { id: 3, class: gpr32all } + - { id: 4, class: gpr32 } +liveins: + - { reg: '%w0', virtual-reg: '%2' } +body: | + ; Check that WZR copy is sunk into the loop preheader. + ; CHECK-LABEL: bb.0.entry: + ; CHECK-NOT: COPY %wzr + bb.0.entry: + successors: %bb.3.for.cond.cleanup, %bb.1.for.body.preheader + liveins: %w0 + + %2 = COPY %w0 + %3 = COPY %wzr + CBZW %2, %bb.3.for.cond.cleanup + + ; CHECK-LABEL: bb.1.for.body.preheader: + ; CHECK: COPY %wzr + + bb.1.for.body.preheader: + successors: %bb.2.for.body + + B %bb.2.for.body + + bb.2.for.body: + successors: %bb.3.for.cond.cleanup, %bb.2.for.body + + %0 = PHI %2, %bb.1.for.body.preheader, %1, %bb.2.for.body + %w0 = COPY %3 + %4 = SUBSWri %0, 1, 0, implicit-def dead %nzcv + %1 = COPY %4 + CBZW %4, %bb.3.for.cond.cleanup + B %bb.2.for.body + + bb.3.for.cond.cleanup: + RET_ReallyLR + +...