]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
S/390: Fix symbol ref alignment
authorkrebbel <krebbel@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 23 Nov 2015 08:05:33 +0000 (08:05 +0000)
committerkrebbel <krebbel@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 23 Nov 2015 08:05:33 +0000 (08:05 +0000)
This patch fixes the treatment of symbol ref alignments for
arrays and structs in S390. Until now, the NOT_NATURALLY_ALIGNED flag
was not correctly set for array elements and structs larger than 8
bytes. Therefore, load relative instructions that require a specific
alignment would not always be generated. This patch uses separate flags
for 2-, 4-, and 8-byte alignment to fix the problem.

gcc/testsuite/ChangeLog:

2015-11-23  Robin Dapp  <rdapp@linux.vnet.ibm.com>

        * gcc.target/s390/load-relative-check.c: New test to check
        generation of load relative instructions.

gcc/ChangeLog:

2015-11-23  Robin Dapp  <rdapp@linux.vnet.ibm.com>

        * config/s390/s390.h: Add new symref flags, _NOTALIGN2 etc.
        * config/s390/s390.c (s390_check_symref_alignment): Use new
        symref flags, early abort on wrong alignment
        (s390_secondary_reload): Use new symref flags.
        (s390_encode_section_info): Likewise.
        * config/s390/predicates.md: Likewise.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@230735 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/config/s390/predicates.md
gcc/config/s390/s390.c
gcc/config/s390/s390.h
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/s390/load-relative-check.c [new file with mode: 0644]

index c584fd9780debea6c9ecef014c4fa0a25166540e..22cf2bd85faae105903a519a0858f74569f41f7a 100644 (file)
@@ -1,3 +1,12 @@
+2015-11-23  Robin Dapp  <rdapp@linux.vnet.ibm.com>
+
+        * config/s390/s390.h: Add new symref flags, _NOTALIGN2 etc.
+        * config/s390/s390.c (s390_check_symref_alignment): Use new
+        symref flags, early abort on wrong alignment
+        (s390_secondary_reload): Use new symref flags.
+        (s390_encode_section_info): Likewise.
+        * config/s390/predicates.md: Likewise.
+
 2015-11-23  Kugan Vivekanandarajah  <kuganv@linaro.org>
 
        PR target/68390
index eeaf1aef9f80e00c35422e2c2d3716abdc90d37c..893092b9f4696f7693265430bd7cde449fed313d 100644 (file)
   if (GET_CODE (op) == LABEL_REF)
     return true;
   if (GET_CODE (op) == SYMBOL_REF)
