[LLVMdev] Casting from float to unsigned char - incorrect output?

Jim Grosbach grosbach at apple.com
Mon Aug 6 13:04:23 PDT 2012


On Aug 6, 2012, at 12:43 PM, ryan baird <ryanrbaird at gmail.com> wrote:

> I am compiling the following code for the MIPS architecture: 
> 
> unsigned char trunc(float f) {
>         return (unsigned char) f;
> }
> 
> and it produces the following assembly (directives removed for convenience: 
> trunc:
>     trunc.w.s    $f0, $f12
>     mfc1    $2, $f0
>     jr    $ra
>     nop
> 
> However, this does not seem to produce the correct output for negative numbers. When I run the following code, I get -1 instead of 255 (which is produced by compiling natively with gcc).
> int trunc(float c);
> int main() {
>   printf("%d\n", trunc(-1.0));
> }

The prototype for trunc() here and it's definition above don't match. Dunno if that's related to the behavior you're seeing, but it's definitely a bug in the source code.

> 
> I am running the mips code on a PISA simulator (SimpleScalar's  Simple-Sim 3.0) instead of a MIPS IV simulator, so there is a little bit of translation occurring before I can simulate it; here is the revised code:
> trunc:
>     cvt.w.s    $f0, $f12
>     mfc1    $2, $f0
>     jr    $ra
>     nop
> the cvt.w.s function in PISA MIPS is rounding towards zero, so it should meet the specification for trunc.w.s in MIPS IV.
> 
> Here are the commands I used to compile test.c (with the trunc function in it):
> clang -emit-llvm -mfloat-abi=hard -ccc-host-triple mipsel-unknown-linux -ccc-clang-archs mipsel -O3 -S -o test_unopt.ll test.c
> opt -std-compile-opts test_unopt.ll -o test.ll
> llc -march=mipsel -mcpu=mips32 -float-abi=hard -relocation-model=static test.ll -o test.s
> 
> Here is the llvm intermediate representation:
> ; ModuleID = 'test_unopt.ll'
> target datalayout = "e-p:32:32:32-i1:8:8-i8:8:32-i16:16:32-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32"
> target triple = "mipsel-unknown-linux"
> 
> define zeroext i8 @trunc(float %f) nounwind readnone {
> entry:
>   %conv = fptoui float %f to i8
>   ret i8 %conv
> }
> 
> This is the assembly produced by another compiler; it is more complex, but it produces the expected output, matching with GCC: (directives removed for convenience)
> trunc:
>         mov.s   $f4,$f12
>         la      $2,L6
>         l.s     $f6,($2)
>         c.lt.s  $f12,$f6
>         bc1t    .L3
>         sub.s   $f0,$f12,$f6
>         cvt.w.s $f0,$f0
>         mfc1    $2,$f0
>         lui     $3,32768
>         addu    $3,$2,$3
>         j       .L4
> .L3:
>          cvt.w.s $f4,$f4
>          mfc1    $3,$f4
> .L4:
>         sll     $2,$3,24
>         srl     $2,$2,24
>         sll     $2,$2,24 
>         srl     $2,$2,24  
>         j       $31
> .data
> .align 4
> L6:
> .word 1325400064
> 
> Am I correct in my analysis that LLVM's assembly output is wrong?  Is there a way for me to get the correct output?
> 
> _______________________________________________
> LLVM Developers mailing list
> LLVMdev at cs.uiuc.edu         http://llvm.cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev




More information about the llvm-dev mailing list