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