diff mbox

[announce] New scalar-storage-order branch in GCC repository

Message ID 51B60F92.2020502@codesourcery.com
State New
Headers show

Commit Message

Bernd Schmidt June 10, 2013, 5:40 p.m. UTC
On 05/27/2013 01:13 PM, Eric Botcazou wrote:
> I have just created a new branch off the trunk named scalar-storage-order to 
> host the (experimental) support to specify a reverse storage order (byte/word 
> order, aka endianness) for scalar components of aggregate types.
> 
> I will be maintaining the branch and start by porting AdaCore's GCC 4.7-based 
> implementation for the Ada compiler to this branch.  Once this is done, I'll 
> welcome suggestions and ideas to support this new feature in other languages.

I experimented with something like this a while ago. The goal was to
have a -f{big,little}-endian switch that changes the default byteorder,
and also to add endianness attributes. It didn't go very far, but I
could compile some simple testcases and it seemed to behave as expected
for those.

The patch is attached for reference. The interesting problems are
byteswapping pointers and how to deal with function arguments; neither
is dealt with in this patch (except for a crummy attempt to get varargs
right). At the moment I don't intend to do further work on this.


Bernd

Comments

Eric Botcazou June 11, 2013, 8:08 a.m. UTC | #1
> I experimented with something like this a while ago. The goal was to
> have a -f{big,little}-endian switch that changes the default byteorder,
> and also to add endianness attributes. It didn't go very far, but I
> could compile some simple testcases and it seemed to behave as expected
> for those.

OK, that seems to be more ambitious than what we have done.  As a matter of 
fact, when we were discussing the specification of the feature, we tried to 
narrow it to something that we believe was reasonably implementable and 
maintainable in the long term, hence the more limited scope of our version.

> The patch is attached for reference. The interesting problems are
> byteswapping pointers and how to deal with function arguments; neither
> is dealt with in this patch (except for a crummy attempt to get varargs
> right). At the moment I don't intend to do further work on this.

Thanks for posting the patch in any case!
diff mbox

Patch

Index: gcc/c-family/c-pretty-print.c
===================================================================
--- gcc/c-family/c-pretty-print.c	(revision 189318)
+++ gcc/c-family/c-pretty-print.c	(working copy)
@@ -474,6 +474,10 @@ 
       pp_c_specifier_qualifier_list (pp, TREE_TYPE (t));
       break;
 
+    case MOD_TYPE:
+      pp_c_ws_string (pp, "bswapped");
+      break;
+
     case VECTOR_TYPE:
     case COMPLEX_TYPE:
       if (code == COMPLEX_TYPE)
Index: gcc/c-family/c.opt
===================================================================
--- gcc/c-family/c.opt	(revision 189318)
+++ gcc/c-family/c.opt	(working copy)
@@ -772,6 +772,10 @@ 
 C++ ObjC++ Joined RejectNegative UInteger Var(max_constexpr_depth) Init(512)
 -fconstexpr-depth=<number>	Specify maximum constexpr recursion depth
 
+fbig-endian
+C Var(flag_big_endian)
+Compile code outside system headers as big-endian
+
 fdebug-cpp
 C ObjC C++ ObjC++
 Emit debug annotations during preprocessing
Index: gcc/c-family/c-common.c
===================================================================
--- gcc/c-family/c-common.c	(revision 189318)
+++ gcc/c-family/c-common.c	(working copy)
@@ -417,6 +417,9 @@ 
   { "_Fract",           RID_FRACT,     D_CONLY | D_EXT },
   { "_Accum",           RID_ACCUM,     D_CONLY | D_EXT },
   { "_Sat",             RID_SAT,       D_CONLY | D_EXT },
+  { "_NativeEndian",    RID_SAT,       D_CONLY | D_EXT },
+  { "_LittleEndian",    RID_SAT,       D_CONLY | D_EXT },
+  { "_BigEndian",       RID_SAT,       D_CONLY | D_EXT },
   { "_Static_assert",   RID_STATIC_ASSERT, D_CONLY },
   { "_Noreturn",        RID_NORETURN,  D_CONLY },
   { "__FUNCTION__",	RID_FUNCTION_NAME, 0 },
