The big committ:
[libfirm] / ir / be / mips / mips_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 = "mips";
8
9 # this strings mark the beginning and the end of a comment in emit
10 $comment_string     = "#";
11 $comment_string_end = "";
12
13 # The node description is done as a perl hash initializer with the
14 # following structure:
15 #
16 # %nodes = (
17 #
18 # <op-name> => {
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",
22 #   "args"      => [
23 #                    { "type" => "type 1", "name" => "name 1" },
24 #                    { "type" => "type 2", "name" => "name 2" },
25 #                    ...
26 #                  ],
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"
32 # },
33 #
34 # ... # (all nodes you need to describe)
35 #
36 # ); # close the %nodes initializer
37
38 # op_flags: flags for the operation, OPTIONAL (default is "N")
39 # the op_flags correspond to the firm irop_flags:
40 #   N   irop_flag_none
41 #   L   irop_flag_labeled
42 #   C   irop_flag_commutative
43 #   X   irop_flag_cfopcode
44 #   I   irop_flag_ip_cfopcode
45 #   F   irop_flag_fragile
46 #   Y   irop_flag_forking
47 #   H   irop_flag_highlevel
48 #   c   irop_flag_constlike
49 #   K   irop_flag_keep
50 #
51 #   R   rematerializeable
52 #   N   not spillable
53 #   I   ignore for register allocation
54 #
55 # state: state of the operation, OPTIONAL (default is "floats")
56 #
57 # arity: arity of the operation, MUST NOT BE OMITTED
58 #
59 # args:  the OPTIONAL arguments of the node constructor (debug, irg and block
60 #        are always the first 3 arguments and are always autmatically
61 #        created)
62 #        If this key is missing the following arguments will be created:
63 #        for i = 1 .. arity: ir_node *op_i
64 #        ir_mode *mode
65 #
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
68 #
69 # comment: OPTIONAL comment for the node constructor
70 #
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
75 #
76 #      This key is OPTIONAL. If omitted, the following constructor will
77 #      be created:
78 #      if (!op_<arch>_<op-name>) assert(0);
79 #      for i = 1 to arity
80 #         set in[i] = op_i
81 #      done
82 #      res = new_ir_node(db, irg, block, op_<arch>_<op-name>, mode, arity, in)
83 #      return res
84 #
85 # NOTE: rd_constructor and args are only optional if and only if arity is 0,1,2 or 3
86
87 # register types:
88 #   0 - no special type
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\
93 %reg_classes = (
94         "gp" => [
95                 { name => "zero", type => 4+2 },  # always zero
96                 { name => "at", type => 4 }, # reserved for assembler
97                 { name => "v0", type => 1 }, # first return value
98                 { name => "v1", type => 1 }, # second return value
99                 { name => "a0", type => 1 }, # first argument
100                 { name => "a1", type => 1 }, # second argument
101                 { name => "a2", type => 1 }, # third argument
102                 { name => "a3", type => 1 }, # fourth argument
103                 { name => "t0", type => 1 },
104                 { name => "t1", type => 1 },
105                 { name => "t2", type => 1 },
106                 { name => "t3", type => 1 },
107                 { name => "t4", type => 1 },
108                 { name => "t5", type => 1 },
109                 { name => "t6", type => 1 },
110                 { name => "t7", type => 1 },
111                 { name => "s0", type => 2 },
112                 { name => "s1", type => 2 },
113                 { name => "s2", type => 2 },
114                 { name => "s3", type => 2 },
115                 { name => "s4", type => 2 },
116                 { name => "s5", type => 2 },
117                 { name => "s6", type => 2 },
118                 { name => "s7", type => 2 },
119                 { name => "t8", type => 1 },
120                 { name => "t9", type => 1 },
121                 { name => "k0", type => 4 }, # reserved for OS
122                 { name => "k1", type => 4 }, # reserved for OS
123                 { name => "gp", type => 4 }, # general purpose
124                 { name => "sp", type => 4+2 }, # stack pointer
125                 { name => "fp", type => 4+2 }, # frame pointer
126                 { name => "ra", type => 2+1 }, # return address. This is also caller
127                                        # save, because the jla instruction that
128                                                # is used for calls modifies the ra
129                                                # register. It is callee save too,
130                                                # because at the last command of a
131                                                # function (the ja $ra) it needs to have
132                                                # it's old value.
133                 { mode => "mode_P" }
134         ],
135 ); # %reg_classes
136
137 #--------------------------------------------------#
138 #                        _                         #
139 #                       (_)                        #
140 #  _ __   _____      __  _ _ __    ___  _ __  ___  #
141 # | '_ \ / _ \ \ /\ / / | | '__|  / _ \| '_ \/ __| #
142 # | | | |  __/\ V  V /  | | |    | (_) | |_) \__ \ #
143 # |_| |_|\___| \_/\_/   |_|_|     \___/| .__/|___/ #
144 #                                      | |         #
145 #                                      |_|         #
146 #--------------------------------------------------#
147
148 %nodes = (
149
150 #-----------------------------------------------------------------#
151 #  _       _                                         _            #
152 # (_)     | |                                       | |           #
153 #  _ _ __ | |_ ___  __ _  ___ _ __   _ __   ___   __| | ___  ___  #
154 # | | '_ \| __/ _ \/ _` |/ _ \ '__| | '_ \ / _ \ / _` |/ _ \/ __| #
155 # | | | | | ||  __/ (_| |  __/ |    | | | | (_) | (_| |  __/\__ \ #
156 # |_|_| |_|\__\___|\__, |\___|_|    |_| |_|\___/ \__,_|\___||___/ #
157 #                   __/ |                                         #
158 #                  |___/                                          #
159 #-----------------------------------------------------------------#
160
161 # commutative operations
162
163 add => {
164   op_flags  => "C",
165   reg_req   => { in => [ "gp", "gp" ], out => [ "gp" ] },
166   emit      => '. addu %D1, %S1, %S2'
167 },
168
169 addi => {
170   reg_req   => { in => [ "gp" ], out => [ "gp" ] },
171   emit      => '. addiu %D1, %S1, %C',
172   cmp_attr => 'return attr_a->tv != attr_b->tv;',
173 },
174
175 and => {
176   op_flags  => "C",
177   reg_req   => { in => [ "gp", "gp" ], out => [ "gp" ] },
178   emit      => '. and %D1, %S1, %S2',
179 },
180
181 andi => {
182   reg_req   => { in => [ "gp" ], out => [ "gp" ] },
183   emit      => '. andi %D1, %S1, %C',
184   cmp_attr => 'return attr_a->tv != attr_b->tv;',
185 },
186
187 div => {
188   reg_req   => { in => [ "gp", "gp" ], out => [ "none", "none", "none", "none" ] },
189   emit      => '
190         mips_attr_t *attr = get_mips_attr(n);
191         if (attr->modes.original_mode->sign) {
192 2.              div %S1, %S2
193         } else {
194 2.              divu %S1, %S2
195         }
196 ',
197 },
198
199 mult => {
200   op_flags  => "C",
201   reg_req   => { in => [ "gp", "gp" ], out => [ "none" ] },
202   emit      => '
203         if (mode_is_signed(get_irn_mode(n))) {
204 2.              mult %S1, %S2
205         }
206         else {
207 2.              multu %S1, %S2
208         }
209 ',
210 },
211
212 nor => {
213   op_flags  => "C",
214   reg_req   => { in => [ "gp", "gp" ], out => [ "gp" ] },
215   emit      => '. nor %D1, %S1, %S2'
216 },
217
218 not => {
219   reg_req   => { in => [ "gp" ], out => [ "gp" ] },
220   emit      => '. nor %D1, %S1, $zero'
221 },
222
223 or => {
224   op_flags  => "C",
225   reg_req   => { in => [ "gp", "gp" ], out => [ "gp" ] },
226   emit      => '. or %D1, %S1, %S2'
227 },
228
229 ori => {
230   reg_req   => { in => [ "gp" ], out => [ "gp" ] },
231   emit      => '. ori %D1, %S1, %C',
232   cmp_attr => 'return attr_a->tv != attr_b->tv;',
233 },
234
235 sl => {
236   reg_req   => { in => [ "gp", "gp" ], out => [ "gp" ] },
237   emit      => '
238         if (mode_is_signed(get_irn_mode(n))) {
239 2.              sal %D1, %S1, %S2
240         }
241         else {
242 2.              sll %D1, %S1, %S2
243         }
244 ',
245 },
246
247 sli => {
248   reg_req   => { in => [ "gp" ], out => [ "gp" ] },
249   emit      => '
250         if (mode_is_signed(get_irn_mode(n))) {
251 2.              sal %D1, %S1, %C
252         }
253         else {
254 2.              sll %D1, %S1, %C
255         }
256 ',
257 },
258
259 sra => {
260   reg_req   => { in => [ "gp", "gp" ], out => [ "gp" ] },
261   emit      => '. sra %D1, %S1, %S2',
262 },
263
264 srai => {
265   reg_req   => { in => [ "gp" ], out => [ "gp" ] },
266   emit      => '. sra %D1, %S1, %C',
267   cmp_attr => 'return attr_a->tv != attr_b->tv;',
268 },
269
270 sr => {
271   reg_req   => { in => [ "gp", "gp" ], out => [ "gp" ] },
272   emit      => '
273         if (mode_is_signed(get_irn_mode(n))) {
274 2.              sra %D1, %S1, %S2
275         }
276         else {
277 2.              srl %D1, %S1, %S2
278         }
279 ',
280 },
281
282 sri => {
283   reg_req   => { in => [ "gp" ], out => [ "gp" ] },
284   emit      => '
285         if (mode_is_signed(get_irn_mode(n))) {
286 2.              sra %D1, %S1, %C
287         }
288         else {
289 2.              srl %D1, %S1, %C
290         }
291 ',
292 },
293
294 srlv => {
295   reg_req   => { in => [ "gp", "gp" ], out => [ "gp" ] },
296   emit      => '. srlv %D1, %S1, %S2',
297 },
298
299 sllv => {
300   reg_req   => { in => [ "gp", "gp" ], out => [ "gp" ] },
301   emit      => '. sllv %D1, %S1, %S2',
302 },
303
304 sub => {
305   reg_req   => { in => [ "gp", "gp" ], out => [ "gp" ] },
306   emit      => '. subu %D1, %S1, %S2',
307 },
308
309 subuzero => {
310   reg_req       => { in => [ "gp" ], out => [ "gp" ] },
311   emit => '. subu %D1, $zero, %S1',
312 },
313
314 xor => {
315   reg_req   => { in => [ "gp", "gp" ], out => [ "gp" ] },
316   emit      => '. xor %D1, %S1, %S2'
317 },
318
319 xori => {
320   reg_req   => { in => [ "gp" ], out => [ "gp" ] },
321   emit      => '. xori %D1, %S1, %C',
322   cmp_attr => 'return attr_a->tv != attr_b->tv;',
323 },
324
325 #   ____                _              _
326 #  / ___|___  _ __  ___| |_ __ _ _ __ | |_ ___
327 # | |   / _ \| '_ \/ __| __/ _` | '_ \| __/ __|
328 # | |__| (_) | | | \__ \ || (_| | | | | |_\__ \
329 #  \____\___/|_| |_|___/\__\__,_|_| |_|\__|___/
330 #
331
332 # load upper imediate
333 lui => {
334   op_flags      => "c",
335   reg_req   => { out => [ "gp" ] },
336   emit      => '. lui %D1, %C',
337   cmp_attr => 'return attr_a->tv != attr_b->tv;',
338 },
339
340 # load lower immediate
341 lli => {
342   op_flags      => "c",
343   reg_req   => { in => [ "gp" ], out => [ "gp" ] },
344   emit      => '. ori %D1, %S1, %C',
345   cmp_attr => 'return attr_a->tv != attr_b->tv;',
346 },
347
348 la => {
349   op_flags      => "c",
350   reg_req   => { out => [ "gp" ] },
351   emit      => '. la %D1, %C',
352   cmp_attr => 'return attr_a->symconst_id != attr_b->symconst_id;',
353 },
354
355 mflo => {
356   reg_req => { in => [ "none" ], out => [ "gp" ] },
357   emit    => '. mflo %D1'
358 },
359
360 mfhi => {
361   reg_req => { in => [ "none" ], out => [ "gp" ] },
362   emit    => '. mfhi %D1'
363 },
364
365 zero => {
366   reg_req => { out => [ "zero" ] },
367   emit => '',
368 },
369
370 #
371 #  ____                       _        __  _
372 # | __ ) _ __ __ _ _ __   ___| |__    / / | |_   _ _ __ ___  _ __
373 # |  _ \| '__/ _` | '_ \ / __| '_ \  / /  | | | | | '_ ` _ \| '_ \
374 # | |_) | | | (_| | | | | (__| | | |/ / |_| | |_| | | | | | | |_) |
375 # |____/|_|  \__,_|_| |_|\___|_| |_/_/ \___/ \__,_|_| |_| |_| .__/
376 #                                                           |_|
377 #
378
379 slt => {
380         reg_req => { in => [ "gp", "gp" ], out => [ "gp" ] },
381         emit => '
382         if (mode_is_signed(get_irn_mode(n))) {
383 2.              slt %D1, %S1, %S2
384         }
385         else {
386 2.              sltu %D1, %S1, %S2
387         }
388 ',
389 },
390
391 slti => {
392         reg_req => { in => [ "gp" ], out => [ "gp" ] },
393         emit => '
394         if (mode_is_signed(get_irn_mode(n))) {
395 2.              slti %D1, %S1, %C
396         }
397         else {
398 2.              sltiu %D1, %S1, %C
399         }
400 ',
401   cmp_attr => 'return attr_a->tv != attr_b->tv;',
402 },
403
404 beq => {
405         op_flags  => "X|Y",
406         # TxT -> TxX
407         reg_req => { in => [ "gp", "gp" ], out => [ "in_r0", "none" ] },
408         emit => '
409         ir_node *jumpblock = mips_get_jump_block(n, 1);
410         assert(jumpblock != NULL);
411
412         (void) cmd_buf;
413         (void) cmnt_buf;
414         lc_efprintf(arg_env, F, "\tbeq %1S, %2S, BLOCK_%d\n", n, n, get_irn_node_nr(jumpblock));
415 '
416 },
417
418 bne => {
419         op_flags  => "X|Y",
420         # TxT -> TxX
421         reg_req => { in => [ "gp", "gp" ], out => [ "in_r0", "none" ] },
422         emit => '
423         ir_node *jumpblock = mips_get_jump_block(n, 1);
424         assert(jumpblock != NULL);
425
426         (void) cmd_buf;
427         (void) cmnt_buf;
428         lc_efprintf(arg_env, F, "\tbne %1S, %2S, BLOCK_%d\n", n, n, get_irn_node_nr(jumpblock));
429 '
430 },
431
432 bgtz => {
433         op_flags  => "X|Y",
434         # TxT -> TxX
435         reg_req => { in => [ "gp" ], out => [ "in_r0", "none" ] },
436         emit => '
437         ir_node *jumpblock = mips_get_jump_block(n, 1);
438         assert(jumpblock != NULL);
439
440         (void) cmd_buf;
441         (void) cmnt_buf;
442         lc_efprintf(arg_env, F, "\tbgtz %1S, BLOCK_%d\n", n, get_irn_node_nr(jumpblock));
443 '
444 },
445
446 blez => {
447         op_flags  => "X|Y",
448         # TxT -> TxX
449         reg_req => { in => [ "gp" ], out => [ "in_r0", "none" ] },
450         emit => '
451         ir_node *jumpblock = mips_get_jump_block(n, 1);
452         assert(jumpblock != NULL);
453
454         (void) cmd_buf;
455         (void) cmnt_buf;
456         lc_efprintf(arg_env, F, "\tblez %1S, BLOCK_%d\n", n, get_irn_node_nr(jumpblock));
457 '
458 },
459
460 j => {
461   op_flags => "X",
462   reg_req => { in => [ "gp" ] },
463   emit => '. j %S1',
464 },
465
466 b => {
467   op_flags => "X",
468   # -> X
469   reg_req => { in => [ ], out => [ "none" ] },
470   emit => '
471         ir_node *jumpblock = get_irn_link(n);
472         assert(jumpblock != NULL);
473
474         (void) cmd_buf;
475         (void) cmnt_buf;
476         lc_efprintf(arg_env, F, "\tb BLOCK_%d\t\t\t# mips_b\n", get_irn_node_nr(jumpblock));
477 '
478 },
479
480 fallthrough => {
481   op_flags => "X",
482   # -> X
483   reg_req => { in => [ ], out => [ "none" ] },
484   emit => '. # fallthrough'
485 },
486
487 SwitchJump => {
488   op_flags => "X",
489   # -> X,X,...
490   reg_req => { in => [ "gp" ], out => [ "none" ] },
491   emit => '. j %S1'
492 },
493
494 #  _                    _
495 # | |    ___   __ _  __| |
496 # | |   / _ \ / _` |/ _` |
497 # | |__| (_) | (_| | (_| |
498 # |_____\___/ \__,_|\__,_|
499 #
500
501 load_r => {
502   reg_req       => { in => [ "none", "gp" ], out => [ "none", "none", "gp" ] },
503   emit          => '
504         mips_attr_t* attr = get_mips_attr(n);
505         ir_mode *mode;
506
507         mode = attr->modes.load_store_mode;
508
509         switch (get_mode_size_bits(mode)) {
510         case 8:
511                 if (mode_is_signed(mode)) {
512 3.                      lb %D3, %C(%S2)
513                 }
514                 else {
515 3.                      lbu %D3, %C(%S2)
516                 }
517                 break;
518         case 16:
519                 if (mode_is_signed(mode)) {
520 3.                      lh %D3, %C(%S2)
521                 }
522                 else {
523 3.                      lhu %D3, %C(%S2)
524                 }
525                 break;
526         case 32:
527 2.              lw %D3, %C(%S2)
528                 break;
529         default:
530                 assert(! "Only 8, 16 and 32 bit loads supported");
531                 break;
532         }
533 ',
534   cmp_attr => 'return attr_a->tv != attr_b->tv || attr_a->stack_entity != attr_b->stack_entity;',
535 },
536
537
538 #  _                    _    ______  _
539 # | |    ___   __ _  __| |  / / ___|| |_ ___  _ __ ___
540 # | |   / _ \ / _` |/ _` | / /\___ \| __/ _ \| '__/ _ \
541 # | |__| (_) | (_| | (_| |/ /  ___) | || (_) | | |  __/
542 # |_____\___/ \__,_|\__,_/_/  |____/ \__\___/|_|  \___|
543 #
544
545 store_r => {
546   reg_req       => { in => [ "none", "gp", "gp" ], out => [ "none", "none" ] },
547   emit          => '
548         mips_attr_t* attr = get_mips_attr(n);
549         ir_mode* mode;
550
551         mode = attr->modes.load_store_mode;
552
553         switch (get_mode_size_bits(mode)) {
554         case 8:
555                 if (mode_is_signed(mode))
556 2.              sb %S3, %C(%S2)
557                 break;
558         case 16:
559                 if (mode_is_signed(mode))
560 2.              sh %S3, %C(%S2)
561                 break;
562         case 32:
563 2.              sw %S3, %C(%S2)
564                 break;
565         default:
566                 assert(! "Only 8, 16 and 32 bit stores supported");
567                 break;
568         }
569 ',
570   cmp_attr => 'return attr_a->tv != attr_b->tv;',
571 },
572
573 store_i => {
574   reg_req       => { in => [ "none", "none", "gp" ], out => [ "none", "none" ] },
575   emit          => '
576         mips_attr_t* attr = get_mips_attr(n);
577         ir_mode *mode;
578
579         mode = attr->modes.load_store_mode;
580
581         switch (get_mode_size_bits(mode)) {
582         case 8:
583 2.              sb %S3, %C
584                 break;
585         case 16:
586 2.              sh %S3, %C
587                 break;
588         case 32:
589 2.              sw %S3, %C
590                 break;
591         default:
592                 assert(! "Only 8, 16 and 32 bit stores supported");
593                 break;
594         }
595 ',
596   cmp_attr => '
597         return attr_a->stack_entity != attr_b->stack_entity;
598 ',
599 },
600
601 move => {
602   reg_req   => { in => [ "gp" ], out => [ "gp" ] },
603   emit      => '. or %D1, $zero, %S1'
604 },
605
606 #
607 # Conversion
608 #
609
610 reinterpret_conv => {
611   reg_req   => { in => [ "gp" ], out => [ "in_r1" ] },
612   emit      => '. # reinterpret %S1 -> %D1',
613 },
614
615 #
616 # Miscelaneous
617 #
618
619 nop => {
620   op_flags  => "K",
621   reg_req       => { in => [], out => [ "none" ] },
622   emit          => '. nop  # nop',
623 },
624
625 ); # end of %nodes