Commit a522972b by Jim Stichnoth

Subzero: Always be sure x87 FP stack is emptied after a call.

In x86-32, floating point values are returned to the caller on the top of the x87 floating point stack. The caller is required to remove it from the x87 FP stack, e.g. via the fstp instruction. This must be done even when the return value is not actually used anywhere else in the function, in which case O2 is likely to want to dead-code eliminate the fstp instruction. We enforce this by adding a fake use of the fstp destination. BUG= none R=jvoung@chromium.org Review URL: https://codereview.chromium.org/563303003
parent 1eb3a55d
......@@ -1900,9 +1900,12 @@ void TargetX8632::lowerCall(const InstCall *Instr) {
} else if (Dest->getType() == IceType_f32 || Dest->getType() == IceType_f64) {
// Special treatment for an FP function which returns its result in
// st(0).
_fstp(Dest);
// If Dest ends up being a physical xmm register, the fstp emit code
// will route st(0) through a temporary stack slot.
_fstp(Dest);
// Create a fake use of Dest in case it actually isn't used,
// because st(0) still needs to be popped.
Context.insert(InstFakeUse::create(Func, Dest));
}
}
......
; Test that for calls returning a floating-point value, the calling
; ABI with respect to the x87 floating point stack is honored. In
; particular, the top-of-stack must be popped regardless of whether
; its value is used.
; RUN: %llvm2ice -O2 --verbose none %s \
; RUN: | llvm-mc -triple=i686-none-nacl -x86-asm-syntax=intel -filetype=obj \
; RUN: | llvm-objdump -d --symbolize -x86-asm-syntax=intel - | FileCheck %s
; RUN: %llvm2ice -Om1 --verbose none %s \
; RUN: | llvm-mc -triple=i686-none-nacl -x86-asm-syntax=intel -filetype=obj \
; RUN: | llvm-objdump -d --symbolize -x86-asm-syntax=intel - | FileCheck %s
; RUN: %llvm2ice --verbose none %s | FileCheck --check-prefix=ERRORS %s
; RUN: %llvm2iceinsts %s | %szdiff %s | FileCheck --check-prefix=DUMP %s
; RUN: %llvm2iceinsts --pnacl %s | %szdiff %s \
; RUN: | FileCheck --check-prefix=DUMP %s
define float @dummy() {
entry:
ret float 0.000000e+00
}
; CHECK-LABEL: dummy
; The call is ignored, but the top of the FP stack still needs to be
; popped.
define i32 @ignored_fp_call() {
entry:
%ignored = call float @dummy()
ret i32 0
}
; CHECK-LABEL: ignored_fp_call
; CHECK: call dummy
; CHECK: fstp
; The top of the FP stack is popped and subsequently used.
define i32 @converted_fp_call() {
entry:
%fp = call float @dummy()
%ret = fptosi float %fp to i32
ret i32 %ret
}
; CHECK-LABEL: converted_fp_call
; CHECK: call dummy
; CHECK: fstp
; CHECK: cvttss2si
; The top of the FP stack is ultimately passed through as the return
; value. Note: the translator could optimized by not popping and
; re-pushing, in which case the test would need to be changed.
define float @returned_fp_call() {
entry:
%fp = call float @dummy()
ret float %fp
}
; CHECK-LABEL: returned_fp_call
; CHECK: call dummy
; CHECK: fstp
; CHECK: fld
; ERRORS-NOT: ICE translation error
; DUMP-NOT: SZ
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment