From 4d818c85402bcd853c5bda92dfec234267dca3ba Mon Sep 17 00:00:00 2001
From: Richard Earnshaw <rearnsha@arm.com>
Date: Tue, 26 May 1998 07:37:15 +0000
Subject: [PATCH] arm.c (bad_signed_byte_operand): New predicate function.

* arm.c (bad_signed_byte_operand): New predicate function.
* arm.h (PREDICATE_CODES): Add it to the list.
* arm.md (*extendqi[sh]i_insn): Split any addresses that ldrsb
can't handle.
(define_split): Two new splits for above insns.

From-SVN: r20057
---
 gcc/ChangeLog         |  8 ++++
 gcc/config/arm/arm.c  | 27 ++++++++++++++
 gcc/config/arm/arm.h  |  1 +
 gcc/config/arm/arm.md | 85 +++++++++++++++++++++++++++++++++++++++----
 4 files changed, 114 insertions(+), 7 deletions(-)

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 2efb4ed09d4b..13750bda9426 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,11 @@
+Tue May 26 07:31:04 1998  Richard Earnshaw (rearnsha@arm.com)
+
+	* arm.c (bad_signed_byte_operand): New predicate function.
+	* arm.h (PREDICATE_CODES): Add it to the list.
+	* arm.md (*extendqi[sh]i_insn): Split any addresses that ldrsb
+	can't handle.
+	(define_split): Two new splits for above insns.
+
 Mon May 25 22:49:56 PDT 1998 Jeff Law  (law@cygnus.com)
 
 	* version.c: Bump for snapshot.
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 28614a2d2e98..ab0faa835ad9 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -1745,6 +1745,33 @@ reload_memory_operand (op, mode)
 		  && REGNO (op) >= FIRST_PSEUDO_REGISTER)));
 }
 
+/* Return 1 if OP is a valid memory address, but not valid for a signed byte
+   memory access (architecture V4) */
+int
+bad_signed_byte_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  if (! memory_operand (op, mode) || GET_CODE (op) != MEM)
+    return 0;
+
+  op = XEXP (op, 0);
+
+  /* A sum of anything more complex than reg + reg or reg + const is bad */
+  if ((GET_CODE (op) == PLUS || GET_CODE (op) == MINUS)
+      && ! s_register_operand (XEXP (op, 0), VOIDmode))
+    return 1;
+
+  /* Big constants are also bad */
+  if (GET_CODE (op) == PLUS && GET_CODE (XEXP (op, 1)) == CONST_INT
+      && (INTVAL (XEXP (op, 1)) > 0xff
+	  || -INTVAL (XEXP (op, 1)) > 0xff))
+    return 1;
+
+  /* Everything else is good, or can will automatically be made so. */
+  return 0;
+}
+
 /* Return TRUE for valid operands for the rhs of an ARM instruction.  */
 
 int
diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h
index 8f4cb2021ada..c6676da52159 100644
--- a/gcc/config/arm/arm.h
+++ b/gcc/config/arm/arm.h
@@ -1781,6 +1781,7 @@ extern int arm_compare_fp;
   {"fpu_rhs_operand", {SUBREG, REG, CONST_DOUBLE}},			\
   {"arm_not_operand", {SUBREG, REG, CONST_INT}},			\
   {"offsettable_memory_operand", {MEM}},				\
+  {"bad_signed_byte_operand", {MEM}},					\
   {"alignable_memory_operand", {MEM}},					\
   {"shiftable_operator", {PLUS, MINUS, AND, IOR, XOR}},			\
   {"minmax_operator", {SMIN, SMAX, UMIN, UMAX}},			\
diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
index 1920112e5c50..4df608726ed7 100644
--- a/gcc/config/arm/arm.md
+++ b/gcc/config/arm/arm.md
@@ -2344,16 +2344,52 @@
   operands[2] = gen_reg_rtx (SImode);
 }")
 
+; Rather than restricting all byte accesses to memory addresses that ldrsb
+; can handle, we fix up the ones that ldrsb can't grok with a split.
 (define_insn "*extendqihi_insn"
   [(set (match_operand:HI 0 "s_register_operand" "=r")
-	(sign_extend:HI (match_operand:QI 1 "memory_operand" "o<>")))]
+	(sign_extend:HI (match_operand:QI 1 "memory_operand" "m")))]
   "arm_arch4"
