Skip to content

Commit a0c8959

Browse files
aaronpucherttstellar
authored andcommitted
[X86] When expanding LCMPXCHG16B_SAVE_RBX, substitute RBX in base (llvm#134109)
The pseudo-instruction LCMPXCHG16B_SAVE_RBX is used when RBX serves as frame base pointer. At a very late stage it is then translated into a regular LCMPXCHG16B, preceded by copying the actual argument into RBX, and followed by restoring the register to the base pointer. However, in case the `cmpxchg` operates on a local variable, RBX might also be used as a base for the memory operand in frame finalization, and we've overwritten RBX with the input operand for `cmpxchg16b`. So we have to rewrite the memory operand base to use the saved value of RBX. Fixes llvm#119959. (cherry picked from commit 9e0ca57)
1 parent a8b5fe0 commit a0c8959

File tree

2 files changed

+46
-2
lines changed

2 files changed

+46
-2
lines changed

llvm/lib/Target/X86/X86ExpandPseudo.cpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -439,8 +439,18 @@ bool X86ExpandPseudo::expandMI(MachineBasicBlock &MBB,
439439
TII->copyPhysReg(MBB, MBBI, DL, X86::RBX, InArg.getReg(), false);
440440
// Create the actual instruction.
441441
MachineInstr *NewInstr = BuildMI(MBB, MBBI, DL, TII->get(X86::LCMPXCHG16B));
442-
// Copy the operands related to the address.
443-
for (unsigned Idx = 1; Idx < 6; ++Idx)
442+
// Copy the operands related to the address. If we access a frame variable,
443+
// we need to replace the RBX base with SaveRbx, as RBX has another value.
444+
const MachineOperand &Base = MBBI->getOperand(1);
445+
if (Base.getReg() == X86::RBX || Base.getReg() == X86::EBX)
446+
NewInstr->addOperand(MachineOperand::CreateReg(
447+
Base.getReg() == X86::RBX
448+
? SaveRbx
449+
: Register(TRI->getSubReg(SaveRbx, X86::sub_32bit)),
450+
/*IsDef=*/false));
451+
else
452+
NewInstr->addOperand(Base);
453+
for (unsigned Idx = 1 + 1; Idx < 1 + X86::AddrNumOperands; ++Idx)
444454
NewInstr->addOperand(MBBI->getOperand(Idx));
445455
// Finally, restore the value of RBX.
446456
TII->copyPhysReg(MBB, MBBI, DL, X86::RBX, SaveRbx,

llvm/test/CodeGen/X86/base-pointer-and-cmpxchg.ll

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,5 +49,39 @@ tail call void asm sideeffect "nop", "~{rax},~{rcx},~{rdx},~{rsi},~{rdi},~{rbp},
4949
store i32 %n, ptr %idx
5050
ret i1 %res
5151
}
52+
53+
; If we compare-and-exchange a frame variable, we additionally need to rewrite
54+
; the memory operand to use the SAVE_rbx instead of rbx, which already contains
55+
; the input operand.
56+
;
57+
; CHECK-LABEL: cmp_and_swap16_frame:
58+
; Check that we actually use rbx.
59+
; gnux32 use the 32bit variant of the registers.
60+
; USE_BASE_64: movq %rsp, %rbx
61+
; USE_BASE_32: movl %esp, %ebx
62+
; Here we drop the inline assembly because the frame pointer is used anyway. So
63+
; rbx is not spilled to the stack but goes into a (hopefully numbered) register.
64+
; USE_BASE: movq %rbx, [[SAVE_rbx:%r[0-9]+]]
65+
;
66+
; USE_BASE: movq {{[^ ]+}}, %rbx
67+
; The use of the frame variable expands to N(%rbx) or N(%ebx). But we've just
68+
; overwritten that with the input operand. We need to use SAVE_rbx instead.
69+
; USE_BASE_64-NEXT: cmpxchg16b {{[0-9]*}}([[SAVE_rbx]])
70+
; USE_BASE_32-NEXT: cmpxchg16b {{[0-9]*}}([[SAVE_rbx]]d)
71+
; USE_BASE-NEXT: movq [[SAVE_rbx]], %rbx
72+
;
73+
; DONT_USE_BASE-NOT: movq %rsp, %rbx
74+
; DONT_USE_BASE-NOT: movl %esp, %ebx
75+
; DONT_USE_BASE: cmpxchg
76+
define i1 @cmp_and_swap16_frame(i128 %a, i128 %b, i32 %n) {
77+
%local = alloca i128, align 16
78+
%dummy = alloca i32, i32 %n
79+
%cmp = cmpxchg ptr %local, i128 %a, i128 %b seq_cst seq_cst
80+
%res = extractvalue { i128, i1 } %cmp, 1
81+
%idx = getelementptr i32, ptr %dummy, i32 5
82+
store i32 %n, ptr %idx
83+
ret i1 %res
84+
}
85+
5286
!llvm.module.flags = !{!0}
5387
!0 = !{i32 2, !"override-stack-alignment", i32 32}

0 commit comments

Comments
 (0)