re PR target/67400 (-fno-plt doesn't work with function pointers)
authorUros Bizjak <uros@gcc.gnu.org>
Wed, 22 Jun 2016 22:06:56 +0000 (00:06 +0200)
committerUros Bizjak <uros@gcc.gnu.org>
Wed, 22 Jun 2016 22:06:56 +0000 (00:06 +0200)
PR target/67400
* config/i386/i386-protos.h (ix86_force_load_from_GOT_p): New.
* config/i386/i386.c (ix86_force_load_from_GOT_p): New function.
(ix86_legitimate_constant_p): Do not allow UNSPEC_GOTPCREL if
ix86_force_load_from_GOT_p returns true.
(ix86_legitimate_address_p): Allow UNSPEC_GOTPCREL if
ix86_force_load_from_GOT_p returns true.
(ix86_print_operand_address_as): Support UNSPEC_GOTPCREL if
ix86_force_load_from_GOT_p returns true.
(ix86_expand_move): Load the external function address via the
GOT slot if ix86_force_load_from_GOT_p returns true.
* config/i386/predicates.md (x86_64_immediate_operand): Return
false for SYMBOL_REFs where ix86_force_load_from_GOT_p returns true.
(x86_64_zext_immediate_operand): Ditto.

testsuite/ChangeLog:

PR target/67400
        * gcc.target/i386/pr67400-1.c: New test.
        * gcc.target/i386/pr67400-2.c: Likewise.
        * gcc.target/i386/pr67400-3.c: Likewise.
        * gcc.target/i386/pr67400-4.c: Likewise.
        * gcc.target/i386/pr67400-5.c: Likewise.
        * gcc.target/i386/pr67400-6.c: Likewise.
        * gcc.target/i386/pr67400-7.c: Likewise.

From-SVN: r237720

12 files changed:
gcc/ChangeLog
gcc/config/i386/i386-protos.h
gcc/config/i386/i386.c
gcc/config/i386/predicates.md
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/i386/pr67400-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/pr67400-2.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/pr67400-3.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/pr67400-4.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/pr67400-5.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/pr67400-6.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/pr67400-7.c [new file with mode: 0644]

index ab5891b..c9d1a16 100644 (file)
@@ -1,3 +1,21 @@
+2016-06-23  Uros Bizjak  <ubizjak@gmail.com>
+           H.J. Lu  <hongjiu.lu@intel.com>
+
+       PR target/67400
+       * config/i386/i386-protos.h (ix86_force_load_from_GOT_p): New.
+       * config/i386/i386.c (ix86_force_load_from_GOT_p): New function.
+       (ix86_legitimate_constant_p): Do not allow UNSPEC_GOTPCREL if
+       ix86_force_load_from_GOT_p returns true.
+       (ix86_legitimate_address_p): Allow UNSPEC_GOTPCREL if
+       ix86_force_load_from_GOT_p returns true.
+       (ix86_print_operand_address_as): Support UNSPEC_GOTPCREL if
+       ix86_force_load_from_GOT_p returns true.
+       (ix86_expand_move): Load the external function address via the
+       GOT slot if ix86_force_load_from_GOT_p returns true.
+       * config/i386/predicates.md (x86_64_immediate_operand): Return
+       false for SYMBOL_REFs where ix86_force_load_from_GOT_p returns true.
+       (x86_64_zext_immediate_operand): Ditto.
+
 2016-06-22  Uros Bizjak  <ubizjak@gmail.com>
 
        * config/i386/i386.c (ix86_expand_move): Simplify SYMBOL_REF handling.
index 9fd14f6..8130161 100644 (file)
@@ -70,6 +70,7 @@ extern bool ix86_expand_set_or_movmem (rtx, rtx, rtx, rtx, rtx, rtx,
 extern bool constant_address_p (rtx);
 extern bool legitimate_pic_operand_p (rtx);
 extern bool legitimate_pic_address_disp_p (rtx);
+extern bool ix86_force_load_from_GOT_p (rtx);
 extern void print_reg (rtx, int, FILE*);
 extern void ix86_print_operand (FILE *, rtx, int);
 
index 02e678a..9c7b015 100644 (file)
@@ -15120,6 +15120,19 @@ darwin_local_data_pic (rtx disp)
          && XINT (disp, 1) == UNSPEC_MACHOPIC_OFFSET);
 }
 
