make sparc+arm backend completely independent from beabi
[libfirm] / ir / be / beemitter_binary.c
1 /*
2  * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
3  *
4  * This file is part of libFirm.
5  *
6  * This file may be distributed and/or modified under the terms of the
7  * GNU General Public License version 2 as published by the Free Software
8  * Foundation and appearing in the file LICENSE.GPL included in the
9  * packaging of this file.
10  *
11  * Licensees holding valid libFirm Professional Edition licenses may use
12  * this file in accordance with the libFirm Commercial License.
13  * Agreement provided with the Software.
14  *
15  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE.
18  */
19
20 /**
21  * @file
22  * @brief       Interface for machine code output
23  * @author      Matthias Braun
24  * @date        12.03.2007
25  * @version     $Id$
26  */
27 #include "config.h"
28
29 #include <assert.h>
30 #include <limits.h>
31
32 #include "beemitter_binary.h"
33 #include "obst.h"
34 #include "pdeq.h"
35 #include "error.h"
36
37 static code_fragment_t *first_fragment;
38 static code_fragment_t *last_fragment;
39 static const unsigned CODE_FRAGMENT_MAGIC = 0x4643414d;  /* "CFMA" */
40
41 struct obstack code_fragment_obst;
42
43 /** returns current fragment (the address stays only valid until the next
44     be_emit(8/16/32/entity) call!) */
45 code_fragment_t *be_get_current_fragment(void)
46 {
47         code_fragment_t *fragment = obstack_base(&code_fragment_obst);
48         assert(obstack_object_size(&code_fragment_obst) >= sizeof(code_fragment_t));
49         assert(fragment->magic == CODE_FRAGMENT_MAGIC);
50
51         return fragment;
52 }
53
54 /** allocates a new fragment on the obstack (warning: address is only valid
55     till next be_emit */
56 static void alloc_fragment(void)
57 {
58         code_fragment_t *fragment;
59
60         /* shouldn't have any growing fragments */
61         assert(obstack_object_size(&code_fragment_obst) == 0);
62
63         obstack_blank(&code_fragment_obst, sizeof(*fragment));
64         fragment = obstack_base(&code_fragment_obst);
65         memset(fragment, 0, sizeof(*fragment));
66 #ifndef NDEBUG
67         fragment->magic = CODE_FRAGMENT_MAGIC;
68 #endif
69         fragment->len        = 0;
70         fragment->alignment  = 1;
71         fragment->offset     = 0;
72         fragment->max_offset = UINT_MAX;
73 }
74
75 static code_fragment_t *finish_fragment(void)
76 {
77         code_fragment_t *fragment = be_get_current_fragment();
78         fragment->len
79                 = obstack_object_size(&code_fragment_obst) - sizeof(*fragment);
80
81         fragment      = (code_fragment_t*) obstack_finish(&code_fragment_obst);
82         last_fragment = fragment;
83
84         if (first_fragment == NULL)
85                 first_fragment = fragment;
86
87         return fragment;
88 }
89
90 void be_start_code_emitter(void)
91 {
92         obstack_init(&code_fragment_obst);
93         first_fragment = NULL;
94         alloc_fragment();
95 }
96
97 void be_start_new_fragment(void)
98 {
99         finish_fragment();
100         alloc_fragment();
101 }
102
103 static void emit(FILE *file, const unsigned char *buffer, size_t len)
104 {
105         size_t i;
106         for (i = 0; i < len; ++i) {
107                 size_t i2;
108                 fputs("\t.byte ", file);
109                 for (i2 = i; i2 < i + 30 && i2 < len; ++i2) {
110                         fprintf(file, "0x%02X", buffer[i2]);
111                 }
112                 i = i2;
113                 fputs("\n", file);
114         }
115 }
116
117 static unsigned align(unsigned offset, unsigned alignment)
118 {
119         if (offset % alignment != 0) {
120                 offset += alignment - (offset % alignment);
121         }
122         return offset;
123 }
124
125 static bool determine_jumpsize_iteration(
126                 const binary_emiter_interface_t *interface)
127 {
128         unsigned         offset     = 0;
129         unsigned         max_offset = 0;
130         bool             changed    = false;
131         code_fragment_t *fragment;
132
133         for (fragment = first_fragment; fragment != NULL;
134              fragment = fragment->next) {
135             unsigned alignment = fragment->alignment;
136
137             /* assure alignment */
138             offset     = align(offset, alignment);
139             max_offset = align(max_offset, alignment);
140
141                 if (offset != fragment->offset) {
142                         changed          = true;
143                         fragment->offset = offset;
144                 }
145             fragment->max_offset = max_offset;
146
147                 /* advance offset */
148                 offset     += fragment->len;
149                 max_offset += fragment->len;
150                 interface->determine_jumpsize(fragment);
151                 offset     += fragment->jumpsize_min;
152                 max_offset += fragment->jumpsize_max;
153         }
154
155         return changed;
156 }
157
158 static void determine_offsets(const binary_emiter_interface_t *interface)
159 {
160         bool changed;
161
162         assert(first_fragment->alignment == 1);
163         first_fragment->offset     = 0;
164         first_fragment->max_offset = 0;
165
166         /* The algorithm calculates a lower and upper bound for the offset of each
167          * fragment. With this information we can calculate a lower and upper bound
168          * for the size of each jump instruction.
169          * A single iteration updates the offset bounds for all fragments and jump
170          * sizes for each fragment. We iterate until we had an iteration where
171          * none of the minimum offsets changed. */
172         do {
173                 changed = determine_jumpsize_iteration(interface);
174                 /* TODO: we should have an abort mode for the case when the offsets
175                    don't converge fast enough. We could simply use a pessimistic
176                    solution after a few iterations... */
177         } while (changed);
178 }
179
180 void be_emit_entity(ir_entity *entity, bool entity_sign, int offset,
181                     bool is_relative)
182 {
183         (void) entity;
184         (void) entity_sign;
185         (void) offset;
186         (void) is_relative;
187         panic("not implemented yet");
188 }
189
190 void be_emit_code(FILE *output, const binary_emiter_interface_t *interface)
191 {
192         unsigned offset;
193
194         code_fragment_t *fragment;
195
196         finish_fragment();
197
198         /* determine near/far jumps */
199         determine_offsets(interface);
200
201         /* emit code */
202         offset = 0;
203         for (fragment = first_fragment; fragment != NULL;
204              fragment = fragment->next) {
205             unsigned char *jmpbuffer;
206                 unsigned nops;
207
208             /* assure alignment by emitting nops */
209             assert(fragment->offset >= offset);
210             nops = fragment->offset - offset;
211             if (nops > 0) {
212                         unsigned char *nopbuffer = obstack_alloc(&code_fragment_obst, nops);
213                         interface->create_nops(nopbuffer, nops);
214                         emit(output, nopbuffer, nops);
215                         offset = fragment->offset;
216                         obstack_free(&code_fragment_obst, nopbuffer);
217                 }
218
219                 /* emit the fragment */
220                 emit(output, fragment->data, fragment->len);
221                 offset += fragment->len;
222
223                 /* emit the jump */
224                 jmpbuffer = obstack_alloc(&code_fragment_obst, fragment->jumpsize_min);
225                 interface->emit_jump(fragment, jmpbuffer);
226                 emit(output, jmpbuffer, fragment->jumpsize_min);
227                 offset += fragment->jumpsize_min;
228                 obstack_free(&code_fragment_obst, jmpbuffer);
229         }
230 }