dbea8bab9b4e54b34859873ebbb036fb2b5caeac
[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 save, because
127                                                                                                                         # the jla instruction that is used for calls modifies
128                                                                                                                         # the ra register. It is callee save too, because at the last
129                                                                                                                         # command of a function (the ja $ra) it needs to have it's
130                                                                                                                         # old value.
131                          { mode => "mode_P" }
132                        ],
133 ); # %reg_classes
134
135 #--------------------------------------------------#
136 #                        _                         #
137 #                       (_)                        #
138 #  _ __   _____      __  _ _ __    ___  _ __  ___  #
139 # | '_ \ / _ \ \ /\ / / | | '__|  / _ \| '_ \/ __| #
140 # | | | |  __/\ V  V /  | | |    | (_) | |_) \__ \ #
141 # |_| |_|\___| \_/\_/   |_|_|     \___/| .__/|___/ #
142 #                                      | |         #
143 #                                      |_|         #
144 #--------------------------------------------------#
145
146 %nodes = (
147
148 #-----------------------------------------------------------------#
149 #  _       _                                         _            #
150 # (_)     | |                                       | |           #
151 #  _ _ __ | |_ ___  __ _  ___ _ __   _ __   ___   __| | ___  ___  #
152 # | | '_ \| __/ _ \/ _` |/ _ \ '__| | '_ \ / _ \ / _` |/ _ \/ __| #
153 # | | | | | ||  __/ (_| |  __/ |    | | | | (_) | (_| |  __/\__ \ #
154 # |_|_| |_|\__\___|\__, |\___|_|    |_| |_|\___/ \__,_|\___||___/ #
155 #                   __/ |                                         #
156 #                  |___/                                          #
157 #-----------------------------------------------------------------#
158
159 # commutative operations
160
161 add => {
162   op_flags  => "C",
163   reg_req   => { in => [ "gp", "gp" ], out => [ "gp" ] },
164   emit      => '. addu %D1, %S1, %S2'
165 },
166
167 addi => {
168   reg_req   => { in => [ "gp" ], out => [ "gp" ] },
169   emit      => '. addiu %D1, %S1, %C',
170   cmp_attr => 'return attr_a->tv != attr_b->tv;',
171 },
172
173 and => {
174   op_flags  => "C",
175   reg_req   => { in => [ "gp", "gp" ], out => [ "gp" ] },
176   emit      => '. and %D1, %S1, %S2',
177 },
178
179 andi => {
180   reg_req   => { in => [ "gp" ], out => [ "gp" ] },
181   emit      => '. andi %D1, %S1, %C',
182   cmp_attr => 'return attr_a->tv != attr_b->tv;',
183 },
184
185 div => {
186   reg_req   => { in => [ "gp", "gp" ], out => [ "none", "none", "none", "none" ] },
187   emit      => '
188         mips_attr_t *attr = get_mips_attr(n);
189         if (attr->modes.original_mode->sign) {
190 2.              div %S1, %S2
191         } else {
192 2.              divu %S1, %S2
193         }
194 ',
195 },
196
197 mult => {
198   op_flags  => "C",
199   reg_req   => { in => [ "gp", "gp" ], out => [ "none" ] },
200   emit      => '
201         if (mode_is_signed(get_irn_mode(n))) {
202 2.              mult %S1, %S2
203         }
204         else {
205 2.              multu %S1, %S2
206         }
207 ',
208 },
209
210 nor => {
211   op_flags  => "C",
212   reg_req   => { in => [ "gp", "gp" ], out => [ "gp" ] },
213   emit      => '. nor %D1, %S1, %S2'
214 },
215
216 not => {
217   reg_req   => { in => [ "gp" ], out => [ "gp" ] },
218   emit      => '. nor %D1, %S1, $zero'
219 },
220
221 or => {
222   op_flags  => "C",
223   reg_req   => { in => [ "gp", "gp" ], out => [ "gp" ] },
224   emit      => '. or %D1, %S1, %S2'
225 },
226
227 ori => {
228   reg_req   => { in => [ "gp" ], out => [ "gp" ] },
229   emit      => '. ori %D1, %S1, %C',
230   cmp_attr => 'return attr_a->tv != attr_b->tv;',
231 },
232
233 sl => {
234   reg_req   => { in => [ "gp", "gp" ], out => [ "gp" ] },
235   emit      => '
236         if (mode_is_signed(get_irn_mode(n))) {
237 2.              sal %D1, %S1, %S2
238         }
239         else {
240 2.              sll %D1, %S1, %S2
241         }
242 ',
243 },
244
245 sli => {
246   reg_req   => { in => [ "gp" ], out => [ "gp" ] },
247   emit      => '
248         if (mode_is_signed(get_irn_mode(n))) {
249 2.              sal %D1, %S1, %C
250         }
251         else {
252 2.              sll %D1, %S1, %C
253         }
254 ',
255 },
256
257 sra => {
258   reg_req   => { in => [ "gp", "gp" ], out => [ "gp" ] },
259   emit      => '. sra %D1, %S1, %S2',
260 },
261
262 srai => {
263   reg_req   => { in => [ "gp" ], out => [ "gp" ] },
264   emit      => '. sra %D1, %S1, %C',
265   cmp_attr => 'return attr_a->tv != attr_b->tv;',
266 },
267
268 sr => {
269   reg_req   => { in => [ "gp", "gp" ], out => [ "gp" ] },
270   emit      => '
271         if (mode_is_signed(get_irn_mode(n))) {
272 2.              sra %D1, %S1, %S2
273         }
274         else {
275 2.              srl %D1, %S1, %S2
276         }
277 ',
278 },
279
280 sri => {
281   reg_req   => { in => [ "gp" ], out => [ "gp" ] },
282   emit      => '
283         if (mode_is_signed(get_irn_mode(n))) {
284 2.              sra %D1, %S1, %C
285         }
286         else {
287 2.              srl %D1, %S1, %C
288         }
289 ',
290 },
291
292 srlv => {
293   reg_req   => { in => [ "gp", "gp" ], out => [ "gp" ] },
294   emit      => '. srlv %D1, %S1, %S2',
295 },
296
297 sllv => {
298   reg_req   => { in => [ "gp", "gp" ], out => [ "gp" ] },
299   emit      => '. sllv %D1, %S1, %S2',
300 },
301
302 sub => {
303   reg_req   => { in => [ "gp", "gp" ], out => [ "gp" ] },
304   emit      => '. subu %D1, %S1, %S2',
305 },
306
307 subuzero => {
308   reg_req       => { in => [ "gp" ], out => [ "gp" ] },
309   emit => '. subu %D1, $zero, %S1',
310 },
311
312 xor => {
313   reg_req   => { in => [ "gp", "gp" ], out => [ "gp" ] },
314   emit      => '. xor %D1, %S1, %S2'
315 },
316
317 xori => {
318   reg_req   => { in => [ "gp" ], out => [ "gp" ] },
319   emit      => '. xori %D1, %S1, %C',
320   cmp_attr => 'return attr_a->tv != attr_b->tv;',
321 },
322
323 #   ____                _              _
324 #  / ___|___  _ __  ___| |_ __ _ _ __ | |_ ___
325 # | |   / _ \| '_ \/ __| __/ _` | '_ \| __/ __|
326 # | |__| (_) | | | \__ \ || (_| | | | | |_\__ \
327 #  \____\___/|_| |_|___/\__\__,_|_| |_|\__|___/
328 #
329
330 # load upper imediate
331 lui => {
332   op_flags      => "c",
333   reg_req   => { out => [ "gp" ] },
334   emit      => '. lui %D1, %C',
335   cmp_attr => 'return attr_a->tv != attr_b->tv;',
336 },
337
338 # load lower immediate
339 lli => {
340   op_flags      => "c",
341   reg_req   => { in => [ "gp" ], out => [ "gp" ] },
342   emit      => '. ori %D1, %S1, %C',
343   cmp_attr => 'return attr_a->tv != attr_b->tv;',
344 },
345
346 la => {
347   op_flags      => "c",
348   reg_req   => { out => [ "gp" ] },
349   emit      => '. la %D1, %C',
350   cmp_attr => 'return attr_a->symconst_id != attr_b->symconst_id;',
351 },
352
353 mflo => {
354   reg_req => { in => [ "none" ], out => [ "gp" ] },
355   emit    => '. mflo %D1'
356 },
357
358 mfhi => {
359   reg_req => { in => [ "none" ], out => [ "gp" ] },
360   emit    => '. mfhi %D1'
361 },
362
363 zero => {
364   reg_req => { out => [ "zero" ] },
365   emit => '',
366 },
367
368 #
369 #  ____                       _        __  _
370 # | __ ) _ __ __ _ _ __   ___| |__    / / | |_   _ _ __ ___  _ __
371 # |  _ \| '__/ _` | '_ \ / __| '_ \  / /  | | | | | '_ ` _ \| '_ \
372 # | |_) | | | (_| | | | | (__| | | |/ / |_| | |_| | | | | | | |_) |
373 # |____/|_|  \__,_|_| |_|\___|_| |_/_/ \___/ \__,_|_| |_| |_| .__/
374 #                                                           |_|
375 #
376
377 slt => {
378         reg_req => { in => [ "gp", "gp" ], out => [ "gp" ] },
379         emit => '
380         if (mode_is_signed(get_irn_mode(n))) {
381 2.              slt %D1, %S1, %S2
382         }
383         else {
384 2.              sltu %D1, %S1, %S2
385         }
386 ',
387 },
388
389 slti => {
390         reg_req => { in => [ "gp" ], out => [ "gp" ] },
391         emit => '
392         if (mode_is_signed(get_irn_mode(n))) {
393 2.              slti %D1, %S1, %C
394         }
395         else {
396 2.              sltiu %D1, %S1, %C
397         }
398 ',
399   cmp_attr => 'return attr_a->tv != attr_b->tv;',
400 },
401
402 beq => {
403         op_flags  => "X|Y",
404         # TxT -> TxX
405         reg_req => { in => [ "gp", "gp" ], out => [ "in_r0", "none" ] },
406         emit => '
407         ir_node *jumpblock = mips_get_jump_block(n, 1);
408         assert(jumpblock != NULL);
409
410         (void) cmd_buf;
411         (void) cmnt_buf;
412         lc_efprintf(arg_env, F, "\tbeq %1S, %2S, BLOCK_%d\n", n, n, get_irn_node_nr(jumpblock));
413 '
414 },
415
416 bne => {
417         op_flags  => "X|Y",
418         # TxT -> TxX
419         reg_req => { in => [ "gp", "gp" ], out => [ "in_r0", "none" ] },
420         emit => '
421         ir_node *jumpblock = mips_get_jump_block(n, 1);
422         assert(jumpblock != NULL);
423
424         (void) cmd_buf;
425         (void) cmnt_buf;
426         lc_efprintf(arg_env, F, "\tbne %1S, %2S, BLOCK_%d\n", n, n, get_irn_node_nr(jumpblock));
427 '
428 },
429
430 bgtz => {
431         op_flags  => "X|Y",
432         # TxT -> TxX
433         reg_req => { in => [ "gp" ], out => [ "in_r0", "none" ] },
434         emit => '
435         ir_node *jumpblock = mips_get_jump_block(n, 1);
436         assert(jumpblock != NULL);
437
438         (void) cmd_buf;
439         (void) cmnt_buf;
440         lc_efprintf(arg_env, F, "\tbgtz %1S, BLOCK_%d\n", n, get_irn_node_nr(jumpblock));
441 '
442 },
443
444 blez => {
445         op_flags  => "X|Y",
446         # TxT -> TxX
447         reg_req => { in => [ "gp" ], out => [ "in_r0", "none" ] },
448         emit => '
449         ir_node *jumpblock = mips_get_jump_block(n, 1);
450         assert(jumpblock != NULL);
451
452         (void) cmd_buf;
453         (void) cmnt_buf;
454         lc_efprintf(arg_env, F, "\tblez %1S, BLOCK_%d\n", n, get_irn_node_nr(jumpblock));
455 '
456 },
457
458 j => {
459   op_flags => "X",
460   reg_req => { in => [ "gp" ] },
461   emit => '. j %S1',
462 },
463
464 b => {
465   op_flags => "X",
466   # -> X
467   reg_req => { in => [ ], out => [ "none" ] },
468   emit => '
469         ir_node *jumpblock = get_irn_link(n);
470         assert(jumpblock != NULL);
471
472         (void) cmd_buf;
473         (void) cmnt_buf;
474         lc_efprintf(arg_env, F, "\tb BLOCK_%d\t\t\t# mips_b\n", get_irn_node_nr(jumpblock));
475 '
476 },
477
478 fallthrough => {
479   op_flags => "X",
480   # -> X
481   reg_req => { in => [ ], out => [ "none" ] },
482   emit => '. # fallthrough'
483 },
484
485 SwitchJump => {
486   op_flags => "X",
487   # -> X,X,...
488   reg_req => { in => [ "gp" ], out => [ "none" ] },
489   emit => '. j %S1'
490 },
491
492 #  _                    _
493 # | |    ___   __ _  __| |
494 # | |   / _ \ / _` |/ _` |
495 # | |__| (_) | (_| | (_| |
496 # |_____\___/ \__,_|\__,_|
497 #
498
499 load_r => {
500   reg_req       => { in => [ "none", "gp" ], out => [ "none", "none", "gp" ] },
501   emit          => '
502         mips_attr_t* attr = get_mips_attr(n);
503         ir_mode *mode;
504
505         mode = attr->modes.load_store_mode;
506
507         switch (get_mode_size_bits(mode)) {
508         case 8:
509                 if (mode_is_signed(mode)) {
510 3.                      lb %D3, %C(%S2)
511                 }
512                 else {
513 3.                      lbu %D3, %C(%S2)
514                 }
515                 break;
516         case 16:
517                 if (mode_is_signed(mode)) {
518 3.                      lh %D3, %C(%S2)
519                 }
520                 else {
521 3.                      lhu %D3, %C(%S2)
522                 }
523                 break;
524         case 32:
525 2.              lw %D3, %C(%S2)
526                 break;
527         default:
528                 assert(! "Only 8, 16 and 32 bit loads supported");
529                 break;
530         }
531 ',
532   cmp_attr => 'return attr_a->tv != attr_b->tv || attr_a->stack_entity != attr_b->stack_entity;',
533 },
534
535
536 #  _                    _    ______  _
537 # | |    ___   __ _  __| |  / / ___|| |_ ___  _ __ ___
538 # | |   / _ \ / _` |/ _` | / /\___ \| __/ _ \| '__/ _ \
539 # | |__| (_) | (_| | (_| |/ /  ___) | || (_) | | |  __/
540 # |_____\___/ \__,_|\__,_/_/  |____/ \__\___/|_|  \___|
541 #
542
543 store_r => {
544   reg_req       => { in => [ "none", "gp", "gp" ], out => [ "none", "none" ] },
545   emit          => '
546         mips_attr_t* attr = get_mips_attr(n);
547         ir_mode* mode;
548
549         mode = attr->modes.load_store_mode;
550
551         switch (get_mode_size_bits(mode)) {
552         case 8:
553                 if (mode_is_signed(mode))
554 2.              sb %S3, %C(%S2)
555                 break;
556         case 16:
557                 if (mode_is_signed(mode))
558 2.              sh %S3, %C(%S2)
559                 break;
560         case 32:
561 2.              sw %S3, %C(%S2)
562                 break;
563         default:
564                 assert(! "Only 8, 16 and 32 bit stores supported");
565                 break;
566         }
567 ',
568   cmp_attr => 'return attr_a->tv != attr_b->tv;',
569 },
570
571 store_i => {
572   reg_req       => { in => [ "none", "none", "gp" ], out => [ "none", "none" ] },
573   emit          => '
574         mips_attr_t* attr = get_mips_attr(n);
575         ir_mode *mode;
576
577         mode = attr->modes.load_store_mode;
578
579         switch (get_mode_size_bits(mode)) {
580         case 8:
581 2.              sb %S3, %C
582                 break;
583         case 16:
584 2.              sh %S3, %C
585                 break;
586         case 32:
587 2.              sw %S3, %C
588                 break;
589         default:
590                 assert(! "Only 8, 16 and 32 bit stores supported");
591                 break;
592         }
593 ',
594   cmp_attr => '
595         return attr_a->stack_entity != attr_b->stack_entity;
596 ',
597 },
598
599 move => {
600   reg_req   => { in => [ "gp" ], out => [ "gp" ] },
601   emit      => '. or %D1, $zero, %S1'
602 },
603
604 #
605 # Conversion
606 #
607
608 reinterpret_conv => {
609   reg_req   => { in => [ "gp" ], out => [ "in_r1" ] },
610   emit      => '. # reinterpret %S1 -> %D1',
611 },
612
613 #
614 # Miscelaneous
615 #
616
617 nop => {
618   op_flags  => "K",
619   reg_req       => { in => [], out => [ "none" ] },
620   emit          => '. nop  # nop',
621 },
622
623 ); # end of %nodes