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 ab5891b437507221dae9d4dc64c2ca681fc38431..c9d1a16180673b649b7d302f227c63079eeca730 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 9fd14f65756251980d8a09b75024a152747396ec..81301612ee0ada4e67cfbbb4477194c0fd92ae27 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 02e678acda52826ec2421a42e0b9d6060ad2ed00..9c7b015e9c8f99ea066046bb9e232b7539eca579 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 b3cf2a3cb04fd03b2fdb439e3b5c357fe6aa067b..2c4cfe68bad076613c84264812468d40efff16c4 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 9c5402232a85f684f6206dd12d649744763f8ae6..a323e0127e91482377dea6d750877e10bec04b45 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," } } */