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; + // Register masks attached to the current instruction. + SmallVector RegMasks; void setPhysRegState(MCPhysReg PhysReg, unsigned NewState); bool isPhysRegFree(MCPhysReg PhysReg) const; @@ -157,8 +159,17 @@ UsedInInstr.insert(*Units); } + // Check if physreg is clobbered by instruction's regmask(s). + bool isClobberedByRegMasks(MCPhysReg PhysReg) const { + return llvm::any_of(RegMasks, [PhysReg](const uint32_t *Mask) { + return MachineOperand::clobbersPhysReg(Mask, PhysReg); + }); + } + /// Check if a physreg or any of its aliases are used in this instruction. bool isRegUsedInInstr(MCPhysReg PhysReg, bool LookAtPhysRegUses) const { + if (LookAtPhysRegUses && isClobberedByRegMasks(PhysReg)) + return true; for (MCRegUnitIterator Units(PhysReg, TRI); Units.isValid(); ++Units) { if (UsedInInstr.count(*Units)) return true; @@ -1088,6 +1099,7 @@ // operands and early-clobbers. UsedInInstr.clear(); + RegMasks.clear(); BundleVirtRegsMap.clear(); // Scan for special cases; Apply pre-assigned register defs to state. @@ -1127,6 +1139,7 @@ } } else if (MO.isRegMask()) { HasRegMask = true; + RegMasks.push_back(MO.getRegMask()); } } @@ -1242,6 +1255,9 @@ continue; } + assert((!MO.isTied() || !isClobberedByRegMasks(MO.getReg())) && + "tied def assigned to clobbered register"); + // Do not free tied operands and early clobbers. if (MO.isTied() || MO.isEarlyClobber()) continue; @@ -1258,19 +1274,16 @@ // 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(!RegMasks.empty() && "expected RegMask"); + // MRI bookkeeping. + for (const auto *RM : RegMasks) + MRI->addPhysRegsUsedFromRegMask(RM); + + // Displace clobbered registers. + for (const LiveReg &LR : LiveVirtRegs) { + MCPhysReg PhysReg = LR.PhysReg; + if (PhysReg != 0 && isClobberedByRegMasks(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 +...