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