Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cast from f64 to f32 not working with latest nightly on Windows #13429

Closed
Overv opened this issue Apr 9, 2014 · 9 comments · Fixed by #17776
Closed

Cast from f64 to f32 not working with latest nightly on Windows #13429

Overv opened this issue Apr 9, 2014 · 9 comments · Fixed by #17776
Labels
A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. P-medium Medium priority

Comments

@Overv
Copy link

Overv commented Apr 9, 2014

I'm compiling the following program with the latest nightly binary for Windows (with gcc 4.7.2):

fn main() {
    let a = 3.14;
    let b = a as f32;
    println!("{:?}", b);
}

This prints 126443840048f32 instead of 3.14f32.

If I change the code to the following, it does work as expected:

fn main() {
    let a = 3.14;
    let b: f32 = a;
    println!("{:?}", b);
}
@alexcrichton
Copy link
Member

Hm, something odd is going on here.

If I break on the println statement in gdb, a has value 3.14, while b has value 1.26e11 (what's printed). Additionally, when compiled with optimizations this works as expected.

Looking at the binary, this sequence of instructions happens for let a and let b

mov $0x40091eb8, 0x5c(%esp)
mov $0x51eb851f, 0x58(%esp)
mov $0x40091eb8, 0x58(%esp)
mov $0x51eb851f, 0x54(%esp)

Note the overlapping stores here (both storing into 0x58(%esp)). Additionally, if the address of &b is interpreted as a double, the value is 3.14.

I suspect an LLVM bug here...

@brson brson mentioned this issue Aug 12, 2014
33 tasks
@nikomatsakis
Copy link
Contributor

It'd be interesting to see what clang on windows does.

@pnkfelix
Copy link
Member

Probably just-a-bug. Probably worth investigating. Probably not worth blocking the release, though.

@pnkfelix
Copy link
Member

P-high, not 1.0 milestone.

@luqmana
Copy link
Member

luqmana commented Aug 28, 2014

So I was able to reduce it to this IR:

; ModuleID = 'bad-float-cast.rs'
target datalayout = "e-p:32:32-i64:64-f80:32-n8:16:32"
target triple = "i686-pc-windows-gnu"

%str_slice = type { i8*, i32 }

@str147 = internal constant [4 x i8] c"%f\0A\00"

declare i32 @printf(i8*, double %f) unnamed_addr

; Function Attrs: uwtable
define internal void @print_double(double %f) unnamed_addr {
entry-block:
  %0 = getelementptr inbounds [4 x i8]* @str147, i32 0, i32 0
  call i32 @printf(i8* %0, double %f)
  ret void
}

define i32 @main(i32, i8**) unnamed_addr {
entry-block:
  %a = alloca double
  %b = alloca float
  store double 3.140000e+00, double* %a
  %2 = load double* %a
  %3 = fptrunc double %2 to float
  store float %3, float* %b
  %4 = load float* %b
  %5 = fpext float %4 to double
  call void @print_double(double %5)
  ret i32 0
}

Running this through llc (from rust's llvm build) first I get the wrong behaviour:

> % llc.exe bad-float-cast.ll && clang bad-float-cast.s -o a.exe && ./a.exe
126443839488.000000

But notice if I feed the IR to clang directly instead:

> % clang bad-float-cast.ll -o a.exe && ./a.exe
warning: overriding the module target triple with i686-w64-windows-gnu
1 warning generated.
3.140000

So, I'm pretty sure this is an LLVM bug and it's not present in whatever version my clang was built with:

> %  clang -v
clang version 3.5.0 (C:/repo/mingw-w64-clang-svn/clang e6ff2fc8ac80ce4441d1a7f1ddd9f0964ed2ba1e) (C:/repo/mingw-w64-clang-svn/llvm c09746dc9ced3d21b0bfd9ac308ef8c06832808e)
Target: i686-w64-windows-gnu
Thread model: posix

@luqmana
Copy link
Member

luqmana commented Aug 28, 2014

This is also not windows specific, I was able to reproduce on both linux and mac.

@luqmana luqmana removed the A-windows label Aug 28, 2014
@luqmana
Copy link
Member

luqmana commented Aug 29, 2014

I bisected LLVM to find the offending commit: llvm-mirror/llvm@6bb00df but I don't think this caused it so much as just exposed a bug. After that commit, it'd no longer try to autodetect the cpu features supported. If you manually enable sse2 with -C target-feature="+sse2" it works:

-> % rustc bad-float-cast.rs --target=i686-apple-darwin -C target-feature="+sse2"
-> % ./bad-float-cast
3.14

-> % rustc bad-float-cast.rs --target=i686-apple-darwin
-> % ./bad-float-cast
126443840048

@luqmana
Copy link
Member

luqmana commented Aug 29, 2014

As for why LLVM is generating bad code in the non-sse case, I've no idea. A small test case to show the bad asm:

; ModuleID = 'bad-float-cast.rs'
target triple = "i686-unknown-linux-gnu"

define void @bar() unnamed_addr {
entry-block:
  %a = alloca double
  %b = alloca float

  store double 3.140000e+00, double* %a
  %0 = load double* %a

  %1 = fptrunc double %0 to float

  store float %1, float* %b

  ret void
}

without SSE:

    .text
    .file   "test.ll"
    .globl  bar
    .align  16, 0x90
    .type   bar,@function
bar:                                    # @bar
    .cfi_startproc
# BB#0:                                 # %entry-block
    subl    $20, %esp
.Ltmp0:
    .cfi_def_cfa_offset 24
    movl    $1074339512, 12(%esp)   # imm = 0x40091EB8
    movl    $1374389535, 8(%esp)    # imm = 0x51EB851F  0x40091EB851EB851F (double) 3.14
    movl    $1074339512, 8(%esp)    # imm = 0x40091EB8
    movl    $1374389535, 4(%esp)    # imm = 0x51EB851F
    addl    $20, %esp
    retl
.Ltmp1:
    .size   bar, .Ltmp1-bar
    .cfi_endproc


    .section    ".note.GNU-stack","",@progbits

With sse2:

    .text
    .file   "test.ll"
    .globl  bar
    .align  16, 0x90
    .type   bar,@function
bar:                                    # @bar
    .cfi_startproc
# BB#0:                                 # %entry-block
    subl    $20, %esp
.Ltmp0:
    .cfi_def_cfa_offset 24
    movl    $1074339512, 12(%esp)   # imm = 0x40091EB8
    movl    $1374389535, 8(%esp)    # imm = 0x51EB851F 0x40091EB851EB851F (double) 3.14
    movl    $1078523331, 4(%esp)    # imm = 0x4048F5C3  0x4048F5C3 (float) 3.14
    addl    $20, %esp
    retl
.Ltmp1:
    .size   bar, .Ltmp1-bar
    .cfi_endproc


    .section    ".note.GNU-stack","",@progbits

@luqmana
Copy link
Member

luqmana commented Aug 29, 2014

Fix submitted upstream: http://reviews.llvm.org/D5125

@luqmana luqmana added the A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. label Sep 7, 2014
@luqmana luqmana mentioned this issue Oct 4, 2014
bors added a commit that referenced this issue Oct 5, 2014
Update our LLVM snapshot to master (as of ~ Wed Oct 1 18:49:58 2014 +0000). 

Since my patches have landed upstream this fixes #13429 and #7298.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. P-medium Medium priority
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants