Hello everyone.
I’m not an expert neither in llvm nor in x86 nor in IEEE standard for floating point numbers, thus any of my following assumptions maybe wrong. If so, I will be grateful if you clarify me what’s goes wrong. But if my guesses are correct we possibly have a bug in fp arithmetics on x86.
I have the following ir:
@g = constant i64 1
define i32 @main() {
%gval = load i64* @g
%gvalfp = bitcast i64 %gval to double
%fmul = fmul double %gvalfp, -5.000000e-01
%fcmp = fcmp ueq double %fmul, -0.000000e+00
%ret = select i1 %fcmp, i32 1, i32 0
ret i32 %ret
}
And I expected that minimal positive denormalized double times -0.5 is equal to -0.0, so correct exit code is 1.
llvm-3.4.2 on x86 linux target produced the following assembly:
.file “fpfail.ll”
.section .rodata.cst8,“aM”,@progbits,8
.align 8
.LCPI0_0:
.quad -4620693217682128896 # double -0.5
.LCPI0_1:
.quad -9223372036854775808 # double -0
.text
.globl main
.align 16, 0x90
.type main,@function
main: # @main
.cfi_startproc
BB#0:
vmovsd g, %xmm0
vmulsd .LCPI0_0, %xmm0, %xmm0
vucomisd .LCPI0_1, %xmm0
sete %al
movzbl %al, %eax
ret
.Ltmp0:
.size main, .Ltmp0-main
.cfi_endproc
.type g,@object # @g
.section .rodata,“a”,@progbits
.globl g
.align 8
g:
.quad 1 # 0x1
.size g, 8
.section “.note.GNU-stack”,“”,@progbits
./llc -march=x86 fpfail.ll; g++ fpfail.s; ./a.out; echo $?
returns 1 as expected.
But llvm-3.5 (on the same target) lowers the previous ir using floating point instructions in the following way.
.text
.file “fpfail.ll”
.section .rodata.cst4,“aM”,@progbits,4
.align 4
.LCPI0_0:
.long 3204448256 # float -0.5
.text
.globl main
.align 16, 0x90
.type main,@function
main: # @main
.cfi_startproc
BB#0:
fldl g
fmuls .LCPI0_0
fldz
fchs
fxch %st(1)
fucompp
fnstsw %ax
kill: AX AX EAX
kill: AH AH EAX
sahf
sete %al
movzbl %al, %eax
retl
.Ltmp0:
.size main, .Ltmp0-main
.cfi_endproc
.type g,@object # @g
.section .rodata,“a”,@progbits
.globl g
.align 8
g:
.quad 1 # 0x1
.size g, 8
.section “.note.GNU-stack”,“”,@progbits
First, it doesn’t assemble with g++ (4.8):
fpfail.s:26: Error: invalid instruction suffix for `ret’
I downloaded Intel manual and haven’t found any mention of retl instruction, so I manually exchanged it with ret and reassemble:
g++ fpfail.s; ./a.out; echo $?
The exit code is 0. This is correct for Intel 80-bit floats but wrong for doubles. What am I do wrong or this is actually a bug or even worse – correct behavior?