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 @@ -1112,6 +1112,12 @@ RegMasks.clear(); BundleVirtRegsMap.clear(); + auto TiedOpIsUndef = [&](const MachineOperand &MO, unsigned Idx) { + assert(MO.isTied()); + unsigned TiedIdx = MI.findTiedOperandIdx(Idx); + const MachineOperand &TiedMO = MI.getOperand(TiedIdx); + return TiedMO.isUndef(); + }; // Scan for special cases; Apply pre-assigned register defs to state. bool HasPhysRegUse = false; bool HasRegMask = false; @@ -1119,7 +1125,8 @@ bool HasDef = false; bool HasEarlyClobber = false; bool NeedToAssignLiveThroughs = false; - for (MachineOperand &MO : MI.operands()) { + for (unsigned I = 0; I < MI.getNumOperands(); ++I) { + MachineOperand &MO = MI.getOperand(I); if (MO.isReg()) { Register Reg = MO.getReg(); if (Reg.isVirtual()) { @@ -1130,7 +1137,8 @@ HasEarlyClobber = true; NeedToAssignLiveThroughs = true; } - if (MO.isTied() || (MO.getSubReg() != 0 && !MO.isUndef())) + if ((MO.isTied() && !TiedOpIsUndef(MO, I)) || + (MO.getSubReg() != 0 && !MO.isUndef())) NeedToAssignLiveThroughs = true; } } else if (Reg.isPhysical()) { @@ -1230,7 +1238,8 @@ MachineOperand &MO = MI.getOperand(OpIdx); LLVM_DEBUG(dbgs() << "Allocating " << MO << '\n'); unsigned Reg = MO.getReg(); - if (MO.isEarlyClobber() || MO.isTied() || + if (MO.isEarlyClobber() || + (MO.isTied() && !TiedOpIsUndef(MO, OpIdx)) || (MO.getSubReg() && !MO.isUndef())) { defineLiveThroughVirtReg(MI, OpIdx, Reg); } else { @@ -1253,7 +1262,8 @@ // Free registers occupied by defs. // Iterate operands in reverse order, so we see the implicit super register // defs first (we added them earlier in case of ). - for (MachineOperand &MO : llvm::reverse(MI.operands())) { + for (signed I = MI.getNumOperands() - 1; I >= 0; --I) { + MachineOperand &MO = MI.getOperand(I); if (!MO.isReg() || !MO.isDef()) continue; @@ -1268,7 +1278,7 @@ "tied def assigned to clobbered register"); // Do not free tied operands and early clobbers. - if (MO.isTied() || MO.isEarlyClobber()) + if ((MO.isTied() && !TiedOpIsUndef(MO, I)) || MO.isEarlyClobber()) continue; Register Reg = MO.getReg(); if (!Reg) diff --git a/llvm/test/CodeGen/X86/fastregalloc-tied-undef.mir b/llvm/test/CodeGen/X86/fastregalloc-tied-undef.mir new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/X86/fastregalloc-tied-undef.mir @@ -0,0 +1,35 @@ +# RUN: llc -mtriple=x86_64-- -run-pass=regallocfast -o - %s | FileCheck %s + +# If the tied use is undef value, fastregalloc should free the def register. +# There is no reload needed for the undef value. +... +--- +name: foo +alignment: 16 +tracksRegLiveness: true +registers: + - { id: 0, class: vr128 } +frameInfo: + maxAlignment: 16 +stack: + - { id: 0, size: 64, alignment: 16 } + - { id: 1, size: 16, alignment: 16 } +machineFunctionInfo: {} +body: | + bb.0.entry: + ; CHECK: renamable $xmm0 = PXORrr undef renamable $xmm0, undef renamable $xmm0 + ; CHECK: MOVAPSmr %stack.1, 1, $noreg, 0, $noreg, renamable $xmm0 + ; CHECK: MOVAPSmr %stack.0, 1, $noreg, 0, $noreg, renamable $xmm0 + ; CHECK: MOVAPSmr %stack.0, 1, $noreg, 16, $noreg, renamable $xmm0 + ; CHECK: MOVAPSmr %stack.0, 1, $noreg, 32, $noreg, renamable $xmm0 + ; CHECK: MOVAPSmr %stack.0, 1, $noreg, 48, $noreg, killed renamable $xmm0 + + %0:vr128 = PXORrr undef %0, undef %0 + MOVAPSmr %stack.1, 1, $noreg, 0, $noreg, %0 + MOVAPSmr %stack.0, 1, $noreg, 0, $noreg, %0 + MOVAPSmr %stack.0, 1, $noreg, 16, $noreg, %0 + MOVAPSmr %stack.0, 1, $noreg, 32, $noreg, %0 + MOVAPSmr %stack.0, 1, $noreg, 48, $noreg, killed %0 + RET 0 + +...