This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
Endianess attribute
- From: Paul Chavent <paul dot chavent at fnac dot net>
- To: gcc at gcc dot gnu dot org
- Date: Thu, 02 Jul 2009 12:02:29 +0200
- Subject: Endianess attribute
Hi.
I already have posted about the endianess attribute (http://gcc.gnu.org/ml/gcc/2008-11/threads.html#00146).
For some year, i really need this feature on c projects.
Today i would like to go inside the internals of gcc, and i would like to implement this feature as an exercise.
You already prevent me that it would be a hard task (aliasing, etc.), but i would like to begin with basic specs.
The spec could be :
- add an attribute (this description could change to be compatible with existing ones (diabdata for example))
__attribute__ ((endian("big")))
__attribute__ ((endian("lil")))
- this attribute only apply to ints
- this attribute only apply to variables declaration
- a pointer to this variable don't inherit the attribute (this behavior could change later, i don't know...)
- the test case is
uint32_t x __attribute__ ((endian("big")));
uint32_t * ptr_x = x;
x = 0xDEADBEEF
if(plf_is_little)
{
assert((*ptr_x == 0xEFBEADDE));
}
else if(plf_is_big)
{
assert((*ptr_x == 0xDEADBEEF));
}
My first work is the patch below.
So my questions to the mailing list are :
- is it a good starting point ?
- how can i get the endianess of the target ?
Thank for your help and suggestion.
8<------------------------------------------------------------------------
diff -abBruN gcc-4.4.0.orig/gcc/c-common.c gcc-4.4.0.mod/gcc/c-common.c
--- gcc-4.4.0.orig/gcc/c-common.c 2009-03-30 19:42:27.000000000 +0200
+++ gcc-4.4.0.mod/gcc/c-common.c 2009-07-02 11:10:28.000000000 +0200
@@ -522,6 +522,7 @@
static bool check_case_bounds (tree, tree, tree *, tree *);
static tree handle_packed_attribute (tree *, tree, tree, int, bool *);
+static tree handle_endian_attribute (tree *, tree, tree, int, bool *);
static tree handle_nocommon_attribute (tree *, tree, tree, int, bool *);
static tree handle_common_attribute (tree *, tree, tree, int, bool *);
static tree handle_noreturn_attribute (tree *, tree, tree, int, bool *);
@@ -761,6 +762,8 @@
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
{ "packed", 0, 0, false, false, false,
handle_packed_attribute },
+ { "endian", 1, 1, false, false, false,
+ handle_endian_attribute },
{ "nocommon", 0, 0, true, false, false,
handle_nocommon_attribute },
{ "common", 0, 0, true, false, false,
@@ -5155,6 +5158,58 @@
return NULL_TREE;
}
+/* Handle an "endian" attribute; arguments as in
+ struct attribute_spec.handler.
+ IDENTIFIER_POINTER (name) gives "endian"
+ TREE_CODE (arg) should be a STRING_CST
+*/
+
+static tree
+handle_endian_attribute (tree *node, tree name, tree args,
+ int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+ tree arg = TREE_VALUE (args);
+
+ if (TREE_CODE (arg) != STRING_CST)
+ {
+ error ("argument of %qE attribute should be a string\n", name);
+ }
+ else if (TREE_CODE (*node) != FIELD_DECL &&
+ TREE_CODE (*node) != VAR_DECL &&
+ TREE_CODE (*node) != TYPE_DECL)
+ {
+ error ("%qE only support FIELD_DECL, VAR_DECL and TYPE_DECL\n", name);
+ }
+ else
+ {
+ if (!strcmp (TREE_STRING_POINTER (arg), "little"))
+ {
+ if(TARGET_BIG_ENDIAN)
+ {
+ DECL_SWAP(*node) = 1;
+ debug_tree(*node);
+ }
+ }
+ else if (!strcmp (TREE_STRING_POINTER (arg), "big"))
+ {
+ if(TARGET_LITTLE_ENDIAN)
+ {
+ DECL_SWAP(*node) = 1;
+ debug_tree(*node);
+ }
+ }
+ else
+ {
+ error ("argument of %qE attribute should be 'little' or 'big'\n", name);
+ *no_add_attrs = true;
+ }
+ }
+
+ *no_add_attrs = true;
+
+ return NULL_TREE;
+}
+
/* Handle a "nocommon" attribute; arguments as in
struct attribute_spec.handler. */
diff -abBruN gcc-4.4.0.orig/gcc/tree.h gcc-4.4.0.mod/gcc/tree.h
--- gcc-4.4.0.orig/gcc/tree.h 2009-03-23 17:29:33.000000000 +0100
+++ gcc-4.4.0.mod/gcc/tree.h 2009-07-02 11:10:28.000000000 +0200
@@ -2721,13 +2721,15 @@
/* In FIELD_DECL, this is DECL_NONADDRESSABLE_P
In VAR_DECL and PARM_DECL, this is DECL_HAS_VALUE_EXPR. */
unsigned decl_flag_3 : 1;
+ /* In FIELD_DECL, VAR_DECL and TYPE_DECL this is DECL_SWAP. */
+ unsigned decl_flag_4 : 1;
/* Logically, these two would go in a theoretical base shared by var and
parm decl. */
unsigned gimple_reg_flag : 1;
/* In a DECL with pointer type, set if no TBAA should be done. */
unsigned no_tbaa_flag : 1;
/* Padding so that 'align' can be on a 32-bit boundary. */
- unsigned decl_common_unused : 2;
+ unsigned decl_common_unused : 1;
unsigned int align : 24;
/* DECL_OFFSET_ALIGN, used only for FIELD_DECLs. */
@@ -2854,6 +2856,10 @@
#define DECL_NONADDRESSABLE_P(NODE) \
(FIELD_DECL_CHECK (NODE)->decl_common.decl_flag_3)
+/* In a FIELD_DECL, indicates this field should be swapped. */
+#define DECL_SWAP(NODE) \
+ (TREE_CHECK3 (NODE, FIELD_DECL, VAR_DECL, TYPE_DECL)->decl_common.decl_flag_4)
+
struct tree_field_decl GTY(())
{
struct tree_decl_common common;
8<------------------------------------------------------------------------