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