This fixes PR82964 which reports ICEs for some CONST_WIDE_INT immediates.
It turns out decimal floating point CONST_DOUBLE get changed into
CONST_WIDE_INT without checking the constraint on the operand, which 
results in failures.  Avoid this by only allowing SF/DF/TF mode floating
point constants in aarch64_legitimate_constant_p.  A similar issue can
occur with 128-bit immediates which may be emitted even when disallowed
in aarch64_legitimate_constant_p, and the constraints in movti_aarch64
don't match.  Fix this with a new constraint and allowing valid immediates
in aarch64_legitimate_constant_p.

Rather than allowing all 128-bit immediates and expanding in up to 8
MOV/MOVK instructions, limit them to 4 instructions and use a literal
load for other cases.  Improve the pr79041-2.c test to use a literal and
skip it for -fpic.

This fixes all reported failures. OK for commit?


ChangeLog:
2018-01-15  Wilco Dijkstra  <wdijk...@arm.com>
            Richard Sandiford  <richard.sandif...@linaro.org>

    gcc/
        PR target/82964
        * config/aarch64/aarch64.md (movti_aarch64): Use Uti constraint.
        * config/aarch64/aarch64.c (aarch64_mov128_immediate): New function.
        (aarch64_legitimate_constant_p): Just support CONST_DOUBLE 
        SF/DF/TF mode to avoid creating illegal CONST_WIDE_INT immediates.
        Call aarch64_mov128_immediate for CONST_WIDE_INT.
        * config/aarch64/aarch64-protos.h (aarch64_mov128_immediate): Add 
declaration.
        * config/aarch64/constraints.md (aarch64_movti_operand): Limit 
immediates.
        * config/aarch64/predicates.md (Uti): Add new constraint.

    gcc/testsuite/
        PR target/79041
        PR target/82964
        * gcc.target/aarch64/pr79041-2.c: improve test, disable with fpic.
--

diff --git a/gcc/config/aarch64/aarch64-protos.h 
b/gcc/config/aarch64/aarch64-protos.h
index 
15c3b46ebef8f305f960e60a8b4e85d8be07e8c7..bc93f4c5753b47c05c144f4a80ba8034603d3736
 100644
--- a/gcc/config/aarch64/aarch64-protos.h
+++ b/gcc/config/aarch64/aarch64-protos.h
@@ -431,6 +431,8 @@ void aarch64_split_128bit_move (rtx, rtx);
 
 bool aarch64_split_128bit_move_p (rtx, rtx);
 
+bool aarch64_mov128_immediate (rtx);
+
 void aarch64_split_simd_combine (rtx, rtx, rtx);
 
 void aarch64_split_simd_move (rtx, rtx);
diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
index 
7b50ab43dbc075e6b6d4541c3fb71e5cc872c88b..e6cdbe74356e395c887082cea66a468b51b2ff47
 100644
--- a/gcc/config/aarch64/aarch64.c
+++ b/gcc/config/aarch64/aarch64.c
@@ -1996,6 +1996,23 @@ aarch64_internal_mov_immediate (rtx dest, rtx imm, bool 
generate,
   return num_insns;
 }
 
+/* Return whether imm is a 128-bit immediate which is simple enough to
+   expand inline.  */
+bool
+aarch64_mov128_immediate (rtx imm)
+{
+  if (GET_CODE (imm) == CONST_INT)
+    return true;
+
+  gcc_assert (CONST_WIDE_INT_NUNITS (imm) == 2);
+
+  rtx lo = GEN_INT (CONST_WIDE_INT_ELT (imm, 0));
+  rtx hi = GEN_INT (CONST_WIDE_INT_ELT (imm, 1));
+
+  return aarch64_internal_mov_immediate (NULL_RTX, lo, false, DImode)
+        + aarch64_internal_mov_immediate (NULL_RTX, hi, false, DImode) <= 4;
+}
+
 /* Add DELTA to REGNUM in mode MODE.  SCRATCHREG can be used to hold a
    temporary value if necessary.  FRAME_RELATED_P should be true if
    the RTX_FRAME_RELATED flag should be set and CFA adjustments added
@@ -10650,7 +10667,10 @@ static bool
 aarch64_legitimate_constant_p (machine_mode mode, rtx x)
 {
   /* Support CSE and rematerialization of common constants.  */
-  if (CONST_INT_P (x) || CONST_DOUBLE_P (x) || GET_CODE (x) == CONST_VECTOR)
+  if (CONST_INT_P (x)
+      || (CONST_DOUBLE_P (x)
+         && (mode == SFmode || mode == DFmode || mode == TFmode))
+      || GET_CODE (x) == CONST_VECTOR)
     return true;
 
   /* Do not allow vector struct mode constants.  We could support
@@ -10658,9 +10678,9 @@ aarch64_legitimate_constant_p (machine_mode mode, rtx x)
   if (aarch64_vect_struct_mode_p (mode))
     return false;
 
-  /* Do not allow wide int constants - this requires support in movti.  */
+  /* Only allow simple 128-bit immediates.  */
   if (CONST_WIDE_INT_P (x))
