This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[arm] Fix invalid store instructions
- From: Paul Brook <paul at codesourcery dot com>
- To: "gcc-patches at gcc dot gnu dot org" <gcc-patches at gcc dot gnu dot org>
- Cc: Richard Earnshaw <rearnsha at arm dot com>
- Date: Fri, 18 Jun 2004 18:54:27 +0100
- Subject: [arm] Fix invalid store instructions
- Organization: CodeSourcery
In an arm store instruction the source register must not be the same as the
base address register when base writeback is enabled.
Some of the gcc regression tests cause this through the use of uninitialized
variables. It turns out it's also possible to cause this with the following
code:
foo(int a, char * b)
{
register char * p asm("r2");
p = b;
while (a--)
{
*p = (char)(int)p;
p++;
}
}
The same restriction applies at stores of all widths, although I've only
managed to reproduce the bad code generation with byte stores.
The attached patch fixes the invalid instructions by outputting a seperate add
instructions. I also added an extra memory constraint and instruction
alternative to avoid pessimizing the non-writeback case.
Tested with cross to arm-none-elf.
Ok?
The test above is somewhat sensitive to the behaviour of the optimizers,
should I add it anyway?
Paul
2004-06-18 Paul Brook <paul@codesourcery.com>
* config/arm/arm-protos.h (arm_store_mem_op, arm_output_store): Add
prototypes.
* config/arm/arm.c (arm_store_mem_op, arm_output_store): New functions.
* config/arm/arm.h (EXTRA_CONSTRAINT_STR_ARM): Handle 'Us'.
* config/arm/arm.md (arm_movsi_insn, movhi_insn_arch4, arm_movqi_insn,
arm_movsf_soft_insn): Add writeback alternative.
* config/arm/iwmmxt.md (iwmmxt_movsi_insn, cond_iwmmxt_movsi_insn):
Ditto.
* config/arm/vfp.md (arm_movsi_vfp, movsf_vfp): Ditto.
* doc/md.texi: Document 'Us' constraint.
Index: config/arm/arm-protos.h
===================================================================
RCS file: /var/cvsroot/gcc-cvs/gcc/gcc/config/arm/arm-protos.h,v
retrieving revision 1.68
diff -u -p -r1.68 arm-protos.h
--- config/arm/arm-protos.h 5 May 2004 23:11:52 -0000 1.68
+++ config/arm/arm-protos.h 18 Jun 2004 16:24:30 -0000
@@ -73,6 +73,7 @@ extern int arm_add_operand (rtx, enum ma
extern int arm_addimm_operand (rtx, enum machine_mode);
extern int arm_not_operand (rtx, enum machine_mode);
extern int arm_extendqisi_mem_op (rtx, enum machine_mode);
+extern int arm_store_mem_op (rtx, enum machine_mode);
extern int offsettable_memory_operand (rtx, enum machine_mode);
extern int alignable_memory_operand (rtx, enum machine_mode);
extern int arm_float_rhs_operand (rtx, enum machine_mode);
@@ -151,6 +152,7 @@ extern int arm_is_longcall_p (rtx, int,
extern int arm_emit_vector_const (FILE *, rtx);
extern const char * arm_output_load_gr (rtx *);
extern const char *vfp_output_fstmx (rtx *);
+extern const char * arm_output_store (rtx *);
#if defined TREE_CODE
extern rtx arm_function_arg (CUMULATIVE_ARGS *, enum machine_mode, tree, int);
Index: config/arm/arm.c
===================================================================
RCS file: /var/cvsroot/gcc-cvs/gcc/gcc/config/arm/arm.c,v
retrieving revision 1.365
diff -u -p -r1.365 arm.c
--- config/arm/arm.c 28 May 2004 16:00:00 -0000 1.365
+++ config/arm/arm.c 18 Jun 2004 15:44:25 -0000
@@ -4545,6 +4545,28 @@ arm_extendqisi_mem_op (rtx op, enum mach
return arm_legitimate_address_p (mode, XEXP (op, 0), SIGN_EXTEND, 0);
}
+
+/* Return nonzero if OP is a valid destinationfor a store instruction, and
+ does not use a writeback addressing mode. */
+
+int
+arm_store_mem_op (rtx op, enum machine_mode mode)
+{
+ enum rtx_code code;
+
+ if (!memory_operand (op, mode))
+ return 0;
+
+ /* Disallow writeback addressing modes. */
+ code = GET_CODE (XEXP (op, 0));
+ if (code == POST_INC || code == PRE_INC
+ || code == POST_DEC || code == PRE_DEC)
+ return 0;
+
+ return 1;
+}
+
+
/* Return nonzero if OP is a Cirrus or general register. */
int
cirrus_register_operand (rtx op, enum machine_mode mode)
@@ -7892,6 +7914,90 @@ arm_output_fldmx (FILE * stream, unsigne
}
+/* Output a store instruction. Invalid writeback addressing modes will be
+ fixed up with an add instruction. */
+
+const char *
+arm_output_store (rtx * operands)
+{
+ rtx op0;
+ rtx op1;
+ enum rtx_code code;
+ const char *s;
+ rtx otherop[3];
+ HOST_WIDE_INT size;
+
+ size = GET_MODE_SIZE (GET_MODE (operands[0]));
+ op0 = XEXP (operands[0], 0);
+ op1 = operands[1];
+
+ switch (size)
+ {
+ case 1:
+ s = "str%?b\t%1, %0";
+ break;
+
+ case 2:
+ s = "str%?h\t%1, %0";
+ break;
+
+ case 4:
+ s = "str%?\t%1, %0";
+ break;
+
+ default:
+ abort ();
+ }
+
+ code = GET_CODE (op0);
+ if (code == POST_INC || code == PRE_INC
+ || code == POST_DEC || code == PRE_DEC)
+ {
+ op0 = XEXP (op0, 0);
+ if (REGNO (op0) == REGNO (op1))
+ {
+ /* Fixup the illegal cases. */
+ otherop[0] = op0;
+ otherop[1] = GEN_INT (size);
+
+ switch (code)
+ {
+ case PRE_INC:
+ XEXP (operands[0], 0) = gen_rtx_MINUS (SImode, op0,
+ GEN_INT (-size));
+ output_asm_insn ("add%?\t%0, %0, %1", otherop);
+ output_asm_insn (s, operands);
+ break;
+
+ case PRE_DEC:
+ XEXP (operands[0], 0) = gen_rtx_MINUS (SImode, op0,
+ GEN_INT (size));
+ output_asm_insn ("sub%?\t%0, %0, %1", otherop);
+ output_asm_insn (s, operands);
+ break;
+
+ case POST_INC:
+ XEXP (operands[0], 0) = op0;
+ output_asm_insn (s, operands);
+ output_asm_insn ("add%?\t%0, %0, %1", otherop);
+ break;
+
+ case POST_DEC:
+ XEXP (operands[0], 0) = op0;
+ output_asm_insn (s, operands);
+ output_asm_insn ("sub%?\t%0, %0, %1", otherop);
+ break;
+
+ default:
+ abort ();
+ }
+ return "";
+ }
+ }
+ return s;
+}
+
+
/* Output the assembly for a store multiple. */
const char *
Index: config/arm/arm.h
===================================================================
RCS file: /var/cvsroot/gcc-cvs/gcc/gcc/config/arm/arm.h,v
retrieving revision 1.237
diff -u -p -r1.237 arm.h
--- config/arm/arm.h 21 May 2004 01:03:16 -0000 1.237
+++ config/arm/arm.h 18 Jun 2004 15:44:25 -0000
@@ -1275,7 +1275,8 @@ enum reg_class
'U' Prefixes an extended memory constraint where:
'Uv' is an address valid for VFP load/store insns.
'Uy' is an address valid for iwmmxt load/store insns.
- 'Uq' is an address valid for ldrsb. */
+ 'Uq' is an address valid for ldrsb.
+ 'Us' is an address valid for arm store insns without base writeback. */
#define EXTRA_CONSTRAINT_STR_ARM(OP, C, STR) \
(((C) == 'Q') ? (GET_CODE (OP) == MEM \
@@ -1288,8 +1289,9 @@ enum reg_class
((C) == 'U' && (STR)[1] == 'v') ? arm_coproc_mem_operand (OP, FALSE) : \
((C) == 'U' && (STR)[1] == 'y') ? arm_coproc_mem_operand (OP, TRUE) : \
((C) == 'U' && (STR)[1] == 'q') \
- ? arm_extendqisi_mem_op (OP, GET_MODE (OP)) \
- : 0)
+ ? arm_extendqisi_mem_op (OP, GET_MODE (OP)) : \
+ ((C) == 'U' && (STR)[1] == 's') ? arm_store_mem_op (OP, GET_MODE(OP)) : \
+ 0)
#define CONSTRAINT_LEN(C,STR) \
((C) == 'U' ? 2 : DEFAULT_CONSTRAINT_LEN (C, STR))
Index: config/arm/arm.md
===================================================================
RCS file: /var/cvsroot/gcc-cvs/gcc/gcc/config/arm/arm.md,v
retrieving revision 1.169
diff -u -p -r1.169 arm.md
--- config/arm/arm.md 20 May 2004 14:59:43 -0000 1.169
+++ config/arm/arm.md 18 Jun 2004 16:24:10 -0000
@@ -4280,22 +4280,29 @@
"
)
+;; We have two store alternatives to avoid pessimizing the non-writeback case.
(define_insn "*arm_movsi_insn"
- [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r, m")
- (match_operand:SI 1 "general_operand" "rI,K,mi,r"))]
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,Us,m")
+ (match_operand:SI 1 "general_operand" "rI,K,mi,r,r"))]
"TARGET_ARM && ! TARGET_IWMMXT
&& !(TARGET_HARD_FLOAT && TARGET_VFP)
&& ( register_operand (operands[0], SImode)
|| register_operand (operands[1], SImode))"
- "@
- mov%?\\t%0, %1
- mvn%?\\t%0, #%B1
- ldr%?\\t%0, %1
- str%?\\t%1, %0"
- [(set_attr "type" "*,*,load1,store1")
+ "*
+ switch (which_alternative)
+ {
+ case 0: return \"mov%?\\t%0, %1\";
+ case 1: return \"mvn%?\\t%0, #%B1\";
+ case 2: return \"ldr%?\\t%0, %1\";
+ case 3: return \"str%?\\t%1, %0\";
+ case 4: return arm_output_store (operands);
+ default: abort ();
+ }"
+ [(set_attr "type" "*,*,load1,store1,store1")
+ (set_attr "length" "4,4,4,8,8")
(set_attr "predicable" "yes")
- (set_attr "pool_range" "*,*,4096,*")
- (set_attr "neg_pool_range" "*,*,4084,*")]
+ (set_attr "pool_range" "*,*,4096,*,*")
+ (set_attr "neg_pool_range" "*,*,4084,*,*")]
)
(define_split
@@ -4853,22 +4860,28 @@
;; Pattern to recognize insn generated default case above
(define_insn "*movhi_insn_arch4"
- [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,m,r")
- (match_operand:HI 1 "general_operand" "rI,K,r,m"))]
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,Us,m,r")
+ (match_operand:HI 1 "general_operand" "rI,K,r,r,m"))]
"TARGET_ARM
&& arm_arch4
&& (GET_CODE (operands[1]) != CONST_INT
|| const_ok_for_arm (INTVAL (operands[1]))
|| const_ok_for_arm (~INTVAL (operands[1])))"
- "@
- mov%?\\t%0, %1\\t%@ movhi
- mvn%?\\t%0, #%B1\\t%@ movhi
- str%?h\\t%1, %0\\t%@ movhi
- ldr%?h\\t%0, %1\\t%@ movhi"
- [(set_attr "type" "*,*,store1,load1")
+ "*
+ switch (which_alternative)
+ {
+ case 0: return \"mov%?\\t%0, %1\\t%@ movhi\";
+ case 1: return \"mvn%?\\t%0, #%B1\\t%@ movhi\";
+ case 2: return \"str%?h\\t%1, %0\\t%@ movhi\";
+ case 3: return arm_output_store (operands);
+ case 4: return \"ldr%?h\\t%0, %1\\t%@ movhi\";
+ default: abort ();
+ }"
+ [(set_attr "type" "*,*,store1,store1,load1")
(set_attr "predicable" "yes")
- (set_attr "pool_range" "*,*,*,256")
- (set_attr "neg_pool_range" "*,*,*,244")]
+ (set_attr "length" "4,4,4,8,4")
+ (set_attr "pool_range" "*,*,*,*,256")
+ (set_attr "neg_pool_range" "*,*,*,*,244")]
)
(define_insn "*movhi_bytes"
@@ -4995,17 +5008,23 @@
(define_insn "*arm_movqi_insn"
- [(set (match_operand:QI 0 "nonimmediate_operand" "=r,r,r,m")
- (match_operand:QI 1 "general_operand" "rI,K,m,r"))]
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=r,r,r,Us,m")
+ (match_operand:QI 1 "general_operand" "rI,K,m,r,r"))]
"TARGET_ARM
&& ( register_operand (operands[0], QImode)
|| register_operand (operands[1], QImode))"
- "@
- mov%?\\t%0, %1
- mvn%?\\t%0, #%B1
- ldr%?b\\t%0, %1
- str%?b\\t%1, %0"
- [(set_attr "type" "*,*,load1,store1")
+ "*
+ switch (which_alternative)
+ {
+ case 0: return \"mov%?\\t%0, %1\";
+ case 1: return \"mvn%?\\t%0, #%B1\";
+ case 2: return \"ldr%?b\\t%0, %1\";
+ case 3: return \"str%?b\\t%1, %0\";
+ case 4: return arm_output_store (operands);
+ default: abort ();
+ }"
+ [(set_attr "type" "*,*,load1,store1,store1")
+ (set_attr "length" "4,4,4,4,8")
(set_attr "predicable" "yes")]
)
@@ -5065,21 +5084,26 @@
)
(define_insn "*arm_movsf_soft_insn"
- [(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,m")
- (match_operand:SF 1 "general_operand" "r,mE,r"))]
+ [(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,Us,m")
+ (match_operand:SF 1 "general_operand" "r,mE,r,r"))]
"TARGET_ARM
&& TARGET_SOFT_FLOAT
&& (GET_CODE (operands[0]) != MEM
|| register_operand (operands[1], SFmode))"
- "@
- mov%?\\t%0, %1
- ldr%?\\t%0, %1\\t%@ float
- str%?\\t%1, %0\\t%@ float"
- [(set_attr "length" "4,4,4")
+ "*
+ switch (which_alternative)
+ {
+ case 0: return \"mov%?\\t%0, %1\";
+ case 1: return \"ldr%?\\t%0, %1\\t%@ float\";
+ case 2: return \"str%?\\t%1, %0\\t%@ float\";
+ case 3: return arm_output_store (operands);
+ default: abort ();
+ }"
+ [(set_attr "length" "4,4,8,4")
(set_attr "predicable" "yes")
- (set_attr "type" "*,load1,store1")
- (set_attr "pool_range" "*,4096,*")
- (set_attr "neg_pool_range" "*,4084,*")]
+ (set_attr "type" "*,load1,store1,store1")
+ (set_attr "pool_range" "*,4096,*,*")
+ (set_attr "neg_pool_range" "*,4084,*,*")]
)
;;; ??? This should have alternatives for constants.
Index: config/arm/iwmmxt.md
===================================================================
RCS file: /var/cvsroot/gcc-cvs/gcc/gcc/config/arm/iwmmxt.md,v
retrieving revision 1.6
diff -u -p -r1.6 iwmmxt.md
--- config/arm/iwmmxt.md 5 May 2004 23:11:54 -0000 1.6
+++ config/arm/iwmmxt.md 18 Jun 2004 16:05:41 -0000
@@ -92,8 +92,8 @@
)
(define_insn "*iwmmxt_movsi_insn"
- [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r, m,z,r,?z,m,z")
- (match_operand:SI 1 "general_operand" "rI,K,mi,r,r,z,m,z,z"))]
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,Us,m,z,r,?z,m,z")
+ (match_operand:SI 1 "general_operand" "rI,K,mi,r,r,r,z,m,z,z"))]
"TARGET_REALLY_IWMMXT
&& ( register_operand (operands[0], SImode)
|| register_operand (operands[1], SImode))"
@@ -104,16 +104,17 @@
case 1: return \"mvn\\t%0, #%B1\";
case 2: return \"ldr\\t%0, %1\";
case 3: return \"str\\t%1, %0\";
- case 4: return \"tmcr\\t%0, %1\";
- case 5: return \"tmrc\\t%0, %1\";
- case 6: return arm_output_load_gr (operands);
- case 7: return \"wstrw\\t%1, %0\";
+ case 4: return arm_output_store (operands);
+ case 5: return \"tmcr\\t%0, %1\";
+ case 6: return \"tmrc\\t%0, %1\";
+ case 7: return arm_output_load_gr (operands);
+ case 8: return \"wstrw\\t%1, %0\";
default:return \"wstrw\\t%1, [sp, #-4]!\;wldrw\\t%0, [sp], #4\\t@move CG reg\";
}"
- [(set_attr "type" "*,*,load1,store1,*,*,load1,store1,*")
- (set_attr "length" "*,*,*, *,*,*, 16, *,8")
- (set_attr "pool_range" "*,*,4096, *,*,*,1024, *,*")
- (set_attr "neg_pool_range" "*,*,4084, *,*,*, *, 1012,*")
+ [(set_attr "type" "*,*,load1,store1,store1,*,*,load1,store1,*")
+ (set_attr "length" "*,*, *, *, 8,*,*, 16, *,8")
+ (set_attr "pool_range" "*,*, 4096, *, *,*,*, 1024, *,*")
+ (set_attr "neg_pool_range" "*,*, 4084, *, *,*,*, *, 1012,*")
;; Note - the "predicable" attribute is not allowed to have alternatives.
;; Since the wSTRw wCx instruction is not predicable, we cannot support
;; predicating any of the alternatives in this template. Instead,
@@ -133,8 +134,8 @@
(match_operator 2 "arm_comparison_operator"
[(match_operand 3 "cc_register" "")
(const_int 0)])
- (set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r, m,z,r")
- (match_operand:SI 1 "general_operand" "rI,K,mi,r,r,z")))]
+ (set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,Us,m,z,r")
+ (match_operand:SI 1 "general_operand" "rI,K,mi,r,r,r,z")))]
"TARGET_REALLY_IWMMXT
&& ( register_operand (operands[0], SImode)
|| register_operand (operands[1], SImode))"
@@ -145,12 +146,14 @@
case 1: return \"mvn%?\\t%0, #%B1\";
case 2: return \"ldr%?\\t%0, %1\";
case 3: return \"str%?\\t%1, %0\";
- case 4: return \"tmcr%?\\t%0, %1\";
+ case 4: return arm_output_store (operands);
+ case 5: return \"tmcr%?\\t%0, %1\";
default: return \"tmrc%?\\t%0, %1\";
}"
- [(set_attr "type" "*,*,load1,store1,*,*")
- (set_attr "pool_range" "*,*,4096, *,*,*")
- (set_attr "neg_pool_range" "*,*,4084, *,*,*")]
+ [(set_attr "type" "*,*,load1,store1,store1,*,*")
+ (set_attr "length" "*,*, *, *, 8,*,*")
+ (set_attr "pool_range" "*,*, 4096, *, *,*,*")
+ (set_attr "neg_pool_range" "*,*, 4084, *, *,*,*")]
)
(define_insn "movv8qi_internal"
Index: config/arm/vfp.md
===================================================================
RCS file: /var/cvsroot/gcc-cvs/gcc/gcc/config/arm/vfp.md,v
retrieving revision 1.6
diff -u -p -r1.6 vfp.md
--- config/arm/vfp.md 5 May 2004 23:11:54 -0000 1.6
+++ config/arm/vfp.md 18 Jun 2004 15:44:25 -0000
@@ -111,25 +111,31 @@
;; ??? For now do not allow loading constants into vfp regs. This causes
;; problems because small constants get converted into adds.
(define_insn "*arm_movsi_vfp"
- [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r ,m,!w,r,!w,!w, Uv")
- (match_operand:SI 1 "general_operand" "rI,K,mi,r,r,!w,!w,Uvi,!w"))]
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,Us,m,!w,r,!w,!w, Uv")
+ (match_operand:SI 1 "general_operand" "rI,K,mi,r,r,r,!w,!w,Uvi,!w"))]
"TARGET_ARM && TARGET_VFP && TARGET_HARD_FLOAT
&& ( s_register_operand (operands[0], SImode)
|| s_register_operand (operands[1], SImode))"
- "@
- mov%?\\t%0, %1
- mvn%?\\t%0, #%B1
- ldr%?\\t%0, %1
- str%?\\t%1, %0
- fmsr%?\\t%0, %1\\t%@ int
- fmrs%?\\t%0, %1\\t%@ int
- fcpys%?\\t%0, %1\\t%@ int
- flds%?\\t%0, %1\\t%@ int
- fsts%?\\t%1, %0\\t%@ int"
- [(set_attr "predicable" "yes")
- (set_attr "type" "*,*,load1,store1,r_2_f,f_2_r,ffarith,f_load,f_store")
- (set_attr "pool_range" "*,*,4096,*,*,*,*,1020,*")
- (set_attr "neg_pool_range" "*,*,4084,*,*,*,*,1008,*")]
+ "*
+ switch (which_alternative)
+ {
+ case 0: return \"mov%?\\t%0, %1\";
+ case 1: return \"mvn%?\\t%0, #%B1\";
+ case 2: return \"ldr%?\\t%0, %1\";
+ case 3: return \"str%?\\t%1, %0\";
+ case 4: return arm_output_store (operands);
+ case 5: return \"fmsr%?\\t%0, %1\\t%@ int\";
+ case 6: return \"fmrs%?\\t%0, %1\\t%@ int\";
+ case 7: return \"fcpys%?\\t%0, %1\\t%@ int\";
+ case 8: return \"flds%?\\t%0, %1\\t%@ int\";
+ case 9: return \"fsts%?\\t%1, %0\\t%@ int\";
+ default: abort();
+ }"
+ [(set_attr "predicable" "yes")
+ (set_attr "type" "*,*,load1,store1,store1,r_2_f,f_2_r,ffarith,f_load,f_store")
+ (set_attr "length" "4,4,4,4,8,4,4,4,4,4")
+ (set_attr "pool_range" "*,*,4096,*,*,*,*,*,1020,*")
+ (set_attr "neg_pool_range" "*,*,4084,*,*,*,*,*,1008,*")]
)
@@ -168,24 +174,30 @@
;; SFmode moves
(define_insn "*movsf_vfp"
- [(set (match_operand:SF 0 "nonimmediate_operand" "=w,r,w ,Uv,r ,m,w,r")
- (match_operand:SF 1 "general_operand" " r,w,UvE,w, mE,r,w,r"))]
+ [(set (match_operand:SF 0 "nonimmediate_operand" "=w,r,w ,Uv,r,Us,m,w,r")
+ (match_operand:SF 1 "general_operand" " r,w,UvE,w, mE,r,r,w,r"))]
"TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP
&& ( s_register_operand (operands[0], SFmode)
|| s_register_operand (operands[1], SFmode))"
- "@
- fmsr%?\\t%0, %1
- fmrs%?\\t%0, %1
- flds%?\\t%0, %1
- fsts%?\\t%1, %0
- ldr%?\\t%0, %1\\t%@ float
- str%?\\t%1, %0\\t%@ float
- fcpys%?\\t%0, %1
- mov%?\\t%0, %1\\t%@ float"
- [(set_attr "predicable" "yes")
- (set_attr "type" "r_2_f,f_2_r,ffarith,*,f_load,f_store,load1,store1")
- (set_attr "pool_range" "*,*,1020,*,4096,*,*,*")
- (set_attr "neg_pool_range" "*,*,1008,*,4080,*,*,*")]
+ "*
+ switch (which_alternative)
+ {
+ case 0: return\"fmsr%?\\t%0, %1\";
+ case 1: return \"fmrs%?\\t%0, %1\";
+ case 2: return \"flds%?\\t%0, %1\";
+ case 3: return \"fsts%?\\t%1, %0\";
+ case 4: return \"ldr%?\\t%0, %1\\t%@ float\";
+ case 5: return \"str%?\\t%1, %0\\t%@ float\";
+ case 6: return arm_output_store (operands);
+ case 7: return \"fcpys%?\\t%0, %1\";
+ case 8: return \"mov%?\\t%0, %1\\t%@ float\";
+ default: abort ();
+ }"
+ [(set_attr "predicable" "yes")
+ (set_attr "type" "r_2_f,f_2_r,f_load,f_store,load1,store1,store1,ffarith,*")
+ (set_attr "length" "4,4,4,4,4,4,8,4,4")
+ (set_attr "pool_range" "*,*,1020,*,4096,*,*,*,*")
+ (set_attr "neg_pool_range" "*,*,1008,*,4080,*,*,*,*")]
)
Index: doc/md.texi
===================================================================
RCS file: /var/cvsroot/gcc-cvs/gcc/gcc/doc/md.texi,v
retrieving revision 1.100
diff -u -p -r1.100 md.texi
--- doc/md.texi 11 May 2004 23:35:57 -0000 1.100
+++ doc/md.texi 18 Jun 2004 16:19:53 -0000
@@ -1369,6 +1369,11 @@ A memory reference suitable for iWMMXt l
@item Uq
A memory reference suitable for for the ARMv4 ldrsb instruction.
+@item Us
+A memory reference suitable for arm store insns, and does not use writeback
+addressing modes. Writeback addressing modes may need fixing up with an extra
+instruction so this is used to avoid pessimizing the normal case.
+
@item AVR family---@file{avr.h}
@table @code
@item l