Moved insert_Perm_after to benode.c
[libfirm] / ir / be / beasm_asm_gnu.c
1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4
5 #include <stdlib.h>
6 #include <string.h>
7 #include <ctype.h>
8
9 #include "obst.h"
10 #include "beasm_asm_gnu.h"
11
12 static struct obstack *get_obstack_for_segment ( gnuasm_privdata_t *privdata, asm_segment_t segment ) {
13
14         switch (segment) {
15                 case ASM_SEGMENT_CONST:
16                         return &privdata->rdata_obst;
17                         break;
18                 case ASM_SEGMENT_DATA_INIT:
19                         return &privdata->data_obst;
20                         break;
21                 case ASM_SEGMENT_CODE:
22                         return &privdata->code_obst;
23                         break;
24                 case ASM_SEGMENT_DATA_UNINIT:
25                         return &privdata->common_obst;
26                         break;
27                 default:
28                         assert(0 && "unknown segment type");
29                         break;
30         }
31   return NULL;
32 }
33
34
35 /**
36  * the dumper callbacks
37  */
38 /*
39 static void gnuasm_dump_align(void *data, asm_segment_t segment, int align) {
40   gnuasm_privdata_t *privdata = data;
41         struct obstack* obst = get_obstack_for_segment( privdata, segment );
42         obstack_printf(obst, "\t.align %d\n", align);
43 }
44 */
45
46 static void gnuasm_dump_arith_tarval(void *data, asm_segment_t segment, tarval *tv, int bytes)
47 {
48   gnuasm_privdata_t *privdata = data;
49         struct obstack* obst = get_obstack_for_segment ( privdata, segment );
50
51         switch (bytes) {
52
53         case 1:
54                 obstack_printf(obst, "0x%02x", get_tarval_sub_bits(tv, 0));
55                 break;
56         case 2:
57                 obstack_printf(obst, "0x%02x%02x", get_tarval_sub_bits(tv, 1), get_tarval_sub_bits(tv, 0));
58                 break;
59
60         case 4:
61                 obstack_printf(obst, "0x%02x%02x%02x%02x",
62                 get_tarval_sub_bits(tv, 3), get_tarval_sub_bits(tv, 2), get_tarval_sub_bits(tv, 1), get_tarval_sub_bits(tv, 0));
63                 break;
64
65         case 8:
66                 obstack_printf(obst, "0x%02x%02x%02x%02x%02x%02x%02x%02x",
67 get_tarval_sub_bits(tv, 7), get_tarval_sub_bits(tv, 6), get_tarval_sub_bits(tv, 5), get_tarval_sub_bits(tv, 4), get_tarval_sub_bits(tv, 3), get_tarval_sub_bits(tv, 2), get_tarval_sub_bits(tv, 1), get_tarval_sub_bits(tv, 0));
68                 break;
69
70         default:
71                 fprintf(stderr, "Try to dump an tarval with %d bytes\n", bytes);
72                 assert(0);
73         }
74 }
75
76
77 static void gnuasm_dump_atomic_decl(void *data, asm_segment_t segment, int bytes)
78 {
79   gnuasm_privdata_t *privdata = data;
80         struct obstack* obst = get_obstack_for_segment( privdata, segment );
81
82         switch (bytes) {
83
84         case 1:
85                 obstack_printf(obst, "\t.byte\t");
86                 break;
87
88         case 2:
89                 obstack_printf(obst, "\t.value\t");
90                 break;
91
92         case 4:
93                 obstack_printf(obst, "\t.long\t");
94                 break;
95
96         case 8:
97                 obstack_printf(obst, "\t.quad\t");
98                 break;
99
100         default:
101                 fprintf(stderr, "Try to dump an tarval with %d bytes\n", bytes);
102                 assert(0);
103         }
104
105 //      obstack_printf(obst, "\n");
106 }
107
108 static void gnuasm_dump_string(void *data, asm_segment_t segment, entity *ent)
109 {
110   gnuasm_privdata_t *privdata = data;
111   int i, n;
112
113   struct obstack* obst = get_obstack_for_segment ( privdata, segment );
114
115   obstack_printf(obst, "\t.string \"");
116   n = get_compound_ent_n_values(ent);
117
118   for (i = 0; i < n-1; ++i) {
119     ir_node *irn;
120     int c;
121
122     irn = get_compound_ent_value(ent, i);
123     c = (int) get_tarval_long(get_Const_tarval(irn));
124
125     switch (c) {
126     case '"' : obstack_printf(obst, "\\\""); break;
127     case '\n': obstack_printf(obst, "\\n");  break;
128     case '\r': obstack_printf(obst, "\\r");  break;
129     case '\t': obstack_printf(obst, "\\t");  break;
130     default:
131       if (isprint(c))
132               obstack_printf(obst, "%c", c);
133       else
134               obstack_printf(obst, "%O", c);
135       break;
136     }
137   }
138   obstack_printf(obst, "\"\n");
139 }
140
141
142 static void gnuasm_dump_declare_initialized_symbol(void *data, asm_segment_t segment, const char* ld_name, int bytes, int align, ent_visibility visibility)
143 {
144   gnuasm_privdata_t* priv_data = data;
145
146   /* get the obstack for the given segment (const, data) */
147   struct obstack* obst = get_obstack_for_segment ( priv_data, segment );
148
149   /* if the symbol is externally visible, declare it so. */
150   if (visibility == visibility_external_visible)
151     obstack_printf(obst, ".globl\t%s\n", ld_name);
152
153   obstack_printf(obst, "\t.type\t%s,@object\n", ld_name);
154   obstack_printf(obst, "\t.size\t%s,%d\n", ld_name, bytes);
155   obstack_printf(obst, "\t.align\t%d\n", align);
156   obstack_printf(obst, "\t%s:\n", ld_name);
157 }
158
159 static void gnuasm_dump_declare_uninitialized_symbol(void *data, asm_segment_t segment, const char* ld_name, int bytes, int align, ent_visibility visibility)
160 {
161   gnuasm_privdata_t *priv_data = data;
162
163   /* external symbols are not required to be declared in gnuasm. */
164   if(visibility == visibility_external_allocated) return;
165
166   /* declare local, uninitialized symbol to the uninit-obst */
167   obstack_printf(&priv_data->common_obst, "\t.comm\t%s,%d,%d\n", ld_name, bytes, align);
168 }
169
170 static void gnuasm_dump_zero_padding(void *data, asm_segment_t segment, int size)
171 {
172   gnuasm_privdata_t *privdata = data;
173         struct obstack* obst = get_obstack_for_segment ( privdata, segment );
174         obstack_printf(obst, "\t.zero\t%d\n", size);
175 }
176
177 ////////////////////////////////////////////////////////////////////////////
178
179 static void gnuasm_dump_arith_op(void *data, asm_segment_t segment, asm_arith_operation_t op)
180 {
181   gnuasm_privdata_t *privdata = data;
182         struct obstack* obst = get_obstack_for_segment ( privdata, segment );
183         switch (op) {
184                 case ASM_ARITH_OPERATION_ADD:
185                         obstack_printf(obst, "+");
186                         break;
187                 case ASM_ARITH_OPERATION_SUB:
188                         obstack_printf(obst, "-");
189                         break;
190                 case ASM_ARITH_OPERATION_MUL:
191                         obstack_printf(obst, "*");
192                         break;
193         }
194         //obstack_printf(obst, "+");
195 }
196
197 static void gnuasm_dump_symconst(void *data, asm_segment_t segment, ir_node *init)
198 {
199   gnuasm_privdata_t *privdata = data;
200   struct obstack* obst = get_obstack_for_segment ( privdata, segment );
201   switch (get_SymConst_kind(init)) {
202     case symconst_addr_name:
203         obstack_printf(obst, "%s", get_id_str(get_SymConst_name(init)));
204       break;
205
206     case symconst_addr_ent:
207         obstack_printf(obst, "%s", get_entity_ld_name(get_SymConst_entity(init)));
208       break;
209
210     case symconst_size:
211         obstack_printf(obst, "%d", get_type_size_bytes(get_SymConst_type(init)));
212       break;
213
214     default:
215       assert(0 && "dump_atomic_init(): don't know how to init from this SymConst");
216     }
217 }
218
219 static void gnuasm_dump_newline(void *data, asm_segment_t segment)
220 {
221   gnuasm_privdata_t *privdata = data;
222         struct obstack* obst = get_obstack_for_segment ( privdata, segment );
223         obstack_printf(obst, "\n");
224 }
225
226 //////////////////////////////////////////////////////////////////////////////
227
228 static void gnuasm_dump_header(void *data) {
229   /*gnuasm_privdata_t *privdata = data;*/
230 }
231
232 static void gnuasm_dump_footer(void *data) {
233   /*gnuasm_privdata_t *privdata = data;*/
234 }
235
236 static void gnuasm_dump_segment_header(void *data) {
237   /*gnuasm_privdata_t *privdata = data;*/
238 }
239
240 //////////////////////////////////////////////////////////////////////////////
241
242 assembler_t *gnuasm_create_assembler ( void ) {
243
244         gnuasm_privdata_t *priv_data = malloc ( sizeof(gnuasm_privdata_t ));
245         assembler_t *assembler = malloc ( sizeof( assembler_t ));
246         memset(assembler, 0, sizeof( assembler_t ));
247         assembler->private_data = priv_data;
248
249         obstack_init (&priv_data->common_obst);
250         obstack_init (&priv_data->data_obst);
251         obstack_init (&priv_data->rdata_obst);
252         obstack_init (&priv_data->code_obst);
253
254
255   assembler->dump_declare_uninitialized_symbol = gnuasm_dump_declare_uninitialized_symbol;
256   assembler->dump_declare_initialized_symbol   = gnuasm_dump_declare_initialized_symbol;
257
258 //  assembler->dump_align = (dump_align_proc) &gnuasm_dump_align;
259         assembler->dump_arith_tarval = gnuasm_dump_arith_tarval;
260         assembler->dump_atomic_decl  = gnuasm_dump_atomic_decl;
261         assembler->dump_string       = gnuasm_dump_string;
262         assembler->dump_zero_padding = gnuasm_dump_zero_padding;
263         assembler->dump_arith_op     = gnuasm_dump_arith_op;
264         assembler->dump_symconst     = gnuasm_dump_symconst;
265         assembler->dump_newline      = gnuasm_dump_newline;
266
267         assembler->dump_header         = gnuasm_dump_header;
268         assembler->dump_footer         = gnuasm_dump_footer;
269         assembler->dump_segment_header = gnuasm_dump_segment_header;
270
271
272         return assembler;
273
274 }
275
276 static void gnuasm_dump_obst(struct obstack *obst, FILE *out) {
277         obstack_grow0 (obst, NULL, 0);
278         fprintf(out, "%s", (char *)obstack_finish(obst));
279 }
280
281 void gnuasm_dump( assembler_t *assembler, FILE *out ) {
282
283         gnuasm_privdata_t *privdata = assembler->private_data;
284
285 //      fprintf(out, "<COMMON>\n");
286         gnuasm_dump_obst ( &privdata->common_obst, out);
287         fprintf(out, ".data\n");
288         gnuasm_dump_obst ( &privdata->data_obst, out);
289         fprintf(out, ".section .rodata\n");
290         gnuasm_dump_obst ( &privdata->rdata_obst, out);
291         fprintf(out, ".text\n");
292         gnuasm_dump_obst ( &privdata->code_obst, out);
293         //////
294 }
295
296 void gnuasm_delete_assembler( assembler_t *assembler ) {
297         free( assembler->private_data );
298         free( assembler );
299 }