@@ -10850,6 +10853,9 @@ 
     case RID_DFLOAT128:
     case RID_FRACT:
     case RID_ACCUM:
+    case RID_NATIVE:
+    case RID_LE:
+    case RID_BE:
     case RID_BOOL:
     case RID_WCHAR:
     case RID_CHAR16:
Index: gcc/c-family/c-common.h
===================================================================
--- gcc/c-family/c-common.h	(revision 189318)
+++ gcc/c-family/c-common.h	(working copy)
@@ -105,6 +105,7 @@ 
   RID_TYPES_COMPATIBLE_P,      RID_BUILTIN_COMPLEX,	     RID_BUILTIN_SHUFFLE,
   RID_DFLOAT32, RID_DFLOAT64, RID_DFLOAT128,
   RID_FRACT, RID_ACCUM,
+  RID_NATIVE, RID_BE, RID_LE,
 
   /* C11 */
   RID_ALIGNAS,
Index: gcc/c/c-convert.c
===================================================================
--- gcc/c/c-convert.c	(revision 189318)
+++ gcc/c/c-convert.c	(working copy)
@@ -92,6 +92,31 @@ 
 
   STRIP_TYPE_NOPS (e);
 
+  if (TREE_CODE (TREE_TYPE (expr)) == MOD_TYPE)
+    {
+      switch (TYPE_PRECISION (TREE_TYPE (expr)))
+	{
+	case 8:
+	  e = fold_build1 (NOP_EXPR, TREE_TYPE (expr), e);
+	  break;
+	case 16:
+	  e = fold_build_call_array_loc (loc, TREE_TYPE (expr),
+					 build_fold_addr_expr (builtin_decl_explicit (BUILT_IN_BSWAP16M)),
+					 1, &e);
+	  break;
+	case 32:
+	  e = fold_build_call_array_loc (loc, TREE_TYPE (expr),
+					 build_fold_addr_expr (builtin_decl_explicit (BUILT_IN_BSWAP32M)),
+					 1, &e);
+	  break;
+	case 64:
+	  e = fold_build_call_array_loc (loc, TREE_TYPE (expr),
+					 build_fold_addr_expr (builtin_decl_explicit (BUILT_IN_BSWAP64M)),
+					 1, &e);
+	  break;
+	}
+    }
+
   if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (expr)))
     return fold_convert_loc (loc, type, expr);
   if (TREE_CODE (TREE_TYPE (expr)) == ERROR_MARK)
@@ -107,6 +132,31 @@ 
     case VOID_TYPE:
       return fold_convert_loc (loc, type, e);
 
+    case MOD_TYPE:
+      e = convert (TREE_TYPE (type), e);
+      switch (TYPE_PRECISION (TREE_TYPE (e)))
+	{
+	case 8:
+	  ret = fold_build1 (NOP_EXPR, TREE_TYPE (e), e);
+	  break;
+	case 16:
+	  ret = fold_build_call_array_loc (loc, type,
+					   build_fold_addr_expr (builtin_decl_explicit (BUILT_IN_BSWAPM16)),
+					   1, &e);
+	  break;
+	case 32:
+	  ret = fold_build_call_array_loc (loc, type,
+					   build_fold_addr_expr (builtin_decl_explicit (BUILT_IN_BSWAPM32)),
+					   1, &e);
+	  break;
+	case 64:
+	  ret = fold_build_call_array_loc (loc, type,
+					   build_fold_addr_expr (builtin_decl_explicit (BUILT_IN_BSWAPM64)),
+					   1, &e);
+	  break;
+	}
+      goto maybe_fold;
+
     case INTEGER_TYPE:
     case ENUMERAL_TYPE:
       ret = convert_to_integer (type, e);
