added silence emitter for Projs and Phis
[libfirm] / ir / be / arm / arm_spec.pl
1 # Creation: 2006/02/13
2 # $Id$
3 # This is a template specification for the Firm-Backend
4
5 # the cpu architecture (ia32, ia64, mips, sparc, ppc, ...)
6
7 $arch = "arm";
8
9 # $comment_string = 'WIRHABENKEINEKOMMENTARE';
10 $comment_string = '/*';
11
12 # the number of additional opcodes you want to register
13 $additional_opcodes = 0;
14
15 # The node description is done as a perl hash initializer with the
16 # following structure:
17 #
18 # %nodes = (
19 #
20 # <op-name> => {
21 #   "op_flags"  => "N|L|C|X|I|F|Y|H|c|K",
22 #   "irn_flags" => "R|N|I"
23 #   "arity"     => "0|1|2|3 ... |variable|dynamic|any",
24 #   "state"     => "floats|pinned|mem_pinned|exc_pinned",
25 #   "args"      => [
26 #                    { "type" => "type 1", "name" => "name 1" },
27 #                    { "type" => "type 2", "name" => "name 2" },
28 #                    ...
29 #                  ],
30 #   "comment"   => "any comment for constructor",
31 #   "reg_req"   => { "in" => [ "reg_class|register" ], "out" => [ "reg_class|register|in_rX" ] },
32 #   "cmp_attr"  => "c source code for comparing node attributes",
33 #   "emit"      => "emit code with templates",
34 #   "rd_constructor" => "c source code which constructs an ir_node"
35 # },
36 #
37 # ... # (all nodes you need to describe)
38 #
39 # ); # close the %nodes initializer
40
41 # op_flags: flags for the operation, OPTIONAL (default is "N")
42 # the op_flags correspond to the firm irop_flags:
43 #   N   irop_flag_none
44 #   L   irop_flag_labeled
45 #   C   irop_flag_commutative
46 #   X   irop_flag_cfopcode
47 #   I   irop_flag_ip_cfopcode
48 #   F   irop_flag_fragile
49 #   Y   irop_flag_forking
50 #   H   irop_flag_highlevel
51 #   c   irop_flag_constlike
52 #   K   irop_flag_keep
53 #
54 # irn_flags: special node flags, OPTIONAL (default is 0)
55 # following irn_flags are supported:
56 #   R   rematerializeable
57 #   N   not spillable
58 #   I   ignore for register allocation
59 #
60 # state: state of the operation, OPTIONAL (default is "floats")
61 #
62 # arity: arity of the operation, MUST NOT BE OMITTED
63 #
64 # args:  the OPTIONAL arguments of the node constructor (debug, irg and block
65 #        are always the first 3 arguments and are always autmatically
66 #        created)
67 #        If this key is missing the following arguments will be created:
68 #        for i = 1 .. arity: ir_node *op_i
69 #        ir_mode *mode
70 #
71 # comment: OPTIONAL comment for the node constructor
72 #
73 # rd_constructor: for every operation there will be a
74 #      new_rd_<arch>_<op-name> function with the arguments from above
75 #      which creates the ir_node corresponding to the defined operation
76 #      you can either put the complete source code of this function here
77 #
78 #      This key is OPTIONAL. If omitted, the following constructor will
79 #      be created:
80 #      if (!op_<arch>_<op-name>) assert(0);
81 #      for i = 1 to arity
82 #         set in[i] = op_i
83 #      done
84 #      res = new_ir_node(db, irg, block, op_<arch>_<op-name>, mode, arity, in)
85 #      return res
86 #
87 # NOTE: rd_constructor and args are only optional if and only if arity is 0,1,2 or 3
88
89 # register types:
90 #   0 - no special type
91 #   1 - caller save (register must be saved by the caller of a function)
92 #   2 - callee save (register must be saved by the called function)
93 #   4 - ignore (do not assign this register)
94 # NOTE: Last entry of each class is the largest Firm-Mode a register can hold
95 %reg_classes = (
96   "general_purpose" => [
97                          { "name" => "r0", "type" => 1 },
98                          { "name" => "r1", "type" => 1 },
99                          { "name" => "r2", "type" => 1 },
100                          { "name" => "r3", "type" => 1 },
101                          { "name" => "r4", "type" => 2 },
102                          { "name" => "r5", "type" => 2 },
103                          { "name" => "r6", "type" => 2 },
104                          { "name" => "r7", "type" => 2 },
105                          { "name" => "r8", "type" => 2 },
106                          { "name" => "r9", "type" => 2 },
107                          { "name" => "r10", "type" => 2 },
108                          { "name" => "r11", "type" => 2 },
109                          { "name" => "r12", "type" => 6 }, # reserved for linker
110                          { "name" => "r13", "type" => 6 }, # this is our stack pointer
111                          { "name" => "r14", "type" => 3 }, # this is our return address
112                          { "name" => "r15", "type" => 6 }, # this is our program counter
113                                                  { "name" => "rxx", "type" => 6 }, # dummy register for no_mem
114                                                  { "name" => "MURX", "type" => 6 }, # this is our workaround-register
115                          { "mode" => "mode_P" }
116                        ],
117   "floating_point"  => [
118                          { "name" => "f0", "type" => 1 },
119                          { "name" => "f1", "type" => 1 },
120                          { "name" => "f2", "type" => 1 },
121                          { "name" => "f3", "type" => 1 },
122                          { "name" => "f4", "type" => 2 },
123                          { "name" => "f5", "type" => 2 },
124                          { "name" => "f6", "type" => 2 },
125                          { "name" => "f7", "type" => 2 },
126                                                  { "name" => "fxx", "type" => 6 }, # dummy register for no_mem
127                          { "mode" => "mode_D" }
128                        ]
129 ); # %reg_classes
130
131 #--------------------------------------------------#
132 #                        _                         #
133 #                       (_)                        #
134 #  _ __   _____      __  _ _ __    ___  _ __  ___  #
135 # | '_ \ / _ \ \ /\ / / | | '__|  / _ \| '_ \/ __| #
136 # | | | |  __/\ V  V /  | | |    | (_) | |_) \__ \ #
137 # |_| |_|\___| \_/\_/   |_|_|     \___/| .__/|___/ #
138 #                                      | |         #
139 #                                      |_|         #
140 #--------------------------------------------------#
141
142 %nodes = (
143
144 #-----------------------------------------------------------------#
145 #  _       _                                         _            #
146 # (_)     | |                                       | |           #
147 #  _ _ __ | |_ ___  __ _  ___ _ __   _ __   ___   __| | ___  ___  #
148 # | | '_ \| __/ _ \/ _` |/ _ \ '__| | '_ \ / _ \ / _` |/ _ \/ __| #
149 # | | | | | ||  __/ (_| |  __/ |    | | | | (_) | (_| |  __/\__ \ #
150 # |_|_| |_|\__\___|\__, |\___|_|    |_| |_|\___/ \__,_|\___||___/ #
151 #                   __/ |                                         #
152 #                  |___/                                          #
153 #-----------------------------------------------------------------#
154
155 # commutative operations
156
157 "Add" => {
158   "op_flags"  => "C",
159   "irn_flags" => "R",
160   "comment"   => "construct Add: Add(a, b) = Add(b, a) = a + b",
161   "reg_req"   => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
162   "emit"      => '. ADD %D1, %S1, %S2\t\t\t/* Add(%S1, %S2) -> %D1, (%A1, %A2) */'
163 },
164
165 "Add_i" => {
166   "irn_flags" => "R",
167   "comment"   => "construct Add: Add(a, const) = Add(const, a) = a + const",
168   "reg_req"   => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
169   "emit"      => '. ADD %D1, %S1, %C\t\t\t/* Add(%C, %S1) -> %D1, (%A1, const) */',
170   "cmp_attr"  =>
171 '    if (attr_a->value == NULL || attr_b->value == NULL)
172             return 1;
173
174     return get_tarval_long(attr_a->value) != get_tarval_long(attr_b->value);
175 '
176 },
177
178 "Mul" => {
179   #"op_flags"  => "C",
180   "irn_flags" => "R",
181   "comment"   => "construct Mul: Mul(a, b) = Mul(b, a) = a * b",
182   "reg_req"   => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "!in_r1" ] },
183   "emit"      =>'. MUL %D1, %S1, %S2\t\t\t/* Mul(%S1, %S2) -> %D1, (%A1, %A2) */'
184 },
185
186 "And" => {
187   "op_flags"  => "C",
188   "irn_flags" => "R",
189   "comment"   => "construct And: And(a, b) = And(b, a) = a AND b",
190   "reg_req"   => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
191   "emit"      => '. AND %D1, %S1, %S2\t\t/* And(%S1, %S2) -> %D1, (%A1, %A2) */'
192 },
193
194 "And_i" => {
195   "irn_flags" => "R",
196   "comment"   => "construct And: And(a, const) = And(const, a) = a AND const",
197   "reg_req"   => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
198   "emit"      => '. AND %D1, %S1, %C\t\t\t/* And(%C, %S1) -> %D1, (%A1, const) */',
199   "cmp_attr"  =>
200 '    if (attr_a->value == NULL || attr_b->value == NULL)
201             return 1;
202
203     return get_tarval_long(attr_a->value) != get_tarval_long(attr_b->value);
204 '
205 },
206
207 "Or" => {
208   "op_flags"  => "C",
209   "irn_flags" => "R",
210   "comment"   => "construct Or: Or(a, b) = Or(b, a) = a OR b",
211   "reg_req"   => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
212   "emit"      => '. ORR %D1, %S1, %S2\t\t/* Or(%S1, %S2) -> %D1, (%A1, %A2) */'
213 },
214
215 "Or_i" => {
216   "irn_flags" => "R",
217   "comment"   => "construct Or: Or(a, const) = Or(const, a) = a OR const",
218   "reg_req"   => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
219   "emit"      => '. ORR %D1, %S1, %C\t\t\t/* Or(%C, %S1) -> %D1, (%A1, const) */',
220   "cmp_attr"  =>
221 '    if (attr_a->value == NULL || attr_b->value == NULL)
222             return 1;
223
224     return get_tarval_long(attr_a->value) != get_tarval_long(attr_b->value);
225 '
226 },
227
228 "Or_Shl_i" => {
229   "irn_flags" => "R",
230   "comment"   => "construct Or with immediate shifter operand",
231   "reg_req"   => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
232   "emit"      => '. ORR %D1, %S1, %S2 LSL %C\t\t\t/* Or_Shl_i(%S1, %S2 << %C) -> %D1, (%A1, const) */',
233   "cmp_attr"  =>
234 '    if (attr_a->value == NULL || attr_b->value == NULL)
235             return 1;
236
237     return get_tarval_long(attr_a->value) != get_tarval_long(attr_b->value);
238 '
239 },
240
241 "Eor" => {
242   "op_flags"  => "C",
243   "irn_flags" => "R",
244   "comment"   => "construct Eor: Eor(a, b) = Eor(b, a) = a EOR b",
245   "reg_req"   => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
246   "emit"      => '. EOR %D1, %S1, %S2\t\t\t/* Xor(%S1, %S2) -> %D1, (%A1, %A2) */'
247 },
248
249 "Eor_i" => {
250   "irn_flags" => "R",
251   "comment"   => "construct Eor: Eor(a, const) = Eor(const, a) = a EOR const",
252   "reg_req"   => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
253   "emit"      => '. EOR %D1, %S1, %C\t\t\t/* Xor(%C, %S1) -> %D1, (%A1, const) */',
254   "cmp_attr"  =>
255 '    if (attr_a->value == NULL || attr_b->value == NULL)
256             return 1;
257
258     return get_tarval_long(attr_a->value) != get_tarval_long(attr_b->value);
259 '
260 },
261
262 # not commutative operations
263
264 "Sub" => {
265   "irn_flags" => "R",
266   "comment"   => "construct Sub: Sub(a, b) = a - b",
267   "reg_req"   => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
268   "emit"      => '. SUB %D1, %S1, %S2\t\t\t/* Sub(%S1, %S2) -> %D1, (%A1, %A2) */'
269 },
270
271 "Sub_i" => {
272   "irn_flags" => "R",
273   "comment"   => "construct Sub: Sub(a, const) = a - const",
274   "reg_req"   => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
275   "emit"      => '. SUB %D1, %S1, %C\t\t\t/* Sub(%S1, %C) -> %D1, (%A1, const) */',
276   "cmp_attr"  =>
277 '    if (attr_a->value == NULL || attr_b->value == NULL)
278             return 1;
279
280     return get_tarval_long(attr_a->value) != get_tarval_long(attr_b->value);
281 '
282 },
283
284 "Shl" => {
285   "irn_flags" => "R",
286   "comment"   => "construct Shl: Shl(a, b) = a << b",
287   "reg_req"   => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
288   "emit"      => '. MOV %D1, %S1, LSL %S2\t/* Shl(%S1, %S2) -> %D1, (%A1, %A2) */'
289 },
290
291 "Shl_i" => {
292   "irn_flags" => "R",
293   "comment"   => "construct Shl: Shl(a, const) = a << const",
294   "reg_req"   => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
295   "emit"      => '. MOV %D1, %S1, LSL %C\t\t\t/* Shl(%S1, %C) -> %D1, (%A1, const) */',
296   "cmp_attr"  =>
297 '    if (attr_a->value == NULL || attr_b->value == NULL)
298             return 1;
299
300     return get_tarval_long(attr_a->value) != get_tarval_long(attr_b->value);
301 '
302 },
303
304 "Shr" => {
305   "irn_flags" => "R",
306   "comment"   => "construct Shr: Shr(a, b) = a >> b",
307   "reg_req"   => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "in_r1" ] },
308   "emit"      => '. MOV %D1, %S1, LSR %S2\t\t\t/* Shr(%S1, %S2) -> %D1, (%A1, %A2) */'
309 },
310
311 "Shr_i" => {
312   "irn_flags" => "R",
313   "comment"   => "construct Shr: Shr(a, const) = a >> const",
314   "reg_req"   => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
315   "emit"      => '. MOV %D1, %S1, LSR %C\t\t\t/* Shr(%S1, %C) -> %D1, (%A1, const) */',
316   "cmp_attr"  =>
317 '    if (attr_a->value == NULL || attr_b->value == NULL)
318             return 1;
319
320     return get_tarval_long(attr_a->value) != get_tarval_long(attr_b->value);
321 '
322 },
323
324 "Shrs" => {
325   "irn_flags" => "R",
326   "comment"   => "construct Shrs: Shrs(a, b) = a >> b",
327   "reg_req"   => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "in_r1" ] },
328   "emit"      => '. MOV %D1, %S1, ASR %S2\t\t\t\t\t/* Shrs(%S1, %S2) -> %D1, (%A1, %A2) */'
329 },
330
331 "Shrs_i" => {
332   "irn_flags" => "R",
333   "comment"   => "construct Shrs: Shrs(a, const) = a >> const",
334   "reg_req"   => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
335   "emit"      => '. MOV %D1, %S1, ASR %C\t\t\t/* Shrs(%S1, %C) -> %D1, (%A1, const) */',
336   "cmp_attr"  =>
337 '    if (attr_a->value == NULL || attr_b->value == NULL)
338             return 1;
339
340     return get_tarval_long(attr_a->value) != get_tarval_long(attr_b->value);
341 '
342 },
343
344 #"Div" => {
345 #  "irn_flags" => "R",
346 #  "comment"   => "construct Div: Div(a, b) = a / b",
347 #  "reg_req"   => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
348 #  "emit"      =>'. div %S1, %S2, %D1\t\t\t/* div(%S1, %S2) -> %D1, (%A1, %A2) */'
349 #},
350 #
351 #"Div_i" => {
352 #  "irn_flags" => "R",
353 #  "comment"   => "construct Div: Div(a, const) = a / const",
354 #  "reg_req"   => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
355 #  "emit"      => '. div %S1, %C, %D1\t\t\t/* signed div(%C, %S1) -> %D1, (%A1, const) */'
356 #},
357 #
358 #"Mod" => {
359 #  "irn_flags" => "R",
360 #  "comment"   => "construct Mod: Mod(a, b) = a % b",
361 #  "reg_req"   => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
362 #  "emit"      =>'. mod %S1, %S2, %D1\t\t\t/* mod(%S1, %S2) -> %D1, (%A1, %A2) */'
363 #},
364 #
365 #"Mod_i" => {
366 #  "irn_flags" => "R",
367 #  "comment"   => "construct mod: Mod(a, const) = a % const",
368 #  "reg_req"   => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
369 #  "emit"      => '. mod %S1, %C, %D1\t\t\t/* mod(%C, %S1) -> %D1, (%A1, const) */'
370 #},
371 #
372 #"DivMod" => {
373 #  "irn_flags" => "R",
374 #  "comment"   => "construct DivMod: DivMod(a, b) = a / b",
375 #  "reg_req"   => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
376 #  "emit"      =>'. div %S1, %S2, %D1\t\t\t/* div(%S1, %S2) -> %D1, (%A1, %A2) */'
377 #},
378 #
379 #"Div_i" => {
380 #  "irn_flags" => "R",
381 #  "comment"   => "construct DivMod: DivMod(a, const) = a / const",
382 #  "reg_req"   => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
383 #  "emit"      => '. div %S1, %C, %D1\t\t\t/* signed div(%C, %S1) -> %D1, (%A1, const) */'
384 #},
385
386 #"RotR" => {
387 #  "irn_flags" => "R",
388 #  "comment"   => "construct RotR: RotR(a, b) = a ROTR b",
389 #  "reg_req"   => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
390 #  "emit"      => '. MOV %D1, %S1, ROR %S2\t\t\t/* RotR(%S1, %S2) -> %D1, (%A1, %A2) */'
391 ##  "emit"      => '. ror %S1, %S2, %D1\t\t\t/* RotR(%S1, %S2) -> %D1, (%A1, %A2) */'
392 #},
393
394 #"RotL" => {
395 #  "irn_flags" => "R",
396 #  "comment"   => "construct RotL: RotL(a, b) = a ROTL b",
397 #  "reg_req"   => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
398 #  "emit"      => '. rol %S1, %S2, %D1\t\t\t/* RotL(%S1, %S2) -> %D1, (%A1, %A2) */'
399 #},
400
401 #"RotL_i" => {
402 #  "irn_flags" => "R",
403 #  "comment"   => "construct RotL: RotL(a, const) = a ROTL const",
404 #  "reg_req"   => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
405 #  "emit"      => '. rol %S1, %C, %D1\t\t\t/* RotL(%S1, %C) -> %D1, (%A1, const) */'
406 #},
407
408 "Minus" => {
409   "irn_flags" => "R",
410   "comment"   => "construct Minus: Minus(a) = -a",
411   "reg_req"   => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
412   "emit"      => '. RSB %D1, %S1, #0\t\t\t/* Neg(%S1) -> %D1, (%A1) */'
413 },
414
415 #"Inc" => {
416 #  "irn_flags" => "R",
417 #  "comment"   => "construct Increment: Inc(a) = a++",
418 #  "reg_req"   => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
419 #  "emit"      => '. inc %S1, %D1\t\t\t/* Inc(%S1) -> %D1, (%A1) */'
420 #},
421 #
422 #"Dec" => {
423 #  "irn_flags" => "R",
424 #  "comment"   => "construct Decrement: Dec(a) = a--",
425 #  "reg_req"   => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
426 #  "emit"      => '. dec %S1, %D1\t\t\t/* Dec(%S1) -> %D1, (%A1) */'
427 #},
428
429 "Not" => {
430   "arity"       => 1,
431 #  "remat"       => 1,
432   "irn_flags"   => "R",
433   "comment"     => "construct Not: Not(a) = !a",
434   "reg_req"     => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
435   "emit"        => '. MVN %D1, %S1\t\t\t/* Not(%S1) -> %D1, (%A1) */'
436 },
437
438 "Abs" => {
439   "irn_flags" => "R",
440   "comment"   => "construct Abs: Abs(a) = |a|",
441   "reg_req"   => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
442   "emit"      =>
443 '. MOVS %S1, %S1, #0\t\t\t/* set condition flag */\n
444 . RSBMI %D1, %S1, #0\t\t\t/* Neg(%S1) -> %D1, (%A1) */'
445 },
446
447 # other operations
448
449 "EmptyReg" => {
450   "op_flags"  => "c",
451   "irn_flags" => "R",
452   "comment"  => "just to get an emptz register for calculations",
453   "reg_req"  => { "out" => [ "general_purpose" ] },
454   "emit"      => '. /* %D1 now available for calculations */',
455   "cmp_attr"  => 'return 1;'
456 },
457
458 "Copy" => {
459   "comment"  => "implements a register copy",
460   "reg_req"  => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
461 },
462
463 "CopyB" => {
464   "op_flags" => "F|H",
465   "state"    => "pinned",
466   "comment"  => "implements a memcopy: CopyB(dst, src, size, mem) == memcpy(dst, src, size)",
467   "reg_req"  => { "in" => [ "!r13", "!r13", "general_purpose", "general_purpose", "general_purpose", "none" ], "out" => [ "none" ] },
468 },
469
470 "Const" => {
471   "irn_flags" => "R",
472   "comment"   => "represents an integer constant",
473   "reg_req"   => { "out" => [ "general_purpose" ] },
474   "emit"      => '. MOV %D1, %C  \t\t\t/* Mov Const into register */',
475   "cmp_attr"  =>
476 '    if (attr_a->value == NULL || attr_b->value == NULL)
477             return 1;
478
479     return get_tarval_long(attr_a->value) != get_tarval_long(attr_b->value);
480 '
481 },
482
483 "Const_Neg" => {
484   "irn_flags" => "R",
485   "comment"   => "represents a negated integer constant",
486   "reg_req"   => { "out" => [ "general_purpose" ] },
487   "emit"      => '. MVN %D1, %C  \t\t\t/* Mov negated Const into register */',
488   "cmp_attr"  =>
489 '    if (attr_a->value == NULL || attr_b->value == NULL)
490             return 1;
491
492     return get_tarval_long(attr_a->value) != get_tarval_long(attr_b->value);
493 '
494 },
495
496 "SymConst" => {
497   "op_flags"  => "c",
498   "irn_flags" => "R",
499   "comment"   => "represents a symbolic constant",
500   "reg_req"   => { "out" => [ "general_purpose" ] },
501 #  "emit"      => '. LDR %D1, %C\t\t\t/* Mov Const into register */',
502   "cmp_attr"  =>
503 '    if (attr_a->value == NULL || attr_b->value == NULL)
504             return 1;
505
506     return get_tarval_long(attr_a->value) != get_tarval_long(attr_b->value);
507 '
508 },
509
510 "CondJmp" => {
511   "op_flags"  => "L|X|Y",
512   "comment"   => "construct conditional jump: CMP A, B && JMPxx LABEL",
513   "cmp_attr"  => "  return arm_comp_condJmp(attr_a, attr_b);\n",
514   "reg_req"   => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "none", "none"] },
515 },
516
517 "SwitchJmp" => {
518   "op_flags"  => "L|X|Y",
519   "comment"   => "construct switch",
520   "reg_req"   => { "in" => [ "general_purpose" ], "out" => [ "none" ] },
521   "cmp_attr"  => "  return 0;\n",
522 },
523
524 # Load / Store
525
526 "Load" => {
527   "op_flags"  => "L|F",
528   "irn_flags" => "R",
529   "state"     => "exc_pinned",
530   "comment"   => "construct Load: Load(ptr, mem) = LD ptr -> reg",
531   "reg_req"   => { "in" => [ "general_purpose", "none" ], "out" => [ "general_purpose" ] },
532   "emit"      => '. LDR %D1, [%S1, #0]\t\t\t/* Load((%S1)) -> %D1, (%A1) */'
533 #  "emit"      => '. LDR %D1, %S1, %O\t\t\t/* Load((%S1)) -> %D1, (%A1) */'
534 },
535
536 "Loadb" => {
537   "op_flags"  => "L|F",
538   "irn_flags" => "R",
539   "state"     => "exc_pinned",
540   "comment"   => "construct Load: Load(ptr, mem) = LD ptr -> reg",
541   "reg_req"   => { "in" => [ "general_purpose", "none" ], "out" => [ "general_purpose" ] },
542   "emit"      => '. LDRB %D1, [%S1, #0]\t\t\t/* Load((%S1)) -> %D1, (%A1) */'
543 #  "emit"      => '. LDRB %D1, %S1, %O\t\t\t/* Load((%S1)) -> %D1, (%A1) */'
544 },
545
546 "Loadbs" => {
547   "op_flags"  => "L|F",
548   "irn_flags" => "R",
549   "state"     => "exc_pinned",
550   "comment"   => "construct Load: Load(ptr, mem) = LD ptr -> reg",
551   "reg_req"   => { "in" => [ "general_purpose", "none" ], "out" => [ "general_purpose" ] },
552   "emit"      => '. LDRSB %D1, [%S1, #0]\t\t\t/* Load((%S1)) -> %D1, (%A1) */'
553 #  "emit"      => '. LDRSB %D1, %S1, %O\t\t\t/* Load((%S1)) -> %D1, (%A1) */'
554 },
555
556 "Loadh" => {
557   "op_flags"  => "L|F",
558   "irn_flags" => "R",
559   "state"     => "exc_pinned",
560   "comment"   => "construct Load: Load(ptr, mem) = LD ptr -> reg",
561   "reg_req"   => { "in" => [ "general_purpose", "none" ], "out" => [ "general_purpose" ] },
562   "emit"      => '. LDRH %D1, [%S1, #0]\t\t\t/* Load((%S1)) -> %D1, (%A1) */'
563 #  "emit"      => '. LDRH %D1, %S1, %O\t\t\t/* Load((%S1)) -> %D1, (%A1) */'
564 },
565
566 "Loadhs" => {
567   "op_flags"  => "L|F",
568   "irn_flags" => "R",
569   "state"     => "exc_pinned",
570   "comment"   => "construct Load: Load(ptr, mem) = LD ptr -> reg",
571   "reg_req"   => { "in" => [ "general_purpose", "none" ], "out" => [ "general_purpose" ] },
572   "emit"      => '. LDRSH %D1, [%S1, #0]\t\t\t/* Load((%S1)) -> %D1, (%A1) */'
573 #  "emit"      => '. LDRSH %D1, %S1, %O\t\t\t/* Load((%S1)) -> %D1, (%A1) */'
574 },
575
576 "Storeb" => {
577   "op_flags"  => "L|F",
578   "irn_flags" => "R",
579   "state"     => "exc_pinned",
580   "comment"   => "construct Store: Store(ptr, val, mem) = ST ptr,val",
581   "reg_req"   => { "in" => [ "general_purpose", "general_purpose", "none" ] },
582   "emit"      => '. STRB %S2, [%S1, #0]\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */'
583 #  "emit"      => '. movl %S2, %O(%S1)\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */'
584 },
585
586 "Storebs" => {
587   "op_flags"  => "L|F",
588   "irn_flags" => "R",
589   "state"     => "exc_pinned",
590   "comment"   => "construct Store: Store(ptr, val, mem) = ST ptr,val",
591   "reg_req"   => { "in" => [ "general_purpose", "general_purpose", "none" ] },
592   "emit"      => '. STRSB %S2, [%S1, #0]\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */'
593 #  "emit"      => '. movl %S2, %O(%S1)\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */'
594 },
595
596 "Storeh" => {
597   "op_flags"  => "L|F",
598   "irn_flags" => "R",
599   "state"     => "exc_pinned",
600   "comment"   => "construct Store: Store(ptr, val, mem) = ST ptr,val",
601   "reg_req"   => { "in" => [ "general_purpose", "general_purpose", "none" ] },
602   "emit"      => '. STRH %S2, [%S1, #0]\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */'
603 #  "emit"      => '. movl %S2, %O(%S1)\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */'
604 },
605
606 "Storehs" => {
607   "op_flags"  => "L|F",
608   "irn_flags" => "R",
609   "state"     => "exc_pinned",
610   "comment"   => "construct Store: Store(ptr, val, mem) = ST ptr,val",
611   "reg_req"   => { "in" => [ "general_purpose", "general_purpose", "none" ] },
612   "emit"      => '. STRSH%S2, [%S1, #0]\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */'
613 #  "emit"      => '. movl %S2, %O(%S1)\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */'
614 },
615
616 "Store" => {
617   "op_flags"  => "L|F",
618   "irn_flags" => "R",
619   "state"     => "exc_pinned",
620   "comment"   => "construct Store: Store(ptr, val, mem) = ST ptr,val",
621   "reg_req"   => { "in" => [ "general_purpose", "general_purpose", "none" ] },
622   "emit"      => '. STR %S2, [%S1, #0]\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */'
623 #  "emit"      => '. movl %S2, %O(%S1)\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */'
624 },
625
626 "StoreStackM4Inc" => {
627   "op_flags"  => "L|F",
628   "irn_flags" => "R",
629   "state"     => "exc_pinned",
630   "comment"   => "construct Store: Store(ptr, val, mem) = ST ptr,val",
631   "reg_req"   => { "in" => [ "r13", "general_purpose", "general_purpose", "general_purpose", "general_purpose", "none" ], "out" => [ "general_purpose", "none" ] },
632   "emit"      => '. STMFD %S1!, {%S2, %S3, %S4, %S5}\t\t\t/* Store multiple on Stack*/'
633 },
634
635 "LoadStackM3" => {
636   "op_flags"  => "L|F",
637   "irn_flags" => "R",
638   "state"     => "exc_pinned",
639   "comment"   => "construct Load: Load(ptr, mem) = LD ptr -> reg",
640   "reg_req"   => { "in" => [ "r13", "none" ], "out" => [ "general_purpose", "general_purpose", "general_purpose", "none" ] },
641   "emit"      => '. LDMFD %S1, {%D1, %D2, %D3}\t\t\t/* Load multiple from Stack */'
642 },
643
644
645
646
647
648
649
650
651 #--------------------------------------------------------#
652 #    __ _             _                     _            #
653 #   / _| |           | |                   | |           #
654 #  | |_| | ___   __ _| |_   _ __   ___   __| | ___  ___  #
655 #  |  _| |/ _ \ / _` | __| | '_ \ / _ \ / _` |/ _ \/ __| #
656 #  | | | | (_) | (_| | |_  | | | | (_) | (_| |  __/\__ \ #
657 #  |_| |_|\___/ \__,_|\__| |_| |_|\___/ \__,_|\___||___/ #
658 #--------------------------------------------------------#
659
660 # commutative operations
661
662 "fAddd" => {
663   "op_flags"  => "C",
664   "irn_flags" => "R",
665   "comment"   => "construct DP FP Add: Add(a, b) = Add(b, a) = a + b",
666   "reg_req"   => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] },
667   "emit"      => '. FADDD %D1, %S1, %S2\t\t\t/* FP Add(%S1, %S2) -> %D1 */'
668 },
669
670 "fAdds" => {
671   "op_flags"  => "C",
672   "irn_flags" => "R",
673   "comment"   => "construct SP FP Add: Add(a, b) = Add(b, a) = a + b",
674   "reg_req"   => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] },
675   "emit"      => '. FADDS %D1, %S1, %S2\t\t\t/* FP Add(%S1, %S2) -> %D1 */'
676 },
677
678 "fMuls" => {
679   "op_flags"  => "C",
680   "comment"   => "construct FP Mul: Mul(a, b) = Mul(b, a) = a * b",
681   "reg_req"   => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] },
682   "emit"      =>'. FMULS %D1, %S1, %S2\t\t\t/* FP Mul(%S1, %S2) -> %D1 */'
683 },
684
685 "fMuld" => {
686   "op_flags"  => "C",
687   "comment"   => "construct FP Mul: Mul(a, b) = Mul(b, a) = a * b",
688   "reg_req"   => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] },
689   "emit"      =>'. FMULD %D1, %S1, %S2\t\t\t/* FP Mul(%S1, %S2) -> %D1 */'
690 },
691
692 "fDivs" => {
693   "comment"   => "construct FP Div: Div(a, b) = a / b",
694   "reg_req"   => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] },
695   "emit"      =>'. FDIVS %D1, %S1, %S2\t\t\t/* FP Div(%S1, %S2) -> %D1 */'
696 },
697
698 "fDivd" => {
699   "comment"   => "construct FP Div: Div(a, b) = a / b",
700   "reg_req"   => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] },
701   "emit"      =>'. FDIVD %D1, %S1, %S2\t\t\t/* FP Div(%S1, %S2) -> %D1 */'
702 },
703
704 "fDiv" => {
705   "comment"   => "construct FP Div: Div(a, b) = a / b",
706   "reg_req"   => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] },
707   "emit"      =>'. FDIV %D1, %S1, %S2\t\t\t/* FP Div(%S1, %S2) -> %D1 */'
708 },
709
710 "fMax" => {
711   "op_flags"  => "C",
712   "irn_flags" => "R",
713   "comment"   => "construct FP Max: Max(a, b) = Max(b, a) = a > b ? a : b",
714   "reg_req"   => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] },
715   "emit"      =>'. fmax %S1, %S2, %D1\t\t\t/* FP Max(%S1, %S2) -> %D1 */'
716 },
717
718 "fMin" => {
719   "op_flags"  => "C",
720   "irn_flags" => "R",
721   "comment"   => "construct FP Min: Min(a, b) = Min(b, a) = a < b ? a : b",
722   "reg_req"   => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] },
723   "emit"      =>'. fmin %S1, %S2, %D1\t\t\t/* FP Min(%S1, %S2) -> %D1 */'
724 },
725
726 # not commutative operations
727
728 "fSubs" => {
729   "irn_flags" => "R",
730   "comment"   => "construct FP Sub: Sub(a, b) = a - b",
731   "reg_req"   => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] },
732   "emit"      => '. FSUBS %D1, %S1, %S2\t\t\t/* FP Sub(%S1, %S2) -> %D1 */'
733 },
734
735 "fSubd" => {
736   "irn_flags" => "R",
737   "comment"   => "construct FP Sub: Sub(a, b) = a - b",
738   "reg_req"   => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] },
739   "emit"      => '. FSUBD %D1, %S1, %S2\t\t\t/* FP Sub(%S1, %S2) -> %D1 */'
740 },
741
742 "fMinus" => {
743   "irn_flags" => "R",
744   "comment"   => "construct FP Minus: Minus(a) = -a",
745   "reg_req"   => { "in" => [ "floating_point" ], "out" => [ "floating_point" ] },
746   "emit"      => '. fneg %S1, %D1\t\t\t/* FP Minus(%S1) -> %D1 */'
747 },
748
749 "fAbss" => {
750   "irn_flags" => "R",
751   "comment"   => "construct FP Absolute value: fAbss(a) = |a|",
752   "reg_req"   => { "in" => [ "floating_point" ], "out" => [ "floating_point" ] },
753   "emit"      => '. FABSS %D1, %S1\t\t\t/* FP Abss(%S1) -> %D1 */'
754 },
755
756 "fAbsd" => {
757   "irn_flags" => "R",
758   "comment"   => "construct FP Absolute value: fAbsd(a) = |a|",
759   "reg_req"   => { "in" => [ "floating_point" ], "out" => [ "floating_point" ] },
760   "emit"      => '. FABSD %D1, %S1\t\t\t/* FP Absd(%S1) -> %D1 */'
761 },
762
763 # other operations
764
765 "fConst" => {
766   "op_flags"  => "c",
767   "irn_flags" => "R",
768   "comment"   => "represents a FP constant",
769   "reg_req"   => { "out" => [ "floating_point" ] },
770   "emit"      => '. FMOV %D1, %C\t\t\t/* Mov fConst into register */',
771   "cmp_attr"  =>
772 '    if (attr_a->value == NULL || attr_b->value == NULL)
773             return 1;
774
775         return get_tarval_double(attr_a->value) != get_tarval_double(attr_b->value);'
776 },
777
778 "fConvD2S" => {
779   "irn_flags" => "R",
780   "comment"   => "convert double to single",
781   "reg_req"   => { "in" => [ "floating_point" ], "out" => [ "floating_point" ] },
782   "emit"      => '. FCVTSD %D1, %S1\t\t\t/* Convert double to single */',
783 },
784
785 "fConvS2D" => {
786   "irn_flags" => "R",
787   "comment"   => "convert single to double",
788   "reg_req"   => { "in" => [ "floating_point" ], "out" => [ "floating_point" ] },
789   "emit"      => '. FCVTDS %D1, %S1\t\t\t/* Convert single to double */',
790 },
791
792
793 # Load / Store
794
795 "fLoads" => {
796   "op_flags"  => "L|F",
797   "irn_flags" => "R",
798   "state"     => "exc_pinned",
799   "comment"   => "construct FP Load: Load(ptr, mem) = LD ptr",
800   "reg_req"   => { "in" => [ "general_purpose", "none" ], "out" => [ "floating_point" ] },
801   "emit"      => '. FLDS %D1, %S1\t\t\t/* Load((%S1)) -> %D1 */'
802 #  "emit"      => '. fmov %O(%S1), %D1\t\t\t/* Load((%S1)) -> %D1 */'
803 },
804
805 "fLoadd" => {
806   "op_flags"  => "L|F",
807   "irn_flags" => "R",
808   "state"     => "exc_pinned",
809   "comment"   => "construct FP Load: Load(ptr, mem) = LD ptr",
810   "reg_req"   => { "in" => [ "general_purpose", "none" ], "out" => [ "floating_point" ] },
811   "emit"      => '. FLDD %D1, %S1\t\t\t/* Load((%S1)) -> %D1 */'
812 #  "emit"      => '. fmov %O(%S1), %D1\t\t\t/* Load((%S1)) -> %D1 */'
813 },
814
815 "fStores" => {
816   "op_flags"  => "L|F",
817   "irn_flags" => "R",
818   "state"     => "exc_pinned",
819   "comment"   => "construct Store: Store(ptr, val, mem) = ST ptr,val",
820   "reg_req"   => { "in" => [ "general_purpose", "floating_point", "none" ] },
821   "emit"      => '. FSTS %S2, %S1\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */'
822 },
823
824 "fStored" => {
825   "op_flags"  => "L|F",
826   "irn_flags" => "R",
827   "state"     => "exc_pinned",
828   "comment"   => "construct Store: Store(ptr, val, mem) = ST ptr,val",
829   "reg_req"   => { "in" => [ "general_purpose", "floating_point", "none" ] },
830   "emit"      => '. FSTD %S2, %S1\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */'
831 },
832
833 ); # end of %nodes