Patchwork RFC: c-common PATCH to allow __int128_t literals

login
register
mail settings
Submitter Jason Merrill
Date Feb. 12, 2013, 4:27 p.m.
Message ID <511A6D71.3050409@redhat.com>
Download mbox | patch
Permalink /patch/219878/
State New
Headers show

Comments

Jason Merrill - Feb. 12, 2013, 4:27 p.m.
Although __int128_t is technically not an extended integer type because 
we don't want to change intmax_t, it seems appropriate to me to give it 
the same semantics as an extended integer type apart from that one aspect.

The only thing we weren't implementing is support for numeric literals, 
which is mostly just a matter of setting the libcpp precision option 
appropriately.  Then I added definitions of the appropriate limits 
macros and updated affected tests.

I also constrained C++11 user-defined literals to stay at unsigned long 
long, since they're being passed to a function with a parameter of that 
type.  If you'd prefer, I could handle that in the front end instead.

Does this make sense to you for 4.9?
Joseph S. Myers - Feb. 14, 2013, 1:51 a.m.
On Tue, 12 Feb 2013, Jason Merrill wrote:

> Although __int128_t is technically not an extended integer type because we
> don't want to change intmax_t, it seems appropriate to me to give it the same
> semantics as an extended integer type apart from that one aspect.
> 
> The only thing we weren't implementing is support for numeric literals, which
> is mostly just a matter of setting the libcpp precision option appropriately.
> Then I added definitions of the appropriate limits macros and updated affected
> tests.

Setting the libcpp precision sounds like it would conflict with the C99 
and C11 requirement that preprocessor arithmetic uses exactly the 
precision of intmax_t (C90 requirements were looser).  Thus, for example, 
"2 * UINTMAX_MAX == UINTMAX_MAX - 1" must be true in a #if expression, but 
it sounds like it would be false with this patch.

Similarly, the expected errors in c99-intconst-2.c are correct whenever 
intmax_t is 64-bit, whether or not __int128 is supported; something with 
the lexical form of an integer constant is required by the Constraints (so 
diagnostic required) to have a type and be within the range of that type, 
and the only types permitted are standard and extended integer types of 
the appropriate signedness.

Handling 128-bit constants without breaking standard requirements and 
without making intmax_t 128-bit means still giving appropriate diagnostics 
at least with -pedantic, and would also mean the preprocessor needs to 
handle multiple precisions to deal with such types in preprocessor 
expressions.

Patch

commit 34f930afff6aaba910800d55a58c580ff2046b03
Author: Jason Merrill <jason@redhat.com>
Date:   Mon Feb 11 15:02:05 2013 -0500

    	* glimits.h (__INT128_MIN__, __UINT128_MAX__): Define.
    	* c-cppbuiltin.c (type_suffix): Handle __int128_t.
    	(c_cpp_builtins): Define __INT128_MAX__.
    	(cpp_atomic_builtins): Define __GCC_ATOMIC_INT128_LOCK_FREE.
    	* c-opts.c (c_common_init): Set cpp max precision to that of the
    	largest integer, not intmax_t.
    	* c-lex.c (interpret_integer): Restrict C++11 user-defined literal
    	precision to unsigned long long.

diff --git a/gcc/c-family/c-cppbuiltin.c b/gcc/c-family/c-cppbuiltin.c
index 3e210d9..4f41fbc 100644
--- a/gcc/c-family/c-cppbuiltin.c
+++ b/gcc/c-family/c-cppbuiltin.c
@@ -668,6 +668,10 @@  cpp_atomic_builtins (cpp_reader *pfile)
 		      (have_swap[SWAP_INDEX (long_integer_type_node)]? 2 : 1));
   builtin_define_with_int_value ("__GCC_ATOMIC_LLONG_LOCK_FREE", 
 		(have_swap[SWAP_INDEX (long_long_integer_type_node)]? 2 : 1));
+  if (int128_integer_type_node != NULL_TREE)
+    builtin_define_with_int_value
+      ("__GCC_ATOMIC_INT128_LOCK_FREE",
+       have_swap[SWAP_INDEX (int128_integer_type_node)]? 2 : 1);
 
   /* If we're dealing with a "set" value that doesn't exactly correspond
      to a boolean truth value, let the library work around that.  */
@@ -751,6 +755,8 @@  c_cpp_builtins (cpp_reader *pfile)
   builtin_define_type_max ("__INT_MAX__", integer_type_node);
   builtin_define_type_max ("__LONG_MAX__", long_integer_type_node);
   builtin_define_type_max ("__LONG_LONG_MAX__", long_long_integer_type_node);
+  if (int128_integer_type_node)
+    builtin_define_type_max ("__INT128_MAX__", int128_integer_type_node);
   builtin_define_type_minmax ("__WCHAR_MIN__", "__WCHAR_MAX__",
 			      underlying_wchar_type_node);
   builtin_define_type_minmax ("__WINT_MIN__", "__WINT_MAX__", wint_type_node);
