beuses: Remove stale start loop test.
[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  */
26 #include "config.h"
27
28 #include <assert.h>
29 #include <limits.h>
30
31 #include "beemitter_binary.h"
32 #include "obst.h"
33 #include "pdeq.h"
34 #include "error.h"
35
36 static code_fragment_t *first_fragment;
37 static code_fragment_t *last_fragment;
38 static const unsigned CODE_FRAGMENT_MAGIC = 0x4643414d;  /* "CFMA" */
39
40 struct obstack code_fragment_obst;
41
42 /** returns current fragment (the address stays only valid until the next
43     be_emit(8/16/32/entity) call!) */
44 code_fragment_t *be_get_current_fragment(void)
45 {
46         code_fragment_t *fragment = (code_fragment_t*)obstack_base(&code_fragment_obst);
47         assert(obstack_object_size(&code_fragment_obst) >= sizeof(code_fragment_t));
48         assert(fragment->magic == CODE_FRAGMENT_MAGIC);
49
50         return fragment;
51 }
52
53 /** allocates a new fragment on the obstack (warning: address is only valid
54     till next be_emit */
55 static void alloc_fragment(void)
56 {
57         code_fragment_t *fragment;
58
59         /* shouldn't have any growing fragments */
60         assert(obstack_object_size(&code_fragment_obst) == 0);
61
62         obstack_blank(&code_fragment_obst, sizeof(*fragment));
63         fragment = (code_fragment_t*)obstack_base(&code_fragment_obst);
64         memset(fragment, 0, sizeof(*fragment));
65 #ifndef NDEBUG
66         fragment->magic = CODE_FRAGMENT_MAGIC;
67 #endif
68         fragment->len        = 0;
69         fragment->alignment  = 1;
70         fragment->offset     = 0;
71         fragment->max_offset = UINT_MAX;
72 }
73
74 static code_fragment_t *finish_fragment(void)
75 {
76         code_fragment_t *fragment = be_get_current_fragment();
77         fragment->len
78                 = obstack_object_size(&code_fragment_obst) - sizeof(*fragment);
79
80         fragment      = (code_fragment_t*) obstack_finish(&code_fragment_obst);
81         last_fragment = fragment;
82
83         if (first_fragment == NULL)
84                 first_fragment = fragment;
85
86         return fragment;
87 }
88
89 void be_start_code_emitter(void)
90 {
91         obstack_init(&code_fragment_obst);
92         first_fragment = NULL;
93         alloc_fragment();
94 }
95
96 void be_start_new_fragment(void)
97 {
98         finish_fragment();
99         alloc_fragment();
100 }
101
102 static void emit(FILE *file, const unsigned char *buffer, size_t len)
103 {
104         size_t i;
105         for (i = 0; i < len; ++i) {
106                 size_t i2;
107                 fputs("\t.byte ", file);
108                 for (i2 = i; i2 < i + 30 && i2 < len; ++i2) {
109                         fprintf(file, "0x%02X", (unsigned)buffer[i2]);
110                 }
111                 i = i2;
112                 fputs("\n", file);
113         }
114 }
115
116 static unsigned align(unsigned offset, unsigned alignment)
117 {
118         if (offset % alignment != 0) {
119                 offset += alignment - (offset % alignment);
120         }
121         return offset;
122 }
123
124 static bool determine_jumpsize_iteration(
125                 const binary_emiter_interface_t *interface)
126 {
127         unsigned         offset     = 0;
128         unsigned         max_offset = 0;
129         bool             changed    = false;
130         code_fragment_t *fragment;
131
132         for (fragment = first_fragment; fragment != NULL;
133              fragment = fragment->next) {
134             unsigned alignment = fragment->alignment;
135
136             /* assure alignment */
137             offset     = align(offset, alignment);
138             max_offset = align(max_offset, alignment);
139
140                 if (offset != fragment->offset) {
141                         changed          = true;
142                         fragment->offset = offset;
143                 }
144             fragment->max_offset = max_offset;
145
146                 /* advance offset */
147                 offset     += fragment->len;
148                 max_offset += fragment->len;
149                 interface->determine_jumpsize(fragment);
150                 offset     += fragment->jumpsize_min;
151                 max_offset += fragment->jumpsize_max;
152         }
153
154         return changed;
155 }
156
157 static void determine_offsets(const binary_emiter_interface_t *interface)
158 {
159         bool changed;
160
161         assert(first_fragment->alignment == 1);
162         first_fragment->offset     = 0;
163         first_fragment->max_offset = 0;
164
165         /* The algorithm calculates a lower and upper bound for the offset of each
166          * fragment. With this information we can calculate a lower and upper bound
167          * for the size of each jump instruction.
168          * A single iteration updates the offset bounds for all fragments and jump
169          * sizes for each fragment. We iterate until we had an iteration where
170          * none of the minimum offsets changed. */
171         do {
172                 changed = determine_jumpsize_iteration(interface);
173                 /* TODO: we should have an abort mode for the case when the offsets
174                    don't converge fast enough. We could simply use a pessimistic
175                    solution after a few iterations... */
176         } while (changed);
177 }
178
179 void be_emit_entity(ir_entity *entity, bool entity_sign, int offset,
180                     bool is_relative)
181 {
182         (void) entity;
183         (void) entity_sign;
184         (void) offset;
185         (void) is_relative;
186         panic("not implemented yet");
187 }
188
189 void be_emit_code(FILE *output, const binary_emiter_interface_t *interface)
190 {
191         unsigned offset;
192
193         code_fragment_t *fragment;
194
195         finish_fragment();
196
197         /* determine near/far jumps */
198         determine_offsets(interface);
199
200         /* emit code */
201         offset = 0;
202         for (fragment = first_fragment; fragment != NULL;
203              fragment = fragment->next) {
204             unsigned char *jmpbuffer;
205                 unsigned nops;
206
207             /* assure alignment by emitting nops */
208             assert(fragment->offset >= offset);
209             nops = fragment->offset - offset;
210             if (nops > 0) {
211                         unsigned char *nopbuffer = (unsigned char*)obstack_alloc(&code_fragment_obst, nops);
212                         interface->create_nops(nopbuffer, nops);
213                         emit(output, nopbuffer, nops);
214                         offset = fragment->offset;
215                         obstack_free(&code_fragment_obst, nopbuffer);
216                 }
217
218                 /* emit the fragment */
219                 emit(output, fragment->data, fragment->len);
220                 offset += fragment->len;
221
222                 /* emit the jump */
223                 jmpbuffer = (unsigned char*)obstack_alloc(&code_fragment_obst, fragment->jumpsize_min);
224                 interface->emit_jump(fragment, jmpbuffer);
225                 emit(output, jmpbuffer, fragment->jumpsize_min);
226                 offset += fragment->jumpsize_min;
227                 obstack_free(&code_fragment_obst, jmpbuffer);
228         }
229 }