+/* True if operand X should be loaded from GOT.  */
+
+bool
+ix86_force_load_from_GOT_p (rtx x)
+{
+  return (TARGET_64BIT && !TARGET_PECOFF && !TARGET_MACHO
+         && !flag_plt && !flag_pic
+         && ix86_cmodel != CM_LARGE
+         && GET_CODE (x) == SYMBOL_REF
+         && SYMBOL_REF_FUNCTION_P (x)
+         && !SYMBOL_REF_LOCAL_P (x));
+}
+
 /* Determine if a given RTX is a valid constant.  We already know this
    satisfies CONSTANT_P.  */
 
@@ -15188,6 +15201,12 @@ ix86_legitimate_constant_p (machine_mode mode, rtx x)
       if (MACHO_DYNAMIC_NO_PIC_P)
        return machopic_symbol_defined_p (x);
 #endif
+
+      /* External function address should be loaded
+        via the GOT slot to avoid PLT.  */
+      if (ix86_force_load_from_GOT_p (x))
+       return false;
+
       break;
 
     CASE_CONST_SCALAR_INT:
@@ -15596,6 +15615,9 @@ ix86_legitimate_address_p (machine_mode, rtx addr, bool strict)
            return false;
 
          case UNSPEC_GOTPCREL:
+           if (ix86_force_load_from_GOT_p (XVECEXP (XEXP (disp, 0), 0, 0)))
+             goto is_legitimate_pic;
+           /* FALLTHRU */
          case UNSPEC_PCREL:
            gcc_assert (flag_pic);
            goto is_legitimate_pic;
@@ -18169,6 +18191,12 @@ ix86_print_operand_address_as (FILE *file, rtx addr,
            fputs ("ds:", file);
          fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (disp));
        }
+      /* Load the external function address via the GOT slot to avoid PLT.  */
+      else if (GET_CODE (disp) == CONST
+              && GET_CODE (XEXP (disp, 0)) == UNSPEC
+              && XINT (XEXP (disp, 0), 1) == UNSPEC_GOTPCREL
+              && ix86_force_load_from_GOT_p (XVECEXP (XEXP (disp, 0), 0, 0)))
+       output_pic_addr_const (file, disp, 0);
       else if (flag_pic)
        output_pic_addr_const (file, disp, 0);
       else
@@ -19417,6 +19445,15 @@ ix86_expand_move (machine_mode mode, rtx operands[])
 
       if (model)
        op1 = legitimize_tls_address (op1, model, true);
+      else if (ix86_force_load_from_GOT_p (op1))
+       {
+         /* Load the external function address via GOT slot to avoid PLT.  */
+         op1 = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op1),
+                               UNSPEC_GOTPCREL);
+         op1 = gen_rtx_CONST (Pmode, op1);
+         op1 = gen_const_mem (Pmode, op1);
+         set_mem_alias_set (op1, ix86_GOT_alias_set ());
+       }
       else
        {
          tmp = legitimize_pe_coff_symbol (op1, addend != NULL_RTX);
index b3cf2a3..2c4cfe6 100644 (file)
         return trunc_int_for_mode (val, SImode) == val;
       }
     case SYMBOL_REF:
+      /* TLS symbols are not constant.  */
+      if (SYMBOL_REF_TLS_MODEL (op))
+       return false;
+
+      /* Load the external function address via the GOT slot.  */
+      if (ix86_force_load_from_GOT_p (op))
+       return false;
+
       /* For certain code models, the symbolic references are known to fit.
         in CM_SMALL_PIC model we know it fits if it is local to the shared
         library.  Don't count TLS SYMBOL_REFs here, since they should fit
         only if inside of UNSPEC handled below.  */
