ryan baird
2012-Aug-06 19:43 UTC
[LLVMdev] Casting from float to unsigned char - incorrect output?
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)); } 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? -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20120806/50365ec6/attachment.html>
Eli Friedman
2012-Aug-06 20:03 UTC
[LLVMdev] Casting from float to unsigned char - incorrect output?
On Mon, 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)); > }That code has undefined behavior; see 6.3.1.4p1 in C99 -Eli
Jim Grosbach
2012-Aug-06 20:04 UTC
[LLVMdev] Casting from float to unsigned char - incorrect output?
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
ryan baird
2012-Aug-06 20:28 UTC
[LLVMdev] Casting from float to unsigned char - incorrect output?
> > I didn't realize the code was undefined, I'll let my professor know; but > for code comparison purposes we're still seeking advice on producing the > output that matches the other compilers (even if it involves doing a > translation on the .ll file or additional translation to the produced > assembly). We can't fairly compare the code if it doesn't do the same > thing. This bug came up in susan from the mibench test suite at the end of > setup_brightness_lut where it casts float temp to an unsigned char. I > don't think we can include the results in our report if we change the tests. > > Even though the behavior is undefined, it doesn't make sense to me that a > function that returns an unsigned char would ever return a 32 bit -1, > because that value does not fit the functions return type. > > > On Mon, Aug 6, 2012 at 2:03 PM, Eli Friedman <eli.friedman at gmail.com>wrote: > >> On Mon, 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)); >> > } >> >> That code has undefined behavior; see 6.3.1.4p1 in C99 >> >> -Eli >> > >-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20120806/a78459c6/attachment.html>
Richard Smith
2012-Aug-06 21:33 UTC
[LLVMdev] Casting from float to unsigned char - incorrect output?
This should work if your float is between INT_MIN and INT_MAX: unsigned char trunc(float f) { return (unsigned char)(int)f; } int main() { printf("%d\n", trunc(-1.0)); } For this, Clang produces: trunc: trunc.w.s $f0, $f12 mfc1 $2, $f0 andi $2, $2, 255 jr $ra nop On Mon, Aug 6, 2012 at 1:28 PM, ryan baird <ryanrbaird at gmail.com> wrote:> I didn't realize the code was undefined, I'll let my professor know; but >> for code comparison purposes we're still seeking advice on producing the >> output that matches the other compilers (even if it involves doing a >> translation on the .ll file or additional translation to the produced >> assembly). We can't fairly compare the code if it doesn't do the same >> thing. This bug came up in susan from the mibench test suite at the end of >> setup_brightness_lut where it casts float temp to an unsigned char. I >> don't think we can include the results in our report if we change the tests. >> >> Even though the behavior is undefined, it doesn't make sense to me that a >> function that returns an unsigned char would ever return a 32 bit -1, >> because that value does not fit the functions return type. >> >> >> On Mon, Aug 6, 2012 at 2:03 PM, Eli Friedman <eli.friedman at gmail.com>wrote: >> >>> On Mon, 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)); >>> > } >>> >>> That code has undefined behavior; see 6.3.1.4p1 in C99 >>> >>> -Eli >>> >> >> > > _______________________________________________ > LLVM Developers mailing list > LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev > >-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20120806/22b2f363/attachment.html>