summaryrefslogtreecommitdiff
path: root/other/burneye2/codegen.c
diff options
context:
space:
mode:
authorRoot THC2026-02-24 12:42:47 +0000
committerRoot THC2026-02-24 12:42:47 +0000
commitc9cbeced5b3f2bdd7407e29c0811e65954132540 (patch)
treeaefc355416b561111819de159ccbd86c3004cf88 /other/burneye2/codegen.c
parent073fe4bf9fca6bf40cef2886d75df832ef4b6fca (diff)
initial
Diffstat (limited to 'other/burneye2/codegen.c')
-rw-r--r--other/burneye2/codegen.c512
1 files changed, 512 insertions, 0 deletions
diff --git a/other/burneye2/codegen.c b/other/burneye2/codegen.c
new file mode 100644
index 0000000..be315c2
--- /dev/null
+++ b/other/burneye2/codegen.c
@@ -0,0 +1,512 @@
1/* codegen.c - generic code generation functions
2 *
3 * by scut
4 */
5
6#include <assert.h>
7#include <stdlib.h>
8#include <string.h>
9#include <limits.h>
10
11#include <common.h>
12#include <utility.h>
13
14#include <ia32/ia32_opcodes.h>
15#include <ia32/ia32-decode.h>
16#include <ia32/ia32-function.h>
17#include <ia32/ia32-dataflow.h>
18#include <codegen.h>
19#include <objwriter.h>
20
21#define CODEGEN_MAX_INST_TRIES 256
22
23/* from ia32-decode.c */
24extern ia32_opcode_e ia32_opcode_table[];
25extern char * ia32_regs_wide[];
26
27
28/*** GLOBALS */
29
30unsigned int codegen_operands[] = {
31 IA32_OP_aaa, IA32_OP_aad, IA32_OP_aam, IA32_OP_aas,
32 IA32_OP_adc, IA32_OP_add, IA32_OP_and, IA32_OP_bsf, IA32_OP_bsr,
33 IA32_OP_bswap, IA32_OP_bt, IA32_OP_btc, IA32_OP_bts, IA32_OP_cbw,
34 IA32_OP_daa, IA32_OP_das, IA32_OP_dec, IA32_OP_imul, IA32_OP_inc,
35 /* IA32_OP_lea, */ IA32_OP_mov, IA32_OP_neg,
36 /* IA32_OP_nop, */ IA32_OP_not, IA32_OP_or, IA32_OP_rcl1, IA32_OP_rcr1,
37 IA32_OP_sbb, IA32_OP_sub, IA32_OP_test, IA32_OP_xadd, IA32_OP_xchg,
38 IA32_OP_xor, 0 };
39
40unsigned int codegen_operands_length =
41 (sizeof (codegen_operands) / sizeof (unsigned int)) - 1;
42
43double * codegen_operands_prob = NULL;
44unsigned int codegen_operands_prob_count;
45
46
47/*** IMPLEMENTATION */
48
49void
50codegen_operands_prob_build (instuse_profile *iprof)
51{
52 unsigned int cgn;
53
54 if (codegen_operands_prob != NULL)
55 return;
56
57 codegen_operands_prob = xcalloc (codegen_operands_length,
58 sizeof (double));
59 codegen_operands_prob_count = codegen_operands_length;
60
61 for (cgn = 0 ; codegen_operands[cgn] != 0 ; ++cgn) {
62 codegen_operands_prob[cgn] =
63 iprof->inst_use[ia32_opnum_index (codegen_operands[cgn])];
64 }
65}
66
67
68ia32_instruction *
69codegen_generate_instruction (unsigned int opcode, unsigned int used_mask,
70 ia32_instruction *place, int source_clobbered, reguse_profile *prof)
71{
72 int imm_source;
73
74 memset (place, 0x00, sizeof (ia32_instruction));
75
76 place->opc.used = OP_SOURCE | OP_TARGET;
77 place->opc.wide = 1;
78
79 place->opc.source_reg = place->opc.target_reg = 0;
80
81 place->opc.target_width = IA32_WIDTH_32;
82 place->opc.target_type = OP_TYPE_REG;
83 place->opc.target_reg = codegen_getreg (used_mask, 1, prof, -1);
84
85 imm_source = be_random_coin (0.5);
86 if (imm_source && ia32_opcode_has_immediate (opcode,
87 IA32_WIDTH_32, IA32_WIDTH_32))
88 {
89 place->opc.imm_size = IA32_WIDTH_32;
90 place->opc.imm_value = be_random (UINT_MAX);
91 place->opc.source_type = OP_TYPE_IMM;
92
93 place->opc.source_reg = place->opc.target_reg;
94 } else {
95 place->opc.source_width = IA32_WIDTH_32;
96 place->opc.source_type = OP_TYPE_REG;
97
98 place->opc.source_reg = codegen_getreg (used_mask,
99 source_clobbered, prof, place->opc.target_reg);
100 }
101
102 /* hardwire to EAX in case its the only possible way (aaa, aam, aas,
103 * das, ..) instructions
104 */
105 if (ia32_instruction_count (opcode) == 1) {
106 ia32_opcode_e * opc = ia32_opcode_find_bynum (opcode);
107 assert (opc != NULL);
108
109 if (OD_TEST (opc->flags, OD_REG_HARD_EAX))
110 place->opc.target_reg = IA32_REG_EAX;
111
112 if ((1 << IA32_REG_EAX) & used_mask)
113 return (NULL);
114 }
115
116 if (place->opc.source_reg == -1 || place->opc.target_reg == -1)
117 return (NULL);
118
119 return (place);
120}
121
122
123/* this code is a bit messy
124 */
125
126int
127codegen_getreg (unsigned int used_mask, int clobber, reguse_profile *prof,
128 int reg_avoid)
129{
130 int reg_order[] = {
131 IA32_REG_EAX, IA32_REG_EDX, IA32_REG_EBX, IA32_REG_ECX,
132 IA32_REG_ESI, IA32_REG_EDI, IA32_REG_EBP, IA32_REG_ESP, -1 };
133 unsigned int regmask = IA32_DF_GET_REG_MASK (used_mask),
134 reg_idx,
135 prob_tries;
136 double prof_sum;
137 double reg_use[IA32_REG_COUNT];
138 int reg_tried[IA32_REG_COUNT],
139 reg_tried_count = 0;
140
141
142 /* do register picking based on probabilities
143 */
144 if (prof != NULL) {
145 reg_tried_count = 0;
146 memset (reg_tried, 0x00, sizeof (reg_tried));
147
148 /* for completely unused registers, at least put some basic
149 * chance in.
150 */
151 prof_sum = prof->sum;
152 memcpy (reg_use, prof->reg_use, sizeof (reg_use));
153 for (reg_idx = 0 ; reg_idx < IA32_REG_COUNT ; ++reg_idx) {
154 if (reg_use[reg_idx] == 0.0) {
155 reg_use[reg_idx] = 0.10;
156 prof_sum += 0.10;
157 }
158 }
159 }
160
161 for (prob_tries = 0 ;
162 prof != NULL && reg_tried_count < IA32_REG_COUNT &&
163 prob_tries < 64 ; ++prob_tries)
164 {
165 reg_idx = be_random_prob (IA32_REG_COUNT, reg_use);
166
167 if (reg_avoid >= 0 && prob_tries == (64 - 1))
168 reg_idx = reg_avoid;
169
170 if (reg_tried[reg_idx])
171 continue;
172
173 if (reg_avoid < 0 || reg_idx != reg_avoid) {
174 reg_tried[reg_idx] = 1;
175 reg_tried_count += 1;
176 }
177
178 /* try to avoid a register if desired and at all possible
179 */
180 if (prob_tries < (64 - 1) && reg_avoid >= 0 &&
181 reg_idx == reg_avoid)
182 continue;
183
184 if (clobber && (((1 << reg_idx) & regmask) == 0))
185 return (reg_idx);
186
187 if (clobber == 0 && ((1 << reg_idx) & regmask))
188 return (reg_idx);
189 }
190
191 /* do the register picking based on fixed order
192 */
193 for (reg_idx = 0 ; reg_order[reg_idx] != -1 ; ++reg_idx) {
194 if (reg_avoid >= 0 && reg_idx == reg_avoid)
195 continue;
196
197 if (clobber && (((1 << reg_order[reg_idx]) & regmask) == 0))
198 return (reg_order[reg_idx]);
199
200 if (clobber == 0 && ((1 << reg_order[reg_idx]) & regmask))
201 return (reg_order[reg_idx]);
202 }
203
204 /* fallback: if there is no used register, select eax
205 */
206 if (clobber == 0)
207 return (IA32_REG_EAX);
208
209 return (-1);
210}
211
212
213unsigned int
214codegen_generate_operation (unsigned int used_mask, int *source_clobbered,
215 instuse_profile *iprof)
216{
217 unsigned int efl_used = IA32_DF_GET_FLAGS (used_mask),
218 efl_def,
219 reg_used = IA32_DF_GET_REG_MASK (used_mask),
220 reg_def;
221 unsigned int oper,
222 in,
223 inst_tries = 0;
224 ia32_opcode_e * oel;
225
226
227 if (iprof != NULL)
228 codegen_operands_prob_build (iprof);
229
230 do {
231loop_cont:
232 if (inst_tries >= CODEGEN_MAX_INST_TRIES)
233 break;
234
235 oel = NULL;
236 if (iprof != NULL) {
237 oper = codegen_operands[be_random_prob
238 (codegen_operands_prob_count,
239 codegen_operands_prob)];
240 } else {
241 oper = codegen_operands[be_random
242 (codegen_operands_length)];
243 }
244
245 for (in = 0 ; ia32_opcode_table[in].opcode_num != 0 ; ++in) {
246 oel = NULL;
247 if (ia32_opcode_table[in].opcode_num != oper)
248 continue;
249
250 oel = &ia32_opcode_table[in];
251
252 /* in case registers get clobbered, try next encoding
253 */
254 reg_def = IA32_DF_DEF_REGMASK (oel->df_implicit_def);
255 if ((reg_def & reg_used) != 0) {
256#ifdef CODEGEN_DEBUG
257 printf ("skipping \"%s\" due to: "
258 "d:0x%02x & u:0x%02x\n",
259 oel->name, reg_def, reg_used);
260#endif
261 oel = NULL;
262 continue;
263 }
264 if (OD_TEST (oel->df_srctgt, IA32_DF_DEF_SOURCE))
265 *source_clobbered = 1;
266 else
267 *source_clobbered = 0;
268
269 if (OD_TEST (oel->flags, OD_REG_HARD_EAX) &&
270 (reg_used & IA32_REG_EAX))
271 {
272#ifdef CODEGEN_DEBUG
273 printf ("skipping \"%s\" due to eax "
274 "clobber\n", oel->name);
275#endif
276 oel = NULL;
277 continue;
278 }
279
280 break;
281 }
282
283 /* no encoding found, continue search for proper opcode
284 */
285 inst_tries += 1;
286
287 if (oel == NULL)
288 goto loop_cont;
289
290 efl_def = IA32_DF_DEF_GET_FLAGS (oel->df_implicit_def);
291 } while ((efl_def & efl_used) != 0);
292
293 if (inst_tries >= CODEGEN_MAX_INST_TRIES)
294 oper = IA32_OP_nop;
295
296#ifdef CODEGEN_DEBUG
297 printf (" == choosing \"%s\"\n", oel->name);
298#endif
299
300 return (oper);
301}
302
303
304void
305codegen_reguse_profile_print (reguse_profile *prof)
306{
307 unsigned int rn; /* register walker */
308
309 printf ("register usage profile\n\n");
310 printf (" reg | percentage\n"
311 "-----+-------------\n");
312 for (rn = 0 ; rn < IA32_REG_COUNT ; ++rn) {
313 printf (" %s | %6.2lf\n", ia32_regs_wide[rn],
314 100.0 * prof->reg_use[rn]);
315 }
316
317 printf ("-----+-------------\n"
318 " sum | %6.2lf, made up from %u instructions\n",
319 100.0 * prof->sum, prof->lines);
320 printf (" '\n");
321}
322
323
324reguse_profile *
325codegen_reguse_profile_create (ia32_function **flist, unsigned int flist_count)
326{
327 ia32_bblock ** all;
328 unsigned int all_count,
329 bn, /* basic block walker */
330 in, /* instruction walker */
331 bitn; /* use bit test walker */
332 ia32_df_bblock * dfb;
333 reguse_profile * prof;
334
335
336 all = obj_bblist_build (flist, flist_count, &all_count);
337 assert (all != NULL);
338
339 prof = xcalloc (1, sizeof (reguse_profile));
340
341 for (bn = 0 ; bn < all_count ; ++bn) {
342 assert (all[bn]->user != NULL && all[bn]->user->dfb != NULL);
343 dfb = (ia32_df_bblock *) all[bn]->user->dfb;
344
345 for (in = 0 ; in < dfb->df_count ; ++in) {
346 for (bitn = 0 ; bitn < IA32_REG_COUNT ; ++bitn) {
347 if (dfb->df[in].use & (1 << bitn))
348 prof->reg_use[bitn] += 1;
349 }
350 prof->lines += 1;
351 }
352 }
353
354 assert (prof->lines > 0);
355 for (bitn = 0 ; bitn < IA32_REG_COUNT ; ++bitn)
356 prof->reg_use[bitn] /= (double) prof->lines;
357
358 prof->sum = 0.0;
359 for (bitn = 0 ; bitn < IA32_REG_COUNT ; ++bitn)
360 prof->sum += prof->reg_use[bitn];
361
362 free (all);
363 return (prof);
364}
365
366
367void
368codegen_instuse_profile_print (instuse_profile *iprof, int machine)
369{
370 unsigned int on;
371
372
373 if (machine == 0) {
374 printf ("instruction usage profile\n\n");
375 printf (" pct | abs | mnemonic\n"
376 "--------+--------+---------------------------------\n");
377 }
378
379 for (on = 0 ; on < IA32_OPNUM_COUNT ; ++on) {
380 if (iprof->inst_use[on] == 0.0)
381 continue;
382
383 if (machine) {
384 printf ("%s,%lf # INSTUSE\n", ia32_opnum_name (on),
385 iprof->inst_use[on] * 100.0);
386 } else {
387 printf (" %6.2lf | %6.0lf | %s\n",
388 iprof->inst_use[on] * 100.0,
389 (double) (iprof->inst_use[on] * iprof->lines),
390 ia32_opnum_name (on));
391 }
392 }
393
394 if (machine == 0) {
395 printf ("--------+--------+---------------------------------\n"
396 " | %6u instructions considered\n"
397 " '\n", iprof->lines);
398 }
399}
400
401
402instuse_profile *
403codegen_instuse_profile_create (ia32_function **flist, unsigned int flist_count)
404{
405 ia32_bblock ** all;
406 unsigned int all_count,
407 bn,
408 on; /* opcode number walker */
409 unsigned int mwlk;
410 int idx;
411 instuse_profile * iuse;
412 ia32_instruction * inst,
413 inst_s;
414
415
416 all = obj_bblist_build (flist, flist_count, &all_count);
417 assert (all != NULL);
418 iuse = xcalloc (1, sizeof (instuse_profile));
419
420 for (bn = 0 ; bn < all_count ; ++bn) {
421 mwlk = 0;
422
423 while (mwlk < (all[bn]->end - all[bn]->start)) {
424 inst = ia32_decode_instruction (&all[bn]->mem[mwlk],
425 &inst_s);
426 assert (inst != NULL);
427
428 idx = ia32_opnum_index (inst->opc.opcode->opcode_num);
429 assert (idx != -1);
430 iuse->inst_use[idx] += 1.0;
431 iuse->lines += 1;
432
433 mwlk += inst->length;
434 }
435 }
436 free (all);
437
438 for (on = 0 ; on < IA32_OPNUM_COUNT ; ++on)
439 iuse->inst_use[on] /= (double) iuse->lines;
440
441 return (iuse);
442}
443
444
445instr_array *
446codegen_instr_array_copy (instr_array *ia)
447{
448 instr_array * new;
449
450 if (ia == NULL)
451 return (NULL);
452
453 new = xcalloc (1, sizeof (instr_array));
454 new->in_count = ia->in_count;
455
456 new->in_points = xcalloc (new->in_count, sizeof (ia32_instruction *));
457 memcpy (new->in_points, ia->in_points,
458 new->in_count * sizeof (ia32_instruction *));
459
460 new->in_points_opcode = xcalloc (new->in_count,
461 sizeof (unsigned int *));
462 memcpy (new->in_points_opcode, ia->in_points_opcode,
463 new->in_count * sizeof (unsigned int *));
464
465 new->in_points_icount = xcalloc (new->in_count, sizeof (unsigned int));
466 memcpy (new->in_points_icount, ia->in_points_icount,
467 new->in_count * sizeof (unsigned int));
468
469 return (new);
470}
471
472
473instr_array *
474codegen_instr_array_split (instr_array *ia, unsigned int split_point)
475{
476 instr_array * new;
477
478 if (ia == NULL)
479 return (NULL);
480
481 assert (split_point <= ia->in_count);
482
483 new = xcalloc (1, sizeof (instr_array));
484 new->in_count = ia->in_count - split_point;
485
486 /* duplicate data, using duplicate code ;-)
487 */
488 new->in_points = xcalloc (new->in_count, sizeof (ia32_instruction *));
489 memcpy (new->in_points, &ia->in_points[split_point],
490 new->in_count * sizeof (ia32_instruction *));
491
492 new->in_points_opcode = xcalloc (new->in_count,
493 sizeof (unsigned int *));
494 memcpy (new->in_points_opcode, &ia->in_points_opcode[split_point],
495 new->in_count * sizeof (unsigned int *));
496
497 new->in_points_icount = xcalloc (new->in_count, sizeof (unsigned int));
498 memcpy (new->in_points_icount, &ia->in_points_icount[split_point],
499 new->in_count * sizeof (unsigned int));
500
501 ia->in_count -= new->in_count;
502 ia->in_points = xrealloc (ia->in_points,
503 ia->in_count * sizeof (ia32_instruction *));
504 ia->in_points_opcode = xrealloc (ia->in_points_opcode,
505 ia->in_count * sizeof (unsigned int *));
506 ia->in_points_icount = xrealloc (ia->in_points_icount,
507 ia->in_count * sizeof (unsigned int));
508
509 return (new);
510}
511
512