-    return (!SYMBOL_REF_ALIGN1_P (op)
+    return (!SYMBOL_FLAG_NOTALIGN2_P (op)
            && SYMBOL_REF_TLS_MODEL (op) == 0
            && (!flag_pic || SYMBOL_REF_LOCAL_P (op)));
 
   if (GET_CODE (op) == LABEL_REF)
     return true;
   if (GET_CODE (op) == SYMBOL_REF)
-    return ((SYMBOL_REF_FLAGS (op) & SYMBOL_FLAG_ALIGN1) == 0
+    return (!SYMBOL_FLAG_NOTALIGN2_P (op)
            && SYMBOL_REF_TLS_MODEL (op) == 0
            && (!flag_pic || SYMBOL_REF_LOCAL_P (op)));
 
index 40ee2f77b3182a3aff177eff8aebe1abcef17717..5a7406c65ce702c23954eb4769a99b4e48b09c80 100644 (file)
@@ -3922,15 +3922,30 @@ s390_check_symref_alignment (rtx addr, HOST_WIDE_INT alignment)
   HOST_WIDE_INT addend;
   rtx symref;
 
+  /* The "required alignment" might be 0 (e.g. for certain structs
+     accessed via BLKmode).  Early abort in this case, as well as when
+     an alignment > 8 is required.  */
+  if (alignment < 2 || alignment > 8)
+    return false;
+
   if (!s390_loadrelative_operand_p (addr, &symref, &addend))
     return false;
 
   if (addend & (alignment - 1))
     return false;
 
-  if (GET_CODE (symref) == SYMBOL_REF
-      && !SYMBOL_REF_NOT_NATURALLY_ALIGNED_P (symref))
-    return true;
+  if (GET_CODE (symref) == SYMBOL_REF)
+    {
+      /* We have load-relative instructions for 2-byte, 4-byte, and
+         8-byte alignment so allow only these.  */
+      switch (alignment)
+       {
+       case 8: return !SYMBOL_FLAG_NOTALIGN8_P (symref);
+       case 4: return !SYMBOL_FLAG_NOTALIGN4_P (symref);
+       case 2: return !SYMBOL_FLAG_NOTALIGN2_P (symref);
+       default: return false;
+       }
+    }
 
   if (GET_CODE (symref) == UNSPEC
       && alignment <= UNITS_PER_LONG)
@@ -4062,7 +4077,7 @@ s390_secondary_reload (bool in_p, rtx x, reg_class_t rclass_i,
       if (in_p
          && s390_loadrelative_operand_p (x, &symref, &offset)
          && mode == Pmode
-         && !SYMBOL_REF_ALIGN1_P (symref)
+         && !SYMBOL_FLAG_NOTALIGN2_P (symref)
          && (offset & 1) == 1)
        sri->icode = ((mode == DImode) ? CODE_FOR_reloaddi_larl_odd_addend_z10
                      : CODE_FOR_reloadsi_larl_odd_addend_z10);
@@ -11813,29 +11828,39 @@ s390_encode_section_info (tree decl, rtx rtl, int first)
 
   if (TREE_CODE (decl) == VAR_DECL)
     {
-      /* If a variable has a forced alignment to < 2 bytes, mark it
-        with SYMBOL_FLAG_ALIGN1 to prevent it from being used as LARL
-        operand.  */
-      if (DECL_USER_ALIGN (decl) && DECL_ALIGN (decl) < 16)
-       SYMBOL_REF_FLAGS (XEXP (rtl, 0)) |= SYMBOL_FLAG_ALIGN1;
-      if (!DECL_SIZE (decl)
-         || !DECL_ALIGN (decl)
-         || !tree_fits_shwi_p (DECL_SIZE (decl))
-         || (DECL_ALIGN (decl) <= 64
-             && DECL_ALIGN (decl) != tree_to_shwi (DECL_SIZE (decl))))
-       SYMBOL_REF_FLAGS (XEXP (rtl, 0)) |= SYMBOL_FLAG_NOT_NATURALLY_ALIGNED;
+      /* Store the alignment to be able to check if we can use
+        a larl/load-relative instruction.  We only handle the cases
+        that can go wrong (i.e. no FUNC_DECLs).  If a symref does
+        not have any flag we assume it to be correctly aligned.  */
+
+      if (DECL_ALIGN (decl) % 64)
+       SYMBOL_FLAG_SET_NOTALIGN8 (XEXP (rtl, 0));
+
+      if (DECL_ALIGN (decl) % 32)
+       SYMBOL_FLAG_SET_NOTALIGN4 (XEXP (rtl, 0));
+
+      if (DECL_ALIGN (decl) == 0 || DECL_ALIGN (decl) % 16)
+       SYMBOL_FLAG_SET_NOTALIGN2 (XEXP (rtl, 0));
     }
 
   /* Literal pool references don't have a decl so they are handled
      differently here.  We rely on the information in the MEM_ALIGN
-     entry to decide upon natural alignment.  */
+     entry to decide upon the alignment.  */
   if (MEM_P (rtl)
       && GET_CODE (XEXP (rtl, 0)) == SYMBOL_REF
       && TREE_CONSTANT_POOL_ADDRESS_P (XEXP (rtl, 0))
-      && (MEM_ALIGN (rtl) == 0
-         || GET_MODE_BITSIZE (GET_MODE (rtl)) == 0
-         || MEM_ALIGN (rtl) < GET_MODE_BITSIZE (GET_MODE (rtl))))
-    SYMBOL_REF_FLAGS (XEXP (rtl, 0)) |= SYMBOL_FLAG_NOT_NATURALLY_ALIGNED;
+      && MEM_ALIGN (rtl) != 0
+      && GET_MODE_BITSIZE (GET_MODE (rtl)) != 0)
+    {
+      if (MEM_ALIGN (rtl) % 64)
+       SYMBOL_FLAG_SET_NOTALIGN8 (XEXP (rtl, 0));
+
+      if (MEM_ALIGN (rtl) % 32)
+       SYMBOL_FLAG_SET_NOTALIGN4 (XEXP (rtl, 0));
+
+      if (MEM_ALIGN (rtl) == 0 || MEM_ALIGN (rtl) % 16)
+       SYMBOL_FLAG_SET_NOTALIGN2 (XEXP (rtl, 0));
+    }
 }
 
 /* Output thunk to FILE that implements a C++ virtual function call (with
index a0faf13ba75a44ca5ceae33653fd624977ce7755..0f9225c6f8446fbb2939f6322fe26b5173ff1c91 100644 (file)
@@ -963,12 +963,35 @@ do {                                                                      \
 #define CLZ_DEFINED_VALUE_AT_ZERO(MODE, VALUE) ((VALUE) = 64, 1)
 
 /* Machine-specific symbol_ref flags.  */
-#define SYMBOL_FLAG_ALIGN1               (SYMBOL_FLAG_MACH_DEP << 0)
-#define SYMBOL_REF_ALIGN1_P(X)         \
-  ((SYMBOL_REF_FLAGS (X) & SYMBOL_FLAG_ALIGN1))
-#define SYMBOL_FLAG_NOT_NATURALLY_ALIGNED (SYMBOL_FLAG_MACH_DEP << 1)
-#define SYMBOL_REF_NOT_NATURALLY_ALIGNED_P(X) \
-  ((SYMBOL_REF_FLAGS (X) & SYMBOL_FLAG_NOT_NATURALLY_ALIGNED))
+#define SYMBOL_FLAG_ALIGN_SHIFT          SYMBOL_FLAG_MACH_DEP_SHIFT
+#define SYMBOL_FLAG_ALIGN_MASK    \
+  ((SYMBOL_FLAG_MACH_DEP << 0) | (SYMBOL_FLAG_MACH_DEP << 1))
+
+#define SYMBOL_FLAG_SET_ALIGN(X, A) \
+    (SYMBOL_REF_FLAGS (X) = (SYMBOL_REF_FLAGS (X) & ~SYMBOL_FLAG_ALIGN_MASK) \
+     | (A << SYMBOL_FLAG_ALIGN_SHIFT))
+
+#define SYMBOL_FLAG_GET_ALIGN(X) \
+    ((SYMBOL_REF_FLAGS (X) & SYMBOL_FLAG_ALIGN_MASK) >> SYMBOL_FLAG_ALIGN_SHIFT)
+
+/* Helpers to access symbol_ref flags.  They are used in
+   check_symref_alignment() and larl_operand to detect if the
+   available alignment matches the required one.  We do not use
+   a positive check like _ALIGN2 because in that case we would have
+   to annotate every symbol_ref.  However, we only want to touch
+   the symbol_refs that can be misaligned and assume that the others
+   are correctly aligned.  Hence, if a symbol_ref does not have
+   a _NOTALIGN flag it is supposed to be correctly aligned.  */
+#define SYMBOL_FLAG_SET_NOTALIGN2(X) SYMBOL_FLAG_SET_ALIGN(X, 1)
+#define SYMBOL_FLAG_SET_NOTALIGN4(X) SYMBOL_FLAG_SET_ALIGN(X, 2)
+#define SYMBOL_FLAG_SET_NOTALIGN8(X) SYMBOL_FLAG_SET_ALIGN(X, 3)
+
+#define SYMBOL_FLAG_NOTALIGN2_P(X) (SYMBOL_FLAG_GET_ALIGN(X) == 1)
+#define SYMBOL_FLAG_NOTALIGN4_P(X) (SYMBOL_FLAG_GET_ALIGN(X) == 2 \
+                                   || SYMBOL_FLAG_GET_ALIGN(X) == 1)
+#define SYMBOL_FLAG_NOTALIGN8_P(X) (SYMBOL_FLAG_GET_ALIGN(X) == 3 \
+                                   || SYMBOL_FLAG_GET_ALIGN(X) == 2 \
+                                   || SYMBOL_FLAG_GET_ALIGN(X) == 1)
 
 /* Check whether integer displacement is in range for a short displacement.  */
 #define SHORT_DISP_IN_RANGE(d) ((d) >= 0 && (d) <= 4095)