Index: gcc/c/c-parser.c
===================================================================
--- gcc/c/c-parser.c	(revision 189318)
+++ gcc/c/c-parser.c	(working copy)
@@ -2185,6 +2185,10 @@ 
 	  align = c_parser_alignas_specifier (parser);
 	  declspecs_add_alignas (loc, specs, align);
 	  break;
+	case RID_BE:
+	case RID_LE:
+	case RID_NATIVE:
+	  declspecs_add_endian (loc, specs, c_parser_peek_token (parser)->keyword);
 	default:
 	  goto out;
 	}
@@ -6229,7 +6233,7 @@ 
   switch (c_parser_peek_token (parser)->type)
     {
     case CPP_NUMBER:
-      expr.value = c_parser_peek_token (parser)->value;
+      expr.value = maybe_byteswap (cte_none, c_parser_peek_token (parser)->value);
       loc = c_parser_peek_token (parser)->location;
       c_parser_consume_token (parser);
       if (TREE_CODE (expr.value) == FIXED_CST
Index: gcc/c/c-typeck.c
===================================================================
--- gcc/c/c-typeck.c	(revision 189318)
+++ gcc/c/c-typeck.c	(working copy)
@@ -1996,6 +1996,9 @@ 
   if (exp == error_mark_node)
     return error_mark_node;
 
+  if (TREE_CODE (type) == MOD_TYPE)
+    exp = convert (TREE_TYPE (type), exp);
+
   promoted_type = targetm.promoted_type (type);
   if (promoted_type)
     return convert (promoted_type, exp);
@@ -2309,6 +2312,9 @@ 
       || TREE_TYPE (index) == error_mark_node)
     return error_mark_node;
 
+  if (TREE_CODE (TREE_TYPE (index)) == MOD_TYPE)
+    index = convert (TREE_TYPE (TREE_TYPE (index)), index);
+
   if (TREE_CODE (TREE_TYPE (array)) != ARRAY_TYPE
       && TREE_CODE (TREE_TYPE (array)) != POINTER_TYPE
       /* Allow vector[index] but not index[vector].  */
@@ -3171,8 +3177,14 @@ 
 	  return -1;
 	}
       else
-	/* Convert `short' and `char' to full-size `int'.  */
-	parmval = default_conversion (val);
+	{
+	  /* Convert `short' and `char' to full-size `int'.  */
+	  parmval = default_conversion (val);
+	  if (C_TYPE_FUNCTION_SWAP_ARGS (TREE_TYPE (function)))
+	    parmval = convert (build_bswap_type (TREE_TYPE (parmval)),
+			       parmval);
+	      
+	}
 
       VEC_replace (tree, values, parmnum, parmval);
       if (parmval == error_mark_node)
@@ -5087,6 +5099,8 @@ 
 			tree function, int parmnum)
 {
   enum tree_code codel = TREE_CODE (type);
+  bool bswappedl = false;
+  bool bswappedr = false;
   tree orig_rhs = rhs;
   tree rhstype;
   enum tree_code coder;
@@ -5240,6 +5254,16 @@ 
   rhs = require_complete_type (rhs);
   if (rhs == error_mark_node)
     return error_mark_node;
+  if (codel == MOD_TYPE)
+    {
+      bswappedl = true;
+      codel = TREE_CODE (TREE_TYPE (type));
+    }
+  if (coder == MOD_TYPE)
+    {
+      bswappedr = true;
+      coder = TREE_CODE (TREE_TYPE (rhstype));
+    }
   /* A type converts to a reference to it.
      This code doesn't fully support references, it's just for the
      special case of va_start and va_copy.  */
@@ -5273,6 +5297,7 @@ 
     }
   /* Some types can interconvert without explicit casts.  */
   else if (codel == VECTOR_TYPE && coder == VECTOR_TYPE
+	   && !bswappedl && !bswappedr
 	   && vector_types_convertible_p (type, TREE_TYPE (rhs), true))
     return convert (type, rhs);
   /* Arithmetic types all interconvert, and enum is treated like int.  */
@@ -6011,6 +6036,7 @@ 
   tree inside_init = init;
   tree semantic_type = NULL_TREE;
   bool maybe_const = true;
