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>