Hi Segher,
+ pcvoid_type_node
+ = build_pointer_type (build_qualified_type (void_type_node,
+ TYPE_QUAL_CONST));
A const void? Interesting. You are building a pointer to a const void
here, not a const pointer to void. Is that what you wanted?
(And yes I do realise this is just moved, not new code).
Sorry, I misdocumented this below. I'll review and make sure this is
correct everywhere.
"const void" is meaningless, and maybe even invalid C. I think the code
is wrong, not (just) the documentation! This wants to be
void *const
but it is
const void *
as far as I can see?
As I said, this isn't new code, but it seems very wrong!
I had to go back and remember where this fits in. tl;dr: This is fine.
:-) More details...
"const void *" is used as part of the overloading machinery. It serves
to reduce the number of built-in functions that we need to register with
the front end. Consider the built-in function that accesses the "lvebx"
instruction. In rs6000-builtin-new.def, we define it this way:
pure vsc __builtin_altivec_lvebx (signed long, const void *);
LVEBX altivec_lvebx {ldvec}
Note that this is a "pure" function (no side effects), and we
contractually guarantee (through "const <type> *") that we will not
modify the data pointed to by the second argument. Normally you might
expect this to be "const char *" or similar. The purpose of the void
pointer is to allow multiple overloaded functions with different type
signatures to map to this built-in function, as follows.
In rs6000-overload.def, you'll see this as part of the overloading for
"vec_lde":
[VEC_LDE, vec_lde, __builtin_vec_lde]
vsc __builtin_vec_lde (signed long, const signed char *);
LVEBX LVEBX_SC
vuc __builtin_vec_lde (signed long, const unsigned char *);
LVEBX LVEBX_UC
The two references to LVEBX here indicate that those two overloads of
__builtin_vec_lde will map to __builtin_altivec_lvebx, above. These two
functions differ in their argument types and their return types.
The overload machinery will replace a call to one of the
__builtin_vec_lde functions as follows:
- Arguments to __builtin_vec_lde are cast to the types expected by
__builtin_altivec_lvebx
- __builtin_altivec_lvebx is called
- The return value from __builtin_altivec_lvebx is cast to the type
expected by the __builtin_vec_lde function.
For vector types, the altivec type semantics allow us to use
reinterpret-cast semantics to interpret any vector type as another
vector type. That handles the return type coercion in this case.
However, we don't have that freedom with pointer types. This is why the
built-in function is defined with a void * argument. Both "const signed
char *" and "const unsigned char *" can be legitimately cast to a "const
void *".
This isn't strictly necessary, but without such a trick, we would have
to have two different __builtin_altivec_lvebx functions (with different
names) to handle the different pointer types. Defining multiple
functions for each such situation is wasteful when defining functions
and when looking them up, and a naming scheme would be needed for
dealing with this.
This is the way the builtin structure has been working since the "dawn
of time," and I'm not proposing changes to that. I'm hopeful with the
new system that it is a little clearer what is going on, though, since
you can easily see the const void * arguments in the definitions.
Thanks,
Bill