2013-12-19 Charles Baylis <charles.baylis@linaro.org>
[official-gcc.git] / gcc / config / arm / arm-ldmstm.ml
blob682aa2c8ee30b742a2ddbb82de8b362093b9b120
1 (* Auto-generate ARM ldm/stm patterns
2 Copyright (C) 2010-2013 Free Software Foundation, Inc.
3 Contributed by CodeSourcery.
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3, or (at your option) any later
10 version.
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>.
21 This is an O'Caml program. The O'Caml compiler is available from:
23 http://caml.inria.fr/
25 Or from your favourite OS's friendly packaging system. Tested with version
26 3.09.2, though other versions will probably work too.
28 Run with:
29 ocaml arm-ldmstm.ml >/path/to/gcc/config/arm/ldmstm.md
32 type amode = IA | IB | DA | DB
34 type optype = IN | OUT | INOUT
36 let rec string_of_addrmode addrmode =
37 match addrmode with
38 IA -> "ia" | IB -> "ib" | DA -> "da" | DB -> "db"
40 let rec initial_offset addrmode nregs =
41 match addrmode with
42 IA -> 0
43 | IB -> 4
44 | DA -> -4 * nregs + 4
45 | DB -> -4 * nregs
47 let rec final_offset addrmode nregs =
48 match addrmode with
49 IA -> nregs * 4
50 | IB -> nregs * 4
51 | DA -> -4 * nregs
52 | DB -> -4 * nregs
54 let constr thumb =
55 if thumb then "l" else "rk"
57 let inout_constr op_type =
58 match op_type with
59 OUT -> "=&"
60 | INOUT -> "+&"
61 | IN -> ""
63 let destreg nregs first op_type thumb =
64 if not first then
65 Printf.sprintf "(match_dup %d)" (nregs + 1)
66 else
67 Printf.sprintf ("(match_operand:SI %d \"s_register_operand\" \"%s%s\")")
68 (nregs + 1) (inout_constr op_type) (constr thumb)
70 let reg_predicate thumb =
71 if thumb then "low_register_operand" else "arm_hard_general_register_operand"
73 let write_ldm_set thumb nregs offset opnr first =
74 let indent = " " in
75 Printf.printf "%s" (if first then " [" else indent);
76 Printf.printf "(set (match_operand:SI %d \"%s\" \"\")\n" opnr (reg_predicate thumb);
77 Printf.printf "%s (mem:SI " indent;
78 begin if offset != 0 then Printf.printf "(plus:SI " end;
79 Printf.printf "%s" (destreg nregs first IN thumb);
80 begin if offset != 0 then Printf.printf "\n%s (const_int %d))" indent offset end;
81 Printf.printf "))"
83 let write_stm_set thumb nregs offset opnr first =
84 let indent = " " in
85 Printf.printf "%s" (if first then " [" else indent);
86 Printf.printf "(set (mem:SI ";
87 begin if offset != 0 then Printf.printf "(plus:SI " end;
88 Printf.printf "%s" (destreg nregs first IN thumb);
89 begin if offset != 0 then Printf.printf " (const_int %d))" offset end;
90 Printf.printf ")\n%s (match_operand:SI %d \"%s\" \"\"))" indent opnr (reg_predicate thumb)
92 let write_ldm_peep_set extra_indent nregs opnr first =
93 let indent = " " ^ extra_indent in
94 Printf.printf "%s" (if first then extra_indent ^ " [" else indent);
95 Printf.printf "(set (match_operand:SI %d \"s_register_operand\" \"\")\n" opnr;
96 Printf.printf "%s (match_operand:SI %d \"memory_operand\" \"\"))" indent (nregs + opnr)
98 let write_stm_peep_set extra_indent nregs opnr first =
99 let indent = " " ^ extra_indent in
100 Printf.printf "%s" (if first then extra_indent ^ " [" else indent);
101 Printf.printf "(set (match_operand:SI %d \"memory_operand\" \"\")\n" (nregs + opnr);
102 Printf.printf "%s (match_operand:SI %d \"s_register_operand\" \"\"))" indent opnr
104 let write_any_load optype nregs opnr first =
105 let indent = " " in
106 Printf.printf "%s" (if first then " [" else indent);
107 Printf.printf "(set (match_operand:SI %d \"s_register_operand\" \"\")\n" opnr;
108 Printf.printf "%s (match_operand:SI %d \"%s\" \"\"))" indent (nregs * 2 + opnr) optype
110 let write_const_store nregs opnr first =
111 let indent = " " in
112 Printf.printf "%s(set (match_operand:SI %d \"memory_operand\" \"\")\n" indent (nregs + opnr);
113 Printf.printf "%s (match_dup %d))" indent opnr
115 let write_const_stm_peep_set nregs opnr first =
116 write_any_load "const_int_operand" nregs opnr first;
117 Printf.printf "\n";
118 write_const_store nregs opnr false
121 let rec write_pat_sets func opnr offset first n_left =
122 func offset opnr first;
123 begin
124 if n_left > 1 then begin
125 Printf.printf "\n";
126 write_pat_sets func (opnr + 1) (offset + 4) false (n_left - 1);
127 end else
128 Printf.printf "]"
131 let rec write_peep_sets func opnr first n_left =
132 func opnr first;
133 begin
134 if n_left > 1 then begin
135 Printf.printf "\n";
136 write_peep_sets func (opnr + 1) false (n_left - 1);
140 let can_thumb addrmode update is_store =
141 match addrmode, update, is_store with
142 (* Thumb1 mode only supports IA with update. However, for LDMIA,
143 if the address register also appears in the list of loaded
144 registers, the loaded value is stored, hence the RTL pattern
145 to describe such an insn does not have an update. We check
146 in the match_parallel predicate that the condition described
147 above is met. *)
148 IA, _, false -> true
149 | IA, true, true -> true
150 | _ -> false
152 exception InvalidAddrMode of string;;
154 let target addrmode thumb =
155 match addrmode, thumb with
156 IA, true -> "TARGET_THUMB1"
157 | IA, false -> "TARGET_32BIT"
158 | DB, false -> "TARGET_32BIT"
159 | _, false -> "TARGET_ARM"
160 | _, _ -> raise (InvalidAddrMode "ERROR: Invalid Addressing mode for Thumb1.")
162 let write_pattern_1 name ls addrmode nregs write_set_fn update thumb =
163 let astr = string_of_addrmode addrmode in
164 Printf.printf "(define_insn \"*%s%s%d_%s%s\"\n"
165 (if thumb then "thumb_" else "") name nregs astr
166 (if update then "_update" else "");
167 Printf.printf " [(match_parallel 0 \"%s_multiple_operation\"\n" ls;
168 begin
169 if update then begin
170 Printf.printf " [(set %s\n (plus:SI %s"
171 (destreg nregs true INOUT thumb) (destreg nregs false IN thumb);
172 Printf.printf " (const_int %d)))\n"
173 (final_offset addrmode nregs)
175 end;
176 write_pat_sets
177 (write_set_fn thumb nregs) 1
178 (initial_offset addrmode nregs)
179 (not update) nregs;
180 Printf.printf ")]\n \"%s && XVECLEN (operands[0], 0) == %d\"\n"
181 (target addrmode thumb)
182 (if update then nregs + 1 else nregs);
183 Printf.printf " \"%s%%(%s%%)\\t%%%d%s, {"
184 name astr (nregs + 1) (if update then "!" else "");
185 for n = 1 to nregs; do
186 Printf.printf "%%%d%s" n (if n < nregs then ", " else "")
187 done;
188 Printf.printf "}\"\n";
189 Printf.printf " [(set_attr \"type\" \"%s%d\")" ls nregs;
190 if not thumb then begin
191 Printf.printf "\n (set_attr \"predicable\" \"yes\")";
192 if addrmode == IA || addrmode == DB then
193 Printf.printf "\n (set_attr \"predicable_short_it\" \"no\")";
194 end;
195 Printf.printf "])\n\n"
197 let write_ldm_pattern addrmode nregs update =
198 write_pattern_1 "ldm" "load" addrmode nregs write_ldm_set update false;
199 begin if can_thumb addrmode update false then
200 write_pattern_1 "ldm" "load" addrmode nregs write_ldm_set update true;
203 let write_stm_pattern addrmode nregs update =
204 write_pattern_1 "stm" "store" addrmode nregs write_stm_set update false;
205 begin if can_thumb addrmode update true then
206 write_pattern_1 "stm" "store" addrmode nregs write_stm_set update true;
209 let write_ldm_commutative_peephole thumb =
210 let nregs = 2 in
211 Printf.printf "(define_peephole2\n";
212 write_peep_sets (write_ldm_peep_set "" nregs) 0 true nregs;
213 let indent = " " in
214 if thumb then begin
215 Printf.printf "\n%s(set (match_operand:SI %d \"s_register_operand\" \"\")\n" indent (nregs * 2);
216 Printf.printf "%s (match_operator:SI %d \"commutative_binary_operator\"\n" indent (nregs * 2 + 1);
217 Printf.printf "%s [(match_operand:SI %d \"s_register_operand\" \"\")\n" indent (nregs * 2 + 2);
218 Printf.printf "%s (match_operand:SI %d \"s_register_operand\" \"\")]))]\n" indent (nregs * 2 + 3)
219 end else begin
220 Printf.printf "\n%s(parallel\n" indent;
221 Printf.printf "%s [(set (match_operand:SI %d \"s_register_operand\" \"\")\n" indent (nregs * 2);
222 Printf.printf "%s (match_operator:SI %d \"commutative_binary_operator\"\n" indent (nregs * 2 + 1);
223 Printf.printf "%s [(match_operand:SI %d \"s_register_operand\" \"\")\n" indent (nregs * 2 + 2);
224 Printf.printf "%s (match_operand:SI %d \"s_register_operand\" \"\")]))\n" indent (nregs * 2 + 3);
225 Printf.printf "%s (clobber (reg:CC CC_REGNUM))])]\n" indent
226 end;
227 Printf.printf " \"((((REGNO (operands[%d]) == REGNO (operands[0]))\n" (nregs * 2 + 2);
228 Printf.printf " && (REGNO (operands[%d]) == REGNO (operands[1])))\n" (nregs * 2 + 3);
229 Printf.printf " || ((REGNO (operands[%d]) == REGNO (operands[0]))\n" (nregs * 2 + 3);
230 Printf.printf " && (REGNO (operands[%d]) == REGNO (operands[1]))))\n" (nregs * 2 + 2);
231 Printf.printf " && (peep2_regno_dead_p (%d, REGNO (operands[0]))\n" (nregs + 1);
232 Printf.printf " || (REGNO (operands[0]) == REGNO (operands[%d])))\n" (nregs * 2);
233 Printf.printf " && (peep2_regno_dead_p (%d, REGNO (operands[1]))\n" (nregs + 1);
234 Printf.printf " || (REGNO (operands[1]) == REGNO (operands[%d]))))\"\n" (nregs * 2);
235 begin
236 if thumb then
237 Printf.printf " [(set (match_dup %d) (match_op_dup %d [(match_dup %d) (match_dup %d)]))]\n"
238 (nregs * 2) (nregs * 2 + 1) (nregs * 2 + 2) (nregs * 2 + 3)
239 else begin
240 Printf.printf " [(parallel\n";
241 Printf.printf " [(set (match_dup %d) (match_op_dup %d [(match_dup %d) (match_dup %d)]))\n"
242 (nregs * 2) (nregs * 2 + 1) (nregs * 2 + 2) (nregs * 2 + 3);
243 Printf.printf " (clobber (reg:CC CC_REGNUM))])]\n"
245 end;
246 Printf.printf "{\n if (!gen_ldm_seq (operands, %d, true))\n FAIL;\n" nregs;
247 Printf.printf "})\n\n"
249 let write_ldm_peephole nregs =
250 Printf.printf "(define_peephole2\n";
251 write_peep_sets (write_ldm_peep_set "" nregs) 0 true nregs;
252 Printf.printf "]\n \"\"\n [(const_int 0)]\n{\n";
253 Printf.printf " if (gen_ldm_seq (operands, %d, false))\n DONE;\n else\n FAIL;\n})\n\n" nregs
255 let write_ldm_peephole_b nregs =
256 if nregs > 2 then begin
257 Printf.printf "(define_peephole2\n";
258 write_ldm_peep_set "" nregs 0 true;
259 Printf.printf "\n (parallel\n";
260 write_peep_sets (write_ldm_peep_set " " nregs) 1 true (nregs - 1);
261 Printf.printf "])]\n \"\"\n [(const_int 0)]\n{\n";
262 Printf.printf " if (gen_ldm_seq (operands, %d, false))\n DONE;\n else\n FAIL;\n})\n\n" nregs
265 let write_stm_peephole nregs =
266 Printf.printf "(define_peephole2\n";
267 write_peep_sets (write_stm_peep_set "" nregs) 0 true nregs;
268 Printf.printf "]\n \"\"\n [(const_int 0)]\n{\n";
269 Printf.printf " if (gen_stm_seq (operands, %d))\n DONE;\n else\n FAIL;\n})\n\n" nregs
271 let write_stm_peephole_b nregs =
272 if nregs > 2 then begin
273 Printf.printf "(define_peephole2\n";
274 write_stm_peep_set "" nregs 0 true;
275 Printf.printf "\n (parallel\n";
276 write_peep_sets (write_stm_peep_set "" nregs) 1 true (nregs - 1);
277 Printf.printf "]\n \"\"\n [(const_int 0)]\n{\n";
278 Printf.printf " if (gen_stm_seq (operands, %d))\n DONE;\n else\n FAIL;\n})\n\n" nregs
281 let write_const_stm_peephole_a nregs =
282 Printf.printf "(define_peephole2\n";
283 write_peep_sets (write_const_stm_peep_set nregs) 0 true nregs;
284 Printf.printf "]\n \"\"\n [(const_int 0)]\n{\n";
285 Printf.printf " if (gen_const_stm_seq (operands, %d))\n DONE;\n else\n FAIL;\n})\n\n" nregs
287 let write_const_stm_peephole_b nregs =
288 Printf.printf "(define_peephole2\n";
289 write_peep_sets (write_any_load "const_int_operand" nregs) 0 true nregs;
290 Printf.printf "\n";
291 write_peep_sets (write_const_store nregs) 0 false nregs;
292 Printf.printf "]\n \"\"\n [(const_int 0)]\n{\n";
293 Printf.printf " if (gen_const_stm_seq (operands, %d))\n DONE;\n else\n FAIL;\n})\n\n" nregs
295 let patterns () =
296 let addrmodes = [ IA; IB; DA; DB ] in
297 let sizes = [ 4; 3; 2] in
298 List.iter
299 (fun n ->
300 List.iter
301 (fun addrmode ->
302 write_ldm_pattern addrmode n false;
303 write_ldm_pattern addrmode n true;
304 write_stm_pattern addrmode n false;
305 write_stm_pattern addrmode n true)
306 addrmodes;
307 write_ldm_peephole n;
308 write_ldm_peephole_b n;
309 write_const_stm_peephole_a n;
310 write_const_stm_peephole_b n;
311 write_stm_peephole n;)
312 sizes;
313 write_ldm_commutative_peephole false;
314 write_ldm_commutative_peephole true
316 let print_lines = List.iter (fun s -> Format.printf "%s@\n" s)
318 (* Do it. *)
320 let _ =
321 print_lines [
322 "/* ARM ldm/stm instruction patterns. This file was automatically generated";
323 " using arm-ldmstm.ml. Please do not edit manually.";
325 " Copyright (C) 2010-2013 Free Software Foundation, Inc.";
326 " Contributed by CodeSourcery.";
328 " This file is part of GCC.";
330 " GCC is free software; you can redistribute it and/or modify it";
331 " under the terms of the GNU General Public License as published";
332 " by the Free Software Foundation; either version 3, or (at your";
333 " option) any later version.";
335 " GCC is distributed in the hope that it will be useful, but WITHOUT";
336 " ANY WARRANTY; without even the implied warranty of MERCHANTABILITY";
337 " or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public";
338 " License for more details.";
340 " You should have received a copy of the GNU General Public License and";
341 " a copy of the GCC Runtime Library Exception along with this program;";
342 " see the files COPYING3 and COPYING.RUNTIME respectively. If not, see";
343 " <http://www.gnu.org/licenses/>. */";
344 ""];
345 patterns ();