aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKyrylo Tkachov <kyrylo.tkachov@arm.com>2018-03-23 16:43:43 +0000
committerKyrylo Tkachov <ktkachov@gcc.gnu.org>2018-03-23 16:43:43 +0000
commit63028caaeb63f5a3fa1dcabaae10fe5902a39048 (patch)
treea60f13219c7d8bb048d9338aa4dbb01fb98eb1e3
parent2fce761ff8de61f2418c36dbba20b3ac63890996 (diff)
downloadgcc-63028caaeb63f5a3fa1dcabaae10fe5902a39048.zip
gcc-63028caaeb63f5a3fa1dcabaae10fe5902a39048.tar.gz
gcc-63028caaeb63f5a3fa1dcabaae10fe5902a39048.tar.bz2
[arm] PR target/85026: Fix ldrsh length estimate in Thumb state
This bug has been reported against GCC 7.3.0 but it is latent in all release branches and on trunk. We underestimate the length of the LRSH instruction in Thumb state. Unlike other load instructions LDRSH can be encoded in 16 bits only when using a register offset. In the testcase we have "ldrsh r2, [r4]" being assigned a length of 2, which is wrong. So we don't calculate branch ranges properly and cause the assembler error. The fix is to make the unaligned_loadhis insn similar to the *arm_extendqihi_insn insn that outputs an LDRSB. Just remove the wrong 2-byte alternative. I don't think this is worth inventing a new "register-offset-only" constraint. This also makes the patch safer for backporting. Bootstrapped and tested on arm-none-linux-gnueabihf. PR target/85026 * config/arm/arm.md (unaligned_loadhis): Remove first alternative. Clean up attributes. * g++.dg/pr85026.C: New test. From-SVN: r258818
-rw-r--r--gcc/ChangeLog6
-rw-r--r--gcc/config/arm/arm.md9
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/g++.dg/pr85026.C61
4 files changed, 75 insertions, 6 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index e407bc7..53b67fb 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,9 @@
+2018-03-23 Kyrylo Tkachov <kyrylo.tkachov@arm.com>
+
+ PR target/85026
+ * config/arm/arm.md (unaligned_loadhis): Remove first alternative.
+ Clean up attributes.
+
2018-03-23 Richard Biener <rguenther@suse.de>
PR debug/85020
diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
index c6229c2..2d5359e 100644
--- a/gcc/config/arm/arm.md
+++ b/gcc/config/arm/arm.md
@@ -4460,16 +4460,13 @@
(set_attr "type" "load_4")])
(define_insn "unaligned_loadhis"
- [(set (match_operand:SI 0 "s_register_operand" "=l,r")
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
(sign_extend:SI
- (unspec:HI [(match_operand:HI 1 "memory_operand" "Uw,Uh")]
+ (unspec:HI [(match_operand:HI 1 "memory_operand" "Uh")]
UNSPEC_UNALIGNED_LOAD)))]
"unaligned_access"
"ldrsh%?\t%0, %1\t@ unaligned"
- [(set_attr "arch" "t2,any")
- (set_attr "length" "2,4")
- (set_attr "predicable" "yes")
- (set_attr "predicable_short_it" "yes,no")
+ [(set_attr "predicable" "yes")
(set_attr "type" "load_byte")])
(define_insn "unaligned_loadhiu"
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 939c8ff..e709ff1 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2018-03-23 Kyrylo Tkachov <kyrylo.tkachov@arm.com>
+
+ PR target/85026
+ * g++.dg/pr85026.C: New test.
+
2018-03-23 David Edelsohn <dje.gcc@gmail.com>
* g++.dg/debug/pr84704.C: XFAIL AIX.
diff --git a/gcc/testsuite/g++.dg/pr85026.C b/gcc/testsuite/g++.dg/pr85026.C
new file mode 100644
index 0000000..e1e3ccd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/pr85026.C
@@ -0,0 +1,61 @@
+/* PR target/85026. */
+/* { dg-do assemble } */
+/* { dg-options "-O2 -std=gnu++11" } */
+
+template <class> class a;
+class b;
+struct c {
+ typedef a<b> &g;
+};
+template <typename d> struct e { typedef typename d::f iter; };
+class h {
+public:
+ void __attribute__((noreturn)) i();
+} ab;
+template <class> class a {
+public:
+ typedef b *f;
+ b &operator[](unsigned m) {
+ if (ac)
+ ab.i();
+ return ad[m];
+ }
+ f n() { return ad; }
+ f m_fn3();
+ b *ad;
+ unsigned ac;
+};
+class b {
+public:
+ short j;
+ short k;
+ signed l;
+} __attribute__((__packed__));
+void o(a<b> &m, b &p2, b &p) {
+ p2 = p = m[0];
+ if (bool at = false)
+ ;
+ else
+ for (c::g au(m);; at = true)
+ if (bool av = false)
+ ;
+ else
+ for (e<a<int>>::iter aw = au.n(), ax = au.m_fn3(); ax;
+ av ? (void)0 : (void)0)
+ if (bool ay = 0)
+ ;
+ else
+ for (b az = *aw; !ay; ay = true) {
+ if (p2.j)
+ p2.j = az.j;
+ else if (p.j)
+ p.j = az.j;
+ if (p2.k)
+ p2.k = az.k;
+ else if (az.k > p.k)
+ p.k = az.k;
+ if (az.l < p2.l)
+ if (az.l > p.l)
+ p.l = az.l;
+ }
+}