dc4274ceba120553eea31ab86a8ee90f32250ac5
[libfirm] / ir / be / scripts / generate_emitter.pl
1 #!/usr/bin/perl -w
2
3 # This script generates C code which emits assembler code for the
4 # assembler ir nodes. It takes a "emit" key from the node specification
5 # and substitutes lines starting with . with a corresponding fprintf().
6 # Creation: 2005/11/07
7 # $Id$
8
9 use strict;
10 use Data::Dumper;
11
12 my $specfile   = $ARGV[0];
13 my $target_dir = $ARGV[1];
14
15 my $target_c = $target_dir."/emitter_gen.c";
16 my $target_h = $target_dir."/emitter_gen.h";
17
18 our $arch;
19 our %nodes;
20
21 # include spec file
22
23 my $return;
24
25 no strict "subs";
26 unless ($return = do $specfile) {
27   warn "couldn't parse $specfile: $@" if $@;
28   warn "couldn't do $specfile: $!"    unless defined $return;
29   warn "couldn't run $specfile"       unless $return;
30 }
31 use strict "subs";
32
33 # stacks for output
34 my @obst_func;   # stack for the emit functions
35 my @obst_header;  # stack for the function prototypes
36
37 my $line;
38
39 foreach my $op (keys(%nodes)) {
40   my %n = %{ $nodes{"$op"} };
41
42   # skip this node description if no emit information is available
43   next if (!$n{"emit"} || length($n{"emit"}) < 1);
44
45   $line = "void emit_".$arch."_".$op."(FILE *F, ir_node *n)";
46   push(@obst_header, $line.";\n");
47   push(@obst_func, $line." {\n");
48
49   my @emit = split(/\n/, $n{"emit"});
50
51   foreach(@emit) {
52     # substitute only lines, starting with a '.'
53     if (/^(\d*)\.\s*/) {
54       my @params;
55       my $regkind;
56       my $indent = "  "; # default indent is 2 spaces
57
58       $indent = " " x $1 if ($1 && $1 > 0);
59       # remove indent, dot and trailing spaces
60       s/^\d*\.\s*//;
61       # substitute all format parameter
62       while (/%(([sd])(\d)|([co]))/) {
63         if ($4 && $4 eq "c") {
64           push(@params, "node_const_to_str(n)");
65         }
66         elsif ($4 && $4 eq "o") {
67           push(@params, "node_offset_to_str(n)");
68         }
69         else {
70           $regkind = ($2 eq "s" ? "source" : "dest");
71           push(@params, "get_".$regkind."_reg(n, $3)");
72         }
73         s/%$1/%%\%s/;
74       }
75       my $parm = "";
76       $parm = ", ".join(", ", @params) if (@params);
77       push(@obst_func, $indent.'fprintf(F, "\t'.$_.'\n"'.$parm.');'."\n");
78     }
79     else {
80       push(@obst_func, $_,"\n");
81     }
82   }
83   push(@obst_func, "}\n\n");
84 }
85
86 open(OUT, ">$target_h") || die("Could not open $target_h, reason: $!\n");
87
88 my $creation_time = localtime(time());
89
90 print OUT<<EOF;
91 #ifndef _EMITTER_GEN_H_
92 #define _EMITTER_GEN_H_
93
94 /**
95  * Function prototypes for the emitter functions.
96  * DO NOT EDIT THIS FILE, your changes will be lost.
97  * Edit $specfile instead.
98  * created by: $0 $specfile $target_dir
99  * date:       $creation_time
100  */
101
102 #include "irnode.h"
103
104 EOF
105
106 print OUT @obst_header;
107
108 print OUT "#endif /* _EMITTER_GEN_H_ */\n";
109
110 close(OUT);
111
112 open(OUT, ">$target_c") || die("Could not open $target_c, reason: $!\n");
113
114 $creation_time = localtime(time());
115
116 print OUT<<EOF;
117 /**
118  * Generated functions to emit code for assembler ir nodes.
119  * DO NOT EDIT THIS FILE, your changes will be lost.
120  * Edit $specfile instead.
121  * created by: $0 $specfile $target_dir
122  * date:       $creation_time
123  */
124
125 #include <stdio.h>
126
127 #include "irnode.h"
128 #include "emitter_gen.h"
129 #include "emitter.h"
130
131 EOF
132
133 print OUT @obst_func;
134
135 close(OUT);