diff mbox

pointer to integer conversion.

Message ID CABOHX+cxn+h+Jr8Z+JE0XBdbOQ6hBtHTUX=0j=LFYyHoq199vg@mail.gmail.com
State New
Headers show

Commit Message

Iain Buclaw Nov. 23, 2013, 9:48 a.m. UTC
Hi,

This is a one line patch to an unexpected behaviour noticed from ARM
and x86 when testing the D frontend.

---
import core.stdc.stdio;
import core.stdc.stdint;

void test(void* p)
{
    uint64_t pl = cast(uint64_t)p;
    uint64_t p2 = cast(uint64_t)cast(int)p;
    int tmp = cast(int)p;
    uint64_t p3 = cast(uint64_t)tmp;

    printf("%llx %llx %llx\n", pl, p2, p3);
}

void main()
{
    void* p = cast(void*)0xFFEECCAA;
    test(p);
}

------------------------------
Output is:
ffffffffffeeccaa ffffffffffeeccaa ffffffffffeeccaa

Expected:
ffeeccaa ffffffffffeeccaa ffffffffffeeccaa



Doing a quick conversion to C found that the same thing occurs with GCC too.

This is the comment associated with the change in the function.

/* Convert to an unsigned integer of the correct width first, and
from there widen/truncate to the required type.  Some targets support
the coexistence of multiple valid pointer sizes, so fetch the one we
need from the type.  */

Currently, GCC is converting the expression to a signed integer
instead of an unsigned one.  Does a test for the testsuite need to be
written for this?


Regards,
Iain.

Comments

Andreas Schwab Nov. 23, 2013, 10:46 a.m. UTC | #1
Iain Buclaw <ibuclaw@gdcproject.org> writes:

> Currently, GCC is converting the expression to a signed integer
> instead of an unsigned one.  Does a test for the testsuite need to be
> written for this?

The C standard makes this implementation-defined, and GCC defines it
like this (*Note (gcc) Arrays and pointers implementation::):

     A cast from pointer to integer discards most-significant bits if
     the pointer representation is larger than the integer type,
     sign-extends(1) if the pointer representation is smaller than the
     integer type, otherwise the bits are unchanged.
 ---------- Footnotes ----------

 (1) Future versions of GCC may zero-extend, or use a target-defined
`ptr_extend' pattern.  Do not rely on sign extension.

Andreas.
Iain Buclaw Nov. 23, 2013, 12:38 p.m. UTC | #2
On 23 November 2013 10:46, Andreas Schwab <schwab@linux-m68k.org> wrote:
> Iain Buclaw <ibuclaw@gdcproject.org> writes:
>
>> Currently, GCC is converting the expression to a signed integer
>> instead of an unsigned one.  Does a test for the testsuite need to be
>> written for this?
>
> The C standard makes this implementation-defined, and GCC defines it
> like this (*Note (gcc) Arrays and pointers implementation::):
>
>      A cast from pointer to integer discards most-significant bits if
>      the pointer representation is larger than the integer type,
>      sign-extends(1) if the pointer representation is smaller than the
>      integer type, otherwise the bits are unchanged.
>  ---------- Footnotes ----------
>
>  (1) Future versions of GCC may zero-extend, or use a target-defined
> `ptr_extend' pattern.  Do not rely on sign extension.
>
> Andreas.
>

OK, I've checked that document, and there's also a comment with it.
Apparently someone spotted this before.

@c ??? We've always claimed that pointers were unsigned entities.
@c Shouldn't we therefore be doing zero-extension?  If so, the bug
@c is in convert_to_integer, where we call type_for_size and request
@c a signed integral type.  On the other hand, it might be most useful
@c for the target if we extend according to POINTERS_EXTEND_UNSIGNED.


So where does this leave languages that say that pointer to integer
conversions are clearly defined?

In any case, the comment in convert_to_integer is - in my eyes - wrong.

Iain.
Ian Lance Taylor Nov. 23, 2013, 3:54 p.m. UTC | #3
On Sat, Nov 23, 2013 at 4:38 AM, Iain Buclaw <ibuclaw@gdcproject.org> wrote:
>
> OK, I've checked that document, and there's also a comment with it.
> Apparently someone spotted this before.
>
> @c ??? We've always claimed that pointers were unsigned entities.
> @c Shouldn't we therefore be doing zero-extension?  If so, the bug
> @c is in convert_to_integer, where we call type_for_size and request
> @c a signed integral type.  On the other hand, it might be most useful
> @c for the target if we extend according to POINTERS_EXTEND_UNSIGNED.
>
>
> So where does this leave languages that say that pointer to integer
> conversions are clearly defined?

The language frontend needs to do the right thing.  In this case it
looks like the right thing is to convert the integer to the language
equivalent of uintptr_t before converting it to a pointer type.

Other than possibly from the frontend function convert, a language
frontend really has no business calling convert_to_integer at all.
The function implements C semantics.  And the whole business of the
middle-end calling the frontend function convert is broken anyhow.

Ian
diff mbox

Patch

diff --git a/gcc/convert.c b/gcc/convert.c
index 4cf5001..262d080 100644
--- a/gcc/convert.c
+++ b/gcc/convert.c
@@ -547,7 +547,7 @@  convert_to_integer (tree type, tree expr)
 	 from the type.  */
       expr = fold_build1 (CONVERT_EXPR,
 			  lang_hooks.types.type_for_size
-			    (TYPE_PRECISION (intype), 0),
+			    (TYPE_PRECISION (intype), 1),
 			  expr);
       return fold_convert (type, expr);