+  bool type_bswapped = false;
 
   if (type == error_mark_node
       || !init
@@ -6018,6 +6044,12 @@ 
       || TREE_TYPE (init) == error_mark_node)
     return error_mark_node;
 
+  if (code == MOD_TYPE)
+    {
+      type_bswapped = true;
+      code = TREE_CODE (TREE_TYPE (type));
+    }
+
   STRIP_TYPE_NOPS (inside_init);
 
   if (TREE_CODE (inside_init) == EXCESS_PRECISION_EXPR)
Index: gcc/c/c-tree.h
===================================================================
--- gcc/c/c-tree.h	(revision 189318)
+++ gcc/c/c-tree.h	(working copy)
@@ -40,6 +40,10 @@ 
    nonzero if the definition of the type has already started.  */
 #define C_TYPE_BEING_DEFINED(TYPE) TYPE_LANG_FLAG_0 (TYPE)
 
+/* In a FUNCTION_TYPE, nonzero if variadic arguments should be passed
+   byte-swapped.  */
+#define C_TYPE_FUNCTION_ARG_SWAP(TYPE) TYPE_LANG_FLAG_3 (TYPE)
+
 /* In an incomplete RECORD_TYPE or UNION_TYPE, a list of variable
    declarations whose type would be completed by completing that type.  */
 #define C_TYPE_INCOMPLETE_VARS(TYPE) TYPE_VFIELD (TYPE)
@@ -256,6 +260,13 @@ 
 			    enumerator.  */
 };
 
+enum c_typespec_endian {
+  cte_none,
+  cte_big,
+  cte_little,
+  cte_native
+};
+
 /* A sequence of declaration specifiers in C.  When a new declaration
    specifier is added, please update the enum c_declspec_word above
    accordingly.  */
@@ -287,6 +298,7 @@ 
   /* The kind of type specifier if one has been seen, ctsk_none
      otherwise.  */
   ENUM_BITFIELD (c_typespec_kind) typespec_kind : 3;
+  ENUM_BITFIELD (c_typespec_endian) endian_kind : 2;
   /* Whether any expressions in typeof specifiers may appear in
      constant expressions.  */
   BOOL_BITFIELD expr_const_operands : 1;
@@ -547,6 +559,8 @@ 
 extern struct c_declspecs *build_null_declspecs (void);
 extern struct c_declspecs *declspecs_add_qual (source_location,
 					       struct c_declspecs *, tree);
+extern struct c_declspecs *declspecs_add_endian (source_location,
+						 struct c_declspecs *, enum rid);
 extern struct c_declspecs *declspecs_add_type (location_t,
 					       struct c_declspecs *,
 					       struct c_typespec);
@@ -575,6 +589,8 @@ 
 
 extern struct c_switch *c_switch_stack;
 
+extern bool in_byteswap_context (void);
+extern tree maybe_byteswap (enum c_typespec_endian, tree);
 extern tree c_objc_common_truthvalue_conversion (location_t, tree);
 extern tree require_complete_type (tree);
 extern int same_translation_unit_p (const_tree, const_tree);
Index: gcc/c/c-decl.c
===================================================================
--- gcc/c/c-decl.c	(revision 189318)
+++ gcc/c/c-decl.c	(working copy)
@@ -5637,6 +5637,8 @@ 
 	    type_quals = TYPE_UNQUALIFIED;
 
 	    type = build_function_type (type, arg_types);
