3 # This is a template specification for the Firm-Backend
5 # the cpu architecture (ia32, ia64, mips, sparc, ppc, ...)
9 # this strings mark the beginning and the end of a comment in emit
10 $comment_string = "#";
11 $comment_string_end = "";
13 # The node description is done as a perl hash initializer with the
14 # following structure:
19 # op_flags => "N|L|C|X|I|F|Y|H|c|K",
20 # "arity" => "0|1|2|3 ... |variable|dynamic|any",
21 # "state" => "floats|pinned|mem_pinned|exc_pinned",
23 # { "type" => "type 1", "name" => "name 1" },
24 # { "type" => "type 2", "name" => "name 2" },
27 # "comment" => "any comment for constructor",
28 # reg_req => { in => [ "reg_class|register" ], out => [ "reg_class|register|in_rX" ] },
29 # "cmp_attr" => "c source code for comparing node attributes",
30 # emit => "emit code with templates",
31 # "rd_constructor" => "c source code which constructs an ir_node"
34 # ... # (all nodes you need to describe)
36 # ); # close the %nodes initializer
38 # op_flags: flags for the operation, OPTIONAL (default is "N")
39 # the op_flags correspond to the firm irop_flags:
42 # C irop_flag_commutative
43 # X irop_flag_cfopcode
44 # I irop_flag_ip_cfopcode
47 # H irop_flag_highlevel
48 # c irop_flag_constlike
53 # I ignore for register allocation
55 # state: state of the operation, OPTIONAL (default is "floats")
57 # arity: arity of the operation, MUST NOT BE OMITTED
59 # args: the OPTIONAL arguments of the node constructor (debug, irg and block
60 # are always the first 3 arguments and are always autmatically
62 # If this key is missing the following arguments will be created:
63 # for i = 1 .. arity: ir_node *op_i
66 # outs: if a node defines more than one output, the names of the projections
67 # nodes having outs having automatically the mode mode_T
69 # comment: OPTIONAL comment for the node constructor
71 # rd_constructor: for every operation there will be a
72 # new_rd_<arch>_<op-name> function with the arguments from above
73 # which creates the ir_node corresponding to the defined operation
74 # you can either put the complete source code of this function here
76 # This key is OPTIONAL. If omitted, the following constructor will
78 # if (!op_<arch>_<op-name>) assert(0);
82 # res = new_ir_node(db, irg, block, op_<arch>_<op-name>, mode, arity, in)
85 # NOTE: rd_constructor and args are only optional if and only if arity is 0,1,2 or 3
89 # 1 - caller save (register must be saved by the caller of a function)
90 # 2 - callee save (register must be saved by the called function)
91 # 4 - ignore (do not assign this register)
92 # NOTE: Last entry of each class is the largest Firm-Mode a register can hold\
95 { name => "zero", type => 4+2 }, # always zero
96 { name => "at", type => 4 }, # reserved for assembler
97 { name => "v0", realname => "2", type => 1 }, # first return value
98 { name => "v1", realname => "3", type => 1 }, # second return value
99 { name => "a0", realname => "4", type => 1 }, # first argument
100 { name => "a1", realname => "5", type => 1 }, # second argument
101 { name => "a2", realname => "6", type => 1 }, # third argument
102 { name => "a3", realname => "7", type => 1 }, # fourth argument
103 { name => "t0", realname => "8", type => 1 },
104 { name => "t1", realname => "9", type => 1 },
105 { name => "t2", realname => "10", type => 1 },
106 { name => "t3", realname => "11", type => 1 },
107 { name => "t4", realname => "12", type => 1 },
108 { name => "t5", realname => "13", type => 1 },
109 { name => "t6", realname => "14", type => 1 },
110 { name => "t7", realname => "15", type => 1 },
111 { name => "s0", realname => "16", type => 2 },
112 { name => "s1", realname => "17", type => 2 },
113 { name => "s2", realname => "18", type => 2 },
114 { name => "s3", realname => "19", type => 2 },
115 { name => "s4", realname => "20", type => 2 },
116 { name => "s5", realname => "21", type => 2 },
117 { name => "s6", realname => "22", type => 2 },
118 { name => "s7", realname => "23", type => 2 },
119 { name => "t8", realname => "24", type => 1 },
120 { name => "t9", realname => "25", type => 1 },
121 { name => "kt0", type => 4 }, # reserved for OS
122 { name => "kt1", type => 4 }, # reserved for OS
123 { name => "gp", type => 4 }, # general purpose
124 { name => "sp", type => 4 }, # stack pointer
125 { name => "fp", type => 4 }, # frame pointer
126 { name => "ra", type => 2+1 }, # return address
127 { mode => "mode_Iu" }
131 #--------------------------------------------------#
134 # _ __ _____ __ _ _ __ ___ _ __ ___ #
135 # | '_ \ / _ \ \ /\ / / | | '__| / _ \| '_ \/ __| #
136 # | | | | __/\ V V / | | | | (_) | |_) \__ \ #
137 # |_| |_|\___| \_/\_/ |_|_| \___/| .__/|___/ #
140 #--------------------------------------------------#
144 #-----------------------------------------------------------------#
147 # _ _ __ | |_ ___ __ _ ___ _ __ _ __ ___ __| | ___ ___ #
148 # | | '_ \| __/ _ \/ _` |/ _ \ '__| | '_ \ / _ \ / _` |/ _ \/ __| #
149 # | | | | | || __/ (_| | __/ | | | | | (_) | (_| | __/\__ \ #
150 # |_|_| |_|\__\___|\__, |\___|_| |_| |_|\___/ \__,_|\___||___/ #
153 #-----------------------------------------------------------------#
155 # commutative operations
159 reg_req => { in => [ "gp", "gp" ], out => [ "gp" ] },
160 emit => '. addu %D1, %S1, %S2',
165 reg_req => { in => [ "gp" ], out => [ "gp" ] },
166 emit => '. addiu %D1, %S1, %C',
167 cmp_attr => 'return attr_a->tv != attr_b->tv;',
173 reg_req => { in => [ "gp", "gp" ], out => [ "gp" ] },
174 emit => '. and %D1, %S1, %S2',
179 reg_req => { in => [ "gp" ], out => [ "gp" ] },
180 emit => '. andi %D1, %S1, %C',
181 cmp_attr => 'return attr_a->tv != attr_b->tv;',
186 reg_req => { in => [ "gp", "gp" ], out => [ "none" ] },
187 emit => '. div %S1, %S2',
192 reg_req => { in => [ "gp", "gp" ], out => [ "none" ] },
193 emit => '. divu %S1, %S2',
199 reg_req => { in => [ "gp", "gp" ], out => [ "none" ] },
200 emit => '. mult %S1, %S2',
206 reg_req => { in => [ "gp", "gp" ], out => [ "none" ] },
207 emit => '. multu %S1, %S2',
213 reg_req => { in => [ "gp", "gp" ], out => [ "gp" ] },
214 emit => '. nor %D1, %S1, %S2',
219 reg_req => { in => [ "gp" ], out => [ "gp" ] },
220 emit => '. nor %D1, %S1, $zero',
226 reg_req => { in => [ "gp", "gp" ], out => [ "gp" ] },
227 emit => '. or %D1, %S1, %S2',
232 reg_req => { in => [ "gp" ], out => [ "gp" ] },
233 emit => '. ori %D1, %S1, %C',
234 cmp_attr => 'return attr_a->tv != attr_b->tv;',
239 reg_req => { in => [ "gp", "gp" ], out => [ "gp" ] },
241 if (mode_is_signed(get_irn_mode(n))) {
251 reg_req => { in => [ "gp" ], out => [ "gp" ] },
253 if (mode_is_signed(get_irn_mode(n))) {
263 reg_req => { in => [ "gp", "gp" ], out => [ "gp" ] },
264 emit => '. sra %D1, %S1, %S2',
269 reg_req => { in => [ "gp" ], out => [ "gp" ] },
270 emit => '. sra %D1, %S1, %C',
271 cmp_attr => 'return attr_a->tv != attr_b->tv;',
276 reg_req => { in => [ "gp", "gp" ], out => [ "gp" ] },
278 if (mode_is_signed(get_irn_mode(n))) {
288 reg_req => { in => [ "gp" ], out => [ "gp" ] },
290 if (mode_is_signed(get_irn_mode(n))) {
300 reg_req => { in => [ "gp", "gp" ], out => [ "gp" ] },
301 emit => '. srlv %D1, %S1, %S2',
306 reg_req => { in => [ "gp", "gp" ], out => [ "gp" ] },
307 emit => '. sllv %D1, %S1, %S2',
312 reg_req => { in => [ "gp", "gp" ], out => [ "gp" ] },
313 emit => '. subu %D1, %S1, %S2',
318 reg_req => { in => [ "gp" ], out => [ "gp" ] },
319 emit => '. subu %D1, $zero, %S1',
324 reg_req => { in => [ "gp", "gp" ], out => [ "gp" ] },
325 emit => '. xor %D1, %S1, %S2',
330 reg_req => { in => [ "gp" ], out => [ "gp" ] },
331 emit => '. xori %D1, %S1, %C',
332 cmp_attr => 'return attr_a->tv != attr_b->tv;',
337 # / ___|___ _ __ ___| |_ __ _ _ __ | |_ ___
338 # | | / _ \| '_ \/ __| __/ _` | '_ \| __/ __|
339 # | |__| (_) | | | \__ \ || (_| | | | | |_\__ \
340 # \____\___/|_| |_|___/\__\__,_|_| |_|\__|___/
343 # load upper imediate
346 reg_req => { out => [ "gp" ] },
347 emit => '. lui %D1, %C',
348 cmp_attr => 'return attr_a->tv != attr_b->tv;',
352 # load lower immediate
355 reg_req => { in => [ "gp" ], out => [ "gp" ] },
356 emit => '. ori %D1, %S1, %C',
357 cmp_attr => 'return attr_a->tv != attr_b->tv;',
363 reg_req => { out => [ "gp" ] },
364 emit => '. la %D1, %C',
365 cmp_attr => 'return attr_a->symconst_id != attr_b->symconst_id;',
370 reg_req => { in => [ "none" ], out => [ "gp" ] },
371 emit => '. mflo %D1',
376 reg_req => { in => [ "none" ], out => [ "gp" ] },
377 emit => '. mfhi %D1',
382 reg_req => { out => [ "zero" ] },
389 # | __ ) _ __ __ _ _ __ ___| |__ / / | |_ _ _ __ ___ _ __
390 # | _ \| '__/ _` | '_ \ / __| '_ \ / / | | | | | '_ ` _ \| '_ \
391 # | |_) | | | (_| | | | | (__| | | |/ / |_| | |_| | | | | | | |_) |
392 # |____/|_| \__,_|_| |_|\___|_| |_/_/ \___/ \__,_|_| |_| |_| .__/
397 reg_req => { in => [ "gp", "gp" ], out => [ "gp" ] },
399 if (mode_is_signed(get_irn_mode(n))) {
403 2. sltu %D1, %S1, %S2
410 reg_req => { in => [ "gp" ], out => [ "gp" ] },
412 if (mode_is_signed(get_irn_mode(n))) {
416 2. sltiu %D1, %S1, %C
419 cmp_attr => 'return attr_a->tv != attr_b->tv;',
426 reg_req => { in => [ "gp", "gp" ], out => [ "in_r0", "none" ] },
428 ir_node *jumpblock = mips_get_jump_block(n, 1);
429 assert(jumpblock != NULL);
433 lc_efprintf(arg_env, F, "\tbeq %1S, %2S, BLOCK_%d\n", n, n, get_irn_node_nr(jumpblock));
440 reg_req => { in => [ "gp", "gp" ], out => [ "in_r0", "none" ] },
442 ir_node *jumpblock = mips_get_jump_block(n, 1);
443 assert(jumpblock != NULL);
447 lc_efprintf(arg_env, F, "\tbne %1S, %2S, BLOCK_%d\n", n, n, get_irn_node_nr(jumpblock));
454 reg_req => { in => [ "gp" ], out => [ "in_r0", "none" ] },
456 ir_node *jumpblock = mips_get_jump_block(n, 1);
457 assert(jumpblock != NULL);
461 lc_efprintf(arg_env, F, "\tbgtz %1S, BLOCK_%d\n", n, get_irn_node_nr(jumpblock));
468 reg_req => { in => [ "gp" ], out => [ "in_r0", "none" ] },
470 ir_node *jumpblock = mips_get_jump_block(n, 1);
471 assert(jumpblock != NULL);
475 lc_efprintf(arg_env, F, "\tblez %1S, BLOCK_%d\n", n, get_irn_node_nr(jumpblock));
481 reg_req => { in => [ "gp" ] },
488 reg_req => { in => [ ], out => [ "none" ] },
490 ir_node *jumpblock = get_irn_link(n);
491 assert(jumpblock != NULL);
495 lc_efprintf(arg_env, F, "\tb BLOCK_%d\t\t\t# mips_b\n", get_irn_node_nr(jumpblock));
502 reg_req => { in => [ ], out => [ "none" ] },
503 emit => '. # fallthrough'
509 reg_req => { in => [ "gp" ], out => [ "none" ] },
515 # | | / _ \ / _` |/ _` |
516 # | |__| (_) | (_| | (_| |
517 # |_____\___/ \__,_|\__,_|
521 reg_req => { in => [ "none", "gp" ], out => [ "none", "none", "gp" ] },
523 mips_attr_t* attr = get_mips_attr(n);
526 mode = attr->modes.load_store_mode;
528 switch (get_mode_size_bits(mode)) {
530 if (mode_is_signed(mode)) {
537 if (mode_is_signed(mode)) {
547 assert(! "Only 8, 16 and 32 bit loads supported");
551 cmp_attr => 'return attr_a->tv != attr_b->tv || attr_a->stack_entity != attr_b->stack_entity;',
556 # | | ___ __ _ __| | / / ___|| |_ ___ _ __ ___
557 # | | / _ \ / _` |/ _` | / /\___ \| __/ _ \| '__/ _ \
558 # | |__| (_) | (_| | (_| |/ / ___) | || (_) | | | __/
559 # |_____\___/ \__,_|\__,_/_/ |____/ \__\___/|_| \___|
563 reg_req => { in => [ "none", "gp", "gp" ], out => [ "none", "none" ] },
565 mips_attr_t* attr = get_mips_attr(n);
568 mode = attr->modes.load_store_mode;
570 switch (get_mode_size_bits(mode)) {
572 if (mode_is_signed(mode))
576 if (mode_is_signed(mode))
583 assert(! "Only 8, 16 and 32 bit stores supported");
587 cmp_attr => 'return attr_a->tv != attr_b->tv;',
591 reg_req => { in => [ "none", "none", "gp" ], out => [ "none", "none" ] },
593 mips_attr_t* attr = get_mips_attr(n);
596 mode = attr->modes.load_store_mode;
598 switch (get_mode_size_bits(mode)) {
609 assert(! "Only 8, 16 and 32 bit stores supported");
613 cmp_attr => 'return attr_a->stack_entity != attr_b->stack_entity;',
617 reg_req => { in => [ "gp" ], out => [ "gp" ] },
618 emit => '. move %D1, %S1',
626 reinterpret_conv => {
627 reg_req => { in => [ "gp" ], out => [ "in_r1" ] },
628 emit => '. # reinterpret %S1 -> %D1',
638 reg_req => { in => [], out => [ "none" ] },