]>
Commit | Line | Data |
---|---|---|
37119410 | 1 | (* Auto-generate ARM ldm/stm patterns |
8d9254fc | 2 | Copyright (C) 2010-2020 Free Software Foundation, Inc. |
37119410 BS |
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: | |
f0433b26 | 29 | ocaml arm-ldmstm.ml >/path/to/gcc/config/arm/ldmstm.md |
37119410 BS |
30 | *) |
31 | ||
32 | type amode = IA | IB | DA | DB | |
33 | ||
34 | type optype = IN | OUT | INOUT | |
35 | ||
bae4ce0f RR |
36 | let rec string_of_addrmode addrmode thumb update = |
37 | if thumb || update | |
38 | then | |
37119410 | 39 | match addrmode with |
bae4ce0f RR |
40 | IA -> "ia" |
41 | | IB -> "ib" | |
42 | | DA -> "da" | |
43 | | DB -> "db" | |
44 | else | |
45 | match addrmode with | |
46 | IA -> "" | |
47 | | IB -> "ib" | |
48 | | DA -> "da" | |
49 | | DB -> "db" | |
37119410 BS |
50 | |
51 | let 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 | ||
58 | let 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 | ||
65 | let constr thumb = | |
66 | if thumb then "l" else "rk" | |
67 | ||
68 | let inout_constr op_type = | |
69 | match op_type with | |
70 | OUT -> "=&" | |
71 | | INOUT -> "+&" | |
72 | | IN -> "" | |
73 | ||
74 | let 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 | ||
9f178d6a CB |
81 | let reg_predicate thumb = |
82 | if thumb then "low_register_operand" else "arm_hard_general_register_operand" | |
83 | ||
37119410 BS |
84 | let write_ldm_set thumb nregs offset opnr first = |
85 | let indent = " " in | |
86 | Printf.printf "%s" (if first then " [" else indent); | |
9f178d6a | 87 | Printf.printf "(set (match_operand:SI %d \"%s\" \"\")\n" opnr (reg_predicate thumb); |
37119410 BS |
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 | ||
94 | let 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; | |
9f178d6a | 101 | Printf.printf ")\n%s (match_operand:SI %d \"%s\" \"\"))" indent opnr (reg_predicate thumb) |
37119410 BS |
102 | |
103 | let 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 | ||
109 | let 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 | ||
115 | let 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 | ||
121 | let 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 | ||
126 | let 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 | ||
132 | let 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 | ||
142 | let 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 | ||
151 | let 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 | ||
0e26bf3d KT |
163 | exception InvalidAddrMode of string;; |
164 | ||
37119410 BS |
165 | let 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" | |
0e26bf3d | 171 | | _, _ -> raise (InvalidAddrMode "ERROR: Invalid Addressing mode for Thumb1.") |
37119410 BS |
172 | |
173 | let write_pattern_1 name ls addrmode nregs write_set_fn update thumb = | |
bae4ce0f | 174 | let astr = string_of_addrmode addrmode thumb update in |
37119410 BS |
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); | |
bae4ce0f RR |
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 ""); | |
37119410 BS |
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; | |
0e26bf3d | 203 | if not thumb then begin |
37119410 | 204 | Printf.printf "\n (set_attr \"predicable\" \"yes\")"; |
0e26bf3d KT |
205 | if addrmode == IA || addrmode == DB then |
206 | Printf.printf "\n (set_attr \"predicable_short_it\" \"no\")"; | |
37119410 BS |
207 | end; |
208 | Printf.printf "])\n\n" | |
209 | ||
210 | let 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 | ||
216 | let 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 | ||
222 | let 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; | |
2d68f67f GY |
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); | |
37119410 BS |
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 | ||
262 | let 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 | ||
268 | let 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 | ||
278 | let 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 | ||
284 | let 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 | ||
294 | let 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 | ||
300 | let 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 | ||
308 | let 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 | ||
329 | let print_lines = List.iter (fun s -> Format.printf "%s@\n" s) | |
330 | ||
331 | (* Do it. *) | |
332 | ||
333 | let _ = | |
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 | ""; | |
8d9254fc | 338 | " Copyright (C) 2010-2020 Free Software Foundation, Inc."; |
37119410 BS |
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 (); |