aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorRobin Dapp <rdapp@linux.vnet.ibm.com>2015-11-23 08:05:33 +0000
committerAndreas Krebbel <krebbel@gcc.gnu.org>2015-11-23 08:05:33 +0000
commite63d44c2a9d2a95c7f23de189966be0a3dcc5923 (patch)
treef06f2517d73d42a2b0cfdbbf9e92039a2fbf3069 /gcc
parent6e9966e8303f5f39870a11d96a64b376a2fab347 (diff)
downloadgcc-e63d44c2a9d2a95c7f23de189966be0a3dcc5923.zip
gcc-e63d44c2a9d2a95c7f23de189966be0a3dcc5923.tar.gz
gcc-e63d44c2a9d2a95c7f23de189966be0a3dcc5923.tar.bz2
S/390: Fix symbol ref alignment
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. From-SVN: r230735
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog9
-rw-r--r--gcc/config/s390/predicates.md4
-rw-r--r--gcc/config/s390/s390.c65
-rw-r--r--gcc/config/s390/s390.h35
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/gcc.target/s390/load-relative-check.c46
6 files changed, 136 insertions, 28 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index c584fd9..22cf2bd 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/config/s390/predicates.md b/gcc/config/s390/predicates.md
index eeaf1ae..893092b 100644
--- a/gcc/config/s390/predicates.md
+++ b/gcc/config/s390/predicates.md
@@ -122,7 +122,7 @@
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)));
@@ -147,7 +147,7 @@
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)));
diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c
index 40ee2f7..5a7406c 100644
--- a/gcc/config/s390/s390.c
+++ b/gcc/config/s390/s390.c
@@ -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
diff --git a/gcc/config/s390/s390.h b/gcc/config/s390/s390.h
index a0faf13ba..0f9225c 100644
--- a/gcc/config/s390/s390.h
+++ b/gcc/config/s390/s390.h
@@ -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)
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 5c67011..7a2484c 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
index 0000000..5290045
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/load-relative-check.c
@@ -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];
+ }