+	    if (in_byteswap_context ())
+	      C_TYPE_FUNCTION_ARG_SWAP (type) = true;
 	    declarator = declarator->declarator;
 
 	    /* Set the TYPE_CONTEXTs for each tagged type which is local to
@@ -8800,6 +8802,7 @@ 
   ret->expr_const_operands = true;
   ret->declspecs_seen_p = false;
   ret->typespec_kind = ctsk_none;
+  ret->endian_kind = cte_none;
   ret->non_sc_seen_p = false;
   ret->typedef_p = false;
   ret->explicit_signed_p = false;
@@ -9691,6 +9694,50 @@ 
   return specs;
 }
 
+struct c_declspecs *
+declspecs_add_endian (source_location loc,
+		      struct c_declspecs *specs, enum rid id)
+{
+  if (specs->endian_kind != cte_none)
+    {
+      error ("incompatible endian specificier");
+      return specs;
+    }
+  specs->endian_kind = (id == RID_NATIVE ? cte_native
+			: id == RID_LE ? cte_little
+			: cte_big);
+}
+
+bool
+in_byteswap_context (void)
+{
+  if (in_system_header)
+    return false;
+  if (flag_big_endian && !BYTES_BIG_ENDIAN)
+    return true;
+  return false;
+}
+
+tree
+maybe_byteswap (enum c_typespec_endian kind, tree x)
+{
+  tree type;
+  if (kind == cte_native
+      || (kind == cte_big && BYTES_BIG_ENDIAN)
+      || (kind == cte_little && !BYTES_BIG_ENDIAN)
+      || (kind == cte_none && !in_byteswap_context ()))
+    return x;
+
+  if (TYPE_P (x))
+    type = x;
+  else
+    type = TREE_TYPE (x);
+  type = build_bswap_type (type);
+  if (TYPE_P (x))
+    return type;
+  return convert (type, x);
+}
+
 /* Combine "long", "short", "signed", "unsigned" and "_Complex" type
    specifiers with any other type specifier to determine the resulting
    type.  This is where ISO C checks on complex types are made, since
@@ -9791,9 +9838,10 @@ 
     case cts_int128:
       gcc_assert (!specs->long_p && !specs->short_p && !specs->long_long_p);
       gcc_assert (!(specs->signed_p && specs->unsigned_p));
-      specs->type = (specs->unsigned_p
-		     ? int128_unsigned_type_node
-		     : int128_integer_type_node);
+      specs->type = maybe_byteswap (specs->endian_kind,
+				    specs->unsigned_p
+				    ? int128_unsigned_type_node
+				    : int128_integer_type_node);
       if (specs->complex_p)
 	{
 	  pedwarn (specs->locations[cdw_complex], OPT_Wpedantic,
@@ -9805,21 +9853,25 @@ 
       gcc_assert (!(specs->long_p && specs->short_p));
       gcc_assert (!(specs->signed_p && specs->unsigned_p));
       if (specs->long_long_p)
-	specs->type = (specs->unsigned_p
-		       ? long_long_unsigned_type_node
-		       : long_long_integer_type_node);
+	specs->type = maybe_byteswap (specs->endian_kind,
+				      specs->unsigned_p
+				      ? long_long_unsigned_type_node
+				      : long_long_integer_type_node);
       else if (specs->long_p)
-	specs->type = (specs->unsigned_p
-		       ? long_unsigned_type_node
-		       : long_integer_type_node);
+	specs->type = maybe_byteswap (specs->endian_kind,
+				      specs->unsigned_p
+				      ? long_unsigned_type_node
+				      : long_integer_type_node);
       else if (specs->short_p)
-	specs->type = (specs->unsigned_p
-		       ? short_unsigned_type_node
-		       : short_integer_type_node);
+	specs->type = maybe_byteswap (specs->endian_kind,
+				      specs->unsigned_p
+				      ? short_unsigned_type_node
+				      : short_integer_type_node);
       else
-	specs->type = (specs->unsigned_p
-		       ? unsigned_type_node
-		       : integer_type_node);
+	specs->type = maybe_byteswap (specs->endian_kind,
+				      specs->unsigned_p
+				      ? unsigned_type_node
+				      : integer_type_node);
       if (specs->complex_p)
 	{
 	  pedwarn (specs->locations[cdw_complex], OPT_Wpedantic,
Index: gcc/tree.c
===================================================================
--- gcc/tree.c	(revision 189318)
+++ gcc/tree.c	(working copy)
@@ -1163,13 +1163,16 @@ 
 tree
 build_int_cst_wide (tree type, unsigned HOST_WIDE_INT low, HOST_WIDE_INT hi)
 {
+  enum tree_code code = TREE_CODE (type);
   tree t;
   int ix = -1;
   int limit = 0;
 
   gcc_assert (type);
 
-  switch (TREE_CODE (type))
+  if (code == MOD_TYPE)
+    code = TREE_CODE (TREE_TYPE (type)); 
+  switch (code)
     {
     case NULLPTR_TYPE:
       gcc_assert (hi == 0 && low == 0);
@@ -7123,6 +7126,16 @@ 
   return val;
 }
 
+/* Construct a modified type that is the byte-swapped version of TYPE.  */
+tree
+build_bswap_type (tree type)
+{
+  tree t = make_node (MOD_TYPE);
+  TREE_TYPE (t) = type;
+  layout_type (t);
+  return t;
+}
+
 /* Constructors for pointer, array and function types.
    (RECORD_TYPE, UNION_TYPE and ENUMERAL_TYPE nodes are
    constructed by language-dependent code, not here.)  */