@@ -1132,7 +1138,10 @@  type_suffix (tree type)
   int is_long;
 
   if (type == long_long_integer_type_node
-      || type == long_long_unsigned_type_node)
+      || type == long_long_unsigned_type_node
+      /* int128_t doesn't have its own suffix.  */
+      || type == int128_integer_type_node
+      || type == int128_unsigned_type_node)
     is_long = 2;
   else if (type == long_integer_type_node
 	   || type == long_unsigned_type_node)
diff --git a/gcc/c-family/c-lex.c b/gcc/c-family/c-lex.c
index 819e9d5..c6c591e 100644
--- a/gcc/c-family/c-lex.c
+++ b/gcc/c-family/c-lex.c
@@ -596,11 +596,20 @@  interpret_integer (const cpp_token *token, unsigned int flags,
   enum integer_type_kind itk;
   cpp_num integer;
   cpp_options *options = cpp_get_options (parse_in);
+  unsigned int precision = options->precision;
 
   *overflow = OT_NONE;
 
+  if (flags & CPP_N_USERDEF)
+    /* A C++11 user-defined literal wants a long long unsigned value even
+       if normal literals can be larger.  */
+    options->precision = TYPE_PRECISION (long_long_unsigned_type_node);
+
   integer = cpp_interpret_integer (parse_in, token, flags);
   integer = cpp_num_sign_extend (integer, options->precision);
+
+  options->precision = precision;
+
   if (integer.overflow)
     *overflow = OT_OVERFLOW;
 
diff --git a/gcc/c-family/c-opts.c b/gcc/c-family/c-opts.c
index 1a922a8..e6db77b 100644
--- a/gcc/c-family/c-opts.c
+++ b/gcc/c-family/c-opts.c
@@ -987,7 +987,19 @@  c_common_init (void)
 {
   /* Set up preprocessor arithmetic.  Must be done after call to
      c_common_nodes_and_builtins for type nodes to be good.  */
-  cpp_opts->precision = TYPE_PRECISION (intmax_type_node);
+
+  /* Set cpp precision to be the precision of the largest integer type,
+     which might be larger than intmax_t (i.e. __int128_t).  */
+  for (unsigned int itk = itk_none - 1; ; itk--)
+    {
+      tree type = integer_types[itk];
+      if (type)
+	{
+	  cpp_opts->precision = TYPE_PRECISION (type);
+	  break;
+	}
+    }
+
   cpp_opts->char_precision = TYPE_PRECISION (char_type_node);
   cpp_opts->int_precision = TYPE_PRECISION (integer_type_node);
   cpp_opts->wchar_precision = TYPE_PRECISION (wchar_type_node);
diff --git a/gcc/glimits.h b/gcc/glimits.h
index 372c2c4..396ca36 100644
--- a/gcc/glimits.h
+++ b/gcc/glimits.h
@@ -123,4 +123,11 @@  see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 # define ULONG_LONG_MAX (LONG_LONG_MAX * 2ULL + 1ULL)
 #endif
 
+#ifdef __INT128_MAX__
+/* Minimum value a 'signed __int128_t' can hold.  */
+#define __INT128_MIN__ (-__INT128_MAX__ - 1)
+/* Maximum value an 'unsigned __int128_t' can hold.  */
+#define __UINT128_MAX__ (__INT128_MAX__ * 2ULL + 1ULL)
+#endif
+
 #endif /* _LIMITS_H___ */
diff --git a/gcc/testsuite/c-c++-common/int128-3.c b/gcc/testsuite/c-c++-common/int128-3.c
new file mode 100644
index 0000000..17a1feb
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/int128-3.c
@@ -0,0 +1,7 @@ 
+/* Test for int128 literals.  */
+/* { dg-do compile { target int128 } } */
+/* { dg-options "-std=gnu99" { target c } } */
+/* { dg-options "" { target c++ } } */
+
+unsigned __int128 i = 0xfffffffffffffffff;
+/*                      12345678901234567 */
diff --git a/gcc/testsuite/gcc.dg/c99-intconst-2.c b/gcc/testsuite/gcc.dg/c99-intconst-2.c
index 3492367..2680996 100644
--- a/gcc/testsuite/gcc.dg/c99-intconst-2.c
+++ b/gcc/testsuite/gcc.dg/c99-intconst-2.c
@@ -3,6 +3,6 @@ 
 /* { dg-do compile } */
 /* { dg-options "-std=iso9899:1999 -pedantic-errors" } */
 
-#if 9223372036854775808LL /* { dg-error "integer constant is so large that it is unsigned" } */
-unsigned long long l = 9223372036854775808LL; /* { dg-error "integer constant is so large that it is unsigned" } */
+#if 9223372036854775808LL /* { dg-error "integer constant is so large that it is unsigned" "" { target { ! int128 } } } */
+unsigned long long l = 9223372036854775808LL; /* { dg-error "integer constant is so large that it is unsigned" "" { target { ! int128 } } } */
 #endif
diff --git a/gcc/testsuite/gcc.dg/cpp/arith-3.c b/gcc/testsuite/gcc.dg/cpp/arith-3.c
index 2f94e98..177a718 100644
--- a/gcc/testsuite/gcc.dg/cpp/arith-3.c
+++ b/gcc/testsuite/gcc.dg/cpp/arith-3.c
@@ -16,7 +16,11 @@ 
 #define APPEND2(NUM, SUFF) NUM ## SUFF
 #define APPEND(NUM, SUFF) APPEND2(NUM, SUFF)
 
+#if __UINT128_MAX__ > ULLONG_MAX
+#define TARGET_UTYPE_MAX  __UINT128_MAX__
+#else
 #define TARGET_UTYPE_MAX  ULLONG_MAX
+#endif
 
 /* The tests in this file depend only on the macros defined in this
    #if block.  Note that it is no good calculating these values, as
@@ -118,6 +122,38 @@ 
 #  define LONG_SMODULO -234582345927345L % 12345678901L
 #  define LONG_SMODULO_ANSWER -2101129444L
 
+#elif TARGET_UTYPE_MAX == 340282366920938463463374607431768211455ULL
+
+#  define TARG_PRECISION 128
+#  define MAX_INT  170141183460469231731687303715884105727
+#  define MAX_UINT 340282366920938463463374607431768211455
+
+#  define TARG_MAX_HEX 0x7fffffffffffffffffffffffffffffff
+#  define TARG_MAX_OCT 01777777777777777777777777777777777777777777
+#  define TARG_MAX_PLUS_1 170141183460469231731687303715884105728L
+#  define TARG_MAX_PLUS_1_U 170141183460469231731687303715884105728UL
+#  define TARG_MAX_PLUS_1_HEX 0x80000000000000000000000000000000
+#  define TARG_MAX_PLUS_1_OCT 02000000000000000000000000000000000000000000
+#  define UTARG_MAX_HEX 0xffffffffffffffffffffffffffffffff
+#  define UTARG_MAX_OCT 03777777777777777777777777777777777777777777
+#  define UTARG_MAX_PLUS_1 340282366920938463463374607431768211456L
+#  define UTARG_MAX_PLUS_1_HEX 0x100000000000000000000000000000000
+#  define UTARG_MAX_PLUS_1_OCT 04000000000000000000000000000000000000000000
+
+#  define TARG_LOWPART_PLUS_1 18446744073709551616
+#  define TARG_LOWPART_PLUS_1_U 18446744073709551616U
+
+  /* Division and modulo; anything that uses the high half in both
+     dividend and divisor.  */
+#  define LONG_UDIVISION 7577378169271152754952UL / 4346979189724050067L
+#  define LONG_UDIVISION_ANSWER 1743
+#  define LONG_SDIVISION -7298376219237659121371L / 4932087234986723097L
+#  define LONG_SDIVISION_ANSWER -1479
+#  define LONG_UMODULO 7577378169271152754952UL % 4346979189724050067L
+#  define LONG_UMODULO_ANSWER 593441582133488171L
+#  define LONG_SMODULO -7298376219237659121371L % 4932087234986723097L
+#  define LONG_SMODULO_ANSWER -3819198692295660908
+
 #else
 
 #  error Please extend the macros here so that this file tests your target
diff --git a/gcc/testsuite/gcc.dg/cpp/if-1.c b/gcc/testsuite/gcc.dg/cpp/if-1.c
index c30f215..b25498b 100644
--- a/gcc/testsuite/gcc.dg/cpp/if-1.c
+++ b/gcc/testsuite/gcc.dg/cpp/if-1.c
@@ -37,5 +37,5 @@ 
 #if 099 /* { dg-error "invalid digit" "decimal in octal constant" } */
 #endif
 
-#if 0xfffffffffffffffff /* { dg-error "integer constant" "range error" } */
+#if 0xfffffffffffffffff /* { dg-error "integer constant" "range error" { target { ! int128 } } } */
 #endif
diff --git a/gcc/testsuite/gcc.dg/wtr-int-type-1.c b/gcc/testsuite/gcc.dg/wtr-int-type-1.c
index c0a600d..7f09d14 100644
--- a/gcc/testsuite/gcc.dg/wtr-int-type-1.c
+++ b/gcc/testsuite/gcc.dg/wtr-int-type-1.c
@@ -25,7 +25,7 @@  testfunc ()
 
   /* But this one should, since it doesn't fit in long (long), but
      does fit in unsigned long (long).  */
-  i = 18446744073709551615; /* { dg-warning "integer constant is so large that it is unsigned" "so large" } */
+  i = 18446744073709551615; /* { dg-warning "integer constant is so large that it is unsigned" "so large" { target { ! int128 } } }*/
   /* { dg-warning "this decimal constant would be unsigned in ISO C90" "ISO C90" { target *-*-* } 28 } */
 
 # 29 "sys-header.h" 3