1(* Auto-generate ARM ldm/stm patterns
2   Copyright (C) 2010-2014 Free Software Foundation, Inc.
3   Contributed by CodeSourcery.
4
5   This file is part of GCC.
6
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.
11
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.
16
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/>.
20
21   This is an O'Caml program.  The O'Caml compiler is available from:
22
23     http://caml.inria.fr/
24
25   Or from your favourite OS's friendly packaging system. Tested with version
26   3.09.2, though other versions will probably work too.
27
28   Run with:
29     ocaml arm-ldmstm.ml >/path/to/gcc/config/arm/ldmstm.md
30*)
31
32type amode = IA | IB | DA | DB
33
34type optype = IN | OUT | INOUT
35
36let rec string_of_addrmode addrmode =
37  match addrmode with
38    IA -> "ia" | IB -> "ib" | DA -> "da" | DB -> "db"
39
40let rec initial_offset addrmode nregs =
41  match addrmode with
42    IA -> 0
43  | IB -> 4
44  | DA -> -4 * nregs + 4
45  | DB -> -4 * nregs
46
47let 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
53
54let constr thumb =
55  if thumb then "l" else "rk"
56
57let inout_constr op_type =
58  match op_type with
59  OUT -> "=&"
60  | INOUT -> "+&"
61  | IN -> ""
62
63let 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)
69
70let reg_predicate thumb =
71  if thumb then "low_register_operand" else "arm_hard_general_register_operand"
72
73let 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 "))"
82
83let 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)
91
92let 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)
97
98let 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
103
104let 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
109
110let 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
114
115let 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
119
120
121let 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 "]"
129  end
130
131let 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);
137    end
138  end
139
140let 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
151
152exception InvalidAddrMode of string;;
153
154let 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.")
161
162let 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)
174    end
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"
196
197let 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;
201  end
202
203let 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;
207  end
208
209let 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"
244    end
245  end;
246  Printf.printf "{\n  if (!gen_ldm_seq (operands, %d, true))\n    FAIL;\n" nregs;
247  Printf.printf "})\n\n"
248
249let 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
254
255let 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
263  end
264
265let 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
270
271let 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
279  end
280
281let 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
286
287let 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
294
295let 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
315
316let print_lines = List.iter (fun s -> Format.printf "%s@\n" s)
317
318(* Do it.  *)
319
320let _ =
321  print_lines [
322"/* ARM ldm/stm instruction patterns.  This file was automatically generated";
323"   using arm-ldmstm.ml.  Please do not edit manually.";
324"";
325"   Copyright (C) 2010-2014 Free Software Foundation, Inc.";
326"   Contributed by CodeSourcery.";
327"";
328"   This file is part of GCC.";
329"";
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.";
334"";
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.";
339"";
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 ();
346