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