Index: gcc/tree.h
===================================================================
--- gcc/tree.h	(revision 189318)
+++ gcc/tree.h	(working copy)
@@ -4378,6 +4378,7 @@ 
 extern tree build_pointer_type (tree);
 extern tree build_reference_type_for_mode (tree, enum machine_mode, bool);
 extern tree build_reference_type (tree);
+extern tree build_bswap_type (tree);
 extern tree build_vector_type_for_mode (tree, enum machine_mode);
 extern tree build_vector_type (tree innertype, int nunits);
 extern tree build_opaque_vector_type (tree innertype, int nunits);
Index: gcc/builtins.c
===================================================================
--- gcc/builtins.c	(revision 189318)
+++ gcc/builtins.c	(working copy)
@@ -6058,6 +6058,12 @@ 
     case BUILT_IN_BSWAP16:
     case BUILT_IN_BSWAP32:
     case BUILT_IN_BSWAP64:
+    case BUILT_IN_BSWAP16M:
+    case BUILT_IN_BSWAP32M:
+    case BUILT_IN_BSWAP64M:
+    case BUILT_IN_BSWAPM16:
+    case BUILT_IN_BSWAPM32:
+    case BUILT_IN_BSWAPM64:
       target = expand_builtin_bswap (target_mode, exp, target, subtarget);
       if (target)
 	return target;
