aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Earnshaw <rearnsha@arm.com>1998-05-26 07:37:15 +0000
committerRichard Earnshaw <rearnsha@gcc.gnu.org>1998-05-26 07:37:15 +0000
commit4d818c85402bcd853c5bda92dfec234267dca3ba (patch)
tree1be04d13d394d482a1db5c5b46d905e0f7974860
parent312a0c90730e796c40ae8e52b4575d4043668d9b (diff)
downloadgcc-4d818c85402bcd853c5bda92dfec234267dca3ba.zip
gcc-4d818c85402bcd853c5bda92dfec234267dca3ba.tar.gz
gcc-4d818c85402bcd853c5bda92dfec234267dca3ba.tar.bz2
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
-rw-r--r--gcc/ChangeLog8
-rw-r--r--gcc/config/arm/arm.c27
-rw-r--r--gcc/config/arm/arm.h1
-rw-r--r--gcc/config/arm/arm.md85
4 files changed, 114 insertions, 7 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 2efb4ed..13750bd 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 28614a2..ab0faa8 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 8f4cb20..c6676da 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 1920112..4df6087 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")