diff --git a/llvm/lib/CodeGen/RegAllocFast.cpp b/llvm/lib/CodeGen/RegAllocFast.cpp --- a/llvm/lib/CodeGen/RegAllocFast.cpp +++ b/llvm/lib/CodeGen/RegAllocFast.cpp @@ -147,6 +147,8 @@ RegUnitSet UsedInInstr; RegUnitSet PhysRegUses; SmallVector DefOperandIndexes; + // RegMask attached to current instruction or null. + const uint32_t *RegMask; void setPhysRegState(MCPhysReg PhysReg, unsigned NewState); bool isPhysRegFree(MCPhysReg PhysReg) const; @@ -159,6 +161,9 @@ /// Check if a physreg or any of its aliases are used in this instruction. bool isRegUsedInInstr(MCPhysReg PhysReg, bool LookAtPhysRegUses) const { + if (LookAtPhysRegUses && RegMask && + MachineOperand::clobbersPhysReg(RegMask, PhysReg)) + return true; for (MCRegUnitIterator Units(PhysReg, TRI); Units.isValid(); ++Units) { if (UsedInInstr.count(*Units)) return true; @@ -1088,6 +1093,7 @@ // operands and early-clobbers. UsedInInstr.clear(); + RegMask = nullptr; BundleVirtRegsMap.clear(); // Scan for special cases; Apply pre-assigned register defs to state. @@ -1127,9 +1133,13 @@ } } else if (MO.isRegMask()) { HasRegMask = true; + RegMask = MO.getRegMask(); } } + // Set of registers allocated to tied defs. + SmallSet AssignedTiedDefs; + // Allocate virtreg defs. if (HasDef) { if (HasVRegDef) { @@ -1242,6 +1252,9 @@ continue; } + if (MO.isTied()) { + AssignedTiedDefs.insert(MO.getReg()); + } // Do not free tied operands and early clobbers. if (MO.isTied() || MO.isEarlyClobber()) continue; @@ -1258,19 +1271,22 @@ // Displace clobbered registers. if (HasRegMask) { - for (const MachineOperand &MO : MI.operands()) { - if (MO.isRegMask()) { - // MRI bookkeeping. - MRI->addPhysRegsUsedFromRegMask(MO.getRegMask()); - - // Displace clobbered registers. - const uint32_t *Mask = MO.getRegMask(); - for (const LiveReg &LR : LiveVirtRegs) { - MCPhysReg PhysReg = LR.PhysReg; - if (PhysReg != 0 && MachineOperand::clobbersPhysReg(Mask, PhysReg)) - displacePhysReg(MI, PhysReg); - } - } + assert(RegMask && "expected RegMask"); + // MRI bookkeeping. + MRI->addPhysRegsUsedFromRegMask(RegMask); + +#ifndef NDEBUG + for (auto R : AssignedTiedDefs) { + assert(!MachineOperand::clobbersPhysReg(RegMask, R) && + "tied def allocated to clobbered register"); + } +#endif + + // Displace clobbered registers. + for (const LiveReg &LR : LiveVirtRegs) { + MCPhysReg PhysReg = LR.PhysReg; + if (PhysReg != 0 && MachineOperand::clobbersPhysReg(RegMask, PhysReg)) + displacePhysReg(MI, PhysReg); } } diff --git a/llvm/test/CodeGen/X86/statepoint-fastregalloc.mir b/llvm/test/CodeGen/X86/statepoint-fastregalloc.mir new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/X86/statepoint-fastregalloc.mir @@ -0,0 +1,21 @@ +# RUN: llc -mtriple=x86_64-- -run-pass=regallocfast -o - %s | FileCheck %s + +# Check that fastregalloc does not displace register assigned to tied def when +# RegMask operand is present. STATEPOINT is an example of such instruction. +# Tied def/use must be assigned to the same register. +--- +name: test_relocate +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $rdi + + ; CHECK: renamable [[REG:\$[a-z0-9]+]] = STATEPOINT 0, 0, 0, target-flags(x86-plt) 0, 2, 0, 2, 0, 2, 0, 2, 1, renamable [[REG]](tied-def 0) + + %1:gr64 = COPY $rdi + ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp + %1:gr64 = STATEPOINT 0, 0, 0, target-flags(x86-plt) 0, 2, 0, 2, 0, 2, 0, 2, 1, %1(tied-def 0), 2, 0, 2, 1, 0, 0, csr_64, implicit-def $rsp, implicit-def $ssp + ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp + $rax = COPY %1 + RET 0, killed $rax +...