index 5c670114c74d5facdec2f4b250d824128611e71a..7a2484cd0a43bcd9d73ad4cd9b9dae0a730ea0d2 100644 (file)
@@ -1,3 +1,8 @@
+2015-11-23  Robin Dapp  <rdapp@linux.vnet.ibm.com>
+
+        * gcc.target/s390/load-relative-check.c: New test to check
+        generation of load relative instructions.
+
 2015-11-22  Jerry DeLisle  <jvdelisle@gcc.gnu.org>
 
        * gfortran.dg/fmt_t_8.f90: New test.
diff --git a/gcc/testsuite/gcc.target/s390/load-relative-check.c b/gcc/testsuite/gcc.target/s390/load-relative-check.c
new file mode 100644 (file)
index 0000000..5290045
--- /dev/null
@@ -0,0 +1,46 @@
+/* Check if load-relative instructions are created */
+/* { dg-do compile { target { s390*-*-* } } } */
+/* { dg-options "-O2 -march=z10" } */
+
+/* { dg-final { scan-assembler "lgfrl\t%r.?,b.4" } } */
+/* { dg-final { scan-assembler "lgfrl\t%r.?,s.12" } } */
+/* { dg-final { scan-assembler "lgrl\t%r.?,s" } } */
+/* { dg-final { scan-assembler "larl\t%r.?,.L.?" } } */
+
+int b[20];
+
+struct s
+{
+  long a;
+  int  b;
+  int  c;
+} s;
+
+struct __attribute__((packed)) s2
+{
+  char a;
+  char b;
+  char c;
+} s2;
+
+char __attribute__((aligned(1))) arr[10];
+
+int foo()
+  {
+    return b[1];
+  }
+
+int bar()
+  {
+    return s.c;
+  }
+
+long bar2()
+  {
+    return s.a;
+  }
+
+int baz()
+  {
+    return arr[1];
+  }