mirror of
https://github.com/openembedded/meta-openembedded.git
synced 2025-12-15 23:05:34 +01:00
4237 lines
150 KiB
Diff
4237 lines
150 KiB
Diff
2010-12-03 Yao Qi <yao@codesourcery.com>
|
||
|
||
* config/arm/arm-ldmstm.ml: Rewrite ldm/stm RTL patterns to fix
|
||
regressions.
|
||
* config/arm/ldmstm.md: Regenreate.
|
||
|
||
2010-12-03 Yao Qi <yao@codesourcery.com>
|
||
|
||
Backport from FSF mainline:
|
||
|
||
2010-08-02 Bernd Schmidt <bernds@codesourcery.com>
|
||
|
||
PR target/40457
|
||
* config/arm/arm.h (arm_regs_in_sequence): Declare.
|
||
* config/arm/arm-protos.h (emit_ldm_seq, emit_stm_seq,
|
||
load_multiple_sequence, store_multiple_sequence): Delete
|
||
declarations.
|
||
(arm_gen_load_multiple, arm_gen_store_multiple): Adjust
|
||
declarations.
|
||
* config/arm/ldmstm.md: New file.
|
||
* config/arm/arm.c (arm_regs_in_sequence): New array.
|
||
(load_multiple_sequence): Now static. New args SAVED_ORDER,
|
||
CHECK_REGS. All callers changed.
|
||
If SAVED_ORDER is nonnull, copy the computed order into it.
|
||
If CHECK_REGS is false, don't sort REGS. Handle Thumb mode.
|
||
(store_multiple_sequence): Now static. New args NOPS_TOTAL,
|
||
SAVED_ORDER, REG_RTXS and CHECK_REGS. All callers changed.
|
||
If SAVED_ORDER is nonnull, copy the computed order into it.
|
||
If CHECK_REGS is false, don't sort REGS. Set up REG_RTXS just
|
||
like REGS. Handle Thumb mode.
|
||
(arm_gen_load_multiple_1): New function, broken out of
|
||
arm_gen_load_multiple.
|
||
(arm_gen_store_multiple_1): New function, broken out of
|
||
arm_gen_store_multiple.
|
||
(arm_gen_multiple_op): New function, with code from
|
||
arm_gen_load_multiple and arm_gen_store_multiple moved here.
|
||
(arm_gen_load_multiple, arm_gen_store_multiple): Now just
|
||
wrappers around arm_gen_multiple_op. Remove argument UP, all callers
|
||
changed.
|
||
(gen_ldm_seq, gen_stm_seq, gen_const_stm_seq): New functions.
|
||
* config/arm/predicates.md (commutative_binary_operator): New.
|
||
(load_multiple_operation, store_multiple_operation): Handle more
|
||
variants of these patterns with different starting offsets. Handle
|
||
Thumb-1.
|
||
* config/arm/arm.md: Include "ldmstm.md".
|
||
(ldmsi_postinc4, ldmsi_postinc4_thumb1, ldmsi_postinc3, ldmsi_postinc2,
|
||
ldmsi4, ldmsi3, ldmsi2, stmsi_postinc4, stmsi_postinc4_thumb1,
|
||
stmsi_postinc3, stmsi_postinc2, stmsi4, stmsi3, stmsi2 and related
|
||
peepholes): Delete.
|
||
* config/arm/ldmstm.md: New file.
|
||
* config/arm/arm-ldmstm.ml: New file.
|
||
|
||
* config/arm/arm.c (arm_rtx_costs_1): Remove second clause from the
|
||
if statement which adds extra costs to frame-related expressions.
|
||
|
||
2010-05-06 Bernd Schmidt <bernds@codesourcery.com>
|
||
|
||
* config/arm/arm.h (MAX_LDM_STM_OPS): New macro.
|
||
* config/arm/arm.c (multiple_operation_profitable_p,
|
||
compute_offset_order): New static functions.
|
||
(load_multiple_sequence, store_multiple_sequence): Use them.
|
||
Replace constant 4 with MAX_LDM_STM_OPS. Compute order[0] from
|
||
memory offsets, not register numbers.
|
||
(emit_ldm_seq, emit_stm_seq): Replace constant 4 with MAX_LDM_STM_OPS.
|
||
|
||
2010-04-16 Bernd Schmidt <bernds@codesourcery.com>
|
||
|
||
* recog.h (struct recog_data): New field is_operator.
|
||
(struct insn_operand_data): New field is_operator.
|
||
* recog.c (extract_insn): Set recog_data.is_operator.
|
||
* genoutput.c (output_operand_data): Emit code to set the
|
||
is_operator field.
|
||
* reload.c (find_reloads): Use it rather than testing for an
|
||
empty constraint string.
|
||
|
||
=== added file 'gcc/config/arm/arm-ldmstm.ml'
|
||
--- old/gcc/config/arm/arm-ldmstm.ml 1970-01-01 00:00:00 +0000
|
||
+++ new/gcc/config/arm/arm-ldmstm.ml 2010-11-16 13:08:47 +0000
|
||
@@ -0,0 +1,333 @@
|
||
+(* Auto-generate ARM ldm/stm patterns
|
||
+ Copyright (C) 2010 Free Software Foundation, Inc.
|
||
+ Contributed by CodeSourcery.
|
||
+
|
||
+ This file is part of GCC.
|
||
+
|
||
+ GCC is free software; you can redistribute it and/or modify it under
|
||
+ the terms of the GNU General Public License as published by the Free
|
||
+ Software Foundation; either version 3, or (at your option) any later
|
||
+ version.
|
||
+
|
||
+ GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||
+ for more details.
|
||
+
|
||
+ You should have received a copy of the GNU General Public License
|
||
+ along with GCC; see the file COPYING3. If not see
|
||
+ <http://www.gnu.org/licenses/>.
|
||
+
|
||
+ This is an O'Caml program. The O'Caml compiler is available from:
|
||
+
|
||
+ http://caml.inria.fr/
|
||
+
|
||
+ Or from your favourite OS's friendly packaging system. Tested with version
|
||
+ 3.09.2, though other versions will probably work too.
|
||
+
|
||
+ Run with:
|
||
+ ocaml arm-ldmstm.ml >/path/to/gcc/config/arm/ldmstm.ml
|
||
+*)
|
||
+
|
||
+type amode = IA | IB | DA | DB
|
||
+
|
||
+type optype = IN | OUT | INOUT
|
||
+
|
||
+let rec string_of_addrmode addrmode =
|
||
+ match addrmode with
|
||
+ IA -> "ia" | IB -> "ib" | DA -> "da" | DB -> "db"
|
||
+
|
||
+let rec initial_offset addrmode nregs =
|
||
+ match addrmode with
|
||
+ IA -> 0
|
||
+ | IB -> 4
|
||
+ | DA -> -4 * nregs + 4
|
||
+ | DB -> -4 * nregs
|
||
+
|
||
+let rec final_offset addrmode nregs =
|
||
+ match addrmode with
|
||
+ IA -> nregs * 4
|
||
+ | IB -> nregs * 4
|
||
+ | DA -> -4 * nregs
|
||
+ | DB -> -4 * nregs
|
||
+
|
||
+let constr thumb =
|
||
+ if thumb then "l" else "rk"
|
||
+
|
||
+let inout_constr op_type =
|
||
+ match op_type with
|
||
+ OUT -> "="
|
||
+ | INOUT -> "+&"
|
||
+ | IN -> ""
|
||
+
|
||
+let destreg nregs first op_type thumb =
|
||
+ if not first then
|
||
+ Printf.sprintf "(match_dup %d)" (nregs)
|
||
+ else
|
||
+ Printf.sprintf ("(match_operand:SI %d \"s_register_operand\" \"%s%s\")")
|
||
+ (nregs) (inout_constr op_type) (constr thumb)
|
||
+
|
||
+let write_ldm_set thumb nregs offset opnr first =
|
||
+ let indent = " " in
|
||
+ Printf.printf "%s" (if first then " [" else indent);
|
||
+ Printf.printf "(set (match_operand:SI %d \"arm_hard_register_operand\" \"\")\n" opnr;
|
||
+ Printf.printf "%s (mem:SI " indent;
|
||
+ begin if offset != 0 then Printf.printf "(plus:SI " end;
|
||
+ Printf.printf "%s" (destreg nregs first IN thumb);
|
||
+ begin if offset != 0 then Printf.printf "\n%s (const_int %d))" indent offset end;
|
||
+ Printf.printf "))"
|
||
+
|
||
+let write_stm_set thumb nregs offset opnr first =
|
||
+ let indent = " " in
|
||
+ Printf.printf "%s" (if first then " [" else indent);
|
||
+ Printf.printf "(set (mem:SI ";
|
||
+ begin if offset != 0 then Printf.printf "(plus:SI " end;
|
||
+ Printf.printf "%s" (destreg nregs first IN thumb);
|
||
+ begin if offset != 0 then Printf.printf " (const_int %d))" offset end;
|
||
+ Printf.printf ")\n%s (match_operand:SI %d \"arm_hard_register_operand\" \"\"))" indent opnr
|
||
+
|
||
+let write_ldm_peep_set extra_indent nregs opnr first =
|
||
+ let indent = " " ^ extra_indent in
|
||
+ Printf.printf "%s" (if first then extra_indent ^ " [" else indent);
|
||
+ Printf.printf "(set (match_operand:SI %d \"s_register_operand\" \"\")\n" opnr;
|
||
+ Printf.printf "%s (match_operand:SI %d \"memory_operand\" \"\"))" indent (nregs + opnr)
|
||
+
|
||
+let write_stm_peep_set extra_indent nregs opnr first =
|
||
+ let indent = " " ^ extra_indent in
|
||
+ Printf.printf "%s" (if first then extra_indent ^ " [" else indent);
|
||
+ Printf.printf "(set (match_operand:SI %d \"memory_operand\" \"\")\n" (nregs + opnr);
|
||
+ Printf.printf "%s (match_operand:SI %d \"s_register_operand\" \"\"))" indent opnr
|
||
+
|
||
+let write_any_load optype nregs opnr first =
|
||
+ let indent = " " in
|
||
+ Printf.printf "%s" (if first then " [" else indent);
|
||
+ Printf.printf "(set (match_operand:SI %d \"s_register_operand\" \"\")\n" opnr;
|
||
+ Printf.printf "%s (match_operand:SI %d \"%s\" \"\"))" indent (nregs * 2 + opnr) optype
|
||
+
|
||
+let write_const_store nregs opnr first =
|
||
+ let indent = " " in
|
||
+ Printf.printf "%s(set (match_operand:SI %d \"memory_operand\" \"\")\n" indent (nregs + opnr);
|
||
+ Printf.printf "%s (match_dup %d))" indent opnr
|
||
+
|
||
+let write_const_stm_peep_set nregs opnr first =
|
||
+ write_any_load "const_int_operand" nregs opnr first;
|
||
+ Printf.printf "\n";
|
||
+ write_const_store nregs opnr false
|
||
+
|
||
+
|
||
+let rec write_pat_sets func opnr offset first n_left =
|
||
+ func offset opnr first;
|
||
+ begin
|
||
+ if n_left > 1 then begin
|
||
+ Printf.printf "\n";
|
||
+ write_pat_sets func (opnr + 1) (offset + 4) false (n_left - 1);
|
||
+ end else
|
||
+ Printf.printf "]"
|
||
+ end
|
||
+
|
||
+let rec write_peep_sets func opnr first n_left =
|
||
+ func opnr first;
|
||
+ begin
|
||
+ if n_left > 1 then begin
|
||
+ Printf.printf "\n";
|
||
+ write_peep_sets func (opnr + 1) false (n_left - 1);
|
||
+ end
|
||
+ end
|
||
+
|
||
+let can_thumb addrmode update is_store =
|
||
+ match addrmode, update, is_store with
|
||
+ (* Thumb1 mode only supports IA with update. However, for LDMIA,
|
||
+ if the address register also appears in the list of loaded
|
||
+ registers, the loaded value is stored, hence the RTL pattern
|
||
+ to describe such an insn does not have an update. We check
|
||
+ in the match_parallel predicate that the condition described
|
||
+ above is met. *)
|
||
+ IA, _, false -> true
|
||
+ | IA, true, true -> true
|
||
+ | _ -> false
|
||
+
|
||
+let target addrmode thumb =
|
||
+ match addrmode, thumb with
|
||
+ IA, true -> "TARGET_THUMB1"
|
||
+ | IA, false -> "TARGET_32BIT"
|
||
+ | DB, false -> "TARGET_32BIT"
|
||
+ | _, false -> "TARGET_ARM"
|
||
+
|
||
+let write_pattern_1 name ls addrmode nregs write_set_fn update thumb =
|
||
+ let astr = string_of_addrmode addrmode in
|
||
+ Printf.printf "(define_insn \"*%s%s%d_%s%s\"\n"
|
||
+ (if thumb then "thumb_" else "") name nregs astr
|
||
+ (if update then "_update" else "");
|
||
+ Printf.printf " [(match_parallel 0 \"%s_multiple_operation\"\n" ls;
|
||
+ begin
|
||
+ if update then begin
|
||
+ Printf.printf " [(set %s\n (plus:SI "
|
||
+ (destreg 1 true OUT thumb); (*destreg 2 true IN thumb*)
|
||
+ Printf.printf "(match_operand:SI 2 \"s_register_operand\" \"1\")";
|
||
+ Printf.printf " (const_int %d)))\n"
|
||
+ (final_offset addrmode nregs)
|
||
+ end
|
||
+ end;
|
||
+ write_pat_sets
|
||
+ (write_set_fn thumb (if update then 2 else 1)) (if update then 3 else 2)
|
||
+ (initial_offset addrmode nregs)
|
||
+ (not update) nregs;
|
||
+ Printf.printf ")]\n \"%s && XVECLEN (operands[0], 0) == %d\"\n"
|
||
+ (target addrmode thumb)
|
||
+ (if update then nregs + 1 else nregs);
|
||
+ Printf.printf " \"%s%%(%s%%)\\t%%%d%s, {"
|
||
+ name astr (1) (if update then "!" else "");
|
||
+ for n = 1 to nregs; do
|
||
+ Printf.printf "%%%d%s" (n+(if update then 2 else 1)) (if n < nregs then ", " else "")
|
||
+ done;
|
||
+ Printf.printf "}\"\n";
|
||
+ Printf.printf " [(set_attr \"type\" \"%s%d\")" ls nregs;
|
||
+ begin if not thumb then
|
||
+ Printf.printf "\n (set_attr \"predicable\" \"yes\")";
|
||
+ end;
|
||
+ Printf.printf "])\n\n"
|
||
+
|
||
+let write_ldm_pattern addrmode nregs update =
|
||
+ write_pattern_1 "ldm" "load" addrmode nregs write_ldm_set update false;
|
||
+ begin if can_thumb addrmode update false then
|
||
+ write_pattern_1 "ldm" "load" addrmode nregs write_ldm_set update true;
|
||
+ end
|
||
+
|
||
+let write_stm_pattern addrmode nregs update =
|
||
+ write_pattern_1 "stm" "store" addrmode nregs write_stm_set update false;
|
||
+ begin if can_thumb addrmode update true then
|
||
+ write_pattern_1 "stm" "store" addrmode nregs write_stm_set update true;
|
||
+ end
|
||
+
|
||
+let write_ldm_commutative_peephole thumb =
|
||
+ let nregs = 2 in
|
||
+ Printf.printf "(define_peephole2\n";
|
||
+ write_peep_sets (write_ldm_peep_set "" nregs) 0 true nregs;
|
||
+ let indent = " " in
|
||
+ if thumb then begin
|
||
+ Printf.printf "\n%s(set (match_operand:SI %d \"s_register_operand\" \"\")\n" indent (nregs * 2);
|
||
+ Printf.printf "%s (match_operator:SI %d \"commutative_binary_operator\"\n" indent (nregs * 2 + 1);
|
||
+ Printf.printf "%s [(match_operand:SI %d \"s_register_operand\" \"\")\n" indent (nregs * 2 + 2);
|
||
+ Printf.printf "%s (match_operand:SI %d \"s_register_operand\" \"\")]))]\n" indent (nregs * 2 + 3)
|
||
+ end else begin
|
||
+ Printf.printf "\n%s(parallel\n" indent;
|
||
+ Printf.printf "%s [(set (match_operand:SI %d \"s_register_operand\" \"\")\n" indent (nregs * 2);
|
||
+ Printf.printf "%s (match_operator:SI %d \"commutative_binary_operator\"\n" indent (nregs * 2 + 1);
|
||
+ Printf.printf "%s [(match_operand:SI %d \"s_register_operand\" \"\")\n" indent (nregs * 2 + 2);
|
||
+ Printf.printf "%s (match_operand:SI %d \"s_register_operand\" \"\")]))\n" indent (nregs * 2 + 3);
|
||
+ Printf.printf "%s (clobber (reg:CC CC_REGNUM))])]\n" indent
|
||
+ end;
|
||
+ Printf.printf " \"(((operands[%d] == operands[0] && operands[%d] == operands[1])\n" (nregs * 2 + 2) (nregs * 2 + 3);
|
||
+ Printf.printf " || (operands[%d] == operands[0] && operands[%d] == operands[1]))\n" (nregs * 2 + 3) (nregs * 2 + 2);
|
||
+ Printf.printf " && peep2_reg_dead_p (%d, operands[0]) && peep2_reg_dead_p (%d, operands[1]))\"\n" (nregs + 1) (nregs + 1);
|
||
+ begin
|
||
+ if thumb then
|
||
+ Printf.printf " [(set (match_dup %d) (match_op_dup %d [(match_dup %d) (match_dup %d)]))]\n"
|
||
+ (nregs * 2) (nregs * 2 + 1) (nregs * 2 + 2) (nregs * 2 + 3)
|
||
+ else begin
|
||
+ Printf.printf " [(parallel\n";
|
||
+ Printf.printf " [(set (match_dup %d) (match_op_dup %d [(match_dup %d) (match_dup %d)]))\n"
|
||
+ (nregs * 2) (nregs * 2 + 1) (nregs * 2 + 2) (nregs * 2 + 3);
|
||
+ Printf.printf " (clobber (reg:CC CC_REGNUM))])]\n"
|
||
+ end
|
||
+ end;
|
||
+ Printf.printf "{\n if (!gen_ldm_seq (operands, %d, true))\n FAIL;\n" nregs;
|
||
+ Printf.printf "})\n\n"
|
||
+
|
||
+let write_ldm_peephole nregs =
|
||
+ Printf.printf "(define_peephole2\n";
|
||
+ write_peep_sets (write_ldm_peep_set "" nregs) 0 true nregs;
|
||
+ Printf.printf "]\n \"\"\n [(const_int 0)]\n{\n";
|
||
+ Printf.printf " if (gen_ldm_seq (operands, %d, false))\n DONE;\n else\n FAIL;\n})\n\n" nregs
|
||
+
|
||
+let write_ldm_peephole_b nregs =
|
||
+ if nregs > 2 then begin
|
||
+ Printf.printf "(define_peephole2\n";
|
||
+ write_ldm_peep_set "" nregs 0 true;
|
||
+ Printf.printf "\n (parallel\n";
|
||
+ write_peep_sets (write_ldm_peep_set " " nregs) 1 true (nregs - 1);
|
||
+ Printf.printf "])]\n \"\"\n [(const_int 0)]\n{\n";
|
||
+ Printf.printf " if (gen_ldm_seq (operands, %d, false))\n DONE;\n else\n FAIL;\n})\n\n" nregs
|
||
+ end
|
||
+
|
||
+let write_stm_peephole nregs =
|
||
+ Printf.printf "(define_peephole2\n";
|
||
+ write_peep_sets (write_stm_peep_set "" nregs) 0 true nregs;
|
||
+ Printf.printf "]\n \"\"\n [(const_int 0)]\n{\n";
|
||
+ Printf.printf " if (gen_stm_seq (operands, %d))\n DONE;\n else\n FAIL;\n})\n\n" nregs
|
||
+
|
||
+let write_stm_peephole_b nregs =
|
||
+ if nregs > 2 then begin
|
||
+ Printf.printf "(define_peephole2\n";
|
||
+ write_stm_peep_set "" nregs 0 true;
|
||
+ Printf.printf "\n (parallel\n";
|
||
+ write_peep_sets (write_stm_peep_set "" nregs) 1 true (nregs - 1);
|
||
+ Printf.printf "]\n \"\"\n [(const_int 0)]\n{\n";
|
||
+ Printf.printf " if (gen_stm_seq (operands, %d))\n DONE;\n else\n FAIL;\n})\n\n" nregs
|
||
+ end
|
||
+
|
||
+let write_const_stm_peephole_a nregs =
|
||
+ Printf.printf "(define_peephole2\n";
|
||
+ write_peep_sets (write_const_stm_peep_set nregs) 0 true nregs;
|
||
+ Printf.printf "]\n \"\"\n [(const_int 0)]\n{\n";
|
||
+ Printf.printf " if (gen_const_stm_seq (operands, %d))\n DONE;\n else\n FAIL;\n})\n\n" nregs
|
||
+
|
||
+let write_const_stm_peephole_b nregs =
|
||
+ Printf.printf "(define_peephole2\n";
|
||
+ write_peep_sets (write_any_load "const_int_operand" nregs) 0 true nregs;
|
||
+ Printf.printf "\n";
|
||
+ write_peep_sets (write_const_store nregs) 0 false nregs;
|
||
+ Printf.printf "]\n \"\"\n [(const_int 0)]\n{\n";
|
||
+ Printf.printf " if (gen_const_stm_seq (operands, %d))\n DONE;\n else\n FAIL;\n})\n\n" nregs
|
||
+
|
||
+let patterns () =
|
||
+ let addrmodes = [ IA; IB; DA; DB ] in
|
||
+ let sizes = [ 4; 3; 2] in
|
||
+ List.iter
|
||
+ (fun n ->
|
||
+ List.iter
|
||
+ (fun addrmode ->
|
||
+ write_ldm_pattern addrmode n false;
|
||
+ write_ldm_pattern addrmode n true;
|
||
+ write_stm_pattern addrmode n false;
|
||
+ write_stm_pattern addrmode n true)
|
||
+ addrmodes;
|
||
+ write_ldm_peephole n;
|
||
+ write_ldm_peephole_b n;
|
||
+ write_const_stm_peephole_a n;
|
||
+ write_const_stm_peephole_b n;
|
||
+ write_stm_peephole n;)
|
||
+ sizes;
|
||
+ write_ldm_commutative_peephole false;
|
||
+ write_ldm_commutative_peephole true
|
||
+
|
||
+let print_lines = List.iter (fun s -> Format.printf "%s@\n" s)
|
||
+
|
||
+(* Do it. *)
|
||
+
|
||
+let _ =
|
||
+ print_lines [
|
||
+"/* ARM ldm/stm instruction patterns. This file was automatically generated";
|
||
+" using arm-ldmstm.ml. Please do not edit manually.";
|
||
+"";
|
||
+" Copyright (C) 2010 Free Software Foundation, Inc.";
|
||
+" Contributed by CodeSourcery.";
|
||
+"";
|
||
+" This file is part of GCC.";
|
||
+"";
|
||
+" GCC is free software; you can redistribute it and/or modify it";
|
||
+" under the terms of the GNU General Public License as published";
|
||
+" by the Free Software Foundation; either version 3, or (at your";
|
||
+" option) any later version.";
|
||
+"";
|
||
+" GCC is distributed in the hope that it will be useful, but WITHOUT";
|
||
+" ANY WARRANTY; without even the implied warranty of MERCHANTABILITY";
|
||
+" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public";
|
||
+" License for more details.";
|
||
+"";
|
||
+" You should have received a copy of the GNU General Public License and";
|
||
+" a copy of the GCC Runtime Library Exception along with this program;";
|
||
+" see the files COPYING3 and COPYING.RUNTIME respectively. If not, see";
|
||
+" <http://www.gnu.org/licenses/>. */";
|
||
+""];
|
||
+ patterns ();
|
||
|
||
=== modified file 'gcc/config/arm/arm-protos.h'
|
||
--- old/gcc/config/arm/arm-protos.h 2011-01-05 12:12:18 +0000
|
||
+++ new/gcc/config/arm/arm-protos.h 2011-01-05 18:20:37 +0000
|
||
@@ -100,14 +100,11 @@
|
||
extern int label_mentioned_p (rtx);
|
||
extern RTX_CODE minmax_code (rtx);
|
||
extern int adjacent_mem_locations (rtx, rtx);
|
||
-extern int load_multiple_sequence (rtx *, int, int *, int *, HOST_WIDE_INT *);
|
||
-extern const char *emit_ldm_seq (rtx *, int);
|
||
-extern int store_multiple_sequence (rtx *, int, int *, int *, HOST_WIDE_INT *);
|
||
-extern const char * emit_stm_seq (rtx *, int);
|
||
-extern rtx arm_gen_load_multiple (int, int, rtx, int, int,
|
||
- rtx, HOST_WIDE_INT *);
|
||
-extern rtx arm_gen_store_multiple (int, int, rtx, int, int,
|
||
- rtx, HOST_WIDE_INT *);
|
||
+extern bool gen_ldm_seq (rtx *, int, bool);
|
||
+extern bool gen_stm_seq (rtx *, int);
|
||
+extern bool gen_const_stm_seq (rtx *, int);
|
||
+extern rtx arm_gen_load_multiple (int *, int, rtx, int, rtx, HOST_WIDE_INT *);
|
||
+extern rtx arm_gen_store_multiple (int *, int, rtx, int, rtx, HOST_WIDE_INT *);
|
||
extern int arm_gen_movmemqi (rtx *);
|
||
extern enum machine_mode arm_select_cc_mode (RTX_CODE, rtx, rtx);
|
||
extern enum machine_mode arm_select_dominance_cc_mode (rtx, rtx,
|
||
|
||
=== modified file 'gcc/config/arm/arm.c'
|
||
--- old/gcc/config/arm/arm.c 2011-01-05 12:12:18 +0000
|
||
+++ new/gcc/config/arm/arm.c 2011-01-05 18:20:37 +0000
|
||
@@ -753,6 +753,12 @@
|
||
"hi", "ls", "ge", "lt", "gt", "le", "al", "nv"
|
||
};
|
||
|
||
+/* The register numbers in sequence, for passing to arm_gen_load_multiple. */
|
||
+int arm_regs_in_sequence[] =
|
||
+{
|
||
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
|
||
+};
|
||
+
|
||
#define ARM_LSL_NAME (TARGET_UNIFIED_ASM ? "lsl" : "asl")
|
||
#define streq(string1, string2) (strcmp (string1, string2) == 0)
|
||
|
||
@@ -9680,142 +9686,16 @@
|
||
return 0;
|
||
}
|
||
|
||
-int
|
||
-load_multiple_sequence (rtx *operands, int nops, int *regs, int *base,
|
||
- HOST_WIDE_INT *load_offset)
|
||
-{
|
||
- int unsorted_regs[4];
|
||
- HOST_WIDE_INT unsorted_offsets[4];
|
||
- int order[4];
|
||
- int base_reg = -1;
|
||
- int i;
|
||
-
|
||
- if (low_irq_latency)
|
||
- return 0;
|
||
-
|
||
- /* Can only handle 2, 3, or 4 insns at present,
|
||
- though could be easily extended if required. */
|
||
- gcc_assert (nops >= 2 && nops <= 4);
|
||
-
|
||
- memset (order, 0, 4 * sizeof (int));
|
||
-
|
||
- /* Loop over the operands and check that the memory references are
|
||
- suitable (i.e. immediate offsets from the same base register). At
|
||
- the same time, extract the target register, and the memory
|
||
- offsets. */
|
||
- for (i = 0; i < nops; i++)
|
||
- {
|
||
- rtx reg;
|
||
- rtx offset;
|
||
-
|
||
- /* Convert a subreg of a mem into the mem itself. */
|
||
- if (GET_CODE (operands[nops + i]) == SUBREG)
|
||
- operands[nops + i] = alter_subreg (operands + (nops + i));
|
||
-
|
||
- gcc_assert (GET_CODE (operands[nops + i]) == MEM);
|
||
-
|
||
- /* Don't reorder volatile memory references; it doesn't seem worth
|
||
- looking for the case where the order is ok anyway. */
|
||
- if (MEM_VOLATILE_P (operands[nops + i]))
|
||
- return 0;
|
||
-
|
||
- offset = const0_rtx;
|
||
-
|
||
- if ((GET_CODE (reg = XEXP (operands[nops + i], 0)) == REG
|
||
- || (GET_CODE (reg) == SUBREG
|
||
- && GET_CODE (reg = SUBREG_REG (reg)) == REG))
|
||
- || (GET_CODE (XEXP (operands[nops + i], 0)) == PLUS
|
||
- && ((GET_CODE (reg = XEXP (XEXP (operands[nops + i], 0), 0))
|
||
- == REG)
|
||
- || (GET_CODE (reg) == SUBREG
|
||
- && GET_CODE (reg = SUBREG_REG (reg)) == REG))
|
||
- && (GET_CODE (offset = XEXP (XEXP (operands[nops + i], 0), 1))
|
||
- == CONST_INT)))
|
||
- {
|
||
- if (i == 0)
|
||
- {
|
||
- base_reg = REGNO (reg);
|
||
- unsorted_regs[0] = (GET_CODE (operands[i]) == REG
|
||
- ? REGNO (operands[i])
|
||
- : REGNO (SUBREG_REG (operands[i])));
|
||
- order[0] = 0;
|
||
- }
|
||
- else
|
||
- {
|
||
- if (base_reg != (int) REGNO (reg))
|
||
- /* Not addressed from the same base register. */
|
||
- return 0;
|
||
-
|
||
- unsorted_regs[i] = (GET_CODE (operands[i]) == REG
|
||
- ? REGNO (operands[i])
|
||
- : REGNO (SUBREG_REG (operands[i])));
|
||
- if (unsorted_regs[i] < unsorted_regs[order[0]])
|
||
- order[0] = i;
|
||
- }
|
||
-
|
||
- /* If it isn't an integer register, or if it overwrites the
|
||
- base register but isn't the last insn in the list, then
|
||
- we can't do this. */
|
||
- if (unsorted_regs[i] < 0 || unsorted_regs[i] > 14
|
||
- || (i != nops - 1 && unsorted_regs[i] == base_reg))
|
||
- return 0;
|
||
-
|
||
- unsorted_offsets[i] = INTVAL (offset);
|
||
- }
|
||
- else
|
||
- /* Not a suitable memory address. */
|
||
- return 0;
|
||
- }
|
||
-
|
||
- /* All the useful information has now been extracted from the
|
||
- operands into unsorted_regs and unsorted_offsets; additionally,
|
||
- order[0] has been set to the lowest numbered register in the
|
||
- list. Sort the registers into order, and check that the memory
|
||
- offsets are ascending and adjacent. */
|
||
-
|
||
- for (i = 1; i < nops; i++)
|
||
- {
|
||
- int j;
|
||
-
|
||
- order[i] = order[i - 1];
|
||
- for (j = 0; j < nops; j++)
|
||
- if (unsorted_regs[j] > unsorted_regs[order[i - 1]]
|
||
- && (order[i] == order[i - 1]
|
||
- || unsorted_regs[j] < unsorted_regs[order[i]]))
|
||
- order[i] = j;
|
||
-
|
||
- /* Have we found a suitable register? if not, one must be used more
|
||
- than once. */
|
||
- if (order[i] == order[i - 1])
|
||
- return 0;
|
||
-
|
||
- /* Is the memory address adjacent and ascending? */
|
||
- if (unsorted_offsets[order[i]] != unsorted_offsets[order[i - 1]] + 4)
|
||
- return 0;
|
||
- }
|
||
-
|
||
- if (base)
|
||
- {
|
||
- *base = base_reg;
|
||
-
|
||
- for (i = 0; i < nops; i++)
|
||
- regs[i] = unsorted_regs[order[i]];
|
||
-
|
||
- *load_offset = unsorted_offsets[order[0]];
|
||
- }
|
||
-
|
||
- if (unsorted_offsets[order[0]] == 0)
|
||
- return 1; /* ldmia */
|
||
-
|
||
- if (TARGET_ARM && unsorted_offsets[order[0]] == 4)
|
||
- return 2; /* ldmib */
|
||
-
|
||
- if (TARGET_ARM && unsorted_offsets[order[nops - 1]] == 0)
|
||
- return 3; /* ldmda */
|
||
-
|
||
- if (unsorted_offsets[order[nops - 1]] == -4)
|
||
- return 4; /* ldmdb */
|
||
-
|
||
+
|
||
+/* Return true iff it would be profitable to turn a sequence of NOPS loads
|
||
+ or stores (depending on IS_STORE) into a load-multiple or store-multiple
|
||
+ instruction. ADD_OFFSET is nonzero if the base address register needs
|
||
+ to be modified with an add instruction before we can use it. */
|
||
+
|
||
+static bool
|
||
+multiple_operation_profitable_p (bool is_store ATTRIBUTE_UNUSED,
|
||
+ int nops, HOST_WIDE_INT add_offset)
|
||
+ {
|
||
/* For ARM8,9 & StrongARM, 2 ldr instructions are faster than an ldm
|
||
if the offset isn't small enough. The reason 2 ldrs are faster
|
||
is because these ARMs are able to do more than one cache access
|
||
@@ -9845,91 +9725,239 @@
|
||
We cheat here and test 'arm_ld_sched' which we currently know to
|
||
only be true for the ARM8, ARM9 and StrongARM. If this ever
|
||
changes, then the test below needs to be reworked. */
|
||
- if (nops == 2 && arm_ld_sched)
|
||
+ if (nops == 2 && arm_ld_sched && add_offset != 0)
|
||
+ return false;
|
||
+
|
||
+ return true;
|
||
+}
|
||
+
|
||
+/* Subroutine of load_multiple_sequence and store_multiple_sequence.
|
||
+ Given an array of UNSORTED_OFFSETS, of which there are NOPS, compute
|
||
+ an array ORDER which describes the sequence to use when accessing the
|
||
+ offsets that produces an ascending order. In this sequence, each
|
||
+ offset must be larger by exactly 4 than the previous one. ORDER[0]
|
||
+ must have been filled in with the lowest offset by the caller.
|
||
+ If UNSORTED_REGS is nonnull, it is an array of register numbers that
|
||
+ we use to verify that ORDER produces an ascending order of registers.
|
||
+ Return true if it was possible to construct such an order, false if
|
||
+ not. */
|
||
+
|
||
+static bool
|
||
+compute_offset_order (int nops, HOST_WIDE_INT *unsorted_offsets, int *order,
|
||
+ int *unsorted_regs)
|
||
+{
|
||
+ int i;
|
||
+ for (i = 1; i < nops; i++)
|
||
+ {
|
||
+ int j;
|
||
+
|
||
+ order[i] = order[i - 1];
|
||
+ for (j = 0; j < nops; j++)
|
||
+ if (unsorted_offsets[j] == unsorted_offsets[order[i - 1]] + 4)
|
||
+ {
|
||
+ /* We must find exactly one offset that is higher than the
|
||
+ previous one by 4. */
|
||
+ if (order[i] != order[i - 1])
|
||
+ return false;
|
||
+ order[i] = j;
|
||
+ }
|
||
+ if (order[i] == order[i - 1])
|
||
+ return false;
|
||
+ /* The register numbers must be ascending. */
|
||
+ if (unsorted_regs != NULL
|
||
+ && unsorted_regs[order[i]] <= unsorted_regs[order[i - 1]])
|
||
+ return false;
|
||
+ }
|
||
+ return true;
|
||
+}
|
||
+
|
||
+/* Used to determine in a peephole whether a sequence of load
|
||
+ instructions can be changed into a load-multiple instruction.
|
||
+ NOPS is the number of separate load instructions we are examining. The
|
||
+ first NOPS entries in OPERANDS are the destination registers, the
|
||
+ next NOPS entries are memory operands. If this function is
|
||
+ successful, *BASE is set to the common base register of the memory
|
||
+ accesses; *LOAD_OFFSET is set to the first memory location's offset
|
||
+ from that base register.
|
||
+ REGS is an array filled in with the destination register numbers.
|
||
+ SAVED_ORDER (if nonnull), is an array filled in with an order that maps
|
||
+ insn numbers to to an ascending order of stores. If CHECK_REGS is true,
|
||
+ the sequence of registers in REGS matches the loads from ascending memory
|
||
+ locations, and the function verifies that the register numbers are
|
||
+ themselves ascending. If CHECK_REGS is false, the register numbers
|
||
+ are stored in the order they are found in the operands. */
|
||
+static int
|
||
+load_multiple_sequence (rtx *operands, int nops, int *regs, int *saved_order,
|
||
+ int *base, HOST_WIDE_INT *load_offset, bool check_regs)
|
||
+{
|
||
+ int unsorted_regs[MAX_LDM_STM_OPS];
|
||
+ HOST_WIDE_INT unsorted_offsets[MAX_LDM_STM_OPS];
|
||
+ int order[MAX_LDM_STM_OPS];
|
||
+ rtx base_reg_rtx = NULL;
|
||
+ int base_reg = -1;
|
||
+ int i, ldm_case;
|
||
+
|
||
+ if (low_irq_latency)
|
||
return 0;
|
||
|
||
- /* Can't do it without setting up the offset, only do this if it takes
|
||
- no more than one insn. */
|
||
- return (const_ok_for_arm (unsorted_offsets[order[0]])
|
||
- || const_ok_for_arm (-unsorted_offsets[order[0]])) ? 5 : 0;
|
||
-}
|
||
-
|
||
-const char *
|
||
-emit_ldm_seq (rtx *operands, int nops)
|
||
-{
|
||
- int regs[4];
|
||
- int base_reg;
|
||
- HOST_WIDE_INT offset;
|
||
- char buf[100];
|
||
- int i;
|
||
-
|
||
- switch (load_multiple_sequence (operands, nops, regs, &base_reg, &offset))
|
||
+ /* Can only handle up to MAX_LDM_STM_OPS insns at present, though could be
|
||
+ easily extended if required. */
|
||
+ gcc_assert (nops >= 2 && nops <= MAX_LDM_STM_OPS);
|
||
+
|
||
+ memset (order, 0, MAX_LDM_STM_OPS * sizeof (int));
|
||
+
|
||
+ /* Loop over the operands and check that the memory references are
|
||
+ suitable (i.e. immediate offsets from the same base register). At
|
||
+ the same time, extract the target register, and the memory
|
||
+ offsets. */
|
||
+ for (i = 0; i < nops; i++)
|
||
{
|
||
- case 1:
|
||
- strcpy (buf, "ldm%(ia%)\t");
|
||
- break;
|
||
-
|
||
- case 2:
|
||
- strcpy (buf, "ldm%(ib%)\t");
|
||
- break;
|
||
-
|
||
- case 3:
|
||
- strcpy (buf, "ldm%(da%)\t");
|
||
- break;
|
||
-
|
||
- case 4:
|
||
- strcpy (buf, "ldm%(db%)\t");
|
||
- break;
|
||
-
|
||
- case 5:
|
||
- if (offset >= 0)
|
||
- sprintf (buf, "add%%?\t%s%s, %s%s, #%ld", REGISTER_PREFIX,
|
||
- reg_names[regs[0]], REGISTER_PREFIX, reg_names[base_reg],
|
||
- (long) offset);
|
||
+ rtx reg;
|
||
+ rtx offset;
|
||
+
|
||
+ /* Convert a subreg of a mem into the mem itself. */
|
||
+ if (GET_CODE (operands[nops + i]) == SUBREG)
|
||
+ operands[nops + i] = alter_subreg (operands + (nops + i));
|
||
+
|
||
+ gcc_assert (GET_CODE (operands[nops + i]) == MEM);
|
||
+
|
||
+ /* Don't reorder volatile memory references; it doesn't seem worth
|
||
+ looking for the case where the order is ok anyway. */
|
||
+ if (MEM_VOLATILE_P (operands[nops + i]))
|
||
+ return 0;
|
||
+
|
||
+ offset = const0_rtx;
|
||
+
|
||
+ if ((GET_CODE (reg = XEXP (operands[nops + i], 0)) == REG
|
||
+ || (GET_CODE (reg) == SUBREG
|
||
+ && GET_CODE (reg = SUBREG_REG (reg)) == REG))
|
||
+ || (GET_CODE (XEXP (operands[nops + i], 0)) == PLUS
|
||
+ && ((GET_CODE (reg = XEXP (XEXP (operands[nops + i], 0), 0))
|
||
+ == REG)
|
||
+ || (GET_CODE (reg) == SUBREG
|
||
+ && GET_CODE (reg = SUBREG_REG (reg)) == REG))
|
||
+ && (GET_CODE (offset = XEXP (XEXP (operands[nops + i], 0), 1))
|
||
+ == CONST_INT)))
|
||
+ {
|
||
+ if (i == 0)
|
||
+ {
|
||
+ base_reg = REGNO (reg);
|
||
+ base_reg_rtx = reg;
|
||
+ if (TARGET_THUMB1 && base_reg > LAST_LO_REGNUM)
|
||
+ return 0;
|
||
+ }
|
||
+ else if (base_reg != (int) REGNO (reg))
|
||
+ /* Not addressed from the same base register. */
|
||
+ return 0;
|
||
+
|
||
+ unsorted_regs[i] = (GET_CODE (operands[i]) == REG
|
||
+ ? REGNO (operands[i])
|
||
+ : REGNO (SUBREG_REG (operands[i])));
|
||
+
|
||
+ /* If it isn't an integer register, or if it overwrites the
|
||
+ base register but isn't the last insn in the list, then
|
||
+ we can't do this. */
|
||
+ if (unsorted_regs[i] < 0
|
||
+ || (TARGET_THUMB1 && unsorted_regs[i] > LAST_LO_REGNUM)
|
||
+ || unsorted_regs[i] > 14
|
||
+ || (i != nops - 1 && unsorted_regs[i] == base_reg))
|
||
+ return 0;
|
||
+
|
||
+ unsorted_offsets[i] = INTVAL (offset);
|
||
+ if (i == 0 || unsorted_offsets[i] < unsorted_offsets[order[0]])
|
||
+ order[0] = i;
|
||
+ }
|
||
else
|
||
- sprintf (buf, "sub%%?\t%s%s, %s%s, #%ld", REGISTER_PREFIX,
|
||
- reg_names[regs[0]], REGISTER_PREFIX, reg_names[base_reg],
|
||
- (long) -offset);
|
||
- output_asm_insn (buf, operands);
|
||
- base_reg = regs[0];
|
||
- strcpy (buf, "ldm%(ia%)\t");
|
||
- break;
|
||
-
|
||
- default:
|
||
- gcc_unreachable ();
|
||
- }
|
||
-
|
||
- sprintf (buf + strlen (buf), "%s%s, {%s%s", REGISTER_PREFIX,
|
||
- reg_names[base_reg], REGISTER_PREFIX, reg_names[regs[0]]);
|
||
-
|
||
- for (i = 1; i < nops; i++)
|
||
- sprintf (buf + strlen (buf), ", %s%s", REGISTER_PREFIX,
|
||
- reg_names[regs[i]]);
|
||
-
|
||
- strcat (buf, "}\t%@ phole ldm");
|
||
-
|
||
- output_asm_insn (buf, operands);
|
||
- return "";
|
||
+ /* Not a suitable memory address. */
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ /* All the useful information has now been extracted from the
|
||
+ operands into unsorted_regs and unsorted_offsets; additionally,
|
||
+ order[0] has been set to the lowest offset in the list. Sort
|
||
+ the offsets into order, verifying that they are adjacent, and
|
||
+ check that the register numbers are ascending. */
|
||
+ if (!compute_offset_order (nops, unsorted_offsets, order,
|
||
+ check_regs ? unsorted_regs : NULL))
|
||
+ return 0;
|
||
+
|
||
+ if (saved_order)
|
||
+ memcpy (saved_order, order, sizeof order);
|
||
+
|
||
+ if (base)
|
||
+ {
|
||
+ *base = base_reg;
|
||
+
|
||
+ for (i = 0; i < nops; i++)
|
||
+ regs[i] = unsorted_regs[check_regs ? order[i] : i];
|
||
+
|
||
+ *load_offset = unsorted_offsets[order[0]];
|
||
+ }
|
||
+
|
||
+ if (TARGET_THUMB1
|
||
+ && !peep2_reg_dead_p (nops, base_reg_rtx))
|
||
+ return 0;
|
||
+
|
||
+ if (unsorted_offsets[order[0]] == 0)
|
||
+ ldm_case = 1; /* ldmia */
|
||
+ else if (TARGET_ARM && unsorted_offsets[order[0]] == 4)
|
||
+ ldm_case = 2; /* ldmib */
|
||
+ else if (TARGET_ARM && unsorted_offsets[order[nops - 1]] == 0)
|
||
+ ldm_case = 3; /* ldmda */
|
||
+ else if (TARGET_32BIT && unsorted_offsets[order[nops - 1]] == -4)
|
||
+ ldm_case = 4; /* ldmdb */
|
||
+ else if (const_ok_for_arm (unsorted_offsets[order[0]])
|
||
+ || const_ok_for_arm (-unsorted_offsets[order[0]]))
|
||
+ ldm_case = 5;
|
||
+ else
|
||
+ return 0;
|
||
+
|
||
+ if (!multiple_operation_profitable_p (false, nops,
|
||
+ ldm_case == 5
|
||
+ ? unsorted_offsets[order[0]] : 0))
|
||
+ return 0;
|
||
+
|
||
+ return ldm_case;
|
||
}
|
||
|
||
-int
|
||
-store_multiple_sequence (rtx *operands, int nops, int *regs, int *base,
|
||
- HOST_WIDE_INT * load_offset)
|
||
+/* Used to determine in a peephole whether a sequence of store instructions can
|
||
+ be changed into a store-multiple instruction.
|
||
+ NOPS is the number of separate store instructions we are examining.
|
||
+ NOPS_TOTAL is the total number of instructions recognized by the peephole
|
||
+ pattern.
|
||
+ The first NOPS entries in OPERANDS are the source registers, the next
|
||
+ NOPS entries are memory operands. If this function is successful, *BASE is
|
||
+ set to the common base register of the memory accesses; *LOAD_OFFSET is set
|
||
+ to the first memory location's offset from that base register. REGS is an
|
||
+ array filled in with the source register numbers, REG_RTXS (if nonnull) is
|
||
+ likewise filled with the corresponding rtx's.
|
||
+ SAVED_ORDER (if nonnull), is an array filled in with an order that maps insn
|
||
+ numbers to to an ascending order of stores.
|
||
+ If CHECK_REGS is true, the sequence of registers in *REGS matches the stores
|
||
+ from ascending memory locations, and the function verifies that the register
|
||
+ numbers are themselves ascending. If CHECK_REGS is false, the register
|
||
+ numbers are stored in the order they are found in the operands. */
|
||
+static int
|
||
+store_multiple_sequence (rtx *operands, int nops, int nops_total,
|
||
+ int *regs, rtx *reg_rtxs, int *saved_order, int *base,
|
||
+ HOST_WIDE_INT *load_offset, bool check_regs)
|
||
{
|
||
- int unsorted_regs[4];
|
||
- HOST_WIDE_INT unsorted_offsets[4];
|
||
- int order[4];
|
||
+ int unsorted_regs[MAX_LDM_STM_OPS];
|
||
+ rtx unsorted_reg_rtxs[MAX_LDM_STM_OPS];
|
||
+ HOST_WIDE_INT unsorted_offsets[MAX_LDM_STM_OPS];
|
||
+ int order[MAX_LDM_STM_OPS];
|
||
int base_reg = -1;
|
||
- int i;
|
||
+ rtx base_reg_rtx = NULL;
|
||
+ int i, stm_case;
|
||
|
||
if (low_irq_latency)
|
||
return 0;
|
||
|
||
- /* Can only handle 2, 3, or 4 insns at present, though could be easily
|
||
- extended if required. */
|
||
- gcc_assert (nops >= 2 && nops <= 4);
|
||
+ /* Can only handle up to MAX_LDM_STM_OPS insns at present, though could be
|
||
+ easily extended if required. */
|
||
+ gcc_assert (nops >= 2 && nops <= MAX_LDM_STM_OPS);
|
||
|
||
- memset (order, 0, 4 * sizeof (int));
|
||
+ memset (order, 0, MAX_LDM_STM_OPS * sizeof (int));
|
||
|
||
/* Loop over the operands and check that the memory references are
|
||
suitable (i.e. immediate offsets from the same base register). At
|
||
@@ -9964,32 +9992,32 @@
|
||
&& (GET_CODE (offset = XEXP (XEXP (operands[nops + i], 0), 1))
|
||
== CONST_INT)))
|
||
{
|
||
+ unsorted_reg_rtxs[i] = (GET_CODE (operands[i]) == REG
|
||
+ ? operands[i] : SUBREG_REG (operands[i]));
|
||
+ unsorted_regs[i] = REGNO (unsorted_reg_rtxs[i]);
|
||
+
|
||
if (i == 0)
|
||
{
|
||
base_reg = REGNO (reg);
|
||
- unsorted_regs[0] = (GET_CODE (operands[i]) == REG
|
||
- ? REGNO (operands[i])
|
||
- : REGNO (SUBREG_REG (operands[i])));
|
||
- order[0] = 0;
|
||
- }
|
||
- else
|
||
- {
|
||
- if (base_reg != (int) REGNO (reg))
|
||
- /* Not addressed from the same base register. */
|
||
+ base_reg_rtx = reg;
|
||
+ if (TARGET_THUMB1 && base_reg > LAST_LO_REGNUM)
|
||
return 0;
|
||
-
|
||
- unsorted_regs[i] = (GET_CODE (operands[i]) == REG
|
||
- ? REGNO (operands[i])
|
||
- : REGNO (SUBREG_REG (operands[i])));
|
||
- if (unsorted_regs[i] < unsorted_regs[order[0]])
|
||
- order[0] = i;
|
||
}
|
||
+ else if (base_reg != (int) REGNO (reg))
|
||
+ /* Not addressed from the same base register. */
|
||
+ return 0;
|
||
|
||
/* If it isn't an integer register, then we can't do this. */
|
||
- if (unsorted_regs[i] < 0 || unsorted_regs[i] > 14)
|
||
+ if (unsorted_regs[i] < 0
|
||
+ || (TARGET_THUMB1 && unsorted_regs[i] > LAST_LO_REGNUM)
|
||
+ || (TARGET_THUMB2 && unsorted_regs[i] == base_reg)
|
||
+ || (TARGET_THUMB2 && unsorted_regs[i] == SP_REGNUM)
|
||
+ || unsorted_regs[i] > 14)
|
||
return 0;
|
||
|
||
unsorted_offsets[i] = INTVAL (offset);
|
||
+ if (i == 0 || unsorted_offsets[i] < unsorted_offsets[order[0]])
|
||
+ order[0] = i;
|
||
}
|
||
else
|
||
/* Not a suitable memory address. */
|
||
@@ -9998,111 +10026,65 @@
|
||
|
||
/* All the useful information has now been extracted from the
|
||
operands into unsorted_regs and unsorted_offsets; additionally,
|
||
- order[0] has been set to the lowest numbered register in the
|
||
- list. Sort the registers into order, and check that the memory
|
||
- offsets are ascending and adjacent. */
|
||
-
|
||
- for (i = 1; i < nops; i++)
|
||
- {
|
||
- int j;
|
||
-
|
||
- order[i] = order[i - 1];
|
||
- for (j = 0; j < nops; j++)
|
||
- if (unsorted_regs[j] > unsorted_regs[order[i - 1]]
|
||
- && (order[i] == order[i - 1]
|
||
- || unsorted_regs[j] < unsorted_regs[order[i]]))
|
||
- order[i] = j;
|
||
-
|
||
- /* Have we found a suitable register? if not, one must be used more
|
||
- than once. */
|
||
- if (order[i] == order[i - 1])
|
||
- return 0;
|
||
-
|
||
- /* Is the memory address adjacent and ascending? */
|
||
- if (unsorted_offsets[order[i]] != unsorted_offsets[order[i - 1]] + 4)
|
||
- return 0;
|
||
- }
|
||
+ order[0] has been set to the lowest offset in the list. Sort
|
||
+ the offsets into order, verifying that they are adjacent, and
|
||
+ check that the register numbers are ascending. */
|
||
+ if (!compute_offset_order (nops, unsorted_offsets, order,
|
||
+ check_regs ? unsorted_regs : NULL))
|
||
+ return 0;
|
||
+
|
||
+ if (saved_order)
|
||
+ memcpy (saved_order, order, sizeof order);
|
||
|
||
if (base)
|
||
{
|
||
*base = base_reg;
|
||
|
||
for (i = 0; i < nops; i++)
|
||
- regs[i] = unsorted_regs[order[i]];
|
||
+ {
|
||
+ regs[i] = unsorted_regs[check_regs ? order[i] : i];
|
||
+ if (reg_rtxs)
|
||
+ reg_rtxs[i] = unsorted_reg_rtxs[check_regs ? order[i] : i];
|
||
+ }
|
||
|
||
*load_offset = unsorted_offsets[order[0]];
|
||
}
|
||
|
||
+ if (TARGET_THUMB1
|
||
+ && !peep2_reg_dead_p (nops_total, base_reg_rtx))
|
||
+ return 0;
|
||
+
|
||
if (unsorted_offsets[order[0]] == 0)
|
||
- return 1; /* stmia */
|
||
-
|
||
- if (unsorted_offsets[order[0]] == 4)
|
||
- return 2; /* stmib */
|
||
-
|
||
- if (unsorted_offsets[order[nops - 1]] == 0)
|
||
- return 3; /* stmda */
|
||
-
|
||
- if (unsorted_offsets[order[nops - 1]] == -4)
|
||
- return 4; /* stmdb */
|
||
-
|
||
- return 0;
|
||
-}
|
||
-
|
||
-const char *
|
||
-emit_stm_seq (rtx *operands, int nops)
|
||
-{
|
||
- int regs[4];
|
||
- int base_reg;
|
||
- HOST_WIDE_INT offset;
|
||
- char buf[100];
|
||
- int i;
|
||
-
|
||
- switch (store_multiple_sequence (operands, nops, regs, &base_reg, &offset))
|
||
- {
|
||
- case 1:
|
||
- strcpy (buf, "stm%(ia%)\t");
|
||
- break;
|
||
-
|
||
- case 2:
|
||
- strcpy (buf, "stm%(ib%)\t");
|
||
- break;
|
||
-
|
||
- case 3:
|
||
- strcpy (buf, "stm%(da%)\t");
|
||
- break;
|
||
-
|
||
- case 4:
|
||
- strcpy (buf, "stm%(db%)\t");
|
||
- break;
|
||
-
|
||
- default:
|
||
- gcc_unreachable ();
|
||
- }
|
||
-
|
||
- sprintf (buf + strlen (buf), "%s%s, {%s%s", REGISTER_PREFIX,
|
||
- reg_names[base_reg], REGISTER_PREFIX, reg_names[regs[0]]);
|
||
-
|
||
- for (i = 1; i < nops; i++)
|
||
- sprintf (buf + strlen (buf), ", %s%s", REGISTER_PREFIX,
|
||
- reg_names[regs[i]]);
|
||
-
|
||
- strcat (buf, "}\t%@ phole stm");
|
||
-
|
||
- output_asm_insn (buf, operands);
|
||
- return "";
|
||
+ stm_case = 1; /* stmia */
|
||
+ else if (TARGET_ARM && unsorted_offsets[order[0]] == 4)
|
||
+ stm_case = 2; /* stmib */
|
||
+ else if (TARGET_ARM && unsorted_offsets[order[nops - 1]] == 0)
|
||
+ stm_case = 3; /* stmda */
|
||
+ else if (TARGET_32BIT && unsorted_offsets[order[nops - 1]] == -4)
|
||
+ stm_case = 4; /* stmdb */
|
||
+ else
|
||
+ return 0;
|
||
+
|
||
+ if (!multiple_operation_profitable_p (false, nops, 0))
|
||
+ return 0;
|
||
+
|
||
+ return stm_case;
|
||
}
|
||
|
||
/* Routines for use in generating RTL. */
|
||
|
||
-rtx
|
||
-arm_gen_load_multiple (int base_regno, int count, rtx from, int up,
|
||
- int write_back, rtx basemem, HOST_WIDE_INT *offsetp)
|
||
+/* Generate a load-multiple instruction. COUNT is the number of loads in
|
||
+ the instruction; REGS and MEMS are arrays containing the operands.
|
||
+ BASEREG is the base register to be used in addressing the memory operands.
|
||
+ WBACK_OFFSET is nonzero if the instruction should update the base
|
||
+ register. */
|
||
+
|
||
+static rtx
|
||
+arm_gen_load_multiple_1 (int count, int *regs, rtx *mems, rtx basereg,
|
||
+ HOST_WIDE_INT wback_offset)
|
||
{
|
||
- HOST_WIDE_INT offset = *offsetp;
|
||
int i = 0, j;
|
||
rtx result;
|
||
- int sign = up ? 1 : -1;
|
||
- rtx mem, addr;
|
||
|
||
/* XScale has load-store double instructions, but they have stricter
|
||
alignment requirements than load-store multiple, so we cannot
|
||
@@ -10139,18 +10121,10 @@
|
||
start_sequence ();
|
||
|
||
for (i = 0; i < count; i++)
|
||
- {
|
||
- addr = plus_constant (from, i * 4 * sign);
|
||
- mem = adjust_automodify_address (basemem, SImode, addr, offset);
|
||
- emit_move_insn (gen_rtx_REG (SImode, base_regno + i), mem);
|
||
- offset += 4 * sign;
|
||
- }
|
||
+ emit_move_insn (gen_rtx_REG (SImode, regs[i]), mems[i]);
|
||
|
||
- if (write_back)
|
||
- {
|
||
- emit_move_insn (from, plus_constant (from, count * 4 * sign));
|
||
- *offsetp = offset;
|
||
- }
|
||
+ if (wback_offset != 0)
|
||
+ emit_move_insn (basereg, plus_constant (basereg, wback_offset));
|
||
|
||
seq = get_insns ();
|
||
end_sequence ();
|
||
@@ -10159,41 +10133,40 @@
|
||
}
|
||
|
||
result = gen_rtx_PARALLEL (VOIDmode,
|
||
- rtvec_alloc (count + (write_back ? 1 : 0)));
|
||
- if (write_back)
|
||
+ rtvec_alloc (count + (wback_offset != 0 ? 1 : 0)));
|
||
+ if (wback_offset != 0)
|
||
{
|
||
XVECEXP (result, 0, 0)
|
||
- = gen_rtx_SET (VOIDmode, from, plus_constant (from, count * 4 * sign));
|
||
+ = gen_rtx_SET (VOIDmode, basereg,
|
||
+ plus_constant (basereg, wback_offset));
|
||
i = 1;
|
||
count++;
|
||
}
|
||
|
||
for (j = 0; i < count; i++, j++)
|
||
- {
|
||
- addr = plus_constant (from, j * 4 * sign);
|
||
- mem = adjust_automodify_address_nv (basemem, SImode, addr, offset);
|
||
- XVECEXP (result, 0, i)
|
||
- = gen_rtx_SET (VOIDmode, gen_rtx_REG (SImode, base_regno + j), mem);
|
||
- offset += 4 * sign;
|
||
- }
|
||
-
|
||
- if (write_back)
|
||
- *offsetp = offset;
|
||
+ XVECEXP (result, 0, i)
|
||
+ = gen_rtx_SET (VOIDmode, gen_rtx_REG (SImode, regs[j]), mems[j]);
|
||
|
||
return result;
|
||
}
|
||
|
||
-rtx
|
||
-arm_gen_store_multiple (int base_regno, int count, rtx to, int up,
|
||
- int write_back, rtx basemem, HOST_WIDE_INT *offsetp)
|
||
+/* Generate a store-multiple instruction. COUNT is the number of stores in
|
||
+ the instruction; REGS and MEMS are arrays containing the operands.
|
||
+ BASEREG is the base register to be used in addressing the memory operands.
|
||
+ WBACK_OFFSET is nonzero if the instruction should update the base
|
||
+ register. */
|
||
+
|
||
+static rtx
|
||
+arm_gen_store_multiple_1 (int count, int *regs, rtx *mems, rtx basereg,
|
||
+ HOST_WIDE_INT wback_offset)
|
||
{
|
||
- HOST_WIDE_INT offset = *offsetp;
|
||
int i = 0, j;
|
||
rtx result;
|
||
- int sign = up ? 1 : -1;
|
||
- rtx mem, addr;
|
||
-
|
||
- /* See arm_gen_load_multiple for discussion of
|
||
+
|
||
+ if (GET_CODE (basereg) == PLUS)
|
||
+ basereg = XEXP (basereg, 0);
|
||
+
|
||
+ /* See arm_gen_load_multiple_1 for discussion of
|
||
the pros/cons of ldm/stm usage for XScale. */
|
||
if (low_irq_latency || (arm_tune_xscale && count <= 2 && ! optimize_size))
|
||
{
|
||
@@ -10202,18 +10175,10 @@
|
||
start_sequence ();
|
||
|
||
for (i = 0; i < count; i++)
|
||
- {
|
||
- addr = plus_constant (to, i * 4 * sign);
|
||
- mem = adjust_automodify_address (basemem, SImode, addr, offset);
|
||
- emit_move_insn (mem, gen_rtx_REG (SImode, base_regno + i));
|
||
- offset += 4 * sign;
|
||
- }
|
||
+ emit_move_insn (mems[i], gen_rtx_REG (SImode, regs[i]));
|
||
|
||
- if (write_back)
|
||
- {
|
||
- emit_move_insn (to, plus_constant (to, count * 4 * sign));
|
||
- *offsetp = offset;
|
||
- }
|
||
+ if (wback_offset != 0)
|
||
+ emit_move_insn (basereg, plus_constant (basereg, wback_offset));
|
||
|
||
seq = get_insns ();
|
||
end_sequence ();
|
||
@@ -10222,29 +10187,319 @@
|
||
}
|
||
|
||
result = gen_rtx_PARALLEL (VOIDmode,
|
||
- rtvec_alloc (count + (write_back ? 1 : 0)));
|
||
- if (write_back)
|
||
+ rtvec_alloc (count + (wback_offset != 0 ? 1 : 0)));
|
||
+ if (wback_offset != 0)
|
||
{
|
||
XVECEXP (result, 0, 0)
|
||
- = gen_rtx_SET (VOIDmode, to,
|
||
- plus_constant (to, count * 4 * sign));
|
||
+ = gen_rtx_SET (VOIDmode, basereg,
|
||
+ plus_constant (basereg, wback_offset));
|
||
i = 1;
|
||
count++;
|
||
}
|
||
|
||
for (j = 0; i < count; i++, j++)
|
||
+ XVECEXP (result, 0, i)
|
||
+ = gen_rtx_SET (VOIDmode, mems[j], gen_rtx_REG (SImode, regs[j]));
|
||
+
|
||
+ return result;
|
||
+}
|
||
+
|
||
+/* Generate either a load-multiple or a store-multiple instruction. This
|
||
+ function can be used in situations where we can start with a single MEM
|
||
+ rtx and adjust its address upwards.
|
||
+ COUNT is the number of operations in the instruction, not counting a
|
||
+ possible update of the base register. REGS is an array containing the
|
||
+ register operands.
|
||
+ BASEREG is the base register to be used in addressing the memory operands,
|
||
+ which are constructed from BASEMEM.
|
||
+ WRITE_BACK specifies whether the generated instruction should include an
|
||
+ update of the base register.
|
||
+ OFFSETP is used to pass an offset to and from this function; this offset
|
||
+ is not used when constructing the address (instead BASEMEM should have an
|
||
+ appropriate offset in its address), it is used only for setting
|
||
+ MEM_OFFSET. It is updated only if WRITE_BACK is true.*/
|
||
+
|
||
+static rtx
|
||
+arm_gen_multiple_op (bool is_load, int *regs, int count, rtx basereg,
|
||
+ bool write_back, rtx basemem, HOST_WIDE_INT *offsetp)
|
||
+{
|
||
+ rtx mems[MAX_LDM_STM_OPS];
|
||
+ HOST_WIDE_INT offset = *offsetp;
|
||
+ int i;
|
||
+
|
||
+ gcc_assert (count <= MAX_LDM_STM_OPS);
|
||
+
|
||
+ if (GET_CODE (basereg) == PLUS)
|
||
+ basereg = XEXP (basereg, 0);
|
||
+
|
||
+ for (i = 0; i < count; i++)
|
||
{
|
||
- addr = plus_constant (to, j * 4 * sign);
|
||
- mem = adjust_automodify_address_nv (basemem, SImode, addr, offset);
|
||
- XVECEXP (result, 0, i)
|
||
- = gen_rtx_SET (VOIDmode, mem, gen_rtx_REG (SImode, base_regno + j));
|
||
- offset += 4 * sign;
|
||
+ rtx addr = plus_constant (basereg, i * 4);
|
||
+ mems[i] = adjust_automodify_address_nv (basemem, SImode, addr, offset);
|
||
+ offset += 4;
|
||
}
|
||
|
||
if (write_back)
|
||
*offsetp = offset;
|
||
|
||
- return result;
|
||
+ if (is_load)
|
||
+ return arm_gen_load_multiple_1 (count, regs, mems, basereg,
|
||
+ write_back ? 4 * count : 0);
|
||
+ else
|
||
+ return arm_gen_store_multiple_1 (count, regs, mems, basereg,
|
||
+ write_back ? 4 * count : 0);
|
||
+}
|
||
+
|
||
+rtx
|
||
+arm_gen_load_multiple (int *regs, int count, rtx basereg, int write_back,
|
||
+ rtx basemem, HOST_WIDE_INT *offsetp)
|
||
+{
|
||
+ return arm_gen_multiple_op (TRUE, regs, count, basereg, write_back, basemem,
|
||
+ offsetp);
|
||
+}
|
||
+
|
||
+rtx
|
||
+arm_gen_store_multiple (int *regs, int count, rtx basereg, int write_back,
|
||
+ rtx basemem, HOST_WIDE_INT *offsetp)
|
||
+{
|
||
+ return arm_gen_multiple_op (FALSE, regs, count, basereg, write_back, basemem,
|
||
+ offsetp);
|
||
+}
|
||
+
|
||
+/* Called from a peephole2 expander to turn a sequence of loads into an
|
||
+ LDM instruction. OPERANDS are the operands found by the peephole matcher;
|
||
+ NOPS indicates how many separate loads we are trying to combine. SORT_REGS
|
||
+ is true if we can reorder the registers because they are used commutatively
|
||
+ subsequently.
|
||
+ Returns true iff we could generate a new instruction. */
|
||
+
|
||
+bool
|
||
+gen_ldm_seq (rtx *operands, int nops, bool sort_regs)
|
||
+{
|
||
+ int regs[MAX_LDM_STM_OPS], mem_order[MAX_LDM_STM_OPS];
|
||
+ rtx mems[MAX_LDM_STM_OPS];
|
||
+ int i, j, base_reg;
|
||
+ rtx base_reg_rtx;
|
||
+ HOST_WIDE_INT offset;
|
||
+ int write_back = FALSE;
|
||
+ int ldm_case;
|
||
+ rtx addr;
|
||
+
|
||
+ ldm_case = load_multiple_sequence (operands, nops, regs, mem_order,
|
||
+ &base_reg, &offset, !sort_regs);
|
||
+
|
||
+ if (ldm_case == 0)
|
||
+ return false;
|
||
+
|
||
+ if (sort_regs)
|
||
+ for (i = 0; i < nops - 1; i++)
|
||
+ for (j = i + 1; j < nops; j++)
|
||
+ if (regs[i] > regs[j])
|
||
+ {
|
||
+ int t = regs[i];
|
||
+ regs[i] = regs[j];
|
||
+ regs[j] = t;
|
||
+ }
|
||
+ base_reg_rtx = gen_rtx_REG (Pmode, base_reg);
|
||
+
|
||
+ if (TARGET_THUMB1)
|
||
+ {
|
||
+ gcc_assert (peep2_reg_dead_p (nops, base_reg_rtx));
|
||
+ gcc_assert (ldm_case == 1 || ldm_case == 5);
|
||
+ write_back = TRUE;
|
||
+ }
|
||
+
|
||
+ if (ldm_case == 5)
|
||
+ {
|
||
+ rtx newbase = TARGET_THUMB1 ? base_reg_rtx : gen_rtx_REG (SImode, regs[0]);
|
||
+ emit_insn (gen_addsi3 (newbase, base_reg_rtx, GEN_INT (offset)));
|
||
+ offset = 0;
|
||
+ if (!TARGET_THUMB1)
|
||
+ {
|
||
+ base_reg = regs[0];
|
||
+ base_reg_rtx = newbase;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ for (i = 0; i < nops; i++)
|
||
+ {
|
||
+ addr = plus_constant (base_reg_rtx, offset + i * 4);
|
||
+ mems[i] = adjust_automodify_address_nv (operands[nops + mem_order[i]],
|
||
+ SImode, addr, 0);
|
||
+ }
|
||
+ emit_insn (arm_gen_load_multiple_1 (nops, regs, mems, base_reg_rtx,
|
||
+ write_back ? offset + i * 4 : 0));
|
||
+ return true;
|
||
+}
|
||
+
|
||
+/* Called from a peephole2 expander to turn a sequence of stores into an
|
||
+ STM instruction. OPERANDS are the operands found by the peephole matcher;
|
||
+ NOPS indicates how many separate stores we are trying to combine.
|
||
+ Returns true iff we could generate a new instruction. */
|
||
+
|
||
+bool
|
||
+gen_stm_seq (rtx *operands, int nops)
|
||
+{
|
||
+ int i;
|
||
+ int regs[MAX_LDM_STM_OPS], mem_order[MAX_LDM_STM_OPS];
|
||
+ rtx mems[MAX_LDM_STM_OPS];
|
||
+ int base_reg;
|
||
+ rtx base_reg_rtx;
|
||
+ HOST_WIDE_INT offset;
|
||
+ int write_back = FALSE;
|
||
+ int stm_case;
|
||
+ rtx addr;
|
||
+ bool base_reg_dies;
|
||
+
|
||
+ stm_case = store_multiple_sequence (operands, nops, nops, regs, NULL,
|
||
+ mem_order, &base_reg, &offset, true);
|
||
+
|
||
+ if (stm_case == 0)
|
||
+ return false;
|
||
+
|
||
+ base_reg_rtx = gen_rtx_REG (Pmode, base_reg);
|
||
+
|
||
+ base_reg_dies = peep2_reg_dead_p (nops, base_reg_rtx);
|
||
+ if (TARGET_THUMB1)
|
||
+ {
|
||
+ gcc_assert (base_reg_dies);
|
||
+ write_back = TRUE;
|
||
+ }
|
||
+
|
||
+ if (stm_case == 5)
|
||
+ {
|
||
+ gcc_assert (base_reg_dies);
|
||
+ emit_insn (gen_addsi3 (base_reg_rtx, base_reg_rtx, GEN_INT (offset)));
|
||
+ offset = 0;
|
||
+ }
|
||
+
|
||
+ addr = plus_constant (base_reg_rtx, offset);
|
||
+
|
||
+ for (i = 0; i < nops; i++)
|
||
+ {
|
||
+ addr = plus_constant (base_reg_rtx, offset + i * 4);
|
||
+ mems[i] = adjust_automodify_address_nv (operands[nops + mem_order[i]],
|
||
+ SImode, addr, 0);
|
||
+ }
|
||
+ emit_insn (arm_gen_store_multiple_1 (nops, regs, mems, base_reg_rtx,
|
||
+ write_back ? offset + i * 4 : 0));
|
||
+ return true;
|
||
+}
|
||
+
|
||
+/* Called from a peephole2 expander to turn a sequence of stores that are
|
||
+ preceded by constant loads into an STM instruction. OPERANDS are the
|
||
+ operands found by the peephole matcher; NOPS indicates how many
|
||
+ separate stores we are trying to combine; there are 2 * NOPS
|
||
+ instructions in the peephole.
|
||
+ Returns true iff we could generate a new instruction. */
|
||
+
|
||
+bool
|
||
+gen_const_stm_seq (rtx *operands, int nops)
|
||
+{
|
||
+ int regs[MAX_LDM_STM_OPS], sorted_regs[MAX_LDM_STM_OPS];
|
||
+ int reg_order[MAX_LDM_STM_OPS], mem_order[MAX_LDM_STM_OPS];
|
||
+ rtx reg_rtxs[MAX_LDM_STM_OPS], orig_reg_rtxs[MAX_LDM_STM_OPS];
|
||
+ rtx mems[MAX_LDM_STM_OPS];
|
||
+ int base_reg;
|
||
+ rtx base_reg_rtx;
|
||
+ HOST_WIDE_INT offset;
|
||
+ int write_back = FALSE;
|
||
+ int stm_case;
|
||
+ rtx addr;
|
||
+ bool base_reg_dies;
|
||
+ int i, j;
|
||
+ HARD_REG_SET allocated;
|
||
+
|
||
+ stm_case = store_multiple_sequence (operands, nops, 2 * nops, regs, reg_rtxs,
|
||
+ mem_order, &base_reg, &offset, false);
|
||
+
|
||
+ if (stm_case == 0)
|
||
+ return false;
|
||
+
|
||
+ memcpy (orig_reg_rtxs, reg_rtxs, sizeof orig_reg_rtxs);
|
||
+
|
||
+ /* If the same register is used more than once, try to find a free
|
||
+ register. */
|
||
+ CLEAR_HARD_REG_SET (allocated);
|
||
+ for (i = 0; i < nops; i++)
|
||
+ {
|
||
+ for (j = i + 1; j < nops; j++)
|
||
+ if (regs[i] == regs[j])
|
||
+ {
|
||
+ rtx t = peep2_find_free_register (0, nops * 2,
|
||
+ TARGET_THUMB1 ? "l" : "r",
|
||
+ SImode, &allocated);
|
||
+ if (t == NULL_RTX)
|
||
+ return false;
|
||
+ reg_rtxs[i] = t;
|
||
+ regs[i] = REGNO (t);
|
||
+ }
|
||
+ }
|
||
+
|
||
+ /* Compute an ordering that maps the register numbers to an ascending
|
||
+ sequence. */
|
||
+ reg_order[0] = 0;
|
||
+ for (i = 0; i < nops; i++)
|
||
+ if (regs[i] < regs[reg_order[0]])
|
||
+ reg_order[0] = i;
|
||
+
|
||
+ for (i = 1; i < nops; i++)
|
||
+ {
|
||
+ int this_order = reg_order[i - 1];
|
||
+ for (j = 0; j < nops; j++)
|
||
+ if (regs[j] > regs[reg_order[i - 1]]
|
||
+ && (this_order == reg_order[i - 1]
|
||
+ || regs[j] < regs[this_order]))
|
||
+ this_order = j;
|
||
+ reg_order[i] = this_order;
|
||
+ }
|
||
+
|
||
+ /* Ensure that registers that must be live after the instruction end
|
||
+ up with the correct value. */
|
||
+ for (i = 0; i < nops; i++)
|
||
+ {
|
||
+ int this_order = reg_order[i];
|
||
+ if ((this_order != mem_order[i]
|
||
+ || orig_reg_rtxs[this_order] != reg_rtxs[this_order])
|
||
+ && !peep2_reg_dead_p (nops * 2, orig_reg_rtxs[this_order]))
|
||
+ return false;
|
||
+ }
|
||
+
|
||
+ /* Load the constants. */
|
||
+ for (i = 0; i < nops; i++)
|
||
+ {
|
||
+ rtx op = operands[2 * nops + mem_order[i]];
|
||
+ sorted_regs[i] = regs[reg_order[i]];
|
||
+ emit_move_insn (reg_rtxs[reg_order[i]], op);
|
||
+ }
|
||
+
|
||
+ base_reg_rtx = gen_rtx_REG (Pmode, base_reg);
|
||
+
|
||
+ base_reg_dies = peep2_reg_dead_p (nops * 2, base_reg_rtx);
|
||
+ if (TARGET_THUMB1)
|
||
+ {
|
||
+ gcc_assert (base_reg_dies);
|
||
+ write_back = TRUE;
|
||
+ }
|
||
+
|
||
+ if (stm_case == 5)
|
||
+ {
|
||
+ gcc_assert (base_reg_dies);
|
||
+ emit_insn (gen_addsi3 (base_reg_rtx, base_reg_rtx, GEN_INT (offset)));
|
||
+ offset = 0;
|
||
+ }
|
||
+
|
||
+ addr = plus_constant (base_reg_rtx, offset);
|
||
+
|
||
+ for (i = 0; i < nops; i++)
|
||
+ {
|
||
+ addr = plus_constant (base_reg_rtx, offset + i * 4);
|
||
+ mems[i] = adjust_automodify_address_nv (operands[nops + mem_order[i]],
|
||
+ SImode, addr, 0);
|
||
+ }
|
||
+ emit_insn (arm_gen_store_multiple_1 (nops, sorted_regs, mems, base_reg_rtx,
|
||
+ write_back ? offset + i * 4 : 0));
|
||
+ return true;
|
||
}
|
||
|
||
int
|
||
@@ -10280,20 +10535,21 @@
|
||
for (i = 0; in_words_to_go >= 2; i+=4)
|
||
{
|
||
if (in_words_to_go > 4)
|
||
- emit_insn (arm_gen_load_multiple (0, 4, src, TRUE, TRUE,
|
||
- srcbase, &srcoffset));
|
||
+ emit_insn (arm_gen_load_multiple (arm_regs_in_sequence, 4, src,
|
||
+ TRUE, srcbase, &srcoffset));
|
||
else
|
||
- emit_insn (arm_gen_load_multiple (0, in_words_to_go, src, TRUE,
|
||
- FALSE, srcbase, &srcoffset));
|
||
+ emit_insn (arm_gen_load_multiple (arm_regs_in_sequence, in_words_to_go,
|
||
+ src, FALSE, srcbase,
|
||
+ &srcoffset));
|
||
|
||
if (out_words_to_go)
|
||
{
|
||
if (out_words_to_go > 4)
|
||
- emit_insn (arm_gen_store_multiple (0, 4, dst, TRUE, TRUE,
|
||
- dstbase, &dstoffset));
|
||
+ emit_insn (arm_gen_store_multiple (arm_regs_in_sequence, 4, dst,
|
||
+ TRUE, dstbase, &dstoffset));
|
||
else if (out_words_to_go != 1)
|
||
- emit_insn (arm_gen_store_multiple (0, out_words_to_go,
|
||
- dst, TRUE,
|
||
+ emit_insn (arm_gen_store_multiple (arm_regs_in_sequence,
|
||
+ out_words_to_go, dst,
|
||
(last_bytes == 0
|
||
? FALSE : TRUE),
|
||
dstbase, &dstoffset));
|
||
|
||
=== modified file 'gcc/config/arm/arm.h'
|
||
--- old/gcc/config/arm/arm.h 2011-01-05 12:12:18 +0000
|
||
+++ new/gcc/config/arm/arm.h 2011-01-05 18:20:37 +0000
|
||
@@ -1143,6 +1143,9 @@
|
||
((MODE) == TImode || (MODE) == EImode || (MODE) == OImode \
|
||
|| (MODE) == CImode || (MODE) == XImode)
|
||
|
||
+/* The register numbers in sequence, for passing to arm_gen_load_multiple. */
|
||
+extern int arm_regs_in_sequence[];
|
||
+
|
||
/* The order in which register should be allocated. It is good to use ip
|
||
since no saving is required (though calls clobber it) and it never contains
|
||
function parameters. It is quite good to use lr since other calls may
|
||
@@ -2823,4 +2826,8 @@
|
||
#define NEED_INDICATE_EXEC_STACK 0
|
||
#endif
|
||
|
||
+/* The maximum number of parallel loads or stores we support in an ldm/stm
|
||
+ instruction. */
|
||
+#define MAX_LDM_STM_OPS 4
|
||
+
|
||
#endif /* ! GCC_ARM_H */
|
||
|
||
=== modified file 'gcc/config/arm/arm.md'
|
||
--- old/gcc/config/arm/arm.md 2011-01-05 12:12:18 +0000
|
||
+++ new/gcc/config/arm/arm.md 2011-01-05 18:20:37 +0000
|
||
@@ -6282,7 +6282,7 @@
|
||
|
||
;; load- and store-multiple insns
|
||
;; The arm can load/store any set of registers, provided that they are in
|
||
-;; ascending order; but that is beyond GCC so stick with what it knows.
|
||
+;; ascending order, but these expanders assume a contiguous set.
|
||
|
||
(define_expand "load_multiple"
|
||
[(match_par_dup 3 [(set (match_operand:SI 0 "" "")
|
||
@@ -6303,126 +6303,12 @@
|
||
FAIL;
|
||
|
||
operands[3]
|
||
- = arm_gen_load_multiple (REGNO (operands[0]), INTVAL (operands[2]),
|
||
+ = arm_gen_load_multiple (arm_regs_in_sequence + REGNO (operands[0]),
|
||
+ INTVAL (operands[2]),
|
||
force_reg (SImode, XEXP (operands[1], 0)),
|
||
- TRUE, FALSE, operands[1], &offset);
|
||
+ FALSE, operands[1], &offset);
|
||
})
|
||
|
||
-;; Load multiple with write-back
|
||
-
|
||
-(define_insn "*ldmsi_postinc4"
|
||
- [(match_parallel 0 "load_multiple_operation"
|
||
- [(set (match_operand:SI 1 "s_register_operand" "=r")
|
||
- (plus:SI (match_operand:SI 2 "s_register_operand" "1")
|
||
- (const_int 16)))
|
||
- (set (match_operand:SI 3 "arm_hard_register_operand" "")
|
||
- (mem:SI (match_dup 2)))
|
||
- (set (match_operand:SI 4 "arm_hard_register_operand" "")
|
||
- (mem:SI (plus:SI (match_dup 2) (const_int 4))))
|
||
- (set (match_operand:SI 5 "arm_hard_register_operand" "")
|
||
- (mem:SI (plus:SI (match_dup 2) (const_int 8))))
|
||
- (set (match_operand:SI 6 "arm_hard_register_operand" "")
|
||
- (mem:SI (plus:SI (match_dup 2) (const_int 12))))])]
|
||
- "TARGET_32BIT && XVECLEN (operands[0], 0) == 5"
|
||
- "ldm%(ia%)\\t%1!, {%3, %4, %5, %6}"
|
||
- [(set_attr "type" "load4")
|
||
- (set_attr "predicable" "yes")]
|
||
-)
|
||
-
|
||
-(define_insn "*ldmsi_postinc4_thumb1"
|
||
- [(match_parallel 0 "load_multiple_operation"
|
||
- [(set (match_operand:SI 1 "s_register_operand" "=l")
|
||
- (plus:SI (match_operand:SI 2 "s_register_operand" "1")
|
||
- (const_int 16)))
|
||
- (set (match_operand:SI 3 "arm_hard_register_operand" "")
|
||
- (mem:SI (match_dup 2)))
|
||
- (set (match_operand:SI 4 "arm_hard_register_operand" "")
|
||
- (mem:SI (plus:SI (match_dup 2) (const_int 4))))
|
||
- (set (match_operand:SI 5 "arm_hard_register_operand" "")
|
||
- (mem:SI (plus:SI (match_dup 2) (const_int 8))))
|
||
- (set (match_operand:SI 6 "arm_hard_register_operand" "")
|
||
- (mem:SI (plus:SI (match_dup 2) (const_int 12))))])]
|
||
- "TARGET_THUMB1 && XVECLEN (operands[0], 0) == 5"
|
||
- "ldmia\\t%1!, {%3, %4, %5, %6}"
|
||
- [(set_attr "type" "load4")]
|
||
-)
|
||
-
|
||
-(define_insn "*ldmsi_postinc3"
|
||
- [(match_parallel 0 "load_multiple_operation"
|
||
- [(set (match_operand:SI 1 "s_register_operand" "=r")
|
||
- (plus:SI (match_operand:SI 2 "s_register_operand" "1")
|
||
- (const_int 12)))
|
||
- (set (match_operand:SI 3 "arm_hard_register_operand" "")
|
||
- (mem:SI (match_dup 2)))
|
||
- (set (match_operand:SI 4 "arm_hard_register_operand" "")
|
||
- (mem:SI (plus:SI (match_dup 2) (const_int 4))))
|
||
- (set (match_operand:SI 5 "arm_hard_register_operand" "")
|
||
- (mem:SI (plus:SI (match_dup 2) (const_int 8))))])]
|
||
- "TARGET_32BIT && XVECLEN (operands[0], 0) == 4"
|
||
- "ldm%(ia%)\\t%1!, {%3, %4, %5}"
|
||
- [(set_attr "type" "load3")
|
||
- (set_attr "predicable" "yes")]
|
||
-)
|
||
-
|
||
-(define_insn "*ldmsi_postinc2"
|
||
- [(match_parallel 0 "load_multiple_operation"
|
||
- [(set (match_operand:SI 1 "s_register_operand" "=r")
|
||
- (plus:SI (match_operand:SI 2 "s_register_operand" "1")
|
||
- (const_int 8)))
|
||
- (set (match_operand:SI 3 "arm_hard_register_operand" "")
|
||
- (mem:SI (match_dup 2)))
|
||
- (set (match_operand:SI 4 "arm_hard_register_operand" "")
|
||
- (mem:SI (plus:SI (match_dup 2) (const_int 4))))])]
|
||
- "TARGET_32BIT && XVECLEN (operands[0], 0) == 3"
|
||
- "ldm%(ia%)\\t%1!, {%3, %4}"
|
||
- [(set_attr "type" "load2")
|
||
- (set_attr "predicable" "yes")]
|
||
-)
|
||
-
|
||
-;; Ordinary load multiple
|
||
-
|
||
-(define_insn "*ldmsi4"
|
||
- [(match_parallel 0 "load_multiple_operation"
|
||
- [(set (match_operand:SI 2 "arm_hard_register_operand" "")
|
||
- (mem:SI (match_operand:SI 1 "s_register_operand" "r")))
|
||
- (set (match_operand:SI 3 "arm_hard_register_operand" "")
|
||
- (mem:SI (plus:SI (match_dup 1) (const_int 4))))
|
||
- (set (match_operand:SI 4 "arm_hard_register_operand" "")
|
||
- (mem:SI (plus:SI (match_dup 1) (const_int 8))))
|
||
- (set (match_operand:SI 5 "arm_hard_register_operand" "")
|
||
- (mem:SI (plus:SI (match_dup 1) (const_int 12))))])]
|
||
- "TARGET_32BIT && XVECLEN (operands[0], 0) == 4"
|
||
- "ldm%(ia%)\\t%1, {%2, %3, %4, %5}"
|
||
- [(set_attr "type" "load4")
|
||
- (set_attr "predicable" "yes")]
|
||
-)
|
||
-
|
||
-(define_insn "*ldmsi3"
|
||
- [(match_parallel 0 "load_multiple_operation"
|
||
- [(set (match_operand:SI 2 "arm_hard_register_operand" "")
|
||
- (mem:SI (match_operand:SI 1 "s_register_operand" "r")))
|
||
- (set (match_operand:SI 3 "arm_hard_register_operand" "")
|
||
- (mem:SI (plus:SI (match_dup 1) (const_int 4))))
|
||
- (set (match_operand:SI 4 "arm_hard_register_operand" "")
|
||
- (mem:SI (plus:SI (match_dup 1) (const_int 8))))])]
|
||
- "TARGET_32BIT && XVECLEN (operands[0], 0) == 3"
|
||
- "ldm%(ia%)\\t%1, {%2, %3, %4}"
|
||
- [(set_attr "type" "load3")
|
||
- (set_attr "predicable" "yes")]
|
||
-)
|
||
-
|
||
-(define_insn "*ldmsi2"
|
||
- [(match_parallel 0 "load_multiple_operation"
|
||
- [(set (match_operand:SI 2 "arm_hard_register_operand" "")
|
||
- (mem:SI (match_operand:SI 1 "s_register_operand" "r")))
|
||
- (set (match_operand:SI 3 "arm_hard_register_operand" "")
|
||
- (mem:SI (plus:SI (match_dup 1) (const_int 4))))])]
|
||
- "TARGET_32BIT && XVECLEN (operands[0], 0) == 2"
|
||
- "ldm%(ia%)\\t%1, {%2, %3}"
|
||
- [(set_attr "type" "load2")
|
||
- (set_attr "predicable" "yes")]
|
||
-)
|
||
-
|
||
(define_expand "store_multiple"
|
||
[(match_par_dup 3 [(set (match_operand:SI 0 "" "")
|
||
(match_operand:SI 1 "" ""))
|
||
@@ -6442,125 +6328,12 @@
|
||
FAIL;
|
||
|
||
operands[3]
|
||
- = arm_gen_store_multiple (REGNO (operands[1]), INTVAL (operands[2]),
|
||
+ = arm_gen_store_multiple (arm_regs_in_sequence + REGNO (operands[1]),
|
||
+ INTVAL (operands[2]),
|
||
force_reg (SImode, XEXP (operands[0], 0)),
|
||
- TRUE, FALSE, operands[0], &offset);
|
||
+ FALSE, operands[0], &offset);
|
||
})
|
||
|
||
-;; Store multiple with write-back
|
||
-
|
||
-(define_insn "*stmsi_postinc4"
|
||
- [(match_parallel 0 "store_multiple_operation"
|
||
- [(set (match_operand:SI 1 "s_register_operand" "=r")
|
||
- (plus:SI (match_operand:SI 2 "s_register_operand" "1")
|
||
- (const_int 16)))
|
||
- (set (mem:SI (match_dup 2))
|
||
- (match_operand:SI 3 "arm_hard_register_operand" ""))
|
||
- (set (mem:SI (plus:SI (match_dup 2) (const_int 4)))
|
||
- (match_operand:SI 4 "arm_hard_register_operand" ""))
|
||
- (set (mem:SI (plus:SI (match_dup 2) (const_int 8)))
|
||
- (match_operand:SI 5 "arm_hard_register_operand" ""))
|
||
- (set (mem:SI (plus:SI (match_dup 2) (const_int 12)))
|
||
- (match_operand:SI 6 "arm_hard_register_operand" ""))])]
|
||
- "TARGET_32BIT && XVECLEN (operands[0], 0) == 5"
|
||
- "stm%(ia%)\\t%1!, {%3, %4, %5, %6}"
|
||
- [(set_attr "predicable" "yes")
|
||
- (set_attr "type" "store4")]
|
||
-)
|
||
-
|
||
-(define_insn "*stmsi_postinc4_thumb1"
|
||
- [(match_parallel 0 "store_multiple_operation"
|
||
- [(set (match_operand:SI 1 "s_register_operand" "=l")
|
||
- (plus:SI (match_operand:SI 2 "s_register_operand" "1")
|
||
- (const_int 16)))
|
||
- (set (mem:SI (match_dup 2))
|
||
- (match_operand:SI 3 "arm_hard_register_operand" ""))
|
||
- (set (mem:SI (plus:SI (match_dup 2) (const_int 4)))
|
||
- (match_operand:SI 4 "arm_hard_register_operand" ""))
|
||
- (set (mem:SI (plus:SI (match_dup 2) (const_int 8)))
|
||
- (match_operand:SI 5 "arm_hard_register_operand" ""))
|
||
- (set (mem:SI (plus:SI (match_dup 2) (const_int 12)))
|
||
- (match_operand:SI 6 "arm_hard_register_operand" ""))])]
|
||
- "TARGET_THUMB1 && XVECLEN (operands[0], 0) == 5"
|
||
- "stmia\\t%1!, {%3, %4, %5, %6}"
|
||
- [(set_attr "type" "store4")]
|
||
-)
|
||
-
|
||
-(define_insn "*stmsi_postinc3"
|
||
- [(match_parallel 0 "store_multiple_operation"
|
||
- [(set (match_operand:SI 1 "s_register_operand" "=r")
|
||
- (plus:SI (match_operand:SI 2 "s_register_operand" "1")
|
||
- (const_int 12)))
|
||
- (set (mem:SI (match_dup 2))
|
||
- (match_operand:SI 3 "arm_hard_register_operand" ""))
|
||
- (set (mem:SI (plus:SI (match_dup 2) (const_int 4)))
|
||
- (match_operand:SI 4 "arm_hard_register_operand" ""))
|
||
- (set (mem:SI (plus:SI (match_dup 2) (const_int 8)))
|
||
- (match_operand:SI 5 "arm_hard_register_operand" ""))])]
|
||
- "TARGET_32BIT && XVECLEN (operands[0], 0) == 4"
|
||
- "stm%(ia%)\\t%1!, {%3, %4, %5}"
|
||
- [(set_attr "predicable" "yes")
|
||
- (set_attr "type" "store3")]
|
||
-)
|
||
-
|
||
-(define_insn "*stmsi_postinc2"
|
||
- [(match_parallel 0 "store_multiple_operation"
|
||
- [(set (match_operand:SI 1 "s_register_operand" "=r")
|
||
- (plus:SI (match_operand:SI 2 "s_register_operand" "1")
|
||
- (const_int 8)))
|
||
- (set (mem:SI (match_dup 2))
|
||
- (match_operand:SI 3 "arm_hard_register_operand" ""))
|
||
- (set (mem:SI (plus:SI (match_dup 2) (const_int 4)))
|
||
- (match_operand:SI 4 "arm_hard_register_operand" ""))])]
|
||
- "TARGET_32BIT && XVECLEN (operands[0], 0) == 3"
|
||
- "stm%(ia%)\\t%1!, {%3, %4}"
|
||
- [(set_attr "predicable" "yes")
|
||
- (set_attr "type" "store2")]
|
||
-)
|
||
-
|
||
-;; Ordinary store multiple
|
||
-
|
||
-(define_insn "*stmsi4"
|
||
- [(match_parallel 0 "store_multiple_operation"
|
||
- [(set (mem:SI (match_operand:SI 1 "s_register_operand" "r"))
|
||
- (match_operand:SI 2 "arm_hard_register_operand" ""))
|
||
- (set (mem:SI (plus:SI (match_dup 1) (const_int 4)))
|
||
- (match_operand:SI 3 "arm_hard_register_operand" ""))
|
||
- (set (mem:SI (plus:SI (match_dup 1) (const_int 8)))
|
||
- (match_operand:SI 4 "arm_hard_register_operand" ""))
|
||
- (set (mem:SI (plus:SI (match_dup 1) (const_int 12)))
|
||
- (match_operand:SI 5 "arm_hard_register_operand" ""))])]
|
||
- "TARGET_32BIT && XVECLEN (operands[0], 0) == 4"
|
||
- "stm%(ia%)\\t%1, {%2, %3, %4, %5}"
|
||
- [(set_attr "predicable" "yes")
|
||
- (set_attr "type" "store4")]
|
||
-)
|
||
-
|
||
-(define_insn "*stmsi3"
|
||
- [(match_parallel 0 "store_multiple_operation"
|
||
- [(set (mem:SI (match_operand:SI 1 "s_register_operand" "r"))
|
||
- (match_operand:SI 2 "arm_hard_register_operand" ""))
|
||
- (set (mem:SI (plus:SI (match_dup 1) (const_int 4)))
|
||
- (match_operand:SI 3 "arm_hard_register_operand" ""))
|
||
- (set (mem:SI (plus:SI (match_dup 1) (const_int 8)))
|
||
- (match_operand:SI 4 "arm_hard_register_operand" ""))])]
|
||
- "TARGET_32BIT && XVECLEN (operands[0], 0) == 3"
|
||
- "stm%(ia%)\\t%1, {%2, %3, %4}"
|
||
- [(set_attr "predicable" "yes")
|
||
- (set_attr "type" "store3")]
|
||
-)
|
||
-
|
||
-(define_insn "*stmsi2"
|
||
- [(match_parallel 0 "store_multiple_operation"
|
||
- [(set (mem:SI (match_operand:SI 1 "s_register_operand" "r"))
|
||
- (match_operand:SI 2 "arm_hard_register_operand" ""))
|
||
- (set (mem:SI (plus:SI (match_dup 1) (const_int 4)))
|
||
- (match_operand:SI 3 "arm_hard_register_operand" ""))])]
|
||
- "TARGET_32BIT && XVECLEN (operands[0], 0) == 2"
|
||
- "stm%(ia%)\\t%1, {%2, %3}"
|
||
- [(set_attr "predicable" "yes")
|
||
- (set_attr "type" "store2")]
|
||
-)
|
||
|
||
;; Move a block of memory if it is word aligned and MORE than 2 words long.
|
||
;; We could let this apply for blocks of less than this, but it clobbers so
|
||
@@ -9031,8 +8804,8 @@
|
||
if (REGNO (reg) == R0_REGNUM)
|
||
{
|
||
/* On thumb we have to use a write-back instruction. */
|
||
- emit_insn (arm_gen_store_multiple (R0_REGNUM, 4, addr, TRUE,
|
||
- TARGET_THUMB ? TRUE : FALSE, mem, &offset));
|
||
+ emit_insn (arm_gen_store_multiple (arm_regs_in_sequence, 4, addr,
|
||
+ TARGET_THUMB ? TRUE : FALSE, mem, &offset));
|
||
size = TARGET_ARM ? 16 : 0;
|
||
}
|
||
else
|
||
@@ -9078,8 +8851,8 @@
|
||
if (REGNO (reg) == R0_REGNUM)
|
||
{
|
||
/* On thumb we have to use a write-back instruction. */
|
||
- emit_insn (arm_gen_load_multiple (R0_REGNUM, 4, addr, TRUE,
|
||
- TARGET_THUMB ? TRUE : FALSE, mem, &offset));
|
||
+ emit_insn (arm_gen_load_multiple (arm_regs_in_sequence, 4, addr,
|
||
+ TARGET_THUMB ? TRUE : FALSE, mem, &offset));
|
||
size = TARGET_ARM ? 16 : 0;
|
||
}
|
||
else
|
||
@@ -10672,87 +10445,6 @@
|
||
""
|
||
)
|
||
|
||
-; Peepholes to spot possible load- and store-multiples, if the ordering is
|
||
-; reversed, check that the memory references aren't volatile.
|
||
-
|
||
-(define_peephole
|
||
- [(set (match_operand:SI 0 "s_register_operand" "=rk")
|
||
- (match_operand:SI 4 "memory_operand" "m"))
|
||
- (set (match_operand:SI 1 "s_register_operand" "=rk")
|
||
- (match_operand:SI 5 "memory_operand" "m"))
|
||
- (set (match_operand:SI 2 "s_register_operand" "=rk")
|
||
- (match_operand:SI 6 "memory_operand" "m"))
|
||
- (set (match_operand:SI 3 "s_register_operand" "=rk")
|
||
- (match_operand:SI 7 "memory_operand" "m"))]
|
||
- "TARGET_ARM && load_multiple_sequence (operands, 4, NULL, NULL, NULL)"
|
||
- "*
|
||
- return emit_ldm_seq (operands, 4);
|
||
- "
|
||
-)
|
||
-
|
||
-(define_peephole
|
||
- [(set (match_operand:SI 0 "s_register_operand" "=rk")
|
||
- (match_operand:SI 3 "memory_operand" "m"))
|
||
- (set (match_operand:SI 1 "s_register_operand" "=rk")
|
||
- (match_operand:SI 4 "memory_operand" "m"))
|
||
- (set (match_operand:SI 2 "s_register_operand" "=rk")
|
||
- (match_operand:SI 5 "memory_operand" "m"))]
|
||
- "TARGET_ARM && load_multiple_sequence (operands, 3, NULL, NULL, NULL)"
|
||
- "*
|
||
- return emit_ldm_seq (operands, 3);
|
||
- "
|
||
-)
|
||
-
|
||
-(define_peephole
|
||
- [(set (match_operand:SI 0 "s_register_operand" "=rk")
|
||
- (match_operand:SI 2 "memory_operand" "m"))
|
||
- (set (match_operand:SI 1 "s_register_operand" "=rk")
|
||
- (match_operand:SI 3 "memory_operand" "m"))]
|
||
- "TARGET_ARM && load_multiple_sequence (operands, 2, NULL, NULL, NULL)"
|
||
- "*
|
||
- return emit_ldm_seq (operands, 2);
|
||
- "
|
||
-)
|
||
-
|
||
-(define_peephole
|
||
- [(set (match_operand:SI 4 "memory_operand" "=m")
|
||
- (match_operand:SI 0 "s_register_operand" "rk"))
|
||
- (set (match_operand:SI 5 "memory_operand" "=m")
|
||
- (match_operand:SI 1 "s_register_operand" "rk"))
|
||
- (set (match_operand:SI 6 "memory_operand" "=m")
|
||
- (match_operand:SI 2 "s_register_operand" "rk"))
|
||
- (set (match_operand:SI 7 "memory_operand" "=m")
|
||
- (match_operand:SI 3 "s_register_operand" "rk"))]
|
||
- "TARGET_ARM && store_multiple_sequence (operands, 4, NULL, NULL, NULL)"
|
||
- "*
|
||
- return emit_stm_seq (operands, 4);
|
||
- "
|
||
-)
|
||
-
|
||
-(define_peephole
|
||
- [(set (match_operand:SI 3 "memory_operand" "=m")
|
||
- (match_operand:SI 0 "s_register_operand" "rk"))
|
||
- (set (match_operand:SI 4 "memory_operand" "=m")
|
||
- (match_operand:SI 1 "s_register_operand" "rk"))
|
||
- (set (match_operand:SI 5 "memory_operand" "=m")
|
||
- (match_operand:SI 2 "s_register_operand" "rk"))]
|
||
- "TARGET_ARM && store_multiple_sequence (operands, 3, NULL, NULL, NULL)"
|
||
- "*
|
||
- return emit_stm_seq (operands, 3);
|
||
- "
|
||
-)
|
||
-
|
||
-(define_peephole
|
||
- [(set (match_operand:SI 2 "memory_operand" "=m")
|
||
- (match_operand:SI 0 "s_register_operand" "rk"))
|
||
- (set (match_operand:SI 3 "memory_operand" "=m")
|
||
- (match_operand:SI 1 "s_register_operand" "rk"))]
|
||
- "TARGET_ARM && store_multiple_sequence (operands, 2, NULL, NULL, NULL)"
|
||
- "*
|
||
- return emit_stm_seq (operands, 2);
|
||
- "
|
||
-)
|
||
-
|
||
(define_split
|
||
[(set (match_operand:SI 0 "s_register_operand" "")
|
||
(and:SI (ge:SI (match_operand:SI 1 "s_register_operand" "")
|
||
@@ -11559,6 +11251,8 @@
|
||
"
|
||
)
|
||
|
||
+;; Load the load/store multiple patterns
|
||
+(include "ldmstm.md")
|
||
;; Load the FPA co-processor patterns
|
||
(include "fpa.md")
|
||
;; Load the Maverick co-processor patterns
|
||
|
||
=== added file 'gcc/config/arm/ldmstm.md'
|
||
--- old/gcc/config/arm/ldmstm.md 1970-01-01 00:00:00 +0000
|
||
+++ new/gcc/config/arm/ldmstm.md 2010-11-16 13:08:47 +0000
|
||
@@ -0,0 +1,1191 @@
|
||
+/* ARM ldm/stm instruction patterns. This file was automatically generated
|
||
+ using arm-ldmstm.ml. Please do not edit manually.
|
||
+
|
||
+ Copyright (C) 2010 Free Software Foundation, Inc.
|
||
+ Contributed by CodeSourcery.
|
||
+
|
||
+ This file is part of GCC.
|
||
+
|
||
+ GCC is free software; you can redistribute it and/or modify it
|
||
+ under the terms of the GNU General Public License as published
|
||
+ by the Free Software Foundation; either version 3, or (at your
|
||
+ option) any later version.
|
||
+
|
||
+ GCC is distributed in the hope that it will be useful, but WITHOUT
|
||
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||
+ License for more details.
|
||
+
|
||
+ You should have received a copy of the GNU General Public License and
|
||
+ a copy of the GCC Runtime Library Exception along with this program;
|
||
+ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
||
+ <http://www.gnu.org/licenses/>. */
|
||
+
|
||
+(define_insn "*ldm4_ia"
|
||
+ [(match_parallel 0 "load_multiple_operation"
|
||
+ [(set (match_operand:SI 2 "arm_hard_register_operand" "")
|
||
+ (mem:SI (match_operand:SI 1 "s_register_operand" "rk")))
|
||
+ (set (match_operand:SI 3 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 1)
|
||
+ (const_int 4))))
|
||
+ (set (match_operand:SI 4 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 1)
|
||
+ (const_int 8))))
|
||
+ (set (match_operand:SI 5 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 1)
|
||
+ (const_int 12))))])]
|
||
+ "TARGET_32BIT && XVECLEN (operands[0], 0) == 4"
|
||
+ "ldm%(ia%)\t%1, {%2, %3, %4, %5}"
|
||
+ [(set_attr "type" "load4")
|
||
+ (set_attr "predicable" "yes")])
|
||
+
|
||
+(define_insn "*thumb_ldm4_ia"
|
||
+ [(match_parallel 0 "load_multiple_operation"
|
||
+ [(set (match_operand:SI 2 "arm_hard_register_operand" "")
|
||
+ (mem:SI (match_operand:SI 1 "s_register_operand" "l")))
|
||
+ (set (match_operand:SI 3 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 1)
|
||
+ (const_int 4))))
|
||
+ (set (match_operand:SI 4 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 1)
|
||
+ (const_int 8))))
|
||
+ (set (match_operand:SI 5 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 1)
|
||
+ (const_int 12))))])]
|
||
+ "TARGET_THUMB1 && XVECLEN (operands[0], 0) == 4"
|
||
+ "ldm%(ia%)\t%1, {%2, %3, %4, %5}"
|
||
+ [(set_attr "type" "load4")])
|
||
+
|
||
+(define_insn "*ldm4_ia_update"
|
||
+ [(match_parallel 0 "load_multiple_operation"
|
||
+ [(set (match_operand:SI 1 "s_register_operand" "=rk")
|
||
+ (plus:SI (match_operand:SI 2 "s_register_operand" "1") (const_int 16)))
|
||
+ (set (match_operand:SI 3 "arm_hard_register_operand" "")
|
||
+ (mem:SI (match_dup 2)))
|
||
+ (set (match_operand:SI 4 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 2)
|
||
+ (const_int 4))))
|
||
+ (set (match_operand:SI 5 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 2)
|
||
+ (const_int 8))))
|
||
+ (set (match_operand:SI 6 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 2)
|
||
+ (const_int 12))))])]
|
||
+ "TARGET_32BIT && XVECLEN (operands[0], 0) == 5"
|
||
+ "ldm%(ia%)\t%1!, {%3, %4, %5, %6}"
|
||
+ [(set_attr "type" "load4")
|
||
+ (set_attr "predicable" "yes")])
|
||
+
|
||
+(define_insn "*thumb_ldm4_ia_update"
|
||
+ [(match_parallel 0 "load_multiple_operation"
|
||
+ [(set (match_operand:SI 1 "s_register_operand" "=l")
|
||
+ (plus:SI (match_operand:SI 2 "s_register_operand" "1") (const_int 16)))
|
||
+ (set (match_operand:SI 3 "arm_hard_register_operand" "")
|
||
+ (mem:SI (match_dup 2)))
|
||
+ (set (match_operand:SI 4 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 2)
|
||
+ (const_int 4))))
|
||
+ (set (match_operand:SI 5 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 2)
|
||
+ (const_int 8))))
|
||
+ (set (match_operand:SI 6 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 2)
|
||
+ (const_int 12))))])]
|
||
+ "TARGET_THUMB1 && XVECLEN (operands[0], 0) == 5"
|
||
+ "ldm%(ia%)\t%1!, {%3, %4, %5, %6}"
|
||
+ [(set_attr "type" "load4")])
|
||
+
|
||
+(define_insn "*stm4_ia"
|
||
+ [(match_parallel 0 "store_multiple_operation"
|
||
+ [(set (mem:SI (match_operand:SI 1 "s_register_operand" "rk"))
|
||
+ (match_operand:SI 2 "arm_hard_register_operand" ""))
|
||
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 4)))
|
||
+ (match_operand:SI 3 "arm_hard_register_operand" ""))
|
||
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 8)))
|
||
+ (match_operand:SI 4 "arm_hard_register_operand" ""))
|
||
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 12)))
|
||
+ (match_operand:SI 5 "arm_hard_register_operand" ""))])]
|
||
+ "TARGET_32BIT && XVECLEN (operands[0], 0) == 4"
|
||
+ "stm%(ia%)\t%1, {%2, %3, %4, %5}"
|
||
+ [(set_attr "type" "store4")
|
||
+ (set_attr "predicable" "yes")])
|
||
+
|
||
+(define_insn "*stm4_ia_update"
|
||
+ [(match_parallel 0 "store_multiple_operation"
|
||
+ [(set (match_operand:SI 1 "s_register_operand" "=rk")
|
||
+ (plus:SI (match_operand:SI 2 "s_register_operand" "1") (const_int 16)))
|
||
+ (set (mem:SI (match_dup 2))
|
||
+ (match_operand:SI 3 "arm_hard_register_operand" ""))
|
||
+ (set (mem:SI (plus:SI (match_dup 2) (const_int 4)))
|
||
+ (match_operand:SI 4 "arm_hard_register_operand" ""))
|
||
+ (set (mem:SI (plus:SI (match_dup 2) (const_int 8)))
|
||
+ (match_operand:SI 5 "arm_hard_register_operand" ""))
|
||
+ (set (mem:SI (plus:SI (match_dup 2) (const_int 12)))
|
||
+ (match_operand:SI 6 "arm_hard_register_operand" ""))])]
|
||
+ "TARGET_32BIT && XVECLEN (operands[0], 0) == 5"
|
||
+ "stm%(ia%)\t%1!, {%3, %4, %5, %6}"
|
||
+ [(set_attr "type" "store4")
|
||
+ (set_attr "predicable" "yes")])
|
||
+
|
||
+(define_insn "*thumb_stm4_ia_update"
|
||
+ [(match_parallel 0 "store_multiple_operation"
|
||
+ [(set (match_operand:SI 1 "s_register_operand" "=l")
|
||
+ (plus:SI (match_operand:SI 2 "s_register_operand" "1") (const_int 16)))
|
||
+ (set (mem:SI (match_dup 2))
|
||
+ (match_operand:SI 3 "arm_hard_register_operand" ""))
|
||
+ (set (mem:SI (plus:SI (match_dup 2) (const_int 4)))
|
||
+ (match_operand:SI 4 "arm_hard_register_operand" ""))
|
||
+ (set (mem:SI (plus:SI (match_dup 2) (const_int 8)))
|
||
+ (match_operand:SI 5 "arm_hard_register_operand" ""))
|
||
+ (set (mem:SI (plus:SI (match_dup 2) (const_int 12)))
|
||
+ (match_operand:SI 6 "arm_hard_register_operand" ""))])]
|
||
+ "TARGET_THUMB1 && XVECLEN (operands[0], 0) == 5"
|
||
+ "stm%(ia%)\t%1!, {%3, %4, %5, %6}"
|
||
+ [(set_attr "type" "store4")])
|
||
+
|
||
+(define_insn "*ldm4_ib"
|
||
+ [(match_parallel 0 "load_multiple_operation"
|
||
+ [(set (match_operand:SI 2 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_operand:SI 1 "s_register_operand" "rk")
|
||
+ (const_int 4))))
|
||
+ (set (match_operand:SI 3 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 1)
|
||
+ (const_int 8))))
|
||
+ (set (match_operand:SI 4 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 1)
|
||
+ (const_int 12))))
|
||
+ (set (match_operand:SI 5 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 1)
|
||
+ (const_int 16))))])]
|
||
+ "TARGET_ARM && XVECLEN (operands[0], 0) == 4"
|
||
+ "ldm%(ib%)\t%1, {%2, %3, %4, %5}"
|
||
+ [(set_attr "type" "load4")
|
||
+ (set_attr "predicable" "yes")])
|
||
+
|
||
+(define_insn "*ldm4_ib_update"
|
||
+ [(match_parallel 0 "load_multiple_operation"
|
||
+ [(set (match_operand:SI 1 "s_register_operand" "=rk")
|
||
+ (plus:SI (match_operand:SI 2 "s_register_operand" "1") (const_int 16)))
|
||
+ (set (match_operand:SI 3 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 2)
|
||
+ (const_int 4))))
|
||
+ (set (match_operand:SI 4 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 2)
|
||
+ (const_int 8))))
|
||
+ (set (match_operand:SI 5 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 2)
|
||
+ (const_int 12))))
|
||
+ (set (match_operand:SI 6 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 2)
|
||
+ (const_int 16))))])]
|
||
+ "TARGET_ARM && XVECLEN (operands[0], 0) == 5"
|
||
+ "ldm%(ib%)\t%1!, {%3, %4, %5, %6}"
|
||
+ [(set_attr "type" "load4")
|
||
+ (set_attr "predicable" "yes")])
|
||
+
|
||
+(define_insn "*stm4_ib"
|
||
+ [(match_parallel 0 "store_multiple_operation"
|
||
+ [(set (mem:SI (plus:SI (match_operand:SI 1 "s_register_operand" "rk") (const_int 4)))
|
||
+ (match_operand:SI 2 "arm_hard_register_operand" ""))
|
||
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 8)))
|
||
+ (match_operand:SI 3 "arm_hard_register_operand" ""))
|
||
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 12)))
|
||
+ (match_operand:SI 4 "arm_hard_register_operand" ""))
|
||
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 16)))
|
||
+ (match_operand:SI 5 "arm_hard_register_operand" ""))])]
|
||
+ "TARGET_ARM && XVECLEN (operands[0], 0) == 4"
|
||
+ "stm%(ib%)\t%1, {%2, %3, %4, %5}"
|
||
+ [(set_attr "type" "store4")
|
||
+ (set_attr "predicable" "yes")])
|
||
+
|
||
+(define_insn "*stm4_ib_update"
|
||
+ [(match_parallel 0 "store_multiple_operation"
|
||
+ [(set (match_operand:SI 1 "s_register_operand" "=rk")
|
||
+ (plus:SI (match_operand:SI 2 "s_register_operand" "1") (const_int 16)))
|
||
+ (set (mem:SI (plus:SI (match_dup 2) (const_int 4)))
|
||
+ (match_operand:SI 3 "arm_hard_register_operand" ""))
|
||
+ (set (mem:SI (plus:SI (match_dup 2) (const_int 8)))
|
||
+ (match_operand:SI 4 "arm_hard_register_operand" ""))
|
||
+ (set (mem:SI (plus:SI (match_dup 2) (const_int 12)))
|
||
+ (match_operand:SI 5 "arm_hard_register_operand" ""))
|
||
+ (set (mem:SI (plus:SI (match_dup 2) (const_int 16)))
|
||
+ (match_operand:SI 6 "arm_hard_register_operand" ""))])]
|
||
+ "TARGET_ARM && XVECLEN (operands[0], 0) == 5"
|
||
+ "stm%(ib%)\t%1!, {%3, %4, %5, %6}"
|
||
+ [(set_attr "type" "store4")
|
||
+ (set_attr "predicable" "yes")])
|
||
+
|
||
+(define_insn "*ldm4_da"
|
||
+ [(match_parallel 0 "load_multiple_operation"
|
||
+ [(set (match_operand:SI 2 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_operand:SI 1 "s_register_operand" "rk")
|
||
+ (const_int -12))))
|
||
+ (set (match_operand:SI 3 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 1)
|
||
+ (const_int -8))))
|
||
+ (set (match_operand:SI 4 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 1)
|
||
+ (const_int -4))))
|
||
+ (set (match_operand:SI 5 "arm_hard_register_operand" "")
|
||
+ (mem:SI (match_dup 1)))])]
|
||
+ "TARGET_ARM && XVECLEN (operands[0], 0) == 4"
|
||
+ "ldm%(da%)\t%1, {%2, %3, %4, %5}"
|
||
+ [(set_attr "type" "load4")
|
||
+ (set_attr "predicable" "yes")])
|
||
+
|
||
+(define_insn "*ldm4_da_update"
|
||
+ [(match_parallel 0 "load_multiple_operation"
|
||
+ [(set (match_operand:SI 1 "s_register_operand" "=rk")
|
||
+ (plus:SI (match_operand:SI 2 "s_register_operand" "1") (const_int -16)))
|
||
+ (set (match_operand:SI 3 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 2)
|
||
+ (const_int -12))))
|
||
+ (set (match_operand:SI 4 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 2)
|
||
+ (const_int -8))))
|
||
+ (set (match_operand:SI 5 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 2)
|
||
+ (const_int -4))))
|
||
+ (set (match_operand:SI 6 "arm_hard_register_operand" "")
|
||
+ (mem:SI (match_dup 2)))])]
|
||
+ "TARGET_ARM && XVECLEN (operands[0], 0) == 5"
|
||
+ "ldm%(da%)\t%1!, {%3, %4, %5, %6}"
|
||
+ [(set_attr "type" "load4")
|
||
+ (set_attr "predicable" "yes")])
|
||
+
|
||
+(define_insn "*stm4_da"
|
||
+ [(match_parallel 0 "store_multiple_operation"
|
||
+ [(set (mem:SI (plus:SI (match_operand:SI 1 "s_register_operand" "rk") (const_int -12)))
|
||
+ (match_operand:SI 2 "arm_hard_register_operand" ""))
|
||
+ (set (mem:SI (plus:SI (match_dup 1) (const_int -8)))
|
||
+ (match_operand:SI 3 "arm_hard_register_operand" ""))
|
||
+ (set (mem:SI (plus:SI (match_dup 1) (const_int -4)))
|
||
+ (match_operand:SI 4 "arm_hard_register_operand" ""))
|
||
+ (set (mem:SI (match_dup 1))
|
||
+ (match_operand:SI 5 "arm_hard_register_operand" ""))])]
|
||
+ "TARGET_ARM && XVECLEN (operands[0], 0) == 4"
|
||
+ "stm%(da%)\t%1, {%2, %3, %4, %5}"
|
||
+ [(set_attr "type" "store4")
|
||
+ (set_attr "predicable" "yes")])
|
||
+
|
||
+(define_insn "*stm4_da_update"
|
||
+ [(match_parallel 0 "store_multiple_operation"
|
||
+ [(set (match_operand:SI 1 "s_register_operand" "=rk")
|
||
+ (plus:SI (match_operand:SI 2 "s_register_operand" "1") (const_int -16)))
|
||
+ (set (mem:SI (plus:SI (match_dup 2) (const_int -12)))
|
||
+ (match_operand:SI 3 "arm_hard_register_operand" ""))
|
||
+ (set (mem:SI (plus:SI (match_dup 2) (const_int -8)))
|
||
+ (match_operand:SI 4 "arm_hard_register_operand" ""))
|
||
+ (set (mem:SI (plus:SI (match_dup 2) (const_int -4)))
|
||
+ (match_operand:SI 5 "arm_hard_register_operand" ""))
|
||
+ (set (mem:SI (match_dup 2))
|
||
+ (match_operand:SI 6 "arm_hard_register_operand" ""))])]
|
||
+ "TARGET_ARM && XVECLEN (operands[0], 0) == 5"
|
||
+ "stm%(da%)\t%1!, {%3, %4, %5, %6}"
|
||
+ [(set_attr "type" "store4")
|
||
+ (set_attr "predicable" "yes")])
|
||
+
|
||
+(define_insn "*ldm4_db"
|
||
+ [(match_parallel 0 "load_multiple_operation"
|
||
+ [(set (match_operand:SI 2 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_operand:SI 1 "s_register_operand" "rk")
|
||
+ (const_int -16))))
|
||
+ (set (match_operand:SI 3 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 1)
|
||
+ (const_int -12))))
|
||
+ (set (match_operand:SI 4 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 1)
|
||
+ (const_int -8))))
|
||
+ (set (match_operand:SI 5 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 1)
|
||
+ (const_int -4))))])]
|
||
+ "TARGET_32BIT && XVECLEN (operands[0], 0) == 4"
|
||
+ "ldm%(db%)\t%1, {%2, %3, %4, %5}"
|
||
+ [(set_attr "type" "load4")
|
||
+ (set_attr "predicable" "yes")])
|
||
+
|
||
+(define_insn "*ldm4_db_update"
|
||
+ [(match_parallel 0 "load_multiple_operation"
|
||
+ [(set (match_operand:SI 1 "s_register_operand" "=rk")
|
||
+ (plus:SI (match_operand:SI 2 "s_register_operand" "1") (const_int -16)))
|
||
+ (set (match_operand:SI 3 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 2)
|
||
+ (const_int -16))))
|
||
+ (set (match_operand:SI 4 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 2)
|
||
+ (const_int -12))))
|
||
+ (set (match_operand:SI 5 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 2)
|
||
+ (const_int -8))))
|
||
+ (set (match_operand:SI 6 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 2)
|
||
+ (const_int -4))))])]
|
||
+ "TARGET_32BIT && XVECLEN (operands[0], 0) == 5"
|
||
+ "ldm%(db%)\t%1!, {%3, %4, %5, %6}"
|
||
+ [(set_attr "type" "load4")
|
||
+ (set_attr "predicable" "yes")])
|
||
+
|
||
+(define_insn "*stm4_db"
|
||
+ [(match_parallel 0 "store_multiple_operation"
|
||
+ [(set (mem:SI (plus:SI (match_operand:SI 1 "s_register_operand" "rk") (const_int -16)))
|
||
+ (match_operand:SI 2 "arm_hard_register_operand" ""))
|
||
+ (set (mem:SI (plus:SI (match_dup 1) (const_int -12)))
|
||
+ (match_operand:SI 3 "arm_hard_register_operand" ""))
|
||
+ (set (mem:SI (plus:SI (match_dup 1) (const_int -8)))
|
||
+ (match_operand:SI 4 "arm_hard_register_operand" ""))
|
||
+ (set (mem:SI (plus:SI (match_dup 1) (const_int -4)))
|
||
+ (match_operand:SI 5 "arm_hard_register_operand" ""))])]
|
||
+ "TARGET_32BIT && XVECLEN (operands[0], 0) == 4"
|
||
+ "stm%(db%)\t%1, {%2, %3, %4, %5}"
|
||
+ [(set_attr "type" "store4")
|
||
+ (set_attr "predicable" "yes")])
|
||
+
|
||
+(define_insn "*stm4_db_update"
|
||
+ [(match_parallel 0 "store_multiple_operation"
|
||
+ [(set (match_operand:SI 1 "s_register_operand" "=rk")
|
||
+ (plus:SI (match_operand:SI 2 "s_register_operand" "1") (const_int -16)))
|
||
+ (set (mem:SI (plus:SI (match_dup 2) (const_int -16)))
|
||
+ (match_operand:SI 3 "arm_hard_register_operand" ""))
|
||
+ (set (mem:SI (plus:SI (match_dup 2) (const_int -12)))
|
||
+ (match_operand:SI 4 "arm_hard_register_operand" ""))
|
||
+ (set (mem:SI (plus:SI (match_dup 2) (const_int -8)))
|
||
+ (match_operand:SI 5 "arm_hard_register_operand" ""))
|
||
+ (set (mem:SI (plus:SI (match_dup 2) (const_int -4)))
|
||
+ (match_operand:SI 6 "arm_hard_register_operand" ""))])]
|
||
+ "TARGET_32BIT && XVECLEN (operands[0], 0) == 5"
|
||
+ "stm%(db%)\t%1!, {%3, %4, %5, %6}"
|
||
+ [(set_attr "type" "store4")
|
||
+ (set_attr "predicable" "yes")])
|
||
+
|
||
+(define_peephole2
|
||
+ [(set (match_operand:SI 0 "s_register_operand" "")
|
||
+ (match_operand:SI 4 "memory_operand" ""))
|
||
+ (set (match_operand:SI 1 "s_register_operand" "")
|
||
+ (match_operand:SI 5 "memory_operand" ""))
|
||
+ (set (match_operand:SI 2 "s_register_operand" "")
|
||
+ (match_operand:SI 6 "memory_operand" ""))
|
||
+ (set (match_operand:SI 3 "s_register_operand" "")
|
||
+ (match_operand:SI 7 "memory_operand" ""))]
|
||
+ ""
|
||
+ [(const_int 0)]
|
||
+{
|
||
+ if (gen_ldm_seq (operands, 4, false))
|
||
+ DONE;
|
||
+ else
|
||
+ FAIL;
|
||
+})
|
||
+
|
||
+(define_peephole2
|
||
+ [(set (match_operand:SI 0 "s_register_operand" "")
|
||
+ (match_operand:SI 4 "memory_operand" ""))
|
||
+ (parallel
|
||
+ [(set (match_operand:SI 1 "s_register_operand" "")
|
||
+ (match_operand:SI 5 "memory_operand" ""))
|
||
+ (set (match_operand:SI 2 "s_register_operand" "")
|
||
+ (match_operand:SI 6 "memory_operand" ""))
|
||
+ (set (match_operand:SI 3 "s_register_operand" "")
|
||
+ (match_operand:SI 7 "memory_operand" ""))])]
|
||
+ ""
|
||
+ [(const_int 0)]
|
||
+{
|
||
+ if (gen_ldm_seq (operands, 4, false))
|
||
+ DONE;
|
||
+ else
|
||
+ FAIL;
|
||
+})
|
||
+
|
||
+(define_peephole2
|
||
+ [(set (match_operand:SI 0 "s_register_operand" "")
|
||
+ (match_operand:SI 8 "const_int_operand" ""))
|
||
+ (set (match_operand:SI 4 "memory_operand" "")
|
||
+ (match_dup 0))
|
||
+ (set (match_operand:SI 1 "s_register_operand" "")
|
||
+ (match_operand:SI 9 "const_int_operand" ""))
|
||
+ (set (match_operand:SI 5 "memory_operand" "")
|
||
+ (match_dup 1))
|
||
+ (set (match_operand:SI 2 "s_register_operand" "")
|
||
+ (match_operand:SI 10 "const_int_operand" ""))
|
||
+ (set (match_operand:SI 6 "memory_operand" "")
|
||
+ (match_dup 2))
|
||
+ (set (match_operand:SI 3 "s_register_operand" "")
|
||
+ (match_operand:SI 11 "const_int_operand" ""))
|
||
+ (set (match_operand:SI 7 "memory_operand" "")
|
||
+ (match_dup 3))]
|
||
+ ""
|
||
+ [(const_int 0)]
|
||
+{
|
||
+ if (gen_const_stm_seq (operands, 4))
|
||
+ DONE;
|
||
+ else
|
||
+ FAIL;
|
||
+})
|
||
+
|
||
+(define_peephole2
|
||
+ [(set (match_operand:SI 0 "s_register_operand" "")
|
||
+ (match_operand:SI 8 "const_int_operand" ""))
|
||
+ (set (match_operand:SI 1 "s_register_operand" "")
|
||
+ (match_operand:SI 9 "const_int_operand" ""))
|
||
+ (set (match_operand:SI 2 "s_register_operand" "")
|
||
+ (match_operand:SI 10 "const_int_operand" ""))
|
||
+ (set (match_operand:SI 3 "s_register_operand" "")
|
||
+ (match_operand:SI 11 "const_int_operand" ""))
|
||
+ (set (match_operand:SI 4 "memory_operand" "")
|
||
+ (match_dup 0))
|
||
+ (set (match_operand:SI 5 "memory_operand" "")
|
||
+ (match_dup 1))
|
||
+ (set (match_operand:SI 6 "memory_operand" "")
|
||
+ (match_dup 2))
|
||
+ (set (match_operand:SI 7 "memory_operand" "")
|
||
+ (match_dup 3))]
|
||
+ ""
|
||
+ [(const_int 0)]
|
||
+{
|
||
+ if (gen_const_stm_seq (operands, 4))
|
||
+ DONE;
|
||
+ else
|
||
+ FAIL;
|
||
+})
|
||
+
|
||
+(define_peephole2
|
||
+ [(set (match_operand:SI 4 "memory_operand" "")
|
||
+ (match_operand:SI 0 "s_register_operand" ""))
|
||
+ (set (match_operand:SI 5 "memory_operand" "")
|
||
+ (match_operand:SI 1 "s_register_operand" ""))
|
||
+ (set (match_operand:SI 6 "memory_operand" "")
|
||
+ (match_operand:SI 2 "s_register_operand" ""))
|
||
+ (set (match_operand:SI 7 "memory_operand" "")
|
||
+ (match_operand:SI 3 "s_register_operand" ""))]
|
||
+ ""
|
||
+ [(const_int 0)]
|
||
+{
|
||
+ if (gen_stm_seq (operands, 4))
|
||
+ DONE;
|
||
+ else
|
||
+ FAIL;
|
||
+})
|
||
+
|
||
+(define_insn "*ldm3_ia"
|
||
+ [(match_parallel 0 "load_multiple_operation"
|
||
+ [(set (match_operand:SI 2 "arm_hard_register_operand" "")
|
||
+ (mem:SI (match_operand:SI 1 "s_register_operand" "rk")))
|
||
+ (set (match_operand:SI 3 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 1)
|
||
+ (const_int 4))))
|
||
+ (set (match_operand:SI 4 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 1)
|
||
+ (const_int 8))))])]
|
||
+ "TARGET_32BIT && XVECLEN (operands[0], 0) == 3"
|
||
+ "ldm%(ia%)\t%1, {%2, %3, %4}"
|
||
+ [(set_attr "type" "load3")
|
||
+ (set_attr "predicable" "yes")])
|
||
+
|
||
+(define_insn "*thumb_ldm3_ia"
|
||
+ [(match_parallel 0 "load_multiple_operation"
|
||
+ [(set (match_operand:SI 2 "arm_hard_register_operand" "")
|
||
+ (mem:SI (match_operand:SI 1 "s_register_operand" "l")))
|
||
+ (set (match_operand:SI 3 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 1)
|
||
+ (const_int 4))))
|
||
+ (set (match_operand:SI 4 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 1)
|
||
+ (const_int 8))))])]
|
||
+ "TARGET_THUMB1 && XVECLEN (operands[0], 0) == 3"
|
||
+ "ldm%(ia%)\t%1, {%2, %3, %4}"
|
||
+ [(set_attr "type" "load3")])
|
||
+
|
||
+(define_insn "*ldm3_ia_update"
|
||
+ [(match_parallel 0 "load_multiple_operation"
|
||
+ [(set (match_operand:SI 1 "s_register_operand" "=rk")
|
||
+ (plus:SI (match_operand:SI 2 "s_register_operand" "1") (const_int 12)))
|
||
+ (set (match_operand:SI 3 "arm_hard_register_operand" "")
|
||
+ (mem:SI (match_dup 2)))
|
||
+ (set (match_operand:SI 4 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 2)
|
||
+ (const_int 4))))
|
||
+ (set (match_operand:SI 5 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 2)
|
||
+ (const_int 8))))])]
|
||
+ "TARGET_32BIT && XVECLEN (operands[0], 0) == 4"
|
||
+ "ldm%(ia%)\t%1!, {%3, %4, %5}"
|
||
+ [(set_attr "type" "load3")
|
||
+ (set_attr "predicable" "yes")])
|
||
+
|
||
+(define_insn "*thumb_ldm3_ia_update"
|
||
+ [(match_parallel 0 "load_multiple_operation"
|
||
+ [(set (match_operand:SI 1 "s_register_operand" "=l")
|
||
+ (plus:SI (match_operand:SI 2 "s_register_operand" "1") (const_int 12)))
|
||
+ (set (match_operand:SI 3 "arm_hard_register_operand" "")
|
||
+ (mem:SI (match_dup 2)))
|
||
+ (set (match_operand:SI 4 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 2)
|
||
+ (const_int 4))))
|
||
+ (set (match_operand:SI 5 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 2)
|
||
+ (const_int 8))))])]
|
||
+ "TARGET_THUMB1 && XVECLEN (operands[0], 0) == 4"
|
||
+ "ldm%(ia%)\t%1!, {%3, %4, %5}"
|
||
+ [(set_attr "type" "load3")])
|
||
+
|
||
+(define_insn "*stm3_ia"
|
||
+ [(match_parallel 0 "store_multiple_operation"
|
||
+ [(set (mem:SI (match_operand:SI 1 "s_register_operand" "rk"))
|
||
+ (match_operand:SI 2 "arm_hard_register_operand" ""))
|
||
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 4)))
|
||
+ (match_operand:SI 3 "arm_hard_register_operand" ""))
|
||
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 8)))
|
||
+ (match_operand:SI 4 "arm_hard_register_operand" ""))])]
|
||
+ "TARGET_32BIT && XVECLEN (operands[0], 0) == 3"
|
||
+ "stm%(ia%)\t%1, {%2, %3, %4}"
|
||
+ [(set_attr "type" "store3")
|
||
+ (set_attr "predicable" "yes")])
|
||
+
|
||
+(define_insn "*stm3_ia_update"
|
||
+ [(match_parallel 0 "store_multiple_operation"
|
||
+ [(set (match_operand:SI 1 "s_register_operand" "=rk")
|
||
+ (plus:SI (match_operand:SI 2 "s_register_operand" "1") (const_int 12)))
|
||
+ (set (mem:SI (match_dup 2))
|
||
+ (match_operand:SI 3 "arm_hard_register_operand" ""))
|
||
+ (set (mem:SI (plus:SI (match_dup 2) (const_int 4)))
|
||
+ (match_operand:SI 4 "arm_hard_register_operand" ""))
|
||
+ (set (mem:SI (plus:SI (match_dup 2) (const_int 8)))
|
||
+ (match_operand:SI 5 "arm_hard_register_operand" ""))])]
|
||
+ "TARGET_32BIT && XVECLEN (operands[0], 0) == 4"
|
||
+ "stm%(ia%)\t%1!, {%3, %4, %5}"
|
||
+ [(set_attr "type" "store3")
|
||
+ (set_attr "predicable" "yes")])
|
||
+
|
||
+(define_insn "*thumb_stm3_ia_update"
|
||
+ [(match_parallel 0 "store_multiple_operation"
|
||
+ [(set (match_operand:SI 1 "s_register_operand" "=l")
|
||
+ (plus:SI (match_operand:SI 2 "s_register_operand" "1") (const_int 12)))
|
||
+ (set (mem:SI (match_dup 2))
|
||
+ (match_operand:SI 3 "arm_hard_register_operand" ""))
|
||
+ (set (mem:SI (plus:SI (match_dup 2) (const_int 4)))
|
||
+ (match_operand:SI 4 "arm_hard_register_operand" ""))
|
||
+ (set (mem:SI (plus:SI (match_dup 2) (const_int 8)))
|
||
+ (match_operand:SI 5 "arm_hard_register_operand" ""))])]
|
||
+ "TARGET_THUMB1 && XVECLEN (operands[0], 0) == 4"
|
||
+ "stm%(ia%)\t%1!, {%3, %4, %5}"
|
||
+ [(set_attr "type" "store3")])
|
||
+
|
||
+(define_insn "*ldm3_ib"
|
||
+ [(match_parallel 0 "load_multiple_operation"
|
||
+ [(set (match_operand:SI 2 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_operand:SI 1 "s_register_operand" "rk")
|
||
+ (const_int 4))))
|
||
+ (set (match_operand:SI 3 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 1)
|
||
+ (const_int 8))))
|
||
+ (set (match_operand:SI 4 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 1)
|
||
+ (const_int 12))))])]
|
||
+ "TARGET_ARM && XVECLEN (operands[0], 0) == 3"
|
||
+ "ldm%(ib%)\t%1, {%2, %3, %4}"
|
||
+ [(set_attr "type" "load3")
|
||
+ (set_attr "predicable" "yes")])
|
||
+
|
||
+(define_insn "*ldm3_ib_update"
|
||
+ [(match_parallel 0 "load_multiple_operation"
|
||
+ [(set (match_operand:SI 1 "s_register_operand" "=rk")
|
||
+ (plus:SI (match_operand:SI 2 "s_register_operand" "1") (const_int 12)))
|
||
+ (set (match_operand:SI 3 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 2)
|
||
+ (const_int 4))))
|
||
+ (set (match_operand:SI 4 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 2)
|
||
+ (const_int 8))))
|
||
+ (set (match_operand:SI 5 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 2)
|
||
+ (const_int 12))))])]
|
||
+ "TARGET_ARM && XVECLEN (operands[0], 0) == 4"
|
||
+ "ldm%(ib%)\t%1!, {%3, %4, %5}"
|
||
+ [(set_attr "type" "load3")
|
||
+ (set_attr "predicable" "yes")])
|
||
+
|
||
+(define_insn "*stm3_ib"
|
||
+ [(match_parallel 0 "store_multiple_operation"
|
||
+ [(set (mem:SI (plus:SI (match_operand:SI 1 "s_register_operand" "rk") (const_int 4)))
|
||
+ (match_operand:SI 2 "arm_hard_register_operand" ""))
|
||
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 8)))
|
||
+ (match_operand:SI 3 "arm_hard_register_operand" ""))
|
||
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 12)))
|
||
+ (match_operand:SI 4 "arm_hard_register_operand" ""))])]
|
||
+ "TARGET_ARM && XVECLEN (operands[0], 0) == 3"
|
||
+ "stm%(ib%)\t%1, {%2, %3, %4}"
|
||
+ [(set_attr "type" "store3")
|
||
+ (set_attr "predicable" "yes")])
|
||
+
|
||
+(define_insn "*stm3_ib_update"
|
||
+ [(match_parallel 0 "store_multiple_operation"
|
||
+ [(set (match_operand:SI 1 "s_register_operand" "=rk")
|
||
+ (plus:SI (match_operand:SI 2 "s_register_operand" "1") (const_int 12)))
|
||
+ (set (mem:SI (plus:SI (match_dup 2) (const_int 4)))
|
||
+ (match_operand:SI 3 "arm_hard_register_operand" ""))
|
||
+ (set (mem:SI (plus:SI (match_dup 2) (const_int 8)))
|
||
+ (match_operand:SI 4 "arm_hard_register_operand" ""))
|
||
+ (set (mem:SI (plus:SI (match_dup 2) (const_int 12)))
|
||
+ (match_operand:SI 5 "arm_hard_register_operand" ""))])]
|
||
+ "TARGET_ARM && XVECLEN (operands[0], 0) == 4"
|
||
+ "stm%(ib%)\t%1!, {%3, %4, %5}"
|
||
+ [(set_attr "type" "store3")
|
||
+ (set_attr "predicable" "yes")])
|
||
+
|
||
+(define_insn "*ldm3_da"
|
||
+ [(match_parallel 0 "load_multiple_operation"
|
||
+ [(set (match_operand:SI 2 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_operand:SI 1 "s_register_operand" "rk")
|
||
+ (const_int -8))))
|
||
+ (set (match_operand:SI 3 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 1)
|
||
+ (const_int -4))))
|
||
+ (set (match_operand:SI 4 "arm_hard_register_operand" "")
|
||
+ (mem:SI (match_dup 1)))])]
|
||
+ "TARGET_ARM && XVECLEN (operands[0], 0) == 3"
|
||
+ "ldm%(da%)\t%1, {%2, %3, %4}"
|
||
+ [(set_attr "type" "load3")
|
||
+ (set_attr "predicable" "yes")])
|
||
+
|
||
+(define_insn "*ldm3_da_update"
|
||
+ [(match_parallel 0 "load_multiple_operation"
|
||
+ [(set (match_operand:SI 1 "s_register_operand" "=rk")
|
||
+ (plus:SI (match_operand:SI 2 "s_register_operand" "1") (const_int -12)))
|
||
+ (set (match_operand:SI 3 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 2)
|
||
+ (const_int -8))))
|
||
+ (set (match_operand:SI 4 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 2)
|
||
+ (const_int -4))))
|
||
+ (set (match_operand:SI 5 "arm_hard_register_operand" "")
|
||
+ (mem:SI (match_dup 2)))])]
|
||
+ "TARGET_ARM && XVECLEN (operands[0], 0) == 4"
|
||
+ "ldm%(da%)\t%1!, {%3, %4, %5}"
|
||
+ [(set_attr "type" "load3")
|
||
+ (set_attr "predicable" "yes")])
|
||
+
|
||
+(define_insn "*stm3_da"
|
||
+ [(match_parallel 0 "store_multiple_operation"
|
||
+ [(set (mem:SI (plus:SI (match_operand:SI 1 "s_register_operand" "rk") (const_int -8)))
|
||
+ (match_operand:SI 2 "arm_hard_register_operand" ""))
|
||
+ (set (mem:SI (plus:SI (match_dup 1) (const_int -4)))
|
||
+ (match_operand:SI 3 "arm_hard_register_operand" ""))
|
||
+ (set (mem:SI (match_dup 1))
|
||
+ (match_operand:SI 4 "arm_hard_register_operand" ""))])]
|
||
+ "TARGET_ARM && XVECLEN (operands[0], 0) == 3"
|
||
+ "stm%(da%)\t%1, {%2, %3, %4}"
|
||
+ [(set_attr "type" "store3")
|
||
+ (set_attr "predicable" "yes")])
|
||
+
|
||
+(define_insn "*stm3_da_update"
|
||
+ [(match_parallel 0 "store_multiple_operation"
|
||
+ [(set (match_operand:SI 1 "s_register_operand" "=rk")
|
||
+ (plus:SI (match_operand:SI 2 "s_register_operand" "1") (const_int -12)))
|
||
+ (set (mem:SI (plus:SI (match_dup 2) (const_int -8)))
|
||
+ (match_operand:SI 3 "arm_hard_register_operand" ""))
|
||
+ (set (mem:SI (plus:SI (match_dup 2) (const_int -4)))
|
||
+ (match_operand:SI 4 "arm_hard_register_operand" ""))
|
||
+ (set (mem:SI (match_dup 2))
|
||
+ (match_operand:SI 5 "arm_hard_register_operand" ""))])]
|
||
+ "TARGET_ARM && XVECLEN (operands[0], 0) == 4"
|
||
+ "stm%(da%)\t%1!, {%3, %4, %5}"
|
||
+ [(set_attr "type" "store3")
|
||
+ (set_attr "predicable" "yes")])
|
||
+
|
||
+(define_insn "*ldm3_db"
|
||
+ [(match_parallel 0 "load_multiple_operation"
|
||
+ [(set (match_operand:SI 2 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_operand:SI 1 "s_register_operand" "rk")
|
||
+ (const_int -12))))
|
||
+ (set (match_operand:SI 3 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 1)
|
||
+ (const_int -8))))
|
||
+ (set (match_operand:SI 4 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 1)
|
||
+ (const_int -4))))])]
|
||
+ "TARGET_32BIT && XVECLEN (operands[0], 0) == 3"
|
||
+ "ldm%(db%)\t%1, {%2, %3, %4}"
|
||
+ [(set_attr "type" "load3")
|
||
+ (set_attr "predicable" "yes")])
|
||
+
|
||
+(define_insn "*ldm3_db_update"
|
||
+ [(match_parallel 0 "load_multiple_operation"
|
||
+ [(set (match_operand:SI 1 "s_register_operand" "=rk")
|
||
+ (plus:SI (match_operand:SI 2 "s_register_operand" "1") (const_int -12)))
|
||
+ (set (match_operand:SI 3 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 2)
|
||
+ (const_int -12))))
|
||
+ (set (match_operand:SI 4 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 2)
|
||
+ (const_int -8))))
|
||
+ (set (match_operand:SI 5 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 2)
|
||
+ (const_int -4))))])]
|
||
+ "TARGET_32BIT && XVECLEN (operands[0], 0) == 4"
|
||
+ "ldm%(db%)\t%1!, {%3, %4, %5}"
|
||
+ [(set_attr "type" "load3")
|
||
+ (set_attr "predicable" "yes")])
|
||
+
|
||
+(define_insn "*stm3_db"
|
||
+ [(match_parallel 0 "store_multiple_operation"
|
||
+ [(set (mem:SI (plus:SI (match_operand:SI 1 "s_register_operand" "rk") (const_int -12)))
|
||
+ (match_operand:SI 2 "arm_hard_register_operand" ""))
|
||
+ (set (mem:SI (plus:SI (match_dup 1) (const_int -8)))
|
||
+ (match_operand:SI 3 "arm_hard_register_operand" ""))
|
||
+ (set (mem:SI (plus:SI (match_dup 1) (const_int -4)))
|
||
+ (match_operand:SI 4 "arm_hard_register_operand" ""))])]
|
||
+ "TARGET_32BIT && XVECLEN (operands[0], 0) == 3"
|
||
+ "stm%(db%)\t%1, {%2, %3, %4}"
|
||
+ [(set_attr "type" "store3")
|
||
+ (set_attr "predicable" "yes")])
|
||
+
|
||
+(define_insn "*stm3_db_update"
|
||
+ [(match_parallel 0 "store_multiple_operation"
|
||
+ [(set (match_operand:SI 1 "s_register_operand" "=rk")
|
||
+ (plus:SI (match_operand:SI 2 "s_register_operand" "1") (const_int -12)))
|
||
+ (set (mem:SI (plus:SI (match_dup 2) (const_int -12)))
|
||
+ (match_operand:SI 3 "arm_hard_register_operand" ""))
|
||
+ (set (mem:SI (plus:SI (match_dup 2) (const_int -8)))
|
||
+ (match_operand:SI 4 "arm_hard_register_operand" ""))
|
||
+ (set (mem:SI (plus:SI (match_dup 2) (const_int -4)))
|
||
+ (match_operand:SI 5 "arm_hard_register_operand" ""))])]
|
||
+ "TARGET_32BIT && XVECLEN (operands[0], 0) == 4"
|
||
+ "stm%(db%)\t%1!, {%3, %4, %5}"
|
||
+ [(set_attr "type" "store3")
|
||
+ (set_attr "predicable" "yes")])
|
||
+
|
||
+(define_peephole2
|
||
+ [(set (match_operand:SI 0 "s_register_operand" "")
|
||
+ (match_operand:SI 3 "memory_operand" ""))
|
||
+ (set (match_operand:SI 1 "s_register_operand" "")
|
||
+ (match_operand:SI 4 "memory_operand" ""))
|
||
+ (set (match_operand:SI 2 "s_register_operand" "")
|
||
+ (match_operand:SI 5 "memory_operand" ""))]
|
||
+ ""
|
||
+ [(const_int 0)]
|
||
+{
|
||
+ if (gen_ldm_seq (operands, 3, false))
|
||
+ DONE;
|
||
+ else
|
||
+ FAIL;
|
||
+})
|
||
+
|
||
+(define_peephole2
|
||
+ [(set (match_operand:SI 0 "s_register_operand" "")
|
||
+ (match_operand:SI 3 "memory_operand" ""))
|
||
+ (parallel
|
||
+ [(set (match_operand:SI 1 "s_register_operand" "")
|
||
+ (match_operand:SI 4 "memory_operand" ""))
|
||
+ (set (match_operand:SI 2 "s_register_operand" "")
|
||
+ (match_operand:SI 5 "memory_operand" ""))])]
|
||
+ ""
|
||
+ [(const_int 0)]
|
||
+{
|
||
+ if (gen_ldm_seq (operands, 3, false))
|
||
+ DONE;
|
||
+ else
|
||
+ FAIL;
|
||
+})
|
||
+
|
||
+(define_peephole2
|
||
+ [(set (match_operand:SI 0 "s_register_operand" "")
|
||
+ (match_operand:SI 6 "const_int_operand" ""))
|
||
+ (set (match_operand:SI 3 "memory_operand" "")
|
||
+ (match_dup 0))
|
||
+ (set (match_operand:SI 1 "s_register_operand" "")
|
||
+ (match_operand:SI 7 "const_int_operand" ""))
|
||
+ (set (match_operand:SI 4 "memory_operand" "")
|
||
+ (match_dup 1))
|
||
+ (set (match_operand:SI 2 "s_register_operand" "")
|
||
+ (match_operand:SI 8 "const_int_operand" ""))
|
||
+ (set (match_operand:SI 5 "memory_operand" "")
|
||
+ (match_dup 2))]
|
||
+ ""
|
||
+ [(const_int 0)]
|
||
+{
|
||
+ if (gen_const_stm_seq (operands, 3))
|
||
+ DONE;
|
||
+ else
|
||
+ FAIL;
|
||
+})
|
||
+
|
||
+(define_peephole2
|
||
+ [(set (match_operand:SI 0 "s_register_operand" "")
|
||
+ (match_operand:SI 6 "const_int_operand" ""))
|
||
+ (set (match_operand:SI 1 "s_register_operand" "")
|
||
+ (match_operand:SI 7 "const_int_operand" ""))
|
||
+ (set (match_operand:SI 2 "s_register_operand" "")
|
||
+ (match_operand:SI 8 "const_int_operand" ""))
|
||
+ (set (match_operand:SI 3 "memory_operand" "")
|
||
+ (match_dup 0))
|
||
+ (set (match_operand:SI 4 "memory_operand" "")
|
||
+ (match_dup 1))
|
||
+ (set (match_operand:SI 5 "memory_operand" "")
|
||
+ (match_dup 2))]
|
||
+ ""
|
||
+ [(const_int 0)]
|
||
+{
|
||
+ if (gen_const_stm_seq (operands, 3))
|
||
+ DONE;
|
||
+ else
|
||
+ FAIL;
|
||
+})
|
||
+
|
||
+(define_peephole2
|
||
+ [(set (match_operand:SI 3 "memory_operand" "")
|
||
+ (match_operand:SI 0 "s_register_operand" ""))
|
||
+ (set (match_operand:SI 4 "memory_operand" "")
|
||
+ (match_operand:SI 1 "s_register_operand" ""))
|
||
+ (set (match_operand:SI 5 "memory_operand" "")
|
||
+ (match_operand:SI 2 "s_register_operand" ""))]
|
||
+ ""
|
||
+ [(const_int 0)]
|
||
+{
|
||
+ if (gen_stm_seq (operands, 3))
|
||
+ DONE;
|
||
+ else
|
||
+ FAIL;
|
||
+})
|
||
+
|
||
+(define_insn "*ldm2_ia"
|
||
+ [(match_parallel 0 "load_multiple_operation"
|
||
+ [(set (match_operand:SI 2 "arm_hard_register_operand" "")
|
||
+ (mem:SI (match_operand:SI 1 "s_register_operand" "rk")))
|
||
+ (set (match_operand:SI 3 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 1)
|
||
+ (const_int 4))))])]
|
||
+ "TARGET_32BIT && XVECLEN (operands[0], 0) == 2"
|
||
+ "ldm%(ia%)\t%1, {%2, %3}"
|
||
+ [(set_attr "type" "load2")
|
||
+ (set_attr "predicable" "yes")])
|
||
+
|
||
+(define_insn "*thumb_ldm2_ia"
|
||
+ [(match_parallel 0 "load_multiple_operation"
|
||
+ [(set (match_operand:SI 2 "arm_hard_register_operand" "")
|
||
+ (mem:SI (match_operand:SI 1 "s_register_operand" "l")))
|
||
+ (set (match_operand:SI 3 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 1)
|
||
+ (const_int 4))))])]
|
||
+ "TARGET_THUMB1 && XVECLEN (operands[0], 0) == 2"
|
||
+ "ldm%(ia%)\t%1, {%2, %3}"
|
||
+ [(set_attr "type" "load2")])
|
||
+
|
||
+(define_insn "*ldm2_ia_update"
|
||
+ [(match_parallel 0 "load_multiple_operation"
|
||
+ [(set (match_operand:SI 1 "s_register_operand" "=rk")
|
||
+ (plus:SI (match_operand:SI 2 "s_register_operand" "1") (const_int 8)))
|
||
+ (set (match_operand:SI 3 "arm_hard_register_operand" "")
|
||
+ (mem:SI (match_dup 2)))
|
||
+ (set (match_operand:SI 4 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 2)
|
||
+ (const_int 4))))])]
|
||
+ "TARGET_32BIT && XVECLEN (operands[0], 0) == 3"
|
||
+ "ldm%(ia%)\t%1!, {%3, %4}"
|
||
+ [(set_attr "type" "load2")
|
||
+ (set_attr "predicable" "yes")])
|
||
+
|
||
+(define_insn "*thumb_ldm2_ia_update"
|
||
+ [(match_parallel 0 "load_multiple_operation"
|
||
+ [(set (match_operand:SI 1 "s_register_operand" "=l")
|
||
+ (plus:SI (match_operand:SI 2 "s_register_operand" "1") (const_int 8)))
|
||
+ (set (match_operand:SI 3 "arm_hard_register_operand" "")
|
||
+ (mem:SI (match_dup 2)))
|
||
+ (set (match_operand:SI 4 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 2)
|
||
+ (const_int 4))))])]
|
||
+ "TARGET_THUMB1 && XVECLEN (operands[0], 0) == 3"
|
||
+ "ldm%(ia%)\t%1!, {%3, %4}"
|
||
+ [(set_attr "type" "load2")])
|
||
+
|
||
+(define_insn "*stm2_ia"
|
||
+ [(match_parallel 0 "store_multiple_operation"
|
||
+ [(set (mem:SI (match_operand:SI 1 "s_register_operand" "rk"))
|
||
+ (match_operand:SI 2 "arm_hard_register_operand" ""))
|
||
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 4)))
|
||
+ (match_operand:SI 3 "arm_hard_register_operand" ""))])]
|
||
+ "TARGET_32BIT && XVECLEN (operands[0], 0) == 2"
|
||
+ "stm%(ia%)\t%1, {%2, %3}"
|
||
+ [(set_attr "type" "store2")
|
||
+ (set_attr "predicable" "yes")])
|
||
+
|
||
+(define_insn "*stm2_ia_update"
|
||
+ [(match_parallel 0 "store_multiple_operation"
|
||
+ [(set (match_operand:SI 1 "s_register_operand" "=rk")
|
||
+ (plus:SI (match_operand:SI 2 "s_register_operand" "1") (const_int 8)))
|
||
+ (set (mem:SI (match_dup 2))
|
||
+ (match_operand:SI 3 "arm_hard_register_operand" ""))
|
||
+ (set (mem:SI (plus:SI (match_dup 2) (const_int 4)))
|
||
+ (match_operand:SI 4 "arm_hard_register_operand" ""))])]
|
||
+ "TARGET_32BIT && XVECLEN (operands[0], 0) == 3"
|
||
+ "stm%(ia%)\t%1!, {%3, %4}"
|
||
+ [(set_attr "type" "store2")
|
||
+ (set_attr "predicable" "yes")])
|
||
+
|
||
+(define_insn "*thumb_stm2_ia_update"
|
||
+ [(match_parallel 0 "store_multiple_operation"
|
||
+ [(set (match_operand:SI 1 "s_register_operand" "=l")
|
||
+ (plus:SI (match_operand:SI 2 "s_register_operand" "1") (const_int 8)))
|
||
+ (set (mem:SI (match_dup 2))
|
||
+ (match_operand:SI 3 "arm_hard_register_operand" ""))
|
||
+ (set (mem:SI (plus:SI (match_dup 2) (const_int 4)))
|
||
+ (match_operand:SI 4 "arm_hard_register_operand" ""))])]
|
||
+ "TARGET_THUMB1 && XVECLEN (operands[0], 0) == 3"
|
||
+ "stm%(ia%)\t%1!, {%3, %4}"
|
||
+ [(set_attr "type" "store2")])
|
||
+
|
||
+(define_insn "*ldm2_ib"
|
||
+ [(match_parallel 0 "load_multiple_operation"
|
||
+ [(set (match_operand:SI 2 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_operand:SI 1 "s_register_operand" "rk")
|
||
+ (const_int 4))))
|
||
+ (set (match_operand:SI 3 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 1)
|
||
+ (const_int 8))))])]
|
||
+ "TARGET_ARM && XVECLEN (operands[0], 0) == 2"
|
||
+ "ldm%(ib%)\t%1, {%2, %3}"
|
||
+ [(set_attr "type" "load2")
|
||
+ (set_attr "predicable" "yes")])
|
||
+
|
||
+(define_insn "*ldm2_ib_update"
|
||
+ [(match_parallel 0 "load_multiple_operation"
|
||
+ [(set (match_operand:SI 1 "s_register_operand" "=rk")
|
||
+ (plus:SI (match_operand:SI 2 "s_register_operand" "1") (const_int 8)))
|
||
+ (set (match_operand:SI 3 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 2)
|
||
+ (const_int 4))))
|
||
+ (set (match_operand:SI 4 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 2)
|
||
+ (const_int 8))))])]
|
||
+ "TARGET_ARM && XVECLEN (operands[0], 0) == 3"
|
||
+ "ldm%(ib%)\t%1!, {%3, %4}"
|
||
+ [(set_attr "type" "load2")
|
||
+ (set_attr "predicable" "yes")])
|
||
+
|
||
+(define_insn "*stm2_ib"
|
||
+ [(match_parallel 0 "store_multiple_operation"
|
||
+ [(set (mem:SI (plus:SI (match_operand:SI 1 "s_register_operand" "rk") (const_int 4)))
|
||
+ (match_operand:SI 2 "arm_hard_register_operand" ""))
|
||
+ (set (mem:SI (plus:SI (match_dup 1) (const_int 8)))
|
||
+ (match_operand:SI 3 "arm_hard_register_operand" ""))])]
|
||
+ "TARGET_ARM && XVECLEN (operands[0], 0) == 2"
|
||
+ "stm%(ib%)\t%1, {%2, %3}"
|
||
+ [(set_attr "type" "store2")
|
||
+ (set_attr "predicable" "yes")])
|
||
+
|
||
+(define_insn "*stm2_ib_update"
|
||
+ [(match_parallel 0 "store_multiple_operation"
|
||
+ [(set (match_operand:SI 1 "s_register_operand" "=rk")
|
||
+ (plus:SI (match_operand:SI 2 "s_register_operand" "1") (const_int 8)))
|
||
+ (set (mem:SI (plus:SI (match_dup 2) (const_int 4)))
|
||
+ (match_operand:SI 3 "arm_hard_register_operand" ""))
|
||
+ (set (mem:SI (plus:SI (match_dup 2) (const_int 8)))
|
||
+ (match_operand:SI 4 "arm_hard_register_operand" ""))])]
|
||
+ "TARGET_ARM && XVECLEN (operands[0], 0) == 3"
|
||
+ "stm%(ib%)\t%1!, {%3, %4}"
|
||
+ [(set_attr "type" "store2")
|
||
+ (set_attr "predicable" "yes")])
|
||
+
|
||
+(define_insn "*ldm2_da"
|
||
+ [(match_parallel 0 "load_multiple_operation"
|
||
+ [(set (match_operand:SI 2 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_operand:SI 1 "s_register_operand" "rk")
|
||
+ (const_int -4))))
|
||
+ (set (match_operand:SI 3 "arm_hard_register_operand" "")
|
||
+ (mem:SI (match_dup 1)))])]
|
||
+ "TARGET_ARM && XVECLEN (operands[0], 0) == 2"
|
||
+ "ldm%(da%)\t%1, {%2, %3}"
|
||
+ [(set_attr "type" "load2")
|
||
+ (set_attr "predicable" "yes")])
|
||
+
|
||
+(define_insn "*ldm2_da_update"
|
||
+ [(match_parallel 0 "load_multiple_operation"
|
||
+ [(set (match_operand:SI 1 "s_register_operand" "=rk")
|
||
+ (plus:SI (match_operand:SI 2 "s_register_operand" "1") (const_int -8)))
|
||
+ (set (match_operand:SI 3 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 2)
|
||
+ (const_int -4))))
|
||
+ (set (match_operand:SI 4 "arm_hard_register_operand" "")
|
||
+ (mem:SI (match_dup 2)))])]
|
||
+ "TARGET_ARM && XVECLEN (operands[0], 0) == 3"
|
||
+ "ldm%(da%)\t%1!, {%3, %4}"
|
||
+ [(set_attr "type" "load2")
|
||
+ (set_attr "predicable" "yes")])
|
||
+
|
||
+(define_insn "*stm2_da"
|
||
+ [(match_parallel 0 "store_multiple_operation"
|
||
+ [(set (mem:SI (plus:SI (match_operand:SI 1 "s_register_operand" "rk") (const_int -4)))
|
||
+ (match_operand:SI 2 "arm_hard_register_operand" ""))
|
||
+ (set (mem:SI (match_dup 1))
|
||
+ (match_operand:SI 3 "arm_hard_register_operand" ""))])]
|
||
+ "TARGET_ARM && XVECLEN (operands[0], 0) == 2"
|
||
+ "stm%(da%)\t%1, {%2, %3}"
|
||
+ [(set_attr "type" "store2")
|
||
+ (set_attr "predicable" "yes")])
|
||
+
|
||
+(define_insn "*stm2_da_update"
|
||
+ [(match_parallel 0 "store_multiple_operation"
|
||
+ [(set (match_operand:SI 1 "s_register_operand" "=rk")
|
||
+ (plus:SI (match_operand:SI 2 "s_register_operand" "1") (const_int -8)))
|
||
+ (set (mem:SI (plus:SI (match_dup 2) (const_int -4)))
|
||
+ (match_operand:SI 3 "arm_hard_register_operand" ""))
|
||
+ (set (mem:SI (match_dup 2))
|
||
+ (match_operand:SI 4 "arm_hard_register_operand" ""))])]
|
||
+ "TARGET_ARM && XVECLEN (operands[0], 0) == 3"
|
||
+ "stm%(da%)\t%1!, {%3, %4}"
|
||
+ [(set_attr "type" "store2")
|
||
+ (set_attr "predicable" "yes")])
|
||
+
|
||
+(define_insn "*ldm2_db"
|
||
+ [(match_parallel 0 "load_multiple_operation"
|
||
+ [(set (match_operand:SI 2 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_operand:SI 1 "s_register_operand" "rk")
|
||
+ (const_int -8))))
|
||
+ (set (match_operand:SI 3 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 1)
|
||
+ (const_int -4))))])]
|
||
+ "TARGET_32BIT && XVECLEN (operands[0], 0) == 2"
|
||
+ "ldm%(db%)\t%1, {%2, %3}"
|
||
+ [(set_attr "type" "load2")
|
||
+ (set_attr "predicable" "yes")])
|
||
+
|
||
+(define_insn "*ldm2_db_update"
|
||
+ [(match_parallel 0 "load_multiple_operation"
|
||
+ [(set (match_operand:SI 1 "s_register_operand" "=rk")
|
||
+ (plus:SI (match_operand:SI 2 "s_register_operand" "1") (const_int -8)))
|
||
+ (set (match_operand:SI 3 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 2)
|
||
+ (const_int -8))))
|
||
+ (set (match_operand:SI 4 "arm_hard_register_operand" "")
|
||
+ (mem:SI (plus:SI (match_dup 2)
|
||
+ (const_int -4))))])]
|
||
+ "TARGET_32BIT && XVECLEN (operands[0], 0) == 3"
|
||
+ "ldm%(db%)\t%1!, {%3, %4}"
|
||
+ [(set_attr "type" "load2")
|
||
+ (set_attr "predicable" "yes")])
|
||
+
|
||
+(define_insn "*stm2_db"
|
||
+ [(match_parallel 0 "store_multiple_operation"
|
||
+ [(set (mem:SI (plus:SI (match_operand:SI 1 "s_register_operand" "rk") (const_int -8)))
|
||
+ (match_operand:SI 2 "arm_hard_register_operand" ""))
|
||
+ (set (mem:SI (plus:SI (match_dup 1) (const_int -4)))
|
||
+ (match_operand:SI 3 "arm_hard_register_operand" ""))])]
|
||
+ "TARGET_32BIT && XVECLEN (operands[0], 0) == 2"
|
||
+ "stm%(db%)\t%1, {%2, %3}"
|
||
+ [(set_attr "type" "store2")
|
||
+ (set_attr "predicable" "yes")])
|
||
+
|
||
+(define_insn "*stm2_db_update"
|
||
+ [(match_parallel 0 "store_multiple_operation"
|
||
+ [(set (match_operand:SI 1 "s_register_operand" "=rk")
|
||
+ (plus:SI (match_operand:SI 2 "s_register_operand" "1") (const_int -8)))
|
||
+ (set (mem:SI (plus:SI (match_dup 2) (const_int -8)))
|
||
+ (match_operand:SI 3 "arm_hard_register_operand" ""))
|
||
+ (set (mem:SI (plus:SI (match_dup 2) (const_int -4)))
|
||
+ (match_operand:SI 4 "arm_hard_register_operand" ""))])]
|
||
+ "TARGET_32BIT && XVECLEN (operands[0], 0) == 3"
|
||
+ "stm%(db%)\t%1!, {%3, %4}"
|
||
+ [(set_attr "type" "store2")
|
||
+ (set_attr "predicable" "yes")])
|
||
+
|
||
+(define_peephole2
|
||
+ [(set (match_operand:SI 0 "s_register_operand" "")
|
||
+ (match_operand:SI 2 "memory_operand" ""))
|
||
+ (set (match_operand:SI 1 "s_register_operand" "")
|
||
+ (match_operand:SI 3 "memory_operand" ""))]
|
||
+ ""
|
||
+ [(const_int 0)]
|
||
+{
|
||
+ if (gen_ldm_seq (operands, 2, false))
|
||
+ DONE;
|
||
+ else
|
||
+ FAIL;
|
||
+})
|
||
+
|
||
+(define_peephole2
|
||
+ [(set (match_operand:SI 0 "s_register_operand" "")
|
||
+ (match_operand:SI 4 "const_int_operand" ""))
|
||
+ (set (match_operand:SI 2 "memory_operand" "")
|
||
+ (match_dup 0))
|
||
+ (set (match_operand:SI 1 "s_register_operand" "")
|
||
+ (match_operand:SI 5 "const_int_operand" ""))
|
||
+ (set (match_operand:SI 3 "memory_operand" "")
|
||
+ (match_dup 1))]
|
||
+ ""
|
||
+ [(const_int 0)]
|
||
+{
|
||
+ if (gen_const_stm_seq (operands, 2))
|
||
+ DONE;
|
||
+ else
|
||
+ FAIL;
|
||
+})
|
||
+
|
||
+(define_peephole2
|
||
+ [(set (match_operand:SI 0 "s_register_operand" "")
|
||
+ (match_operand:SI 4 "const_int_operand" ""))
|
||
+ (set (match_operand:SI 1 "s_register_operand" "")
|
||
+ (match_operand:SI 5 "const_int_operand" ""))
|
||
+ (set (match_operand:SI 2 "memory_operand" "")
|
||
+ (match_dup 0))
|
||
+ (set (match_operand:SI 3 "memory_operand" "")
|
||
+ (match_dup 1))]
|
||
+ ""
|
||
+ [(const_int 0)]
|
||
+{
|
||
+ if (gen_const_stm_seq (operands, 2))
|
||
+ DONE;
|
||
+ else
|
||
+ FAIL;
|
||
+})
|
||
+
|
||
+(define_peephole2
|
||
+ [(set (match_operand:SI 2 "memory_operand" "")
|
||
+ (match_operand:SI 0 "s_register_operand" ""))
|
||
+ (set (match_operand:SI 3 "memory_operand" "")
|
||
+ (match_operand:SI 1 "s_register_operand" ""))]
|
||
+ ""
|
||
+ [(const_int 0)]
|
||
+{
|
||
+ if (gen_stm_seq (operands, 2))
|
||
+ DONE;
|
||
+ else
|
||
+ FAIL;
|
||
+})
|
||
+
|
||
+(define_peephole2
|
||
+ [(set (match_operand:SI 0 "s_register_operand" "")
|
||
+ (match_operand:SI 2 "memory_operand" ""))
|
||
+ (set (match_operand:SI 1 "s_register_operand" "")
|
||
+ (match_operand:SI 3 "memory_operand" ""))
|
||
+ (parallel
|
||
+ [(set (match_operand:SI 4 "s_register_operand" "")
|
||
+ (match_operator:SI 5 "commutative_binary_operator"
|
||
+ [(match_operand:SI 6 "s_register_operand" "")
|
||
+ (match_operand:SI 7 "s_register_operand" "")]))
|
||
+ (clobber (reg:CC CC_REGNUM))])]
|
||
+ "(((operands[6] == operands[0] && operands[7] == operands[1])
|
||
+ || (operands[7] == operands[0] && operands[6] == operands[1]))
|
||
+ && peep2_reg_dead_p (3, operands[0]) && peep2_reg_dead_p (3, operands[1]))"
|
||
+ [(parallel
|
||
+ [(set (match_dup 4) (match_op_dup 5 [(match_dup 6) (match_dup 7)]))
|
||
+ (clobber (reg:CC CC_REGNUM))])]
|
||
+{
|
||
+ if (!gen_ldm_seq (operands, 2, true))
|
||
+ FAIL;
|
||
+})
|
||
+
|
||
+(define_peephole2
|
||
+ [(set (match_operand:SI 0 "s_register_operand" "")
|
||
+ (match_operand:SI 2 "memory_operand" ""))
|
||
+ (set (match_operand:SI 1 "s_register_operand" "")
|
||
+ (match_operand:SI 3 "memory_operand" ""))
|
||
+ (set (match_operand:SI 4 "s_register_operand" "")
|
||
+ (match_operator:SI 5 "commutative_binary_operator"
|
||
+ [(match_operand:SI 6 "s_register_operand" "")
|
||
+ (match_operand:SI 7 "s_register_operand" "")]))]
|
||
+ "(((operands[6] == operands[0] && operands[7] == operands[1])
|
||
+ || (operands[7] == operands[0] && operands[6] == operands[1]))
|
||
+ && peep2_reg_dead_p (3, operands[0]) && peep2_reg_dead_p (3, operands[1]))"
|
||
+ [(set (match_dup 4) (match_op_dup 5 [(match_dup 6) (match_dup 7)]))]
|
||
+{
|
||
+ if (!gen_ldm_seq (operands, 2, true))
|
||
+ FAIL;
|
||
+})
|
||
+
|
||
|
||
=== modified file 'gcc/config/arm/predicates.md'
|
||
--- old/gcc/config/arm/predicates.md 2010-11-04 10:45:05 +0000
|
||
+++ new/gcc/config/arm/predicates.md 2010-11-16 12:32:34 +0000
|
||
@@ -211,6 +211,11 @@
|
||
(and (match_code "ior,xor,and")
|
||
(match_test "mode == GET_MODE (op)")))
|
||
|
||
+;; True for commutative operators
|
||
+(define_special_predicate "commutative_binary_operator"
|
||
+ (and (match_code "ior,xor,and,plus")
|
||
+ (match_test "mode == GET_MODE (op)")))
|
||
+
|
||
;; True for shift operators.
|
||
(define_special_predicate "shift_operator"
|
||
(and (ior (ior (and (match_code "mult")
|
||
@@ -334,16 +339,20 @@
|
||
(match_code "parallel")
|
||
{
|
||
HOST_WIDE_INT count = XVECLEN (op, 0);
|
||
- int dest_regno;
|
||
+ unsigned dest_regno;
|
||
rtx src_addr;
|
||
HOST_WIDE_INT i = 1, base = 0;
|
||
+ HOST_WIDE_INT offset = 0;
|
||
rtx elt;
|
||
+ bool addr_reg_loaded = false;
|
||
+ bool update = false;
|
||
|
||
if (low_irq_latency)
|
||
return false;
|
||
|
||
if (count <= 1
|
||
- || GET_CODE (XVECEXP (op, 0, 0)) != SET)
|
||
+ || GET_CODE (XVECEXP (op, 0, 0)) != SET
|
||
+ || !REG_P (SET_DEST (XVECEXP (op, 0, 0))))
|
||
return false;
|
||
|
||
/* Check to see if this might be a write-back. */
|
||
@@ -351,6 +360,7 @@
|
||
{
|
||
i++;
|
||
base = 1;
|
||
+ update = true;
|
||
|
||
/* Now check it more carefully. */
|
||
if (GET_CODE (SET_DEST (elt)) != REG
|
||
@@ -369,6 +379,15 @@
|
||
|
||
dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, i - 1)));
|
||
src_addr = XEXP (SET_SRC (XVECEXP (op, 0, i - 1)), 0);
|
||
+ if (GET_CODE (src_addr) == PLUS)
|
||
+ {
|
||
+ if (GET_CODE (XEXP (src_addr, 1)) != CONST_INT)
|
||
+ return false;
|
||
+ offset = INTVAL (XEXP (src_addr, 1));
|
||
+ src_addr = XEXP (src_addr, 0);
|
||
+ }
|
||
+ if (!REG_P (src_addr))
|
||
+ return false;
|
||
|
||
for (; i < count; i++)
|
||
{
|
||
@@ -377,16 +396,28 @@
|
||
if (GET_CODE (elt) != SET
|
||
|| GET_CODE (SET_DEST (elt)) != REG
|
||
|| GET_MODE (SET_DEST (elt)) != SImode
|
||
- || REGNO (SET_DEST (elt)) != (unsigned int)(dest_regno + i - base)
|
||
+ || REGNO (SET_DEST (elt)) <= dest_regno
|
||
|| GET_CODE (SET_SRC (elt)) != MEM
|
||
|| GET_MODE (SET_SRC (elt)) != SImode
|
||
- || GET_CODE (XEXP (SET_SRC (elt), 0)) != PLUS
|
||
- || !rtx_equal_p (XEXP (XEXP (SET_SRC (elt), 0), 0), src_addr)
|
||
- || GET_CODE (XEXP (XEXP (SET_SRC (elt), 0), 1)) != CONST_INT
|
||
- || INTVAL (XEXP (XEXP (SET_SRC (elt), 0), 1)) != (i - base) * 4)
|
||
+ || ((GET_CODE (XEXP (SET_SRC (elt), 0)) != PLUS
|
||
+ || !rtx_equal_p (XEXP (XEXP (SET_SRC (elt), 0), 0), src_addr)
|
||
+ || GET_CODE (XEXP (XEXP (SET_SRC (elt), 0), 1)) != CONST_INT
|
||
+ || INTVAL (XEXP (XEXP (SET_SRC (elt), 0), 1)) != offset + (i - base) * 4)
|
||
+ && (!REG_P (XEXP (SET_SRC (elt), 0))
|
||
+ || offset + (i - base) * 4 != 0)))
|
||
return false;
|
||
+ dest_regno = REGNO (SET_DEST (elt));
|
||
+ if (dest_regno == REGNO (src_addr))
|
||
+ addr_reg_loaded = true;
|
||
}
|
||
-
|
||
+ /* For Thumb, we only have updating instructions. If the pattern does
|
||
+ not describe an update, it must be because the address register is
|
||
+ in the list of loaded registers - on the hardware, this has the effect
|
||
+ of overriding the update. */
|
||
+ if (update && addr_reg_loaded)
|
||
+ return false;
|
||
+ if (TARGET_THUMB1)
|
||
+ return update || addr_reg_loaded;
|
||
return true;
|
||
})
|
||
|
||
@@ -394,9 +425,9 @@
|
||
(match_code "parallel")
|
||
{
|
||
HOST_WIDE_INT count = XVECLEN (op, 0);
|
||
- int src_regno;
|
||
+ unsigned src_regno;
|
||
rtx dest_addr;
|
||
- HOST_WIDE_INT i = 1, base = 0;
|
||
+ HOST_WIDE_INT i = 1, base = 0, offset = 0;
|
||
rtx elt;
|
||
|
||
if (low_irq_latency)
|
||
@@ -430,6 +461,16 @@
|
||
src_regno = REGNO (SET_SRC (XVECEXP (op, 0, i - 1)));
|
||
dest_addr = XEXP (SET_DEST (XVECEXP (op, 0, i - 1)), 0);
|
||
|
||
+ if (GET_CODE (dest_addr) == PLUS)
|
||
+ {
|
||
+ if (GET_CODE (XEXP (dest_addr, 1)) != CONST_INT)
|
||
+ return false;
|
||
+ offset = INTVAL (XEXP (dest_addr, 1));
|
||
+ dest_addr = XEXP (dest_addr, 0);
|
||
+ }
|
||
+ if (!REG_P (dest_addr))
|
||
+ return false;
|
||
+
|
||
for (; i < count; i++)
|
||
{
|
||
elt = XVECEXP (op, 0, i);
|
||
@@ -437,14 +478,17 @@
|
||
if (GET_CODE (elt) != SET
|
||
|| GET_CODE (SET_SRC (elt)) != REG
|
||
|| GET_MODE (SET_SRC (elt)) != SImode
|
||
- || REGNO (SET_SRC (elt)) != (unsigned int)(src_regno + i - base)
|
||
+ || REGNO (SET_SRC (elt)) <= src_regno
|
||
|| GET_CODE (SET_DEST (elt)) != MEM
|
||
|| GET_MODE (SET_DEST (elt)) != SImode
|
||
- || GET_CODE (XEXP (SET_DEST (elt), 0)) != PLUS
|
||
- || !rtx_equal_p (XEXP (XEXP (SET_DEST (elt), 0), 0), dest_addr)
|
||
- || GET_CODE (XEXP (XEXP (SET_DEST (elt), 0), 1)) != CONST_INT
|
||
- || INTVAL (XEXP (XEXP (SET_DEST (elt), 0), 1)) != (i - base) * 4)
|
||
+ || ((GET_CODE (XEXP (SET_DEST (elt), 0)) != PLUS
|
||
+ || !rtx_equal_p (XEXP (XEXP (SET_DEST (elt), 0), 0), dest_addr)
|
||
+ || GET_CODE (XEXP (XEXP (SET_DEST (elt), 0), 1)) != CONST_INT
|
||
+ || INTVAL (XEXP (XEXP (SET_DEST (elt), 0), 1)) != offset + (i - base) * 4)
|
||
+ && (!REG_P (XEXP (SET_DEST (elt), 0))
|
||
+ || offset + (i - base) * 4 != 0)))
|
||
return false;
|
||
+ src_regno = REGNO (SET_SRC (elt));
|
||
}
|
||
|
||
return true;
|
||
|
||
=== modified file 'gcc/config/i386/i386.md'
|
||
--- old/gcc/config/i386/i386.md 2011-01-05 12:12:18 +0000
|
||
+++ new/gcc/config/i386/i386.md 2011-01-05 18:20:37 +0000
|
||
@@ -20023,15 +20023,14 @@
|
||
;; leal (%edx,%eax,4), %eax
|
||
|
||
(define_peephole2
|
||
- [(parallel [(set (match_operand 0 "register_operand" "")
|
||
+ [(match_scratch:SI 5 "r")
|
||
+ (parallel [(set (match_operand 0 "register_operand" "")
|
||
(ashift (match_operand 1 "register_operand" "")
|
||
(match_operand 2 "const_int_operand" "")))
|
||
(clobber (reg:CC FLAGS_REG))])
|
||
- (set (match_operand 3 "register_operand")
|
||
- (match_operand 4 "x86_64_general_operand" ""))
|
||
- (parallel [(set (match_operand 5 "register_operand" "")
|
||
- (plus (match_operand 6 "register_operand" "")
|
||
- (match_operand 7 "register_operand" "")))
|
||
+ (parallel [(set (match_operand 3 "register_operand" "")
|
||
+ (plus (match_dup 0)
|
||
+ (match_operand 4 "x86_64_general_operand" "")))
|
||
(clobber (reg:CC FLAGS_REG))])]
|
||
"INTVAL (operands[2]) >= 0 && INTVAL (operands[2]) <= 3
|
||
/* Validate MODE for lea. */
|
||
@@ -20041,30 +20040,21 @@
|
||
|| GET_MODE (operands[0]) == SImode
|
||
|| (TARGET_64BIT && GET_MODE (operands[0]) == DImode))
|
||
/* We reorder load and the shift. */
|
||
- && !rtx_equal_p (operands[1], operands[3])
|
||
- && !reg_overlap_mentioned_p (operands[0], operands[4])
|
||
- /* Last PLUS must consist of operand 0 and 3. */
|
||
- && !rtx_equal_p (operands[0], operands[3])
|
||
- && (rtx_equal_p (operands[3], operands[6])
|
||
- || rtx_equal_p (operands[3], operands[7]))
|
||
- && (rtx_equal_p (operands[0], operands[6])
|
||
- || rtx_equal_p (operands[0], operands[7]))
|
||
- /* The intermediate operand 0 must die or be same as output. */
|
||
- && (rtx_equal_p (operands[0], operands[5])
|
||
- || peep2_reg_dead_p (3, operands[0]))"
|
||
- [(set (match_dup 3) (match_dup 4))
|
||
+ && !reg_overlap_mentioned_p (operands[0], operands[4])"
|
||
+ [(set (match_dup 5) (match_dup 4))
|
||
(set (match_dup 0) (match_dup 1))]
|
||
{
|
||
- enum machine_mode mode = GET_MODE (operands[5]) == DImode ? DImode : SImode;
|
||
+ enum machine_mode mode = GET_MODE (operands[1]) == DImode ? DImode : SImode;
|
||
int scale = 1 << INTVAL (operands[2]);
|
||
rtx index = gen_lowpart (Pmode, operands[1]);
|
||
- rtx base = gen_lowpart (Pmode, operands[3]);
|
||
- rtx dest = gen_lowpart (mode, operands[5]);
|
||
+ rtx base = gen_lowpart (Pmode, operands[5]);
|
||
+ rtx dest = gen_lowpart (mode, operands[3]);
|
||
|
||
operands[1] = gen_rtx_PLUS (Pmode, base,
|
||
gen_rtx_MULT (Pmode, index, GEN_INT (scale)));
|
||
if (mode != Pmode)
|
||
operands[1] = gen_rtx_SUBREG (mode, operands[1], 0);
|
||
+ operands[5] = base;
|
||
operands[0] = dest;
|
||
})
|
||
|
||
|
||
=== modified file 'gcc/df-problems.c'
|
||
--- old/gcc/df-problems.c 2010-11-16 22:17:17 +0000
|
||
+++ new/gcc/df-problems.c 2010-12-02 13:42:47 +0000
|
||
@@ -3748,9 +3748,22 @@
|
||
for (def_rec = DF_INSN_UID_DEFS (uid); *def_rec; def_rec++)
|
||
{
|
||
df_ref def = *def_rec;
|
||
- /* If the def is to only part of the reg, it does
|
||
- not kill the other defs that reach here. */
|
||
- if (!(DF_REF_FLAGS (def) & (DF_REF_PARTIAL | DF_REF_CONDITIONAL)))
|
||
+ bitmap_set_bit (defs, DF_REF_REGNO (def));
|
||
+ }
|
||
+}
|
||
+
|
||
+/* Find the set of real DEFs, which are not clobbers, for INSN. */
|
||
+
|
||
+void
|
||
+df_simulate_find_noclobber_defs (rtx insn, bitmap defs)
|
||
+{
|
||
+ df_ref *def_rec;
|
||
+ unsigned int uid = INSN_UID (insn);
|
||
+
|
||
+ for (def_rec = DF_INSN_UID_DEFS (uid); *def_rec; def_rec++)
|
||
+ {
|
||
+ df_ref def = *def_rec;
|
||
+ if (!(DF_REF_FLAGS (def) & (DF_REF_MUST_CLOBBER | DF_REF_MAY_CLOBBER)))
|
||
bitmap_set_bit (defs, DF_REF_REGNO (def));
|
||
}
|
||
}
|
||
@@ -3921,7 +3934,7 @@
|
||
{
|
||
df_ref def = *def_rec;
|
||
if (DF_REF_FLAGS (def) & DF_REF_AT_TOP)
|
||
- bitmap_clear_bit (live, DF_REF_REGNO (def));
|
||
+ bitmap_set_bit (live, DF_REF_REGNO (def));
|
||
}
|
||
}
|
||
|
||
@@ -3942,7 +3955,7 @@
|
||
while here the scan is performed forwards! So, first assume that the
|
||
def is live, and if this is not true REG_UNUSED notes will rectify the
|
||
situation. */
|
||
- df_simulate_find_defs (insn, live);
|
||
+ df_simulate_find_noclobber_defs (insn, live);
|
||
|
||
/* Clear all of the registers that go dead. */
|
||
for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
|
||
|
||
=== modified file 'gcc/df.h'
|
||
--- old/gcc/df.h 2010-01-29 12:14:47 +0000
|
||
+++ new/gcc/df.h 2010-12-02 13:42:47 +0000
|
||
@@ -978,6 +978,7 @@
|
||
extern void df_md_add_problem (void);
|
||
extern void df_md_simulate_artificial_defs_at_top (basic_block, bitmap);
|
||
extern void df_md_simulate_one_insn (basic_block, rtx, bitmap);
|
||
+extern void df_simulate_find_noclobber_defs (rtx, bitmap);
|
||
extern void df_simulate_find_defs (rtx, bitmap);
|
||
extern void df_simulate_defs (rtx, bitmap);
|
||
extern void df_simulate_uses (rtx, bitmap);
|
||
|
||
=== modified file 'gcc/fwprop.c'
|
||
--- old/gcc/fwprop.c 2010-04-02 18:54:46 +0000
|
||
+++ new/gcc/fwprop.c 2010-11-16 12:32:34 +0000
|
||
@@ -228,7 +228,10 @@
|
||
|
||
process_uses (df_get_artificial_uses (bb_index), DF_REF_AT_TOP);
|
||
process_defs (df_get_artificial_defs (bb_index), DF_REF_AT_TOP);
|
||
- df_simulate_initialize_forwards (bb, local_lr);
|
||
+
|
||
+ /* We don't call df_simulate_initialize_forwards, as it may overestimate
|
||
+ the live registers if there are unused artificial defs. We prefer
|
||
+ liveness to be underestimated. */
|
||
|
||
FOR_BB_INSNS (bb, insn)
|
||
if (INSN_P (insn))
|
||
|
||
=== modified file 'gcc/genoutput.c'
|
||
--- old/gcc/genoutput.c 2009-04-08 14:00:34 +0000
|
||
+++ new/gcc/genoutput.c 2010-11-16 12:32:34 +0000
|
||
@@ -266,6 +266,8 @@
|
||
|
||
printf (" %d,\n", d->strict_low);
|
||
|
||
+ printf (" %d,\n", d->constraint == NULL ? 1 : 0);
|
||
+
|
||
printf (" %d\n", d->eliminable);
|
||
|
||
printf(" },\n");
|
||
|
||
=== modified file 'gcc/genrecog.c'
|
||
--- old/gcc/genrecog.c 2009-06-22 09:29:13 +0000
|
||
+++ new/gcc/genrecog.c 2010-11-16 12:32:34 +0000
|
||
@@ -1782,20 +1782,11 @@
|
||
int odepth = strlen (oldpos);
|
||
int ndepth = strlen (newpos);
|
||
int depth;
|
||
- int old_has_insn, new_has_insn;
|
||
|
||
/* Pop up as many levels as necessary. */
|
||
for (depth = odepth; strncmp (oldpos, newpos, depth) != 0; --depth)
|
||
continue;
|
||
|
||
- /* Hunt for the last [A-Z] in both strings. */
|
||
- for (old_has_insn = odepth - 1; old_has_insn >= 0; --old_has_insn)
|
||
- if (ISUPPER (oldpos[old_has_insn]))
|
||
- break;
|
||
- for (new_has_insn = ndepth - 1; new_has_insn >= 0; --new_has_insn)
|
||
- if (ISUPPER (newpos[new_has_insn]))
|
||
- break;
|
||
-
|
||
/* Go down to desired level. */
|
||
while (depth < ndepth)
|
||
{
|
||
|
||
=== modified file 'gcc/ifcvt.c'
|
||
--- old/gcc/ifcvt.c 2011-01-05 12:12:18 +0000
|
||
+++ new/gcc/ifcvt.c 2011-01-05 18:20:37 +0000
|
||
@@ -4011,6 +4011,7 @@
|
||
basic_block new_dest = dest_edge->dest;
|
||
rtx head, end, jump, earliest = NULL_RTX, old_dest;
|
||
bitmap merge_set = NULL;
|
||
+ bitmap merge_set_noclobber = NULL;
|
||
/* Number of pending changes. */
|
||
int n_validated_changes = 0;
|
||
rtx new_dest_label;
|
||
@@ -4169,6 +4170,7 @@
|
||
end of the block. */
|
||
|
||
merge_set = BITMAP_ALLOC (®_obstack);
|
||
+ merge_set_noclobber = BITMAP_ALLOC (®_obstack);
|
||
|
||
/* If we allocated new pseudos (e.g. in the conditional move
|
||
expander called from noce_emit_cmove), we must resize the
|
||
@@ -4187,6 +4189,7 @@
|
||
df_ref def = *def_rec;
|
||
bitmap_set_bit (merge_set, DF_REF_REGNO (def));
|
||
}
|
||
+ df_simulate_find_noclobber_defs (insn, merge_set_noclobber);
|
||
}
|
||
}
|
||
|
||
@@ -4197,7 +4200,7 @@
|
||
unsigned i;
|
||
bitmap_iterator bi;
|
||
|
||
- EXECUTE_IF_SET_IN_BITMAP (merge_set, 0, i, bi)
|
||
+ EXECUTE_IF_SET_IN_BITMAP (merge_set_noclobber, 0, i, bi)
|
||
{
|
||
if (i < FIRST_PSEUDO_REGISTER
|
||
&& ! fixed_regs[i]
|
||
@@ -4233,7 +4236,7 @@
|
||
TEST_SET & DF_LIVE_IN (merge_bb)
|
||
are empty. */
|
||
|
||
- if (bitmap_intersect_p (merge_set, test_set)
|
||
+ if (bitmap_intersect_p (merge_set_noclobber, test_set)
|
||
|| bitmap_intersect_p (merge_set, test_live)
|
||
|| bitmap_intersect_p (test_set, df_get_live_in (merge_bb)))
|
||
intersect = true;
|
||
@@ -4320,6 +4323,7 @@
|
||
remove_reg_equal_equiv_notes_for_regno (i);
|
||
|
||
BITMAP_FREE (merge_set);
|
||
+ BITMAP_FREE (merge_set_noclobber);
|
||
}
|
||
|
||
reorder_insns (head, end, PREV_INSN (earliest));
|
||
@@ -4340,7 +4344,10 @@
|
||
cancel_changes (0);
|
||
fail:
|
||
if (merge_set)
|
||
- BITMAP_FREE (merge_set);
|
||
+ {
|
||
+ BITMAP_FREE (merge_set);
|
||
+ BITMAP_FREE (merge_set_noclobber);
|
||
+ }
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
=== modified file 'gcc/recog.c'
|
||
--- old/gcc/recog.c 2010-08-05 15:28:47 +0000
|
||
+++ new/gcc/recog.c 2010-11-16 12:32:34 +0000
|
||
@@ -2082,6 +2082,7 @@
|
||
recog_data.operand_loc,
|
||
recog_data.constraints,
|
||
recog_data.operand_mode, NULL);
|
||
+ memset (recog_data.is_operator, 0, sizeof recog_data.is_operator);
|
||
if (noperands > 0)
|
||
{
|
||
const char *p = recog_data.constraints[0];
|
||
@@ -2111,6 +2112,7 @@
|
||
for (i = 0; i < noperands; i++)
|
||
{
|
||
recog_data.constraints[i] = insn_data[icode].operand[i].constraint;
|
||
+ recog_data.is_operator[i] = insn_data[icode].operand[i].is_operator;
|
||
recog_data.operand_mode[i] = insn_data[icode].operand[i].mode;
|
||
/* VOIDmode match_operands gets mode from their real operand. */
|
||
if (recog_data.operand_mode[i] == VOIDmode)
|
||
@@ -2909,6 +2911,10 @@
|
||
|
||
static struct peep2_insn_data peep2_insn_data[MAX_INSNS_PER_PEEP2 + 1];
|
||
static int peep2_current;
|
||
+
|
||
+static bool peep2_do_rebuild_jump_labels;
|
||
+static bool peep2_do_cleanup_cfg;
|
||
+
|
||
/* The number of instructions available to match a peep2. */
|
||
int peep2_current_count;
|
||
|
||
@@ -2917,6 +2923,16 @@
|
||
DF_LIVE_OUT for the block. */
|
||
#define PEEP2_EOB pc_rtx
|
||
|
||
+/* Wrap N to fit into the peep2_insn_data buffer. */
|
||
+
|
||
+static int
|
||
+peep2_buf_position (int n)
|
||
+{
|
||
+ if (n >= MAX_INSNS_PER_PEEP2 + 1)
|
||
+ n -= MAX_INSNS_PER_PEEP2 + 1;
|
||
+ return n;
|
||
+}
|
||
+
|
||
/* Return the Nth non-note insn after `current', or return NULL_RTX if it
|
||
does not exist. Used by the recognizer to find the next insn to match
|
||
in a multi-insn pattern. */
|
||
@@ -2926,9 +2942,7 @@
|
||
{
|
||
gcc_assert (n <= peep2_current_count);
|
||
|
||
- n += peep2_current;
|
||
- if (n >= MAX_INSNS_PER_PEEP2 + 1)
|
||
- n -= MAX_INSNS_PER_PEEP2 + 1;
|
||
+ n = peep2_buf_position (peep2_current + n);
|
||
|
||
return peep2_insn_data[n].insn;
|
||
}
|
||
@@ -2941,9 +2955,7 @@
|
||
{
|
||
gcc_assert (ofs < MAX_INSNS_PER_PEEP2 + 1);
|
||
|
||
- ofs += peep2_current;
|
||
- if (ofs >= MAX_INSNS_PER_PEEP2 + 1)
|
||
- ofs -= MAX_INSNS_PER_PEEP2 + 1;
|
||
+ ofs = peep2_buf_position (peep2_current + ofs);
|
||
|
||
gcc_assert (peep2_insn_data[ofs].insn != NULL_RTX);
|
||
|
||
@@ -2959,9 +2971,7 @@
|
||
|
||
gcc_assert (ofs < MAX_INSNS_PER_PEEP2 + 1);
|
||
|
||
- ofs += peep2_current;
|
||
- if (ofs >= MAX_INSNS_PER_PEEP2 + 1)
|
||
- ofs -= MAX_INSNS_PER_PEEP2 + 1;
|
||
+ ofs = peep2_buf_position (peep2_current + ofs);
|
||
|
||
gcc_assert (peep2_insn_data[ofs].insn != NULL_RTX);
|
||
|
||
@@ -2996,12 +3006,8 @@
|
||
gcc_assert (from < MAX_INSNS_PER_PEEP2 + 1);
|
||
gcc_assert (to < MAX_INSNS_PER_PEEP2 + 1);
|
||
|
||
- from += peep2_current;
|
||
- if (from >= MAX_INSNS_PER_PEEP2 + 1)
|
||
- from -= MAX_INSNS_PER_PEEP2 + 1;
|
||
- to += peep2_current;
|
||
- if (to >= MAX_INSNS_PER_PEEP2 + 1)
|
||
- to -= MAX_INSNS_PER_PEEP2 + 1;
|
||
+ from = peep2_buf_position (peep2_current + from);
|
||
+ to = peep2_buf_position (peep2_current + to);
|
||
|
||
gcc_assert (peep2_insn_data[from].insn != NULL_RTX);
|
||
REG_SET_TO_HARD_REG_SET (live, peep2_insn_data[from].live_before);
|
||
@@ -3010,8 +3016,7 @@
|
||
{
|
||
HARD_REG_SET this_live;
|
||
|
||
- if (++from >= MAX_INSNS_PER_PEEP2 + 1)
|
||
- from = 0;
|
||
+ from = peep2_buf_position (from + 1);
|
||
gcc_assert (peep2_insn_data[from].insn != NULL_RTX);
|
||
REG_SET_TO_HARD_REG_SET (this_live, peep2_insn_data[from].live_before);
|
||
IOR_HARD_REG_SET (live, this_live);
|
||
@@ -3104,19 +3109,234 @@
|
||
COPY_REG_SET (peep2_insn_data[MAX_INSNS_PER_PEEP2].live_before, live);
|
||
}
|
||
|
||
+/* While scanning basic block BB, we found a match of length MATCH_LEN,
|
||
+ starting at INSN. Perform the replacement, removing the old insns and
|
||
+ replacing them with ATTEMPT. Returns the last insn emitted. */
|
||
+
|
||
+static rtx
|
||
+peep2_attempt (basic_block bb, rtx insn, int match_len, rtx attempt)
|
||
+{
|
||
+ int i;
|
||
+ rtx last, note, before_try, x;
|
||
+ bool was_call = false;
|
||
+
|
||
+ /* If we are splitting a CALL_INSN, look for the CALL_INSN
|
||
+ in SEQ and copy our CALL_INSN_FUNCTION_USAGE and other
|
||
+ cfg-related call notes. */
|
||
+ for (i = 0; i <= match_len; ++i)
|
||
+ {
|
||
+ int j;
|
||
+ rtx old_insn, new_insn, note;
|
||
+
|
||
+ j = peep2_buf_position (peep2_current + i);
|
||
+ old_insn = peep2_insn_data[j].insn;
|
||
+ if (!CALL_P (old_insn))
|
||
+ continue;
|
||
+ was_call = true;
|
||
+
|
||
+ new_insn = attempt;
|
||
+ while (new_insn != NULL_RTX)
|
||
+ {
|
||
+ if (CALL_P (new_insn))
|
||
+ break;
|
||
+ new_insn = NEXT_INSN (new_insn);
|
||
+ }
|
||
+
|
||
+ gcc_assert (new_insn != NULL_RTX);
|
||
+
|
||
+ CALL_INSN_FUNCTION_USAGE (new_insn)
|
||
+ = CALL_INSN_FUNCTION_USAGE (old_insn);
|
||
+
|
||
+ for (note = REG_NOTES (old_insn);
|
||
+ note;
|
||
+ note = XEXP (note, 1))
|
||
+ switch (REG_NOTE_KIND (note))
|
||
+ {
|
||
+ case REG_NORETURN:
|
||
+ case REG_SETJMP:
|
||
+ add_reg_note (new_insn, REG_NOTE_KIND (note),
|
||
+ XEXP (note, 0));
|
||
+ break;
|
||
+ default:
|
||
+ /* Discard all other reg notes. */
|
||
+ break;
|
||
+ }
|
||
+
|
||
+ /* Croak if there is another call in the sequence. */
|
||
+ while (++i <= match_len)
|
||
+ {
|
||
+ j = peep2_buf_position (peep2_current + i);
|
||
+ old_insn = peep2_insn_data[j].insn;
|
||
+ gcc_assert (!CALL_P (old_insn));
|
||
+ }
|
||
+ break;
|
||
+ }
|
||
+
|
||
+ i = peep2_buf_position (peep2_current + match_len);
|
||
+
|
||
+ note = find_reg_note (peep2_insn_data[i].insn, REG_EH_REGION, NULL_RTX);
|
||
+
|
||
+ /* Replace the old sequence with the new. */
|
||
+ last = emit_insn_after_setloc (attempt,
|
||
+ peep2_insn_data[i].insn,
|
||
+ INSN_LOCATOR (peep2_insn_data[i].insn));
|
||
+ before_try = PREV_INSN (insn);
|
||
+ delete_insn_chain (insn, peep2_insn_data[i].insn, false);
|
||
+
|
||
+ /* Re-insert the EH_REGION notes. */
|
||
+ if (note || (was_call && nonlocal_goto_handler_labels))
|
||
+ {
|
||
+ edge eh_edge;
|
||
+ edge_iterator ei;
|
||
+
|
||
+ FOR_EACH_EDGE (eh_edge, ei, bb->succs)
|
||
+ if (eh_edge->flags & (EDGE_EH | EDGE_ABNORMAL_CALL))
|
||
+ break;
|
||
+
|
||
+ if (note)
|
||
+ copy_reg_eh_region_note_backward (note, last, before_try);
|
||
+
|
||
+ if (eh_edge)
|
||
+ for (x = last; x != before_try; x = PREV_INSN (x))
|
||
+ if (x != BB_END (bb)
|
||
+ && (can_throw_internal (x)
|
||
+ || can_nonlocal_goto (x)))
|
||
+ {
|
||
+ edge nfte, nehe;
|
||
+ int flags;
|
||
+
|
||
+ nfte = split_block (bb, x);
|
||
+ flags = (eh_edge->flags
|
||
+ & (EDGE_EH | EDGE_ABNORMAL));
|
||
+ if (CALL_P (x))
|
||
+ flags |= EDGE_ABNORMAL_CALL;
|
||
+ nehe = make_edge (nfte->src, eh_edge->dest,
|
||
+ flags);
|
||
+
|
||
+ nehe->probability = eh_edge->probability;
|
||
+ nfte->probability
|
||
+ = REG_BR_PROB_BASE - nehe->probability;
|
||
+
|
||
+ peep2_do_cleanup_cfg |= purge_dead_edges (nfte->dest);
|
||
+ bb = nfte->src;
|
||
+ eh_edge = nehe;
|
||
+ }
|
||
+
|
||
+ /* Converting possibly trapping insn to non-trapping is
|
||
+ possible. Zap dummy outgoing edges. */
|
||
+ peep2_do_cleanup_cfg |= purge_dead_edges (bb);
|
||
+ }
|
||
+
|
||
+ /* If we generated a jump instruction, it won't have
|
||
+ JUMP_LABEL set. Recompute after we're done. */
|
||
+ for (x = last; x != before_try; x = PREV_INSN (x))
|
||
+ if (JUMP_P (x))
|
||
+ {
|
||
+ peep2_do_rebuild_jump_labels = true;
|
||
+ break;
|
||
+ }
|
||
+
|
||
+ return last;
|
||
+}
|
||
+
|
||
+/* After performing a replacement in basic block BB, fix up the life
|
||
+ information in our buffer. LAST is the last of the insns that we
|
||
+ emitted as a replacement. PREV is the insn before the start of
|
||
+ the replacement. MATCH_LEN is the number of instructions that were
|
||
+ matched, and which now need to be replaced in the buffer. */
|
||
+
|
||
+static void
|
||
+peep2_update_life (basic_block bb, int match_len, rtx last, rtx prev)
|
||
+{
|
||
+ int i = peep2_buf_position (peep2_current + match_len + 1);
|
||
+ rtx x;
|
||
+ regset_head live;
|
||
+
|
||
+ INIT_REG_SET (&live);
|
||
+ COPY_REG_SET (&live, peep2_insn_data[i].live_before);
|
||
+
|
||
+ gcc_assert (peep2_current_count >= match_len + 1);
|
||
+ peep2_current_count -= match_len + 1;
|
||
+
|
||
+ x = last;
|
||
+ do
|
||
+ {
|
||
+ if (INSN_P (x))
|
||
+ {
|
||
+ df_insn_rescan (x);
|
||
+ if (peep2_current_count < MAX_INSNS_PER_PEEP2)
|
||
+ {
|
||
+ peep2_current_count++;
|
||
+ if (--i < 0)
|
||
+ i = MAX_INSNS_PER_PEEP2;
|
||
+ peep2_insn_data[i].insn = x;
|
||
+ df_simulate_one_insn_backwards (bb, x, &live);
|
||
+ COPY_REG_SET (peep2_insn_data[i].live_before, &live);
|
||
+ }
|
||
+ }
|
||
+ x = PREV_INSN (x);
|
||
+ }
|
||
+ while (x != prev);
|
||
+ CLEAR_REG_SET (&live);
|
||
+
|
||
+ peep2_current = i;
|
||
+}
|
||
+
|
||
+/* Add INSN, which is in BB, at the end of the peep2 insn buffer if possible.
|
||
+ Return true if we added it, false otherwise. The caller will try to match
|
||
+ peepholes against the buffer if we return false; otherwise it will try to
|
||
+ add more instructions to the buffer. */
|
||
+
|
||
+static bool
|
||
+peep2_fill_buffer (basic_block bb, rtx insn, regset live)
|
||
+{
|
||
+ int pos;
|
||
+
|
||
+ /* Once we have filled the maximum number of insns the buffer can hold,
|
||
+ allow the caller to match the insns against peepholes. We wait until
|
||
+ the buffer is full in case the target has similar peepholes of different
|
||
+ length; we always want to match the longest if possible. */
|
||
+ if (peep2_current_count == MAX_INSNS_PER_PEEP2)
|
||
+ return false;
|
||
+
|
||
+ /* If an insn has RTX_FRAME_RELATED_P set, peephole substitution would lose
|
||
+ the REG_FRAME_RELATED_EXPR that is attached. */
|
||
+ if (RTX_FRAME_RELATED_P (insn))
|
||
+ {
|
||
+ /* Let the buffer drain first. */
|
||
+ if (peep2_current_count > 0)
|
||
+ return false;
|
||
+ /* Step over the insn then return true without adding the insn
|
||
+ to the buffer; this will cause us to process the next
|
||
+ insn. */
|
||
+ df_simulate_one_insn_forwards (bb, insn, live);
|
||
+ return true;
|
||
+ }
|
||
+
|
||
+ pos = peep2_buf_position (peep2_current + peep2_current_count);
|
||
+ peep2_insn_data[pos].insn = insn;
|
||
+ COPY_REG_SET (peep2_insn_data[pos].live_before, live);
|
||
+ peep2_current_count++;
|
||
+
|
||
+ df_simulate_one_insn_forwards (bb, insn, live);
|
||
+ return true;
|
||
+}
|
||
+
|
||
/* Perform the peephole2 optimization pass. */
|
||
|
||
static void
|
||
peephole2_optimize (void)
|
||
{
|
||
- rtx insn, prev;
|
||
+ rtx insn;
|
||
bitmap live;
|
||
int i;
|
||
basic_block bb;
|
||
- bool do_cleanup_cfg = false;
|
||
- bool do_rebuild_jump_labels = false;
|
||
+
|
||
+ peep2_do_cleanup_cfg = false;
|
||
+ peep2_do_rebuild_jump_labels = false;
|
||
|
||
df_set_flags (DF_LR_RUN_DCE);
|
||
+ df_note_add_problem ();
|
||
df_analyze ();
|
||
|
||
/* Initialize the regsets we're going to use. */
|
||
@@ -3126,214 +3346,59 @@
|
||
|
||
FOR_EACH_BB_REVERSE (bb)
|
||
{
|
||
+ bool past_end = false;
|
||
+ int pos;
|
||
+
|
||
rtl_profile_for_bb (bb);
|
||
|
||
/* Start up propagation. */
|
||
- bitmap_copy (live, DF_LR_OUT (bb));
|
||
- df_simulate_initialize_backwards (bb, live);
|
||
+ bitmap_copy (live, DF_LR_IN (bb));
|
||
+ df_simulate_initialize_forwards (bb, live);
|
||
peep2_reinit_state (live);
|
||
|
||
- for (insn = BB_END (bb); ; insn = prev)
|
||
+ insn = BB_HEAD (bb);
|
||
+ for (;;)
|
||
{
|
||
- prev = PREV_INSN (insn);
|
||
- if (NONDEBUG_INSN_P (insn))
|
||
+ rtx attempt, head;
|
||
+ int match_len;
|
||
+
|
||
+ if (!past_end && !NONDEBUG_INSN_P (insn))
|
||
{
|
||
- rtx attempt, before_try, x;
|
||
- int match_len;
|
||
- rtx note;
|
||
- bool was_call = false;
|
||
-
|
||
- /* Record this insn. */
|
||
- if (--peep2_current < 0)
|
||
- peep2_current = MAX_INSNS_PER_PEEP2;
|
||
- if (peep2_current_count < MAX_INSNS_PER_PEEP2
|
||
- && peep2_insn_data[peep2_current].insn == NULL_RTX)
|
||
- peep2_current_count++;
|
||
- peep2_insn_data[peep2_current].insn = insn;
|
||
- df_simulate_one_insn_backwards (bb, insn, live);
|
||
- COPY_REG_SET (peep2_insn_data[peep2_current].live_before, live);
|
||
-
|
||
- if (RTX_FRAME_RELATED_P (insn))
|
||
- {
|
||
- /* If an insn has RTX_FRAME_RELATED_P set, peephole
|
||
- substitution would lose the
|
||
- REG_FRAME_RELATED_EXPR that is attached. */
|
||
- peep2_reinit_state (live);
|
||
- attempt = NULL;
|
||
- }
|
||
- else
|
||
- /* Match the peephole. */
|
||
- attempt = peephole2_insns (PATTERN (insn), insn, &match_len);
|
||
-
|
||
- if (attempt != NULL)
|
||
- {
|
||
- /* If we are splitting a CALL_INSN, look for the CALL_INSN
|
||
- in SEQ and copy our CALL_INSN_FUNCTION_USAGE and other
|
||
- cfg-related call notes. */
|
||
- for (i = 0; i <= match_len; ++i)
|
||
- {
|
||
- int j;
|
||
- rtx old_insn, new_insn, note;
|
||
-
|
||
- j = i + peep2_current;
|
||
- if (j >= MAX_INSNS_PER_PEEP2 + 1)
|
||
- j -= MAX_INSNS_PER_PEEP2 + 1;
|
||
- old_insn = peep2_insn_data[j].insn;
|
||
- if (!CALL_P (old_insn))
|
||
- continue;
|
||
- was_call = true;
|
||
-
|
||
- new_insn = attempt;
|
||
- while (new_insn != NULL_RTX)
|
||
- {
|
||
- if (CALL_P (new_insn))
|
||
- break;
|
||
- new_insn = NEXT_INSN (new_insn);
|
||
- }
|
||
-
|
||
- gcc_assert (new_insn != NULL_RTX);
|
||
-
|
||
- CALL_INSN_FUNCTION_USAGE (new_insn)
|
||
- = CALL_INSN_FUNCTION_USAGE (old_insn);
|
||
-
|
||
- for (note = REG_NOTES (old_insn);
|
||
- note;
|
||
- note = XEXP (note, 1))
|
||
- switch (REG_NOTE_KIND (note))
|
||
- {
|
||
- case REG_NORETURN:
|
||
- case REG_SETJMP:
|
||
- add_reg_note (new_insn, REG_NOTE_KIND (note),
|
||
- XEXP (note, 0));
|
||
- break;
|
||
- default:
|
||
- /* Discard all other reg notes. */
|
||
- break;
|
||
- }
|
||
-
|
||
- /* Croak if there is another call in the sequence. */
|
||
- while (++i <= match_len)
|
||
- {
|
||
- j = i + peep2_current;
|
||
- if (j >= MAX_INSNS_PER_PEEP2 + 1)
|
||
- j -= MAX_INSNS_PER_PEEP2 + 1;
|
||
- old_insn = peep2_insn_data[j].insn;
|
||
- gcc_assert (!CALL_P (old_insn));
|
||
- }
|
||
- break;
|
||
- }
|
||
-
|
||
- i = match_len + peep2_current;
|
||
- if (i >= MAX_INSNS_PER_PEEP2 + 1)
|
||
- i -= MAX_INSNS_PER_PEEP2 + 1;
|
||
-
|
||
- note = find_reg_note (peep2_insn_data[i].insn,
|
||
- REG_EH_REGION, NULL_RTX);
|
||
-
|
||
- /* Replace the old sequence with the new. */
|
||
- attempt = emit_insn_after_setloc (attempt,
|
||
- peep2_insn_data[i].insn,
|
||
- INSN_LOCATOR (peep2_insn_data[i].insn));
|
||
- before_try = PREV_INSN (insn);
|
||
- delete_insn_chain (insn, peep2_insn_data[i].insn, false);
|
||
-
|
||
- /* Re-insert the EH_REGION notes. */
|
||
- if (note || (was_call && nonlocal_goto_handler_labels))
|
||
- {
|
||
- edge eh_edge;
|
||
- edge_iterator ei;
|
||
-
|
||
- FOR_EACH_EDGE (eh_edge, ei, bb->succs)
|
||
- if (eh_edge->flags & (EDGE_EH | EDGE_ABNORMAL_CALL))
|
||
- break;
|
||
-
|
||
- if (note)
|
||
- copy_reg_eh_region_note_backward (note, attempt,
|
||
- before_try);
|
||
-
|
||
- if (eh_edge)
|
||
- for (x = attempt ; x != before_try ; x = PREV_INSN (x))
|
||
- if (x != BB_END (bb)
|
||
- && (can_throw_internal (x)
|
||
- || can_nonlocal_goto (x)))
|
||
- {
|
||
- edge nfte, nehe;
|
||
- int flags;
|
||
-
|
||
- nfte = split_block (bb, x);
|
||
- flags = (eh_edge->flags
|
||
- & (EDGE_EH | EDGE_ABNORMAL));
|
||
- if (CALL_P (x))
|
||
- flags |= EDGE_ABNORMAL_CALL;
|
||
- nehe = make_edge (nfte->src, eh_edge->dest,
|
||
- flags);
|
||
-
|
||
- nehe->probability = eh_edge->probability;
|
||
- nfte->probability
|
||
- = REG_BR_PROB_BASE - nehe->probability;
|
||
-
|
||
- do_cleanup_cfg |= purge_dead_edges (nfte->dest);
|
||
- bb = nfte->src;
|
||
- eh_edge = nehe;
|
||
- }
|
||
-
|
||
- /* Converting possibly trapping insn to non-trapping is
|
||
- possible. Zap dummy outgoing edges. */
|
||
- do_cleanup_cfg |= purge_dead_edges (bb);
|
||
- }
|
||
-
|
||
- if (targetm.have_conditional_execution ())
|
||
- {
|
||
- for (i = 0; i < MAX_INSNS_PER_PEEP2 + 1; ++i)
|
||
- peep2_insn_data[i].insn = NULL_RTX;
|
||
- peep2_insn_data[peep2_current].insn = PEEP2_EOB;
|
||
- peep2_current_count = 0;
|
||
- }
|
||
- else
|
||
- {
|
||
- /* Back up lifetime information past the end of the
|
||
- newly created sequence. */
|
||
- if (++i >= MAX_INSNS_PER_PEEP2 + 1)
|
||
- i = 0;
|
||
- bitmap_copy (live, peep2_insn_data[i].live_before);
|
||
-
|
||
- /* Update life information for the new sequence. */
|
||
- x = attempt;
|
||
- do
|
||
- {
|
||
- if (INSN_P (x))
|
||
- {
|
||
- if (--i < 0)
|
||
- i = MAX_INSNS_PER_PEEP2;
|
||
- if (peep2_current_count < MAX_INSNS_PER_PEEP2
|
||
- && peep2_insn_data[i].insn == NULL_RTX)
|
||
- peep2_current_count++;
|
||
- peep2_insn_data[i].insn = x;
|
||
- df_insn_rescan (x);
|
||
- df_simulate_one_insn_backwards (bb, x, live);
|
||
- bitmap_copy (peep2_insn_data[i].live_before,
|
||
- live);
|
||
- }
|
||
- x = PREV_INSN (x);
|
||
- }
|
||
- while (x != prev);
|
||
-
|
||
- peep2_current = i;
|
||
- }
|
||
-
|
||
- /* If we generated a jump instruction, it won't have
|
||
- JUMP_LABEL set. Recompute after we're done. */
|
||
- for (x = attempt; x != before_try; x = PREV_INSN (x))
|
||
- if (JUMP_P (x))
|
||
- {
|
||
- do_rebuild_jump_labels = true;
|
||
- break;
|
||
- }
|
||
- }
|
||
+ next_insn:
|
||
+ insn = NEXT_INSN (insn);
|
||
+ if (insn == NEXT_INSN (BB_END (bb)))
|
||
+ past_end = true;
|
||
+ continue;
|
||
}
|
||
+ if (!past_end && peep2_fill_buffer (bb, insn, live))
|
||
+ goto next_insn;
|
||
|
||
- if (insn == BB_HEAD (bb))
|
||
+ /* If we did not fill an empty buffer, it signals the end of the
|
||
+ block. */
|
||
+ if (peep2_current_count == 0)
|
||
break;
|
||
+
|
||
+ /* The buffer filled to the current maximum, so try to match. */
|
||
+
|
||
+ pos = peep2_buf_position (peep2_current + peep2_current_count);
|
||
+ peep2_insn_data[pos].insn = PEEP2_EOB;
|
||
+ COPY_REG_SET (peep2_insn_data[pos].live_before, live);
|
||
+
|
||
+ /* Match the peephole. */
|
||
+ head = peep2_insn_data[peep2_current].insn;
|
||
+ attempt = peephole2_insns (PATTERN (head), head, &match_len);
|
||
+ if (attempt != NULL)
|
||
+ {
|
||
+ rtx last;
|
||
+ last = peep2_attempt (bb, head, match_len, attempt);
|
||
+ peep2_update_life (bb, match_len, last, PREV_INSN (attempt));
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ /* If no match, advance the buffer by one insn. */
|
||
+ peep2_current = peep2_buf_position (peep2_current + 1);
|
||
+ peep2_current_count--;
|
||
+ }
|
||
}
|
||
}
|
||
|
||
@@ -3341,7 +3406,7 @@
|
||
for (i = 0; i < MAX_INSNS_PER_PEEP2 + 1; ++i)
|
||
BITMAP_FREE (peep2_insn_data[i].live_before);
|
||
BITMAP_FREE (live);
|
||
- if (do_rebuild_jump_labels)
|
||
+ if (peep2_do_rebuild_jump_labels)
|
||
rebuild_jump_labels (get_insns ());
|
||
}
|
||
#endif /* HAVE_peephole2 */
|
||
|
||
=== modified file 'gcc/recog.h'
|
||
--- old/gcc/recog.h 2009-10-26 21:55:59 +0000
|
||
+++ new/gcc/recog.h 2010-11-16 12:32:34 +0000
|
||
@@ -194,6 +194,9 @@
|
||
/* Gives the constraint string for operand N. */
|
||
const char *constraints[MAX_RECOG_OPERANDS];
|
||
|
||
+ /* Nonzero if operand N is a match_operator or a match_parallel. */
|
||
+ char is_operator[MAX_RECOG_OPERANDS];
|
||
+
|
||
/* Gives the mode of operand N. */
|
||
enum machine_mode operand_mode[MAX_RECOG_OPERANDS];
|
||
|
||
@@ -260,6 +263,8 @@
|
||
|
||
const char strict_low;
|
||
|
||
+ const char is_operator;
|
||
+
|
||
const char eliminable;
|
||
};
|
||
|
||
|
||
=== modified file 'gcc/reload.c'
|
||
--- old/gcc/reload.c 2009-12-21 16:32:44 +0000
|
||
+++ new/gcc/reload.c 2010-11-16 12:32:34 +0000
|
||
@@ -3631,7 +3631,7 @@
|
||
|| modified[j] != RELOAD_WRITE)
|
||
&& j != i
|
||
/* Ignore things like match_operator operands. */
|
||
- && *recog_data.constraints[j] != 0
|
||
+ && !recog_data.is_operator[j]
|
||
/* Don't count an input operand that is constrained to match
|
||
the early clobber operand. */
|
||
&& ! (this_alternative_matches[j] == i
|
||
|