3 # This is a template specification for the Firm-Backend
5 # the cpu architecture (ia32, ia64, mips, sparc, ppc, ...)
9 # The node description is done as a perl hash initializer with the
10 # following structure:
15 # "op_flags" => "N|L|C|X|I|F|Y|H|c|K",
16 # "arity" => "0|1|2|3|variable|dynamic|all",
17 # "state" => "floats|pinned",
19 # { "type" => "type 1", "name" => "name 1" },
20 # { "type" => "type 2", "name" => "name 2" },
23 # "comment" => "any comment for constructor",
24 # "rd_constructor" => "c source code which constructs an ir_node"
27 # ... # (all nodes you need to describe)
29 # ); # close the %nodes initializer
31 # the op_flags correspond to the firm irop_flags:
34 # C irop_flag_commutative
35 # X irop_flag_cfopcode
36 # I irop_flag_ip_cfopcode
39 # H irop_flag_highlevel
40 # c irop_flag_constlike
43 # op_flags: flags for the operation, OPTIONAL (default is "N")
45 # state: state of the operation, OPTIONAL (default is "pinned")
47 # arity: arity of the operation, MUST NOT BE OMITTED
49 # args: the OPTIONAL arguments of the node constructor (debug, irg and block
50 # are always the first 3 arguments and are always autmatically
52 # If this key is missing the following arguments will be created:
53 # for i = 1 .. arity: ir_node *op_i
56 # comment: OPTIONAL comment for the node constructor
58 # rd_constructor: for every operation there will be a
59 # new_rd_<arch>_<op-name> function with the arguments from above
60 # which creates the ir_node corresponding to the defined operation
61 # you can either put the complete source code of this function here
63 # This key is OPTIONAL. If omitted, the following constructor will
65 # if (!op_<arch>_<op-name>) assert(0);
69 # res = new_ir_node(db, irg, block, op_<arch>_<op-name>, mode, arity, in)
72 # NOTE: rd_constructor and args are only optional if and only if arity is 0,1,2 or 3
76 # 1 - write invariant (writes to this register doesn't change it's content)
77 # 2 - caller save (register must be saved by the caller of a function)
78 # 3 - callee save (register must be saved by the called function)
79 # 4 - ignore (do not assign this register)
80 # NOTE: Make sure to list the registers returning the call-result before all other
81 # caller save registers and in the correct order, otherwise it will break
85 "general_purpose" => [
86 { "name" => "r0", "type" => 2 },
87 { "name" => "r1", "type" => 2 },
88 { "name" => "r2", "type" => 3 },
89 { "name" => "r3", "type" => 2 },
90 { "name" => "r4", "type" => 3 },
91 { "name" => "r5", "type" => 3 },
92 { "name" => "r6", "type" => 4 }, # this is our stackpointer
93 { "name" => "r7", "type" => 3 },
94 { "name" => "r8", "type" => 3 },
95 { "name" => "r9", "type" => 3 },
96 { "name" => "r10", "type" => 3 },
97 { "name" => "r11", "type" => 3 },
98 { "name" => "r12", "type" => 3 },
99 { "name" => "r13", "type" => 3 },
100 { "name" => "r14", "type" => 3 },
101 { "name" => "r15", "type" => 3 }
103 "floating_point" => [
104 { "name" => "f0", "type" => 2 },
105 { "name" => "f1", "type" => 2 },
106 { "name" => "f2", "type" => 2 },
107 { "name" => "f3", "type" => 2 },
108 { "name" => "f4", "type" => 2 },
109 { "name" => "f5", "type" => 2 },
110 { "name" => "f6", "type" => 2 },
111 { "name" => "f7", "type" => 2 },
112 { "name" => "f8", "type" => 2 },
113 { "name" => "f9", "type" => 2 },
114 { "name" => "f10", "type" => 2 },
115 { "name" => "f11", "type" => 2 },
116 { "name" => "f12", "type" => 2 },
117 { "name" => "f13", "type" => 2 },
118 { "name" => "f14", "type" => 2 },
119 { "name" => "f15", "type" => 2 }
123 #--------------------------------------------------#
126 # _ __ _____ __ _ _ __ ___ _ __ ___ #
127 # | '_ \ / _ \ \ /\ / / | | '__| / _ \| '_ \/ __| #
128 # | | | | __/\ V V / | | | | (_) | |_) \__ \ #
129 # |_| |_|\___| \_/\_/ |_|_| \___/| .__/|___/ #
132 #--------------------------------------------------#
136 #-----------------------------------------------------------------#
139 # _ _ __ | |_ ___ __ _ ___ _ __ _ __ ___ __| | ___ ___ #
140 # | | '_ \| __/ _ \/ _` |/ _ \ '__| | '_ \ / _ \ / _` |/ _ \/ __| #
141 # | | | | | || __/ (_| | __/ | | | | | (_) | (_| | __/\__ \ #
142 # |_|_| |_|\__\___|\__, |\___|_| |_| |_|\___/ \__,_|\___||___/ #
145 #-----------------------------------------------------------------#
147 # commutative operations
153 "comment" => "construct Add: Add(a, b) = Add(b, a) = a + b",
154 "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
155 "emit" => '. add %S1, %S2, %D1\t\t\t/* Add(%S1, %S2) -> %D1, (%A1, %A2) */'
161 "comment" => "construct Add: Add(a, const) = Add(const, a) = a + const",
162 "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
163 "emit" => '. add %S1, %C, %D1\t\t\t/* Add(%C, %S1) -> %D1, (%A1, const) */'
169 "comment" => "construct Mul: Mul(a, b) = Mul(b, a) = a * b",
170 "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
171 "emit" =>'. mul %S1, %S2, %D1\t\t\t/* Mul(%S1, %S2) -> %D1, (%A1, %A2) */'
177 "comment" => "construct Mul: Mul(a, const) = Mul(const, a) = a * const",
178 "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
179 "emit" => '. mul %S1, %C, %D1\t\t\t/* signed Mul(%C, %S1) -> %D1, (%A1, const) */'
186 "comment" => "construct And: And(a, b) = And(b, a) = a AND b",
187 "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
188 "emit" => '. and %S1, %S2, %D1\t\t\t/* And(%S1, %S2) -> %D1, (%A1, %A2) */'
194 "comment" => "construct And: And(a, const) = And(const, a) = a AND const",
195 "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
196 "emit" => '. and %S1, %C, %D1\t\t\t/* And(%C, %S1) -> %D1, (%A1, const) */'
203 "comment" => "construct Or: Or(a, b) = Or(b, a) = a OR b",
204 "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
205 "emit" => '. or %S1, %S2, %D1\t\t\t/* Or(%S1, %S2) -> %D1, (%A1, %A2) */'
211 "comment" => "construct Or: Or(a, const) = Or(const, a) = a OR const",
212 "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
213 "emit" => '. or %S1, %C, %D1\t\t\t/* Or(%C, %S1) -> %D1, (%A1, const) */'
220 "comment" => "construct Eor: Eor(a, b) = Eor(b, a) = a EOR b",
221 "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
222 "emit" => '. xor %S1, %S2, %D1\t\t\t/* Xor(%S1, %S2) -> %D1, (%A1, %A2) */'
228 "comment" => "construct Eor: Eor(a, const) = Eor(const, a) = a EOR const",
229 "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
230 "emit" => '. xor %S1, %C, %D1\t\t\t/* Xor(%C, %S1) -> %D1, (%A1, const) */'
233 # not commutative operations
238 "comment" => "construct Sub: Sub(a, b) = a - b",
239 "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
240 "emit" => '. sub %S1, %S2, %D1\t\t\t/* Sub(%S1, %S2) -> %D1, (%A1, %A2) */'
246 "comment" => "construct Sub: Sub(a, const) = a - const",
247 "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
248 "emit" => '. subl %S1, %C, %D1\t\t\t/* Sub(%S1, %C) -> %D1, (%A1, const) */'
254 "comment" => "construct Shl: Shl(a, b) = a << b",
255 "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
256 "emit" => '. shl %S1, %S2, %D1\t\t\t/* Shl(%S1, %S2) -> %D1, (%A1, %A2) */'
262 "comment" => "construct Shl: Shl(a, const) = a << const",
263 "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
264 "emit" => '. shl %S1, %C, %D1\t\t\t/* Shl(%S1, %C) -> %D1, (%A1, const) */'
270 "comment" => "construct Shr: Shr(a, b) = a >> b",
271 "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "in_r1" ] },
272 "emit" => '. shr %S2, %D1\t\t\t/* Shr(%S1, %S2) -> %D1, (%A1, %A2) */'
278 "comment" => "construct Shr: Shr(a, const) = a >> const",
279 "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
280 "emit" => '. shr %S1, %C, %D1\t\t\t/* Shr(%S1, %C) -> %D1, (%A1, const) */'
286 "comment" => "construct RotR: RotR(a, b) = a ROTR b",
287 "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
288 "emit" => '. ror %S1, %S2, %D1\t\t\t/* RotR(%S1, %S2) -> %D1, (%A1, %A2) */'
294 "comment" => "construct RotL: RotL(a, b) = a ROTL b",
295 "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
296 "emit" => '. rol %S1, %S2, %D1\t\t\t/* RotL(%S1, %S2) -> %D1, (%A1, %A2) */'
302 "comment" => "construct RotL: RotL(a, const) = a ROTL const",
303 "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
304 "emit" => '. rol %S1, %C, %D1\t\t\t/* RotL(%S1, %C) -> %D1, (%A1, const) */'
310 "comment" => "construct Minus: Minus(a) = -a",
311 "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
312 "emit" => '. neg %S1, %D1\t\t\t/* Neg(%S1) -> %D1, (%A1) */'
318 "comment" => "construct Increment: Inc(a) = a++",
319 "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
320 "emit" => '. inc %S1, %D1\t\t\t/* Inc(%S1) -> %D1, (%A1) */'
326 "comment" => "construct Decrement: Dec(a) = a--",
327 "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
328 "emit" => '. dec %S1, %D1\t\t\t/* Dec(%S1) -> %D1, (%A1) */'
334 "comment" => "construct Not: Not(a) = !a",
335 "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
336 "emit" => '. not %S1, %D1\t\t\t/* Not(%S1) -> %D1, (%A1) */'
345 "comment" => "represents an integer constant",
346 "reg_req" => { "out" => [ "general_purpose" ] },
347 "emit" => '. mov %C, %D1\t\t\t/* Mov Const into register */',
350 if (attr_a->tp == attr_b->tp) {
351 if (attr_a->tp == asmop_SymConst) {
352 if (attr_a->old_ir == NULL || attr_b->old_ir == NULL)
355 return strcmp(get_sc_name(attr_a->old_ir), get_sc_name(attr_b->old_ir));
358 if (attr_a->old_ir == NULL || attr_b->old_ir == NULL)
361 if (tarval_cmp(attr_a->tv, attr_b->tv) == pn_Cmp_Eq)
376 "state" => "exc_pinned",
379 "comment" => "construct Load: Load(ptr, mem) = LD ptr -> reg",
380 "reg_req" => { "in" => [ "general_purpose", "none" ], "out" => [ "general_purpose" ] },
381 "emit" => '. mov %O(%S1), %D1\t\t\t/* Load((%S1)) -> %D1, (%A1) */'
386 "state" => "exc_pinned",
389 "comment" => "construct Store: Store(ptr, val, mem) = ST ptr,val",
390 "reg_req" => { "in" => [ "general_purpose", "general_purpose", "none" ] },
391 "emit" => '. movl %S2, %O(%S1)\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */'
394 #--------------------------------------------------------#
397 # | |_| | ___ __ _| |_ _ __ ___ __| | ___ ___ #
398 # | _| |/ _ \ / _` | __| | '_ \ / _ \ / _` |/ _ \/ __| #
399 # | | | | (_) | (_| | |_ | | | | (_) | (_| | __/\__ \ #
400 # |_| |_|\___/ \__,_|\__| |_| |_|\___/ \__,_|\___||___/ #
401 #--------------------------------------------------------#
403 # commutative operations
409 "comment" => "construct FP Add: Add(a, b) = Add(b, a) = a + b",
410 "reg_req" => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] },
411 "emit" => '. fadd %S1, %S2, %D1\t\t\t/* FP Add(%S1, %S2) -> %D1 */'
417 "comment" => "construct FP Mul: Mul(a, b) = Mul(b, a) = a * b",
418 "reg_req" => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] },
419 "emit" =>'. fmul %S1, %S2, %D1\t\t\t/* FP Mul(%S1, %S2) -> %D1 */'
426 "comment" => "construct FP Max: Max(a, b) = Max(b, a) = a > b ? a : b",
427 "reg_req" => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] },
428 "emit" =>'. fmax %S1, %S2, %D1\t\t\t/* FP Max(%S1, %S2) -> %D1 */'
435 "comment" => "construct FP Min: Min(a, b) = Min(b, a) = a < b ? a : b",
436 "reg_req" => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] },
437 "emit" =>'. fmin %S1, %S2, %D1\t\t\t/* FP Min(%S1, %S2) -> %D1 */'
440 # not commutative operations
445 "comment" => "construct FP Sub: Sub(a, b) = a - b",
446 "reg_req" => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] },
447 "emit" => '. fsub %S1, %S2, %D1\t\t\t/* FP Sub(%S1, %S2) -> %D1 */'
453 "comment" => "construct FP Div: Div(a, b) = a / b",
454 "reg_req" => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] },
455 "emit" => '. fdiv %S1, %S2, %D1\t\t\t/* FP Div(%S1, %S2) -> %D1 */'
461 "comment" => "construct FP Minus: Minus(a) = -a",
462 "reg_req" => { "in" => [ "floating_point" ], "out" => [ "floating_point" ] },
463 "emit" => '. fneg %S1, %D1\t\t\t/* FP Minus(%S1) -> %D1 */'
472 "comment" => "represents a FP constant",
473 "reg_req" => { "out" => [ "floating_point" ] },
474 "emit" => '. fmov %C, %D1\t\t\t/* Mov fConst into register */',
477 if (attr_a->tp == attr_b->tp) {
478 if (attr_a->tp == asmop_SymConst) {
479 if (attr_a->old_ir == NULL || attr_b->old_ir == NULL)
482 return strcmp(get_sc_name(attr_a->old_ir), get_sc_name(attr_b->old_ir));
485 if (attr_a->old_ir == NULL || attr_b->old_ir == NULL)
488 if (tarval_cmp(attr_a->tv, attr_b->tv) == pn_Cmp_Eq)
503 "state" => "exc_pinned",
506 "comment" => "construct FP Load: Load(ptr, mem) = LD ptr",
507 "reg_req" => { "in" => [ "general_purpose", "none" ], "out" => [ "floating_point" ] },
508 "emit" => '. fmov %O(%S1), %D1\t\t\t/* Load((%S1)) -> %D1 */'
513 "state" => "exc_pinned",
516 "comment" => "construct Store: Store(ptr, val, mem) = ST ptr,val",
517 "reg_req" => { "in" => [ "general_purpose", "floating_point", "none" ] },
518 "emit" => '. fmov %S2, %O(%S1)\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */'
525 "state" => "mem_pinned",
526 "arity" => "variable",
527 "comment" => "construct Call: Call(...)",
529 { "type" => "int", "name" => "n" },
530 { "type" => "ir_node **", "name" => "in" }
533 " if (!op_ia32_Call) assert(0);
534 return new_ir_node(db, irg, block, op_ia32_Call, mode_T, n, in);
544 "comment" => "construct Alloca: allocate memory on Stack",
545 "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] }
552 "comment" => "construct Alloca: allocate memory on Stack",
553 "reg_req" => { "out" => [ "general_purpose" ] }