@@ -8152,7 +8158,15 @@ 
 static tree
 fold_builtin_bswap (tree fndecl, tree arg)
 {
-  if (! validate_arg (arg, INTEGER_TYPE))
+  enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
+  if (fcode == BUILT_IN_BSWAP16M || fcode == BUILT_IN_BSWAP32M
+      || fcode == BUILT_IN_BSWAP64M)
+    {
+      if (!validate_arg (arg, MOD_TYPE)
+	  || !INTEGRAL_TYPE_P (TREE_TYPE (TREE_TYPE (arg))))
+	return NULL_TREE;
+    }
+  else if (!validate_arg (arg, INTEGER_TYPE))
     return NULL_TREE;
 
   /* Optimize constant value.  */
@@ -8168,9 +8182,15 @@ 
 
       switch (DECL_FUNCTION_CODE (fndecl))
 	{
-	  case BUILT_IN_BSWAP16:
-	  case BUILT_IN_BSWAP32:
-	  case BUILT_IN_BSWAP64:
+	case BUILT_IN_BSWAP16:
+	case BUILT_IN_BSWAP32:
+	case BUILT_IN_BSWAP64:
+	case BUILT_IN_BSWAP16M:
+	case BUILT_IN_BSWAP32M:
+	case BUILT_IN_BSWAP64M:
+	case BUILT_IN_BSWAPM16:
+	case BUILT_IN_BSWAPM32:
+	case BUILT_IN_BSWAPM64:
 	    {
 	      int s;
 
@@ -10556,6 +10576,12 @@ 
     case BUILT_IN_BSWAP16:
     case BUILT_IN_BSWAP32:
     case BUILT_IN_BSWAP64:
+    case BUILT_IN_BSWAP16M:
+    case BUILT_IN_BSWAP32M:
+    case BUILT_IN_BSWAP64M:
+    case BUILT_IN_BSWAPM16:
+    case BUILT_IN_BSWAPM32:
+    case BUILT_IN_BSWAPM64:
       return fold_builtin_bswap (fndecl, arg0);
 
     CASE_INT_FN (BUILT_IN_FFS):
@@ -14336,6 +14362,12 @@ 
       case BUILT_IN_BSWAP16:
       case BUILT_IN_BSWAP32:
       case BUILT_IN_BSWAP64:
+      case BUILT_IN_BSWAP16M:
+      case BUILT_IN_BSWAP32M:
+      case BUILT_IN_BSWAP64M:
+      case BUILT_IN_BSWAPM16:
+      case BUILT_IN_BSWAPM32:
+      case BUILT_IN_BSWAPM64:
       case BUILT_IN_CLZ:
       case BUILT_IN_CLZIMAX:
       case BUILT_IN_CLZL:
Index: gcc/builtin-types.def
===================================================================
--- gcc/builtin-types.def	(revision 189318)
+++ gcc/builtin-types.def	(working copy)
@@ -79,6 +79,9 @@ 
 DEF_PRIMITIVE_TYPE (BT_UINT16, uint16_type_node)
 DEF_PRIMITIVE_TYPE (BT_UINT32, uint32_type_node)
 DEF_PRIMITIVE_TYPE (BT_UINT64, uint64_type_node)
+DEF_PRIMITIVE_TYPE (BT_UINT16_M, build_bswap_type (uint16_type_node))
+DEF_PRIMITIVE_TYPE (BT_UINT32_M, build_bswap_type (uint32_type_node))
+DEF_PRIMITIVE_TYPE (BT_UINT64_M, build_bswap_type (uint64_type_node))
 DEF_PRIMITIVE_TYPE (BT_WORD, (*lang_hooks.types.type_for_mode) (word_mode, 1))
 DEF_PRIMITIVE_TYPE (BT_UNWINDWORD, (*lang_hooks.types.type_for_mode)
 				    (targetm.unwind_word_mode (), 1))
@@ -230,6 +233,12 @@ 
 DEF_FUNCTION_TYPE_1 (BT_FN_UINT16_UINT16, BT_UINT16, BT_UINT16)
 DEF_FUNCTION_TYPE_1 (BT_FN_UINT32_UINT32, BT_UINT32, BT_UINT32)
 DEF_FUNCTION_TYPE_1 (BT_FN_UINT64_UINT64, BT_UINT64, BT_UINT64)
+DEF_FUNCTION_TYPE_1 (BT_FN_UINT16_UINT16_M, BT_UINT16, BT_UINT16_M)
+DEF_FUNCTION_TYPE_1 (BT_FN_UINT32_UINT32_M, BT_UINT32, BT_UINT32_M)
+DEF_FUNCTION_TYPE_1 (BT_FN_UINT64_UINT64_M, BT_UINT64, BT_UINT64_M)
+DEF_FUNCTION_TYPE_1 (BT_FN_UINT16_M_UINT16, BT_UINT16_M, BT_UINT16)
+DEF_FUNCTION_TYPE_1 (BT_FN_UINT32_M_UINT32, BT_UINT32_M, BT_UINT32)
+DEF_FUNCTION_TYPE_1 (BT_FN_UINT64_M_UINT64, BT_UINT64_M, BT_UINT64)
 
 DEF_POINTER_TYPE (BT_PTR_FN_VOID_PTR, BT_FN_VOID_PTR)
 
Index: gcc/builtins.def
===================================================================
--- gcc/builtins.def	(revision 189318)
+++ gcc/builtins.def	(working copy)
@@ -631,6 +631,12 @@ 
 DEF_GCC_BUILTIN        (BUILT_IN_BSWAP16, "bswap16", BT_FN_UINT16_UINT16, ATTR_CONST_NOTHROW_LEAF_LIST)
 DEF_GCC_BUILTIN        (BUILT_IN_BSWAP32, "bswap32", BT_FN_UINT32_UINT32, ATTR_CONST_NOTHROW_LEAF_LIST)
 DEF_GCC_BUILTIN        (BUILT_IN_BSWAP64, "bswap64", BT_FN_UINT64_UINT64, ATTR_CONST_NOTHROW_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_BSWAP16M, "bswap16m", BT_FN_UINT16_UINT16_M, ATTR_CONST_NOTHROW_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_BSWAP32M, "bswap32m", BT_FN_UINT32_UINT32_M, ATTR_CONST_NOTHROW_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_BSWAP64M, "bswap64m", BT_FN_UINT64_UINT64_M, ATTR_CONST_NOTHROW_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_BSWAPM16, "bswapm16", BT_FN_UINT16_M_UINT16, ATTR_CONST_NOTHROW_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_BSWAPM32, "bswapm32", BT_FN_UINT32_M_UINT32, ATTR_CONST_NOTHROW_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_BSWAPM64, "bswapm64", BT_FN_UINT64_M_UINT64, ATTR_CONST_NOTHROW_LEAF_LIST)
 DEF_EXT_LIB_BUILTIN    (BUILT_IN_CLEAR_CACHE, "__clear_cache", BT_FN_VOID_PTR_PTR, ATTR_NOTHROW_LEAF_LIST)
 /* [trans-mem]: Adjust BUILT_IN_TM_CALLOC if BUILT_IN_CALLOC is changed.  */
 DEF_LIB_BUILTIN        (BUILT_IN_CALLOC, "calloc", BT_FN_PTR_SIZE_SIZE, ATTR_MALLOC_NOTHROW_LEAF_LIST)
Index: gcc/stor-layout.c
===================================================================
--- gcc/stor-layout.c	(revision 189318)
+++ gcc/stor-layout.c	(working copy)
@@ -2069,6 +2069,14 @@ 
 	 of the language-specific code.  */
       gcc_unreachable ();
 
+    case MOD_TYPE:
+      SET_TYPE_MODE (type, TYPE_MODE (TREE_TYPE (type)));
+      TYPE_UNSIGNED (type) = TYPE_UNSIGNED (TREE_TYPE (type));
+      TYPE_SIZE (type) = TYPE_SIZE (TREE_TYPE (type));
+      TYPE_SIZE_UNIT (type) = TYPE_SIZE_UNIT (TREE_TYPE (type));
+      TYPE_PRECISION (type) = TYPE_PRECISION (TREE_TYPE (type));
+      break;
+
     case BOOLEAN_TYPE:  /* Used for Java, Pascal, and Chill.  */
       if (TYPE_PRECISION (type) == 0)
 	TYPE_PRECISION (type) = 1; /* default to one byte/boolean.  */
Index: gcc/tree.def
===================================================================
--- gcc/tree.def	(revision 189318)
+++ gcc/tree.def	(working copy)
@@ -166,6 +166,10 @@ 
    automatically to the value it points to.  Used in C++.  */
 DEFTREECODE (REFERENCE_TYPE, "reference_type", tcc_type, 0)
 
+/* A modification of another type.  Used to describe byte-swapped
+   types.  */
+DEFTREECODE (MOD_TYPE, "mod_type", tcc_type, 0)
+
 /* The C++ decltype(nullptr) type.  */
 DEFTREECODE (NULLPTR_TYPE, "nullptr_type", tcc_type, 0)
 
Index: gcc/varasm.c
===================================================================
--- gcc/varasm.c	(revision 189318)
+++ gcc/varasm.c	(working copy)
@@ -4508,6 +4508,8 @@ 
     }
 
   code = TREE_CODE (TREE_TYPE (exp));
+  if (code == MOD_TYPE)
+    code = TREE_CODE (TREE_TYPE (TREE_TYPE (exp)));
   thissize = int_size_in_bytes (TREE_TYPE (exp));
 
   /* Allow a constructor with no elements for any data type.