Skip to content

Commit f615436

Browse files
Freax13phoebewang
authored andcommitted
fix stack probe lowering for x86_intrcc
The x86_intrcc calling convention will build two STACKALLOC_W_PROBING machine instructions if the function takes an error code. This is caused by an additional call to emitSPUpdate in llvm/lib/Target/X86/X86FrameLowering.cpp:1650. Previously only the first STACKALLOC_W_PROBING machine instruction was properly handled, the second one was simply ignored. This lead to miscompilations where the stack pointer wasn't properly updated (see rust-lang/rust#109918). This patch fixes this by handling all STACKALLOC_W_PROBING machine instructions. To be honest I don't quite understand why this didn't lead to more noticeable miscompilations previously. This is my first time contributing to LLVM. Reviewed By: pengfei Differential Revision: https://reviews.llvm.org/D150033
1 parent 74fd474 commit f615436

File tree

2 files changed

+30
-1
lines changed

2 files changed

+30
-1
lines changed

llvm/lib/Target/X86/X86FrameLowering.cpp

+13-1
Original file line numberDiff line numberDiff line change
@@ -1644,7 +1644,19 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF,
16441644
Fn.arg_size() == 2) {
16451645
StackSize += 8;
16461646
MFI.setStackSize(StackSize);
1647-
emitSPUpdate(MBB, MBBI, DL, -8, /*InEpilogue=*/false);
1647+
1648+
// Update the stack pointer by pushing a register. This is the instruction
1649+
// emitted that would be end up being emitted by a call to `emitSPUpdate`.
1650+
// Hard-coding the update to a push avoids emitting a second
1651+
// `STACKALLOC_W_PROBING` instruction in the save block: We know that stack
1652+
// probing isn't needed anyways for an 8-byte update.
1653+
// Pushing a register leaves us in a similar situation to a regular
1654+
// function call where we know that the address at (rsp-8) is writeable.
1655+
// That way we avoid any off-by-ones with stack probing for additional
1656+
// stack pointer updates later on.
1657+
BuildMI(MBB, MBBI, DL, TII.get(X86::PUSH64r))
1658+
.addReg(X86::RAX, RegState::Undef)
1659+
.setMIFlag(MachineInstr::FrameSetup);
16481660
}
16491661

16501662
// If this is x86-64 and the Red Zone is not disabled, if we are a leaf

llvm/test/CodeGen/X86/x86-64-intrcc.ll

+17
Original file line numberDiff line numberDiff line change
@@ -174,5 +174,22 @@ entry:
174174
ret void
175175
}
176176

177+
define x86_intrcc void @test_stack_allocation(ptr byval(%struct.interrupt_frame) %frame, i64 %err) #1 {
178+
; CHECK-LABEL: test_stack_allocation:
179+
; CHECK: # %bb.0: # %entry
180+
181+
;; Ensure that STACKALLOC_W_PROBING isn't emitted.
182+
; CHECK-NOT: # fixed size alloca with probing
183+
;; Ensure that stack space is allocated.
184+
; CHECK: subq $280, %rsp
185+
entry:
186+
%some_allocation = alloca i64
187+
;; Call a un-inlineable function to ensure the allocation isn't put in the red zone.
188+
call void @external_function(ptr %some_allocation)
189+
ret void
190+
}
191+
192+
declare void @external_function(ptr)
177193

178194
attributes #0 = { nounwind "frame-pointer"="all" }
195+
attributes #1 = { nounwind "probe-stack"="inline-asm" }

0 commit comments

Comments
 (0)