This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: RFA: handling of mode attribute
2009/9/27 Richard Guenther <richard.guenther@gmail.com>:
> On Sun, Sep 27, 2009 at 12:26 PM, Kai Tietz <ktietz70@googlemail.com> wrote:
>> 2009/9/27 Richard Guenther <richard.guenther@gmail.com>:
>>> On Sun, Sep 27, 2009 at 9:57 AM, Kai Tietz <ktietz70@googlemail.com> wrote:
>>>>
>>>> Hello Joseph,
>>>>
>>>> well the issue described in 32187 is related. I want to use base type
>>>> mode specifiers to have an ability to provide for mingw x64 target
>>>> __int128 type and also for 32-bit mingw targets the types __int8,
>>>> __int16, __int32, and __int64. I spoke here with Ian about this, as we
>>>> would have here also the possibility to extend C/C++ FE keywords, but
>>>> we both came to the opinion that it would be better to be able to
>>>> implement them as pre-defined macros. The patch I attached could be
>>>> used for the __float128 type, too.
>>>>
>>>> As the "mode" attribute can't be changed, I rewrote my patch to use
>>>> attribute "basetype_mode". Major difference between the "mode"
>>>> attribute is, that it always associate to the base type, not to the
>>>> current type declaration.
>>>> Additionally it does not support vector types.
>>>
>>> I'm not really convinced that this will work (nor do I think this is the
>>> best solution).
>>
>> Well, it seems to work as well (as the vector_size attribute works).
>> The best way for sure would be to have ability in C/C++ FE to specify
>> target specific types. But as the signed/unsigned/__complex__ checks
>> aren't designed for this, and builtin-types are based to RID_...
>> constants, it looks for me at the moment as the best way to go.
>> The same mechanism would solve also the issues about float DFmode
>> types, where some issues about the __complex__ extension are present,
>> as typedefs can't get additional base type attributes.
>>
>>> Try to at least conver more cases in your testcase, like for example
>>>
>>> ?const attr_int64 *p
>>>
>>> or
>>>
>>> ?unsigned attr_int64 * const p,
>>
>> Well, I can add const/volatile pointer things here to test-case, if
>> you think it is necessary. But I don't think that here something
>> special will happen, as vector types would have then the same issues
>> AFAICS.
>>
>>> I'd even suggest to run the compile torture with -Dint=__int32
>>>
>>> You only need the modes for types where you do not have a
>>> keyword specifier, right? ?Which means just TImode ints? ?Wouldn't it make
>>> sense to instead add new keywords to C that corresponds to that,
>>> like __long_long_long?
>>
>> Hmm, well. TImode was the initial point, but even to express __int8,
>> __int16, etc via this attribute can make sense here, as for example
>> this prevents checks in gcc related to real 'long long' types.
>
> __int8 should map to char, __int16 to short. ?I don't see the issue here.
> After all if the result should behave as a builtin type it better should be one.
>
> Richard.
>
So I ran c-torture by defining int as 'int __attribute__
((basetype_mode(SI)))'. While running it there were no special failure
by this (beside for those testcases using __attribute__ ((mode(XX)))
on a int type (what was to be expecting).
I extend the testcase to use some cases with const and volatile
keywords for integer using basetype_mode attribute.
Cheers,
Kai
--
| (\_/) This is Bunny. Copy and paste
| (='.'=) Bunny into your signature to help
| (")_(") him gain world domination
Index: gcc/gcc/c-common.c
===================================================================
--- gcc.orig/gcc/c-common.c 2009-09-27 09:25:32.396178000 +0200
+++ gcc/gcc/c-common.c 2009-09-27 09:26:57.668178200 +0200
@@ -499,6 +499,7 @@
static tree handle_constructor_attribute (tree *, tree, tree, int, bool *);
static tree handle_destructor_attribute (tree *, tree, tree, int, bool *);
static tree handle_mode_attribute (tree *, tree, tree, int, bool *);
+static tree handle_basetype_mode_attribute (tree *, tree, tree, int, bool *);
static tree handle_section_attribute (tree *, tree, tree, int, bool *);
static tree handle_aligned_attribute (tree *, tree, tree, int, bool *);
static tree handle_weak_attribute (tree *, tree, tree, int, bool *) ;
@@ -762,6 +763,8 @@
handle_destructor_attribute },
{ "mode", 1, 1, false, true, false,
handle_mode_attribute },
+ { "basetype_mode", 1, 1, false, true, false,
+ handle_basetype_mode_attribute },
{ "section", 1, 1, true, false, false,
handle_section_attribute },
{ "aligned", 0, 1, false, false, false,
@@ -6350,6 +6353,166 @@
return NULL_TREE;
}
+/* Handle a "basetype_mode" attribute; arguments as in
+ struct attribute_spec.handler.
+ Note: Difference to "mode" attribute is, that it
+ gets always associated to the base type. */
+
+static tree
+handle_basetype_mode_attribute (tree *node, tree name, tree args,
+ int ARG_UNUSED (flags),
+ bool *no_add_attrs)
+{
+ tree type = *node;
+ tree ident = TREE_VALUE (args);
+
+ while (POINTER_TYPE_P (type)
+ || TREE_CODE (type) == FUNCTION_TYPE
+ || TREE_CODE (type) == METHOD_TYPE
+ || TREE_CODE (type) == ARRAY_TYPE
+ || TREE_CODE (type) == OFFSET_TYPE)
+ type = TREE_TYPE (type);
+
+ *no_add_attrs = true;
+
+ if (TREE_CODE (ident) != IDENTIFIER_NODE)
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ else
+ {
+ int j;
+ const char *p = IDENTIFIER_POINTER (ident);
+ int len = strlen (p);
+ enum machine_mode mode = VOIDmode;
+ tree typefm;
+ bool valid_mode;
+
+ if (len > 4 && p[0] == '_' && p[1] == '_'
+ && p[len - 1] == '_' && p[len - 2] == '_')
+ {
+ char *newp = (char *) alloca (len - 1);
+
+ strcpy (newp, &p[2]);
+ newp[len - 4] = '\0';
+ p = newp;
+ }
+
+ /* Change this type to have a type with the specified mode.
+ First check for the special modes. */
+ if (!strcmp (p, "byte"))
+ mode = byte_mode;
+ else if (!strcmp (p, "word"))
+ mode = word_mode;
+ else if (!strcmp (p, "pointer"))
+ mode = ptr_mode;
+ else if (!strcmp (p, "libgcc_cmp_return"))
+ mode = targetm.libgcc_cmp_return_mode ();
+ else if (!strcmp (p, "libgcc_shift_count"))
+ mode = targetm.libgcc_shift_count_mode ();
+ else if (!strcmp (p, "unwind_word"))
+ mode = targetm.unwind_word_mode ();
+ else
+ for (j = 0; j < NUM_MACHINE_MODES; j++)
+ if (!strcmp (p, GET_MODE_NAME (j)))
+ {
+ mode = (enum machine_mode) j;
+ break;
+ }
+
+ if (mode == VOIDmode)
+ {
+ error ("unknown machine mode %qE", ident);
+ return NULL_TREE;
+ }
+
+ valid_mode = false;
+ switch (GET_MODE_CLASS (mode))
+ {
+ case MODE_INT:
+ case MODE_PARTIAL_INT:
+ case MODE_FLOAT:
+ case MODE_DECIMAL_FLOAT:
+ case MODE_FRACT:
+ case MODE_UFRACT:
+ case MODE_ACCUM:
+ case MODE_UACCUM:
+ valid_mode = targetm.scalar_mode_supported_p (mode);
+ break;
+
+ case MODE_COMPLEX_INT:
+ case MODE_COMPLEX_FLOAT:
+ valid_mode = targetm.scalar_mode_supported_p (GET_MODE_INNER (mode));
+ break;
+
+ default:
+ break;
+ }
+ if (!valid_mode)
+ {
+ error ("unable to emulate %qs", p);
+ return NULL_TREE;
+ }
+ /* For fixed-point modes, we need to test if the signness of type
+ and the machine mode are consistent. */
+ if (ALL_FIXED_POINT_MODE_P (mode)
+ && TYPE_UNSIGNED (type) != UNSIGNED_FIXED_POINT_MODE_P (mode))
+ {
+ error ("signness of type and machine mode %qs don't match", p);
+ return NULL_TREE;
+ }
+ /* For fixed-point modes, we need to pass saturating info. */
+ typefm = lang_hooks.types.type_for_mode (mode,
+ ALL_FIXED_POINT_MODE_P (mode) ? TYPE_SATURATING (type)
+ : TYPE_UNSIGNED (type));
+
+ if (typefm == NULL_TREE)
+ {
+ error ("no data type for mode %qs", p);
+ return NULL_TREE;
+ }
+ else if (TREE_CODE (type) == ENUMERAL_TYPE)
+ {
+ /* For enumeral types, copy the precision from the integer
+ type returned above. If not an INTEGER_TYPE, we can't use
+ this mode for this type. */
+ if (TREE_CODE (typefm) != INTEGER_TYPE)
+ {
+ error ("cannot use mode %qs for enumeral types", p);
+ return NULL_TREE;
+ }
+
+ if (flags & ATTR_FLAG_TYPE_IN_PLACE)
+ {
+ TYPE_PRECISION (type) = TYPE_PRECISION (typefm);
+ typefm = type;
+ }
+ else
+ {
+ /* We cannot build a type variant, as there's code that assumes
+ that TYPE_MAIN_VARIANT has the same mode. This includes the
+ debug generators. Instead, create a subrange type. This
+ results in all of the enumeral values being emitted only once
+ in the original, and the subtype gets them by reference. */
+ if (TYPE_UNSIGNED (type))
+ typefm = make_unsigned_type (TYPE_PRECISION (typefm));
+ else
+ typefm = make_signed_type (TYPE_PRECISION (typefm));
+ TREE_TYPE (typefm) = type;
+ }
+ }
+ else if (VECTOR_MODE_P (mode)
+ ? TREE_CODE (type) != TREE_CODE (TREE_TYPE (typefm))
+ : TREE_CODE (type) != TREE_CODE (typefm))
+ {
+ error ("mode %qs applied to inappropriate type", p);
+ return NULL_TREE;
+ }
+
+ *node = lang_hooks.types.reconstruct_complex_type (*node, typefm);
+ }
+
+ return NULL_TREE;
+}
+
/* Handle a "mode" attribute; arguments as in
struct attribute_spec.handler. */
Index: gcc/gcc/testsuite/gcc.c-torture/execute/attribute_mode.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ gcc/gcc/testsuite/gcc.c-torture/execute/attribute_mode.c 2009-09-27 13:36:34.105486300 +0200
@@ -0,0 +1,52 @@
+__extension__ typedef __SIZE_TYPE__ size_t;
+extern void abort (void);
+extern int memcmp (const void *, const void *, size_t);
+
+#define attr_int64 int __attribute__ ((basetype_mode(DI)))
+
+attr_int64
+foo (unsigned attr_int64 b)
+{
+ return ((attr_int64) b);
+}
+
+attr_int64
+foo2 (unsigned attr_int64 * const b)
+{
+ return (attr_int64) (*b);
+}
+
+int
+foo3 (const unsigned attr_int64 a, volatile const attr_int64 * const b)
+{
+ return (*b != a ? 0 : 1);
+}
+
+void
+bar (unsigned attr_int64 b[4])
+{
+ b[1]=0LL; b[0]=1LL; b[2]=2LL; b[3]=5LL;
+}
+
+unsigned int tab1[8] = {
+ 1, 0, 0, 0, 2, 0, 5, 0
+};
+
+int
+main ()
+{
+ unsigned attr_int64 a[4];
+ if (sizeof (a) != 32)
+ abort ();
+ if (foo (1ULL) != 1LL)
+ abort ();
+ bar (a);
+ if (memcmp (a, tab1, 32) != 0)
+ abort ();
+ if (foo2 (&a[0]) != 1LL)
+ abort ();
+ if (foo3 (2ULL, &a[2]) == 0)
+ abort ();
+ return 0;
+}
+
Index: gcc/gcc/doc/extend.texi
===================================================================
--- gcc.orig/gcc/doc/extend.texi 2009-09-27 09:25:32.401178000 +0200
+++ gcc/gcc/doc/extend.texi 2009-09-27 09:26:57.713178200 +0200
@@ -4002,6 +4002,23 @@
@samp{__word__} for the mode of a one-word integer, and @samp{pointer}
or @samp{__pointer__} for the mode used to represent pointers.
+@item basetype_mode (@var{mode})
+@cindex @code{basetype_mode} attribute
+This attribute specifies the base data type for the declaration
+---whichever type corresponds to the mode @var{mode}. This in effect
+lets you request an integer or floating point type according to its
+width.
+
+You may also specify a mode of @samp{byte} or @samp{__byte__} to
+indicate the mode corresponding to a one-byte integer, @samp{word} or
+@samp{__word__} for the mode of a one-word integer, and @samp{pointer}
+or @samp{__pointer__} for the mode used to represent pointers.
+
+Difference to @code{mode} attribute is, that it always gets associated
+to the base type, and not to the current type with modifiers. Additionally
+aren't vector modes allowed here. For vector modes, see @code{vector_size}
+attribute.
+
@item packed
@cindex @code{packed} attribute
The @code{packed} attribute specifies that a variable or structure field