Matthew Fernandez via llvm-dev
2015-Oct-20 10:38 UTC
[llvm-dev] [compiler-rt] Undefined negation in float emulation functions
Hi,
I recently came across the following in __floatsidf in compiler-rt:
__floatsidf(int a) {
...
if (a < 0) {
...
a = -a;
In the case where a == INT_MIN, is this negation not undefined behaviour? AIUI
this function is used for software
emulation on targets that have no hardware floating point support. Perhaps there
is an in-built assumption that this
code is never called with INT_MIN, though I don't immediately see anything
to indicate this. Indeed there is a later
comment in this function that indicates INT_MIN is an anticipated input, but the
negation has already occurred by this
point.
I am not a floating point expert, so perhaps I am missing some subtlety here. If
so, apologies for the noise. The above
refers to r218935 and similar code is present in __floatsisf.
Thanks,
Matthew
Stephen Canon via llvm-dev
2015-Oct-20 13:15 UTC
[llvm-dev] [compiler-rt] Undefined negation in float emulation functions
Yup, this is UB. If you want to propose a patch, I would do something like the
following:
rep_t sign = 0;
unsigned int aAbs = a;
if (a < 0) {
sign = signBit;
aAbs = -aAbs;
}
// Now use aAbs instead of a.
– Steve
> On Oct 20, 2015, at 6:38 AM, Matthew Fernandez via llvm-dev <llvm-dev at
lists.llvm.org> wrote:
>
> Hi,
>
> I recently came across the following in __floatsidf in compiler-rt:
>
> __floatsidf(int a) {
> ...
> if (a < 0) {
> ...
> a = -a;
>
> In the case where a == INT_MIN, is this negation not undefined behaviour?
AIUI this function is used for software emulation on targets that have no
hardware floating point support. Perhaps there is an in-built assumption that
this code is never called with INT_MIN, though I don't immediately see
anything to indicate this. Indeed there is a later comment in this function that
indicates INT_MIN is an anticipated input, but the negation has already occurred
by this point.
>
> I am not a floating point expert, so perhaps I am missing some subtlety
here. If so, apologies for the noise. The above refers to r218935 and similar
code is present in __floatsisf.
>
> Thanks,
> Matthew
> _______________________________________________
> LLVM Developers mailing list
> llvm-dev at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
Matthew Fernandez via llvm-dev
2015-Oct-24 02:43 UTC
[llvm-dev] [compiler-rt] Undefined negation in float emulation functions
Thanks for the confirmation, Steve. Your suggestion looks good to me, but I
don't have an environment set up to build
the test suite so it may take me a little while to get back to you with a
validated patch.
A bit of creative grepping yields the following that also look problematic to
me:
compiler-rt/test/builtins/Unit/absvsi2_test.c: expected =
-expected;
compiler-rt/test/builtins/Unit/absvti2_test.c: expected =
-expected;
compiler-rt/test/builtins/Unit/absvdi2_test.c: expected =
-expected;
I confess I don't fully understand the way these tests are written. E.g.
compiler-rt/test/builtins/Unit/absvsi2_test.c:
int test__absvsi2(si_int a)
{
si_int x = __absvsi2(a);
si_int expected = a;
if (expected < 0)
expected = -expected;
if (x != expected || expected < 0)
printf("error in __absvsi2(0x%X) = %d, expected positive
%d\n",
a, x, expected);
return x != expected;
}
The printf suggests to me that the test should fail if `expected` is negative
(which seems perfectly reasonable), but
the return statement does not include this condition. I tried to explore this a
little, but it turns out calling
__absvisi2 with INT_MIN triggers compilerrt_abort(). Seems perfectly reasonable
as abs(INT_MIN) is documented to be
undefined, however the call to compilerrt_abort sits behind this check:
const int N = (int)(sizeof(si_int) * CHAR_BIT);
if (a == (1 << (N-1)))
compilerrt_abort();
The shift in this expression is done on a signed int (the literal "1")
and I believe shifting into the sign bit like
this is also UB.
Where do you suggest we go from here? My intended approach is (1) propose a
patch that avoids the signed negation in
__floatsidf and __floatsisf as you suggested, (2) leave test__absv.i2 as-is as
INT_MIN as an input is documented to be
undefined, and (3) propose a patch that rephrases the left shifts in __absv.i2
to avoid UB there. I don't want to cause
unnecessary headaches, so if there is a better way to go about this or if you
disagree with anything I've said please
let me know. And to think this was just supposed to be a quick afternoon
tinkering with LLVM for me ;)
On 21/10/15 00:15, Stephen Canon wrote:> Yup, this is UB. If you want to propose a patch, I would do something like
the following:
>
> rep_t sign = 0;
> unsigned int aAbs = a;
> if (a < 0) {
> sign = signBit;
> aAbs = -aAbs;
> }
> // Now use aAbs instead of a.
>
> – Steve
>
>> On Oct 20, 2015, at 6:38 AM, Matthew Fernandez via llvm-dev
<llvm-dev at lists.llvm.org> wrote:
>>
>> Hi,
>>
>> I recently came across the following in __floatsidf in compiler-rt:
>>
>> __floatsidf(int a) {
>> ...
>> if (a < 0) {
>> ...
>> a = -a;
>>
>> In the case where a == INT_MIN, is this negation not undefined
behaviour? AIUI this function is used for software emulation on targets that
have no hardware floating point support. Perhaps there is an in-built assumption
that this code is never called with INT_MIN, though I don't immediately see
anything to indicate this. Indeed there is a later comment in this function that
indicates INT_MIN is an anticipated input, but the negation has already occurred
by this point.
>>
>> I am not a floating point expert, so perhaps I am missing some subtlety
here. If so, apologies for the noise. The above refers to r218935 and similar
code is present in __floatsisf.
>>
>> Thanks,
>> Matthew
>> _______________________________________________
>> LLVM Developers mailing list
>> llvm-dev at lists.llvm.org
>> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
>
Apparently Analagous Threads
- [compiler-rt] Undefined negation in float emulation functions
- [compiler-rt] Undefined negation in float emulation functions
- [compiler-rt] Undefined negation in float emulation functions
- [LLVMdev] compiler-rt: Infinite loop/stack overflow in __modsi3()
- [OpenCL] Implicit arithmetic conversion of INT_MIN to int vector type