-    return false;
+    return aarch64_mov128_immediate (x);
 
   /* Do not allow const (plus (anchor_symbol, const_int)).  */
   if (GET_CODE (x) == CONST)
diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index 
d14b57b0ef7f4eeca40bfdcaf3ebb02a1031cb99..382953e6ec42ae4475d66143be1e25d22e48571f
 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -1023,9 +1023,9 @@ (define_expand "movti"
 
 (define_insn "*movti_aarch64"
   [(set (match_operand:TI 0
-        "nonimmediate_operand"  "=r, w,r,w,r,m,m,w,m")
+        "nonimmediate_operand"  "=   r,w, r,w,r,m,m,w,m")
        (match_operand:TI 1
-        "aarch64_movti_operand" " rn,r,w,w,m,r,Z,m,w"))]
+        "aarch64_movti_operand" " rUti,r, w,w,m,r,Z,m,w"))]
   "(register_operand (operands[0], TImode)
     || aarch64_reg_or_zero (operands[1], TImode))"
   "@
diff --git a/gcc/config/aarch64/constraints.md 
b/gcc/config/aarch64/constraints.md
index 
af4143ef756464afac29d17f124b436520f90451..b13fec91fbc337c60d2c7e24080d25fdf1706e7b
 100644
--- a/gcc/config/aarch64/constraints.md
+++ b/gcc/config/aarch64/constraints.md
@@ -69,6 +69,12 @@ (define_constraint "N"
  (and (match_code "const_int")
       (match_test "aarch64_move_imm (ival, DImode)")))
 
+(define_constraint "Uti"
+ "A constant that can be used with a 128-bit MOV immediate operation."
+ (and (ior (match_code "const_int")
+          (match_code "const_wide_int"))
+      (match_test "aarch64_mov128_immediate (op)")))
+
 (define_constraint "UsO"
  "A constant that can be used with a 32-bit and operation."
  (and (match_code "const_int")
diff --git a/gcc/config/aarch64/predicates.md b/gcc/config/aarch64/predicates.md
index 
2eaf0a7630169c3f4c23632d2a90be9ca15680df..fc06365cc11c4d86f7b95489a83d9a5698265290
 100644
--- a/gcc/config/aarch64/predicates.md
+++ b/gcc/config/aarch64/predicates.md
@@ -257,15 +257,14 @@ (define_predicate "aarch64_mov_operand"
                 (match_test "aarch64_mov_operand_p (op, mode)")))))
 
 (define_predicate "aarch64_movti_operand"
-  (and (match_code "reg,subreg,mem,const_int")
-       (ior (match_operand 0 "register_operand")
-           (ior (match_operand 0 "memory_operand")
-                (match_operand 0 "const_int_operand")))))
+  (ior (match_operand 0 "register_operand")
+       (match_operand 0 "memory_operand")
+       (and (match_operand 0 "const_scalar_int_operand")
+           (match_test "aarch64_mov128_immediate (op)"))))
 
 (define_predicate "aarch64_reg_or_imm"
-  (and (match_code "reg,subreg,const_int")
-       (ior (match_operand 0 "register_operand")
-           (match_operand 0 "const_int_operand"))))
+  (ior (match_operand 0 "register_operand")
+       (match_operand 0 "const_scalar_int_operand")))
 
 ;; True for integer comparisons and for FP comparisons other than LTGT or UNEQ.
 (define_special_predicate "aarch64_comparison_operator"
diff --git a/gcc/testsuite/gcc.target/aarch64/pr79041-2.c 
b/gcc/testsuite/gcc.target/aarch64/pr79041-2.c
index 
a889dfdd89549fdd19d2e167d43835ff0cbb236a..4695b5c1b2b7c9b515995e242dd38e0519a48a2b
 100644
--- a/gcc/testsuite/gcc.target/aarch64/pr79041-2.c
+++ b/gcc/testsuite/gcc.target/aarch64/pr79041-2.c
@@ -1,11 +1,12 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -mcmodel=large -mpc-relative-literal-loads" } */
 /* { dg-require-effective-target lp64 } */
+/* { dg-skip-if "-mcmodel=large, no support for -fpic" { aarch64-*-* }  { 
"-fpic" } { "" } } */
 
 __int128
 t (void)
 {
-  return (__int128)1 << 80;
+  return ((__int128)0x123456789abcdef << 64) | 0xfedcba987654321;
 }
 
 /* { dg-final { scan-assembler "adr" } } */

Reply via email to