-  "ldr%?sb\\t%0, %1"
-[(set_attr "type" "load")])
+  "*
+  /* If the address is invalid, this will split the instruction into two. */
+  if (bad_signed_byte_operand(operands[1], QImode))
+    return \"#\";
+  return \"ldr%?sb\\t%0, %1\";
+"
+[(set_attr "type" "load")
+ (set_attr "length" "8")])
+
+(define_split
+  [(set (match_operand:HI 0 "s_register_operand" "")
+	(sign_extend:HI (match_operand:QI 1 "bad_signed_byte_operand" "")))]
+  "arm_arch4 && reload_completed"
+  [(set (match_dup 3) (match_dup 1))
+   (set (match_dup 0) (sign_extend:HI (match_dup 2)))]
+  "
+  {
+    HOST_WIDE_INT offset;
+
+    operands[3] = gen_rtx (REG, SImode, REGNO (operands[0]));
+    operands[2] = gen_rtx (MEM, QImode, operands[3]);
+    MEM_IN_STRUCT_P (operands[2]) = MEM_IN_STRUCT_P (operands[1]);
+    RTX_UNCHANGING_P (operands[2]) = RTX_UNCHANGING_P (operands[1]);
+    operands[1] = XEXP (operands[1], 0);
+    if (GET_CODE (operands[1]) == PLUS
+	&& GET_CODE (XEXP (operands[1], 1)) == CONST_INT
+	&& ! (const_ok_for_arm (offset = INTVAL (XEXP (operands[1], 1)))
+	      || const_ok_for_arm (-offset)))
+      {
+	HOST_WIDE_INT low = (offset > 0
+			     ? (offset & 0xff) : -((-offset) & 0xff));
+	XEXP (operands[2], 0) = plus_constant (operands[3], low);
+	operands[1] = plus_constant (XEXP (operands[1], 0), offset - low);
+      }
+  }
+")
 
 (define_expand "extendqisi2"
   [(set (match_dup 2)
-	(ashift:SI (match_operand:QI 1 "s_register_operand" "")
+	(ashift:SI (match_operand:QI 1 "general_operand" "")
 		   (const_int 24)))
    (set (match_operand:SI 0 "s_register_operand" "")
 	(ashiftrt:SI (match_dup 2)
@@ -2373,12 +2409,47 @@
   operands[2] = gen_reg_rtx (SImode);
 }")
 
+; Rather than restricting all byte accesses to memory addresses that ldrsb
+; can handle, we fix up the ones that ldrsb can't grok with a split.
 (define_insn "*extendqisi_insn"
   [(set (match_operand:SI 0 "s_register_operand" "=r")
-	(sign_extend:SI (match_operand:QI 1 "memory_operand" "o<>")))]
+	(sign_extend:SI (match_operand:QI 1 "memory_operand" "m")))]
   "arm_arch4"
-  "ldr%?sb\\t%0, %1"
-[(set_attr "type" "load")])
+  "*
+  /* If the address is invalid, this will split the instruction into two. */
+  if (bad_signed_byte_operand(operands[1], QImode))
+    return \"#\";
+  return \"ldr%?sb\\t%0, %1\";
+"
+[(set_attr "type" "load")
+ (set_attr "length" "8")])
+
+(define_split
+  [(set (match_operand:SI 0 "s_register_operand" "")
+	(sign_extend:SI (match_operand:QI 1 "bad_signed_byte_operand" "")))]
+  "arm_arch4 && reload_completed"
+  [(set (match_dup 0) (match_dup 1))
+   (set (match_dup 0) (sign_extend:SI (match_dup 2)))]
+  "
+  {
+    HOST_WIDE_INT offset;
+
+    operands[2] = gen_rtx (MEM, QImode, operands[0]);
+    MEM_IN_STRUCT_P (operands[2]) = MEM_IN_STRUCT_P (operands[1]);
+    RTX_UNCHANGING_P (operands[2]) = RTX_UNCHANGING_P (operands[1]);
+    operands[1] = XEXP (operands[1], 0);
+    if (GET_CODE (operands[1]) == PLUS
+	&& GET_CODE (XEXP (operands[1], 1)) == CONST_INT
+	&& ! (const_ok_for_arm (offset = INTVAL (XEXP (operands[1], 1)))
+	      || const_ok_for_arm (-offset)))
+      {
+	HOST_WIDE_INT low = (offset > 0
+			     ? (offset & 0xff) : -((-offset) & 0xff));
+	XEXP (operands[2], 0) = plus_constant (operands[0], low);
+	operands[1] = plus_constant (XEXP (operands[1], 0), offset - low);
+      }
+  }
+")
 
 (define_insn "extendsfdf2"
   [(set (match_operand:DF 0 "s_register_operand" "=f")
-- 
GitLab