On Wed, Oct 3, 2012 at 12:07 AM, DJ Delorie <d...@redhat.com> wrote: > > Here's my current patch for the bitfield reversal feature I've been > working on for a while, with an RX-specific pragma to apply it > "globally". Could someone please review this? It would be nice > to get it in before stage1 closes again...
ChangeLog missing, new functions need a toplevel comment documenting function, argument and return value as per coding conventions. Richard. > > Index: gcc/doc/extend.texi > =================================================================== > --- gcc/doc/extend.texi (revision 192009) > +++ gcc/doc/extend.texi (working copy) > @@ -5427,12 +5427,74 @@ Note that the type visibility is applied > associated with the class (vtable, typeinfo node, etc.). In > particular, if a class is thrown as an exception in one shared object > and caught in another, the class must have default visibility. > Otherwise the two shared objects will be unable to use the same > typeinfo node and exception handling will break. > > +@item bit_order > +Normally, GCC allocates bitfields from either the least significant or > +most significant bit in the underlying type, such that bitfields > +happen to be allocated from lowest address to highest address. > +Specifically, big-endian targets allocate the MSB first, where > +little-endian targets allocate the LSB first. The @code{bit_order} > +attribute overrides this default, allowing you to force allocation to > +be MSB-first, LSB-first, or the opposite of whatever gcc defaults to. The > +@code{bit_order} attribute takes an optional argument: > + > +@table @code > + > +@item native > +This is the default, and also the mode when no argument is given. GCC > +allocates LSB-first on little endian targets, and MSB-first on big > +endian targets. > + > +@item swapped > +Bitfield allocation is the opposite of @code{native}. > + > +@item lsb > +Bits are allocated LSB-first. > + > +@item msb > +Bits are allocated MSB-first. > + > +@end table > + > +A short example demonstrates bitfield allocation: > + > +@example > +struct __attribute__((bit_order(msb))) @{ > + char a:3; > + char b:3; > +@} foo = @{ 3, 5 @}; > +@end example > + > +With LSB-first allocation, @code{foo.a} will be in the 3 least > +significant bits (mask 0x07) and @code{foo.b} will be in the next 3 > +bits (mask 0x38). With MSB-first allocation, @code{foo.a} will be in > +the 3 most significant bits (mask 0xE0) and @code{foo.b} will be in > +the next 3 bits (mask 0x1C). > + > +Note that it is entirely up to the programmer to define bitfields that > +make sense when swapped. Consider: > + > +@example > +struct __attribute__((bit_order(msb))) @{ > + short a:7; > + char b:6; > +@} foo = @{ 3, 5 @}; > +@end example > + > +On some targets, or if the struct is @code{packed}, GCC may only use > +one byte of storage for A despite it being a @code{short} type. > +Swapping the bit order of A would cause it to overlap B. Worse, the > +bitfield for B may span bytes, so ``swapping'' would no longer be > +defined as there is no ``char'' to swap within. To avoid such > +problems, the programmer should either fully-define each underlying > +type, or ensure that their target's ABI allocates enough space for > +each underlying type regardless of how much of it is used. > + > @end table > > To specify multiple attributes, separate them by commas within the > double parentheses: for example, @samp{__attribute__ ((aligned (16), > packed))}. > > Index: gcc/c-family/c-common.c > =================================================================== > --- gcc/c-family/c-common.c (revision 192009) > +++ gcc/c-family/c-common.c (working copy) > @@ -310,12 +310,13 @@ struct visibility_flags visibility_optio > > static tree c_fully_fold_internal (tree expr, bool, bool *, bool *); > static tree check_case_value (tree); > static bool check_case_bounds (tree, tree, tree *, tree *); > > static tree handle_packed_attribute (tree *, tree, tree, int, bool *); > +static tree handle_bitorder_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 *); > static tree handle_hot_attribute (tree *, tree, tree, int, bool *); > static tree handle_cold_attribute (tree *, tree, tree, int, bool *); > static tree handle_noinline_attribute (tree *, tree, tree, int, bool *); > @@ -601,12 +602,14 @@ const unsigned int num_c_common_reswords > const struct attribute_spec c_common_attribute_table[] = > { > /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler, > affects_type_identity } */ > { "packed", 0, 0, false, false, false, > handle_packed_attribute , false}, > + { "bit_order", 0, 1, false, true, false, > + handle_bitorder_attribute , false}, > { "nocommon", 0, 0, true, false, false, > handle_nocommon_attribute, false}, > { "common", 0, 0, true, false, false, > handle_common_attribute, false }, > /* FIXME: logically, noreturn attributes should be listed as > "false, true, true" and apply to function types. But implementing this > @@ -6237,12 +6240,42 @@ handle_packed_attribute (tree *node, tre > *no_add_attrs = true; > } > > return NULL_TREE; > } > > +/* Handle a "bit_order" attribute; arguments as in > + struct attribute_spec.handler. */ > + > +static tree > +handle_bitorder_attribute (tree *ARG_UNUSED (node), tree ARG_UNUSED (name), > + tree ARG_UNUSED (args), > + int ARG_UNUSED (flags), bool *no_add_attrs) > +{ > + tree bmode; > + const char *bname; > + > + /* Allow no arguments to mean "native". */ > + if (args == NULL_TREE) > + return NULL_TREE; > + > + bmode = TREE_VALUE (args); > + > + bname = IDENTIFIER_POINTER (bmode); > + if (strcmp (bname, "msb") > + && strcmp (bname, "lsb") > + && strcmp (bname, "swapped") > + && strcmp (bname, "native")) > + { > + error ("%qE is not a valid bit_order - use lsb, msb, native, or > swapped", bmode); > + *no_add_attrs = true; > + } > + > + return NULL_TREE; > +} > + > /* Handle a "nocommon" attribute; arguments as in > struct attribute_spec.handler. */ > > static tree > handle_nocommon_attribute (tree *node, tree name, > tree ARG_UNUSED (args), > Index: gcc/stor-layout.c > =================================================================== > --- gcc/stor-layout.c (revision 192009) > +++ gcc/stor-layout.c (working copy) > @@ -1738,12 +1738,92 @@ finalize_type_size (tree type) > TYPE_ALIGN (variant) = align; > TYPE_USER_ALIGN (variant) = user_align; > SET_TYPE_MODE (variant, mode); > } > } > } > + > +static void > +reverse_bitfield_layout (record_layout_info rli) > +{ > + tree field, oldtype, oldbtype; > + > + for (field = TYPE_FIELDS (rli->t); field; field = TREE_CHAIN (field)) > + { > + tree type = TREE_TYPE (field); > + tree bit, byte, bmod, byte_offset; > + > + if (TREE_CODE (field) != FIELD_DECL) > + continue; > + if (TREE_CODE (field) == ERROR_MARK || TREE_CODE (type) == ERROR_MARK) > + return; > + > + oldtype = TREE_TYPE (DECL_FIELD_BIT_OFFSET (field)); > + oldbtype = TREE_TYPE (DECL_FIELD_OFFSET (field)); > + > + bit = DECL_FIELD_BIT_OFFSET (field); > + byte = DECL_FIELD_OFFSET (field); > + > + /* Sometimes, the next field might be in the next type-size > + container. We have to calculate which *container* it's in, > + and swap within that container. Example: { char a:5; char > + b:5; } will put B in the next char, but the byte/bit numbers > + might show that as "bit 8 of byte 0". */ > + bmod = size_binop (FLOOR_DIV_EXPR, bit, TYPE_SIZE (type)); > + bmod = size_binop (MULT_EXPR, bmod, TYPE_SIZE (type)); > + bit = size_binop (MINUS_EXPR, bit, bmod); > + > + byte_offset = size_binop (FLOOR_DIV_EXPR, bmod, bitsize_int > (BITS_PER_UNIT)); > + byte_offset = fold_convert (sizetype, byte_offset); > + byte = size_binop (PLUS_EXPR, byte, byte_offset); > + > + DECL_FIELD_BIT_OFFSET (field) > + = size_binop (MINUS_EXPR, > + size_binop (MINUS_EXPR, TYPE_SIZE (type), > + DECL_SIZE (field)), > + bit); > + DECL_FIELD_OFFSET (field) = byte; > + > + TREE_TYPE (DECL_FIELD_BIT_OFFSET (field)) = oldtype; > + TREE_TYPE (DECL_FIELD_OFFSET (field)) = oldbtype; > + } > +} > + > +static int > +reverse_bitfields_p (record_layout_info rli) > +{ > + tree st, arg; > + const char *mode; > + > + st = rli->t; > + > + arg = lookup_attribute ("bit_order", TYPE_ATTRIBUTES (st)); > + > + if (!arg) > + return 0; > + arg = TREE_VALUE (TREE_VALUE (arg)); > + if (!arg) > + return 0; > + > + mode = IDENTIFIER_POINTER (arg); > + > + if (strcmp (mode, "swapped") == 0) > + return 1; > + if (BYTES_BIG_ENDIAN) > + { > + if (strcmp (mode, "lsb") == 0) > + return 1; > + } > + else > + { > + if (strcmp (mode, "msb") == 0) > + return 1; > + } > + > + return 0; > +} > > /* Return a new underlying object for a bitfield started with FIELD. */ > > static tree > start_bitfield_representative (tree field) > { > @@ -1940,12 +2020,24 @@ finish_bitfield_layout (record_layout_in > || operand_equal_p (DECL_FIELD_OFFSET (repr), > DECL_FIELD_OFFSET (field), 0))) > { > finish_bitfield_representative (repr, prev); > repr = start_bitfield_representative (field); > } > + > + /* If the bitfield-order attribute has been used on this > + structure, the fields might not be in bit-order. In that > + case, we need a separate representative for each > + field. */ > + else if (DECL_FIELD_OFFSET (field) < DECL_FIELD_OFFSET (repr) > + || (DECL_FIELD_OFFSET (field) == DECL_FIELD_OFFSET (repr) > + && DECL_FIELD_BIT_OFFSET (field) < > DECL_FIELD_BIT_OFFSET (repr))) > + { > + finish_bitfield_representative (repr, prev); > + repr = start_bitfield_representative (field); > + } > } > else > continue; > > if (repr) > DECL_BIT_FIELD_REPRESENTATIVE (field) = repr; > @@ -1965,12 +2057,15 @@ finish_bitfield_layout (record_layout_in > > void > finish_record_layout (record_layout_info rli, int free_p) > { > tree variant; > > + if (reverse_bitfields_p (rli)) > + reverse_bitfield_layout (rli); > + > /* Compute the final size. */ > finalize_record_size (rli); > > /* Compute the TYPE_MODE for the record. */ > compute_record_mode (rli->t); > > Index: gcc/varasm.c > =================================================================== > --- gcc/varasm.c (revision 192009) > +++ gcc/varasm.c (working copy) > @@ -4716,25 +4716,17 @@ output_constructor_array_range (oc_local > > /* Count its size. */ > local->total_bytes += fieldsize; > } > } > > -/* Helper for output_constructor. From the current LOCAL state, output a > - field element that is not true bitfield or part of an outer one. */ > - > -static void > -output_constructor_regular_field (oc_local_state *local) > +/* Helper for output_constructor_regular_field */ > +static HOST_WIDE_INT > +constructor_regular_field_bytepos (oc_local_state *local) > { > - /* Field size and position. Since this structure is static, we know the > - positions are constant. */ > - unsigned HOST_WIDE_INT fieldsize; > HOST_WIDE_INT fieldpos; > - > - unsigned int align2; > - > if (local->index != NULL_TREE) > { > /* Perform the index calculation in modulo arithmetic but > sign-extend the result because Ada has negative DECL_FIELD_OFFSETs > but we are using an unsigned sizetype. */ > unsigned prec = TYPE_PRECISION (sizetype); > @@ -4745,12 +4737,29 @@ output_constructor_regular_field (oc_loc > * idx.low); > } > else if (local->field != NULL_TREE) > fieldpos = int_byte_position (local->field); > else > fieldpos = 0; > + return fieldpos; > +} > + > +/* Helper for output_constructor. From the current LOCAL state, output a > + field element that is not true bitfield or part of an outer one. */ > + > +static void > +output_constructor_regular_field (oc_local_state *local) > +{ > + /* Field size and position. Since this structure is static, we know the > + positions are constant. */ > + unsigned HOST_WIDE_INT fieldsize; > + HOST_WIDE_INT fieldpos; > + > + unsigned int align2; > + > + fieldpos = constructor_regular_field_bytepos (local); > > /* Output any buffered-up bit-fields preceding this element. */ > if (local->byte_buffer_in_use) > { > assemble_integer (GEN_INT (local->byte), 1, BITS_PER_UNIT, 1); > local->total_bytes++; > @@ -5001,18 +5010,49 @@ output_constructor_bitfield (oc_local_st > } > > /* Subroutine of output_constant, used for CONSTRUCTORs (aggregate > constants). > Generate at least SIZE bytes, padding if necessary. OUTER designates the > caller output state of relevance in recursive invocations. */ > > +typedef struct { > + unsigned HOST_WIDE_INT cnt; > + tree val; > + tree index; > + tree field; > + int what_to_do; > +} constructor_field_list; > + > +#define WHAT_ARRAY 1 > +#define WHAT_REGULAR 2 > +#define WHAT_BITFIELD 3 > + > +static int > +constructor_field_sort (const void *va, const void *vb) > +{ > + const constructor_field_list *a = (const constructor_field_list *)va; > + const constructor_field_list *b = (const constructor_field_list *)vb; > + /* A field that's exactly a whole number of bytes might show up as a > + "regular" type instead of a "field" byte. We can tell the > + difference here, because those will have FIELD set. Just > + preserve the original order for non-field components. */ > + if (! a->field || ! b->field) > + return a->cnt - b->cnt; > + /* For two fields, compare byte offset first, then bit offset. */ > + if (int_byte_position (a->field) != int_byte_position (b->field)) > + return int_byte_position (a->field) - int_byte_position (b->field); > + return int_bit_position (a->field) - int_bit_position (b->field); > +} > + > static unsigned HOST_WIDE_INT > output_constructor (tree exp, unsigned HOST_WIDE_INT size, > unsigned int align, oc_outer_state * outer) > { > unsigned HOST_WIDE_INT cnt; > constructor_elt *ce; > + constructor_field_list *constructor_fields; > + unsigned HOST_WIDE_INT constructor_field_count; > > oc_local_state local; > > /* Setup our local state to communicate with helpers. */ > local.exp = exp; > local.size = size; > @@ -5043,12 +5083,15 @@ output_constructor (tree exp, unsigned H > more one). */ > > local.field = NULL_TREE; > if (TREE_CODE (local.type) == RECORD_TYPE) > local.field = TYPE_FIELDS (local.type); > > + constructor_field_count = VEC_length (constructor_elt, CONSTRUCTOR_ELTS > (exp)); > + constructor_fields = XNEWVEC (constructor_field_list, > constructor_field_count); > + > for (cnt = 0; > VEC_iterate (constructor_elt, CONSTRUCTOR_ELTS (exp), cnt, ce); > cnt++, local.field = local.field ? DECL_CHAIN (local.field) : 0) > { > local.val = ce->value; > local.index = NULL_TREE; > @@ -5069,41 +5112,72 @@ output_constructor (tree exp, unsigned H > : "<anonymous>"); > > /* Eliminate the marker that makes a cast not be an lvalue. */ > if (local.val != NULL_TREE) > STRIP_NOPS (local.val); > > - /* Output the current element, using the appropriate helper ... */ > + constructor_fields[cnt].cnt = cnt; > + constructor_fields[cnt].val = local.val; > + constructor_fields[cnt].index = local.index; > + constructor_fields[cnt].field = local.field; > > /* For an array slice not part of an outer bitfield. */ > if (!outer > && local.index != NULL_TREE > && TREE_CODE (local.index) == RANGE_EXPR) > - output_constructor_array_range (&local); > + constructor_fields[cnt].what_to_do = WHAT_ARRAY; > > /* For a field that is neither a true bitfield nor part of an outer > one, > known to be at least byte aligned and multiple-of-bytes long. */ > else if (!outer > && (local.field == NULL_TREE > || !CONSTRUCTOR_BITFIELD_P (local.field))) > - output_constructor_regular_field (&local); > + constructor_fields[cnt].what_to_do = WHAT_REGULAR; > > /* For a true bitfield or part of an outer one. Only INTEGER_CSTs are > supported for scalar fields, so we may need to convert first. */ > else > { > if (TREE_CODE (local.val) == REAL_CST) > local.val > = fold_unary (VIEW_CONVERT_EXPR, > build_nonstandard_integer_type > (TYPE_PRECISION (TREE_TYPE (local.val)), 0), > local.val); > + constructor_fields[cnt].what_to_do = WHAT_BITFIELD; > + } > + } > + > + qsort (constructor_fields, constructor_field_count, > + sizeof(constructor_field_list), constructor_field_sort); > + > + for (cnt = 0; > + cnt < constructor_field_count; > + cnt++) > + { > + /* Output the current element, using the appropriate helper ... */ > + local.val = constructor_fields[cnt].val; > + local.index = constructor_fields[cnt].index; > + local.field = constructor_fields[cnt].field; > + > + switch (constructor_fields[cnt].what_to_do) > + { > + case WHAT_ARRAY: > + output_constructor_array_range (&local); > + break; > + case WHAT_REGULAR: > + output_constructor_regular_field (&local); > + break; > + case WHAT_BITFIELD: > output_constructor_bitfield (&local, outer); > + break; > } > } > > + XDELETEVEC (constructor_fields); > + > /* If we are not at toplevel, save the pending data for our caller. > Otherwise output the pending data and padding zeros as needed. */ > if (outer) > outer->byte = local.byte; > else > { > Index: gcc/config.gcc > =================================================================== > --- gcc/config.gcc (revision 192009) > +++ gcc/config.gcc (working copy) > @@ -2119,12 +2119,13 @@ rl78-*-elf*) > target_has_targetm_common=no > c_target_objs="rl78-c.o" > cxx_target_objs="rl78-c.o" > tmake_file="${tmake_file} rl78/t-rl78" > ;; > rx-*-elf*) > + c_target_objs="rx-c.o" > tm_file="dbxelf.h elfos.h newlib-stdint.h ${tm_file}" > tmake_file="${tmake_file} rx/t-rx" > ;; > s390-*-linux*) > default_gnu_indirect_function=yes > tm_file="s390/s390.h dbxelf.h elfos.h gnu-user.h linux.h > glibc-stdint.h s390/linux.h" > Index: gcc/config/rx/rx.h > =================================================================== > --- gcc/config/rx/rx.h (revision 192009) > +++ gcc/config/rx/rx.h (working copy) > @@ -49,12 +49,14 @@ > builtin_define ("__RX_AS100_SYNTAX__"); \ > else \ > builtin_define ("__RX_GAS_SYNTAX__"); \ > } \ > while (0) > > +#define REGISTER_TARGET_PRAGMAS() rx_register_pragmas () > + > #undef CC1_SPEC > #define CC1_SPEC "\ > %{mas100-syntax:%{gdwarf*:%e-mas100-syntax is incompatible with -gdwarf}} \ > %{mcpu=rx200:%{fpu:%erx200 cpu does not have FPU hardware}}" > > #undef STARTFILE_SPEC > Index: gcc/config/rx/rx.c > =================================================================== > --- gcc/config/rx/rx.c (revision 192009) > +++ gcc/config/rx/rx.c (working copy) > @@ -1157,12 +1157,69 @@ static bool > rx_return_in_msb (const_tree valtype) > { > return TARGET_BIG_ENDIAN_DATA > && (AGGREGATE_TYPE_P (valtype) || TREE_CODE (valtype) == COMPLEX_TYPE); > } > > +#define BITORDER_DEFAULT 0 > +#define BITORDER_LEFT 1 > +#define BITORDER_RIGHT 2 > + > +static int rx_bitorder = BITORDER_DEFAULT; > + > +#undef TARGET_SET_DEFAULT_TYPE_ATTRIBUTES > +#define TARGET_SET_DEFAULT_TYPE_ATTRIBUTES rx_set_default_type_attributes > +static void > +rx_set_default_type_attributes (tree node) > +{ > + unsigned addr; > + tree attr, type_attr_list; > + char *bit_order; > + > + if (TREE_CODE (node) != RECORD_TYPE > + && TREE_CODE (node) != UNION_TYPE) > + return; > + > + type_attr_list = TYPE_ATTRIBUTES (node); > + > + for (attr=type_attr_list; attr; attr = TREE_CHAIN (attr)) > + { > + if (strcmp (IDENTIFIER_POINTER (TREE_PURPOSE (attr)), > + "bit_order") == 0) > + return; > + } > + > + if (rx_bitorder == BITORDER_LEFT) > + bit_order = "msb"; > + else if (rx_bitorder == BITORDER_RIGHT) > + bit_order = "lsb"; > + else > + return; > + > + type_attr_list = tree_cons (get_identifier ("bit_order"), > + build_tree_list (NULL_TREE, get_identifier > (bit_order)), > + type_attr_list); > + > + TYPE_ATTRIBUTES (node) = type_attr_list; > +} > + > +void > +rx_note_pragma_bitorder (char *mode) > +{ > + if (mode == NULL) > + rx_bitorder = BITORDER_DEFAULT; > + else if (strcmp (mode, "left") == 0) > + rx_bitorder = BITORDER_LEFT; > + else if (strcmp (mode, "right") == 0) > + rx_bitorder = BITORDER_RIGHT; > + else if (strcmp (mode, "native") == 0) > + rx_bitorder = BITORDER_DEFAULT; > + else > + error ("pragma bit_order only takes left or right"); > +} > + > /* Returns true if the provided function has the specified attribute. */ > > static inline bool > has_func_attr (const_tree decl, const char * func_attr) > { > if (decl == NULL_TREE) > Index: gcc/config/rx/t-rx > =================================================================== > --- gcc/config/rx/t-rx (revision 192009) > +++ gcc/config/rx/t-rx (working copy) > @@ -24,6 +24,13 @@ MULTILIB_OPTIONS = m64bit-doubles no > MULTILIB_DIRNAMES = 64-bit-double no-fpu-libs big-endian-data pid > > MULTILIB_MATCHES = nofpu=mnofpu nofpu=mcpu?rx200 > > MULTILIB_EXCEPTIONS = > MULTILIB_EXTRA_OPTS = > + > +rx-c.o: $(srcdir)/config/rx/rx-c.c \ > + $(srcdir)/config/rx/rx-protos.h $(CONFIG_H) $(SYSTEM_H) coretypes.h \ > + $(TM_H) $(TREE_H) $(TM_P_H) $(FLAGS_H) $(C_COMMON_H) $(GGC_H) \ > + $(TARGET_H) $(TARGET_DEF_H) $(CPPLIB_H) $(C_PRAGMA_H) > + $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ > + $(srcdir)/config/rx/rx-c.c > Index: gcc/config/rx/rx-c.c > =================================================================== > --- gcc/config/rx/rx-c.c (revision 0) > +++ gcc/config/rx/rx-c.c (revision 0) > @@ -0,0 +1,86 @@ > +/* Subroutines used for macro/preprocessor support on the RX. > + Copyright (C) 2008, 2009, 2010 > + Free Software Foundation, Inc. > + > +This file is part of GCC. > + > +GCC is free software; you can redistribute it and/or modify > +it under the terms of the GNU General Public License as published by > +the Free Software Foundation; either version 3, or (at your option) > +any later version. > + > +GCC is distributed in the hope that it will be useful, > +but WITHOUT ANY WARRANTY; without even the implied warranty of > +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > +GNU General Public License for more details. > + > +You should have received a copy of the GNU General Public License > +along with GCC; see the file COPYING3. If not see > +<http://www.gnu.org/licenses/>. */ > + > +#include "config.h" > +#include "system.h" > +#include "coretypes.h" > +#include "tm.h" > +#include "tree.h" > +#include "tm_p.h" > +#include "flags.h" > +#include "c-family/c-common.h" > +#include "ggc.h" > +#include "target.h" > +#include "target-def.h" > +#include "cpplib.h" > +#include "c-family/c-pragma.h" > + > +/* Implements the "pragma bit_order" pragma. This pragma takes an > + optional left or right to force bitfield allocation. */ > +static void > +rx_pragma_bitorder (cpp_reader * reader ATTRIBUTE_UNUSED) > +{ > + tree mode; > + enum cpp_ttype type; > + > + type = pragma_lex (&mode); > + if (type == CPP_EOF) > + { > + rx_note_pragma_bitorder (NULL); > + return; > + } > + if (type == CPP_NAME) > + { > + rx_note_pragma_bitorder (IDENTIFIER_POINTER (mode)); > + > + type = pragma_lex (&mode); > + if (type != CPP_EOF) > + { > + error ("junk at end of #pragma bit_order"); > + } > + return; > + } > + error ("malformed #pragma bit_order [left|right|native]"); > +} > + > +/* Additional pragmas purely for compatibility with existing RXC I/O > + headers. */ > + > +#define SET_GLOBAL_ALIGNMENT(N) maximum_field_alignment = (N) > + > +static void > +rx_pragma_unpack (cpp_reader * reader ATTRIBUTE_UNUSED) > +{ > + SET_GLOBAL_ALIGNMENT (4*8); > +} > + > +static void > +rx_pragma_packoption (cpp_reader * reader ATTRIBUTE_UNUSED) > +{ > + SET_GLOBAL_ALIGNMENT (initial_max_fld_align); > +} > + > +void > +rx_register_pragmas (void) > +{ > + c_register_pragma (NULL, "bit_order", rx_pragma_bitorder); > + c_register_pragma (NULL, "unpack", rx_pragma_unpack); > + c_register_pragma (NULL, "packoption", rx_pragma_packoption); > +}