-      /* TLS symbols are not constant.  */
-      if (SYMBOL_REF_TLS_MODEL (op))
-       return false;
       return (ix86_cmodel == CM_SMALL || ix86_cmodel == CM_KERNEL
              || (ix86_cmodel == CM_MEDIUM && !SYMBOL_REF_FAR_ADDR_P (op)));
 
              /* TLS symbols are not constant.  */
              if (SYMBOL_REF_TLS_MODEL (op1))
                return false;
+
+             /* Load the external function address via the GOT slot.  */
+             if (ix86_force_load_from_GOT_p (op1))
+               return false;
+
              /* For CM_SMALL assume that latest object is 16MB before
                 end of 31bits boundary.  We may also accept pretty
                 large negative constants knowing that all objects are
       return !(INTVAL (op) & ~(HOST_WIDE_INT) 0xffffffff);
 
     case SYMBOL_REF:
-      /* For certain code models, the symbolic references are known to fit.  */
       /* TLS symbols are not constant.  */
       if (SYMBOL_REF_TLS_MODEL (op))
        return false;
+
+      /* Load the external function address via the GOT slot.  */
+      if (ix86_force_load_from_GOT_p (op))
+       return false;
+
+     /* For certain code models, the symbolic references are known to fit.  */
       return (ix86_cmodel == CM_SMALL
              || (ix86_cmodel == CM_MEDIUM
                  && !SYMBOL_REF_FAR_ADDR_P (op)));
              /* TLS symbols are not constant.  */
              if (SYMBOL_REF_TLS_MODEL (op1))
                return false;
+
+             /* Load the external function address via the GOT slot.  */
+             if (ix86_force_load_from_GOT_p (op1))
+               return false;
+
              /* For small code model we may accept pretty large positive
                 offsets, since one bit is available for free.  Negative
                 offsets are limited by the size of NULL pointer area
index 9c54022..a323e01 100644 (file)
@@ -1,3 +1,14 @@
+2016-06-23  H.J. Lu  <hongjiu.lu@intel.com>
+
+       PR target/67400
+        * gcc.target/i386/pr67400-1.c: New test.
+        * gcc.target/i386/pr67400-2.c: Likewise.
+        * gcc.target/i386/pr67400-3.c: Likewise.
+        * gcc.target/i386/pr67400-4.c: Likewise.
+        * gcc.target/i386/pr67400-5.c: Likewise.
+        * gcc.target/i386/pr67400-6.c: Likewise.
+        * gcc.target/i386/pr67400-7.c: Likewise.
+
 2016-06-22  David Malcolm  <dmalcolm@redhat.com>
 
        * c-c++-common/missing-header-1.c: New test case.
 
 2016-06-15  Uros Bizjak  <ubizjak@gmail.com>
 
-        * gcc.dg/torture/float128-nan.c: Include stdint.h to define uint64_t.
+       * gcc.dg/torture/float128-nan.c: Include stdint.h to define uint64_t.
 
 2016-06-15  Alan Hayward  <alan.hayward@arm.com>
 
 
 2016-06-14  Uros Bizjak  <ubizjak@gmail.com>
 
-        * gcc.target/i386/float128-3.c: New test.
-        * gcc.target/i386/quad-sse4.c: Ditto.
-        * gcc.target/i386/quad-sse.c: Use -msse instead of -msse2.
-        Update scan strings.
+       * gcc.target/i386/float128-3.c: New test.
+       * gcc.target/i386/quad-sse4.c: Ditto.
+       * gcc.target/i386/quad-sse.c: Use -msse instead of -msse2.
+       Update scan strings.
 
 2016-06-14  Richard Biener  <rguenther@suse.de>
 
diff --git a/gcc/testsuite/gcc.target/i386/pr67400-1.c b/gcc/testsuite/gcc.target/i386/pr67400-1.c
new file mode 100644 (file)
index 0000000..18b3790
--- /dev/null
@@ -0,0 +1,13 @@
+/* { dg-do compile { target { *-*-linux* && { ! ia32 } } } } */
+/* { dg-options "-O2 -fno-pic -fno-plt" } */
+
+extern void bar (void);
+
+void *
+foo (void)
+{
+  return &bar;
+}
+
+/* { dg-final { scan-assembler "mov\(l|q\)\[ \t\]*bar@GOTPCREL" } } */
+/* { dg-final { scan-assembler-not "\(mov|lea\)\(l|q\)\[ \t\]*\(\\\$|\)bar," } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr67400-2.c b/gcc/testsuite/gcc.target/i386/pr67400-2.c
new file mode 100644 (file)
index 0000000..8f61c3f
--- /dev/null
@@ -0,0 +1,14 @@
+/* { dg-do compile { target { *-*-linux* && { ! ia32 } } } } */
+/* { dg-options "-O2 -fno-pic -fno-plt" } */
+
+extern void bar (void);
+extern void *p;
+
+void
+foo (void)
+{
+  p = &bar;
+}
+
+/* { dg-final { scan-assembler "mov\(l|q\)\[ \t\]*bar@GOTPCREL" } } */
+/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*\\\$bar," } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr67400-3.c b/gcc/testsuite/gcc.target/i386/pr67400-3.c
new file mode 100644 (file)
index 0000000..40d3521
--- /dev/null
@@ -0,0 +1,16 @@
+/* { dg-do compile { target { *-*-linux* && { ! ia32 } } } } */
+/* { dg-options "-O2 -fno-pic -fno-plt" } */
+
+static void
+bar (void)
+{
+}
+
+void *
+foo (void)
+{
+  return &bar;
+}
+
+/* { dg-final { scan-assembler "mov\(l|q\)\[ \t\]*\\\$bar," } } */
+/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*bar@GOTPCREL" } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr67400-4.c b/gcc/testsuite/gcc.target/i386/pr67400-4.c
new file mode 100644 (file)
index 0000000..a329bbf
--- /dev/null
@@ -0,0 +1,13 @@
+/* { dg-do compile { target { *-*-linux* && { ! ia32 } } } } */
+/* { dg-options "-O2 -fno-pic -fno-plt" } */
+
+extern void bar (void) __attribute__ ((visibility ("hidden")));
+
+void *
+foo (void)
+{
+  return &bar;
+}
+
+/* { dg-final { scan-assembler "mov\(l|q\)\[ \t\]*\\\$bar," } } */
+/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*bar@GOTPCREL" } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr67400-5.c b/gcc/testsuite/gcc.target/i386/pr67400-5.c
new file mode 100644 (file)
index 0000000..2d26a68
--- /dev/null
@@ -0,0 +1,11 @@
+/* { dg-do compile { target { *-*-linux* && { ! ia32 } } } } */
+/* { dg-options "-O2 -fno-pic -fno-plt" } */
+
+extern void foo (void);
+extern void bar (int, int, int, int, int, int, void *);
+
+void
+x (void)
+{
+  bar (1, 2, 3, 4, 5, 6, foo);
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr67400-6.c b/gcc/testsuite/gcc.target/i386/pr67400-6.c
new file mode 100644 (file)
index 0000000..bb766cd
--- /dev/null
@@ -0,0 +1,13 @@
+/* { dg-do compile { target { *-*-linux* && { ! ia32 } } } } */
+/* { dg-options "-O2 -fno-pic -fno-plt" } */
+
+extern int bar (void);
+
+int
+check (void *p)
+{
+  return p != &bar;
+}
+
+/* { dg-final { scan-assembler "cmp\(l|q\)\[ \t\]*.*bar@GOTPCREL" } } */
+/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*\\\$bar," } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr67400-7.c b/gcc/testsuite/gcc.target/i386/pr67400-7.c
new file mode 100644 (file)
index 0000000..32ae85f
--- /dev/null
@@ -0,0 +1,13 @@
+/* { dg-do compile { target { *-*-linux* && { ! ia32 } } } } */
+/* { dg-options "-O2 -fno-pic -fno-plt" } */
+
+extern void bar (void);
+
+void *
+foo (void)
+{
+  return &bar+1;
+}
+
+/* { dg-final { scan-assembler "mov\(l|q\)\[ \t\]*bar@GOTPCREL" } } */
+/* { dg-final { scan-assembler-not "\(mov|lea\)\(l|q\)\[ \t\]*\(\\\$|\)bar," } } */