Print this page
new smatch
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/tools/smatch/src/example.c
+++ new/usr/src/tools/smatch/src/example.c
1 1 /*
2 2 * Example of how to write a compiler with sparse
3 3 */
4 4 #include <stdio.h>
5 5 #include <stdlib.h>
6 6 #include <stdarg.h>
7 7 #include <string.h>
8 8 #include <assert.h>
9 9
10 10 #include "symbol.h"
11 11 #include "expression.h"
12 12 #include "linearize.h"
13 13 #include "flow.h"
14 14 #include "storage.h"
15 15 #include "target.h"
16 16
17 17 static const char *opcodes[] = {
↓ open down ↓ |
17 lines elided |
↑ open up ↑ |
18 18 [OP_BADOP] = "bad_op",
19 19
20 20 /* Fn entrypoint */
21 21 [OP_ENTRY] = "<entry-point>",
22 22
23 23 /* Terminator */
24 24 [OP_RET] = "ret",
25 25 [OP_BR] = "br",
26 26 [OP_CBR] = "cbr",
27 27 [OP_SWITCH] = "switch",
28 - [OP_INVOKE] = "invoke",
29 28 [OP_COMPUTEDGOTO] = "jmp *",
30 - [OP_UNWIND] = "unwind",
31 29
32 30 /* Binary */
33 31 [OP_ADD] = "add",
34 32 [OP_SUB] = "sub",
35 - [OP_MULU] = "mulu",
36 - [OP_MULS] = "muls",
33 + [OP_MUL] = "mul",
37 34 [OP_DIVU] = "divu",
38 35 [OP_DIVS] = "divs",
39 36 [OP_MODU] = "modu",
40 37 [OP_MODS] = "mods",
41 38 [OP_SHL] = "shl",
42 39 [OP_LSR] = "lsr",
43 40 [OP_ASR] = "asr",
44 41
45 42 /* Logical */
46 43 [OP_AND] = "and",
47 44 [OP_OR] = "or",
48 45 [OP_XOR] = "xor",
49 - [OP_AND_BOOL] = "and-bool",
50 - [OP_OR_BOOL] = "or-bool",
51 46
52 47 /* Binary comparison */
53 48 [OP_SET_EQ] = "seteq",
54 49 [OP_SET_NE] = "setne",
55 50 [OP_SET_LE] = "setle",
56 51 [OP_SET_GE] = "setge",
57 52 [OP_SET_LT] = "setlt",
58 53 [OP_SET_GT] = "setgt",
59 54 [OP_SET_B] = "setb",
60 55 [OP_SET_A] = "seta",
61 56 [OP_SET_BE] = "setbe",
↓ open down ↓ |
1 lines elided |
↑ open up ↑ |
62 57 [OP_SET_AE] = "setae",
63 58
64 59 /* Uni */
65 60 [OP_NOT] = "not",
66 61 [OP_NEG] = "neg",
67 62
68 63 /* Special three-input */
69 64 [OP_SEL] = "select",
70 65
71 66 /* Memory */
72 - [OP_MALLOC] = "malloc",
73 - [OP_FREE] = "free",
74 - [OP_ALLOCA] = "alloca",
75 67 [OP_LOAD] = "load",
76 68 [OP_STORE] = "store",
77 69 [OP_SETVAL] = "set",
78 - [OP_GET_ELEMENT_PTR] = "getelem",
79 70
80 71 /* Other */
81 72 [OP_PHI] = "phi",
82 73 [OP_PHISOURCE] = "phisrc",
83 74 [OP_COPY] = "copy",
84 - [OP_CAST] = "cast",
85 - [OP_SCAST] = "scast",
86 - [OP_FPCAST] = "fpcast",
75 + [OP_SEXT] = "sext",
76 + [OP_ZEXT] = "zext",
77 + [OP_TRUNC] = "trunc",
78 + [OP_FCVTU] = "fcvtu",
79 + [OP_FCVTS] = "fcvts",
80 + [OP_UCVTF] = "ucvtf",
81 + [OP_SCVTF] = "scvtf",
82 + [OP_FCVTF] = "fcvtf",
83 + [OP_UTPTR] = "utptr",
84 + [OP_PTRTU] = "utptr",
87 85 [OP_PTRCAST] = "ptrcast",
88 86 [OP_CALL] = "call",
89 - [OP_VANEXT] = "va_next",
90 - [OP_VAARG] = "va_arg",
91 87 [OP_SLICE] = "slice",
92 - [OP_SNOP] = "snop",
93 - [OP_LNOP] = "lnop",
94 88 [OP_NOP] = "nop",
95 89 [OP_DEATHNOTE] = "dead",
96 90 [OP_ASM] = "asm",
97 91
98 92 /* Sparse tagging (line numbers, context, whatever) */
99 93 [OP_CONTEXT] = "context",
100 94 };
101 95
102 96 static int last_reg, stack_offset;
103 97
104 98 struct hardreg {
105 99 const char *name;
106 100 struct pseudo_list *contains;
107 101 unsigned busy:16,
108 102 dead:8,
109 103 used:1;
110 104 };
111 105
112 106 #define TAG_DEAD 1
113 107 #define TAG_DIRTY 2
114 108
115 109 /* Our "switch" generation is very very stupid. */
116 110 #define SWITCH_REG (1)
117 111
118 112 static void output_bb(struct basic_block *bb, unsigned long generation);
119 113
120 114 /*
121 115 * We only know about the caller-clobbered registers
122 116 * right now.
123 117 */
124 118 static struct hardreg hardregs[] = {
125 119 { .name = "%eax" },
126 120 { .name = "%edx" },
127 121 { .name = "%ecx" },
128 122 { .name = "%ebx" },
129 123 { .name = "%esi" },
130 124 { .name = "%edi" },
131 125
132 126 { .name = "%ebp" },
133 127 { .name = "%esp" },
134 128 };
135 129 #define REGNO 6
136 130 #define REG_EBP 6
137 131 #define REG_ESP 7
138 132
139 133 struct bb_state {
140 134 struct position pos;
141 135 struct storage_hash_list *inputs;
142 136 struct storage_hash_list *outputs;
143 137 struct storage_hash_list *internal;
144 138
145 139 /* CC cache.. */
146 140 int cc_opcode, cc_dead;
147 141 pseudo_t cc_target;
148 142 };
149 143
150 144 enum optype {
151 145 OP_UNDEF,
152 146 OP_REG,
153 147 OP_VAL,
154 148 OP_MEM,
155 149 OP_ADDR,
156 150 };
157 151
158 152 struct operand {
159 153 enum optype type;
160 154 int size;
161 155 union {
162 156 struct hardreg *reg;
163 157 long long value;
164 158 struct /* OP_MEM and OP_ADDR */ {
165 159 unsigned int offset;
166 160 unsigned int scale;
167 161 struct symbol *sym;
168 162 struct hardreg *base;
169 163 struct hardreg *index;
170 164 };
171 165 };
172 166 };
173 167
174 168 static const char *show_op(struct bb_state *state, struct operand *op)
175 169 {
176 170 static char buf[256][4];
177 171 static int bufnr;
178 172 char *p, *ret;
179 173 int nr;
180 174
181 175 nr = (bufnr + 1) & 3;
182 176 bufnr = nr;
183 177 ret = p = buf[nr];
184 178
185 179 switch (op->type) {
186 180 case OP_UNDEF:
187 181 return "undef";
188 182 case OP_REG:
189 183 return op->reg->name;
190 184 case OP_VAL:
191 185 sprintf(p, "$%lld", op->value);
192 186 break;
193 187 case OP_MEM:
194 188 case OP_ADDR:
195 189 if (op->offset)
196 190 p += sprintf(p, "%d", op->offset);
197 191 if (op->sym)
198 192 p += sprintf(p, "%s%s",
199 193 op->offset ? "+" : "",
200 194 show_ident(op->sym->ident));
201 195 if (op->base || op->index) {
202 196 p += sprintf(p, "(%s%s%s",
203 197 op->base ? op->base->name : "",
204 198 (op->base && op->index) ? "," : "",
205 199 op->index ? op->index->name : "");
206 200 if (op->scale > 1)
207 201 p += sprintf(p, ",%d", op->scale);
208 202 *p++ = ')';
209 203 *p = '\0';
210 204 }
211 205 break;
212 206 }
213 207 return ret;
214 208 }
215 209
216 210 static struct storage_hash *find_storage_hash(pseudo_t pseudo, struct storage_hash_list *list)
217 211 {
218 212 struct storage_hash *entry;
219 213 FOR_EACH_PTR(list, entry) {
220 214 if (entry->pseudo == pseudo)
221 215 return entry;
222 216 } END_FOR_EACH_PTR(entry);
223 217 return NULL;
224 218 }
225 219
226 220 static struct storage_hash *find_or_create_hash(pseudo_t pseudo, struct storage_hash_list **listp)
227 221 {
228 222 struct storage_hash *entry;
229 223
230 224 entry = find_storage_hash(pseudo, *listp);
231 225 if (!entry) {
232 226 entry = alloc_storage_hash(alloc_storage());
233 227 entry->pseudo = pseudo;
234 228 add_ptr_list(listp, entry);
235 229 }
236 230 return entry;
237 231 }
238 232
239 233 /* Eventually we should just build it up in memory */
240 234 static void FORMAT_ATTR(2) output_line(struct bb_state *state, const char *fmt, ...)
241 235 {
242 236 va_list args;
243 237
244 238 va_start(args, fmt);
245 239 vprintf(fmt, args);
246 240 va_end(args);
247 241 }
248 242
249 243 static void FORMAT_ATTR(2) output_label(struct bb_state *state, const char *fmt, ...)
250 244 {
251 245 static char buffer[512];
252 246 va_list args;
253 247
254 248 va_start(args, fmt);
255 249 vsnprintf(buffer, sizeof(buffer), fmt, args);
256 250 va_end(args);
257 251
258 252 output_line(state, "%s:\n", buffer);
259 253 }
260 254
261 255 static void FORMAT_ATTR(2) output_insn(struct bb_state *state, const char *fmt, ...)
262 256 {
263 257 static char buffer[512];
264 258 va_list args;
265 259
266 260 va_start(args, fmt);
267 261 vsnprintf(buffer, sizeof(buffer), fmt, args);
268 262 va_end(args);
269 263
270 264 output_line(state, "\t%s\n", buffer);
271 265 }
272 266
273 267 #define output_insn(state, fmt, arg...) \
274 268 output_insn(state, fmt "\t\t# %s" , ## arg , __FUNCTION__)
275 269
276 270 static void FORMAT_ATTR(2) output_comment(struct bb_state *state, const char *fmt, ...)
277 271 {
278 272 static char buffer[512];
279 273 va_list args;
280 274
281 275 if (!verbose)
282 276 return;
283 277 va_start(args, fmt);
284 278 vsnprintf(buffer, sizeof(buffer), fmt, args);
285 279 va_end(args);
286 280
287 281 output_line(state, "\t# %s\n", buffer);
288 282 }
289 283
290 284 static const char *show_memop(struct storage *storage)
291 285 {
292 286 static char buffer[1000];
293 287
294 288 if (!storage)
295 289 return "undef";
296 290 switch (storage->type) {
297 291 case REG_FRAME:
298 292 sprintf(buffer, "%d(FP)", storage->offset);
299 293 break;
300 294 case REG_STACK:
301 295 sprintf(buffer, "%d(SP)", storage->offset);
302 296 break;
303 297 case REG_REG:
304 298 return hardregs[storage->regno].name;
305 299 default:
306 300 return show_storage(storage);
307 301 }
308 302 return buffer;
309 303 }
310 304
311 305 static int alloc_stack_offset(int size)
312 306 {
313 307 int ret = stack_offset;
314 308 stack_offset = ret + size;
315 309 return ret;
316 310 }
317 311
318 312 static void alloc_stack(struct bb_state *state, struct storage *storage)
319 313 {
320 314 storage->type = REG_STACK;
321 315 storage->offset = alloc_stack_offset(4);
322 316 }
323 317
324 318 /*
325 319 * Can we re-generate the pseudo, so that we don't need to
326 320 * flush it to memory? We can regenerate:
327 321 * - immediates and symbol addresses
328 322 * - pseudos we got as input in non-registers
329 323 * - pseudos we've already saved off earlier..
330 324 */
331 325 static int can_regenerate(struct bb_state *state, pseudo_t pseudo)
332 326 {
333 327 struct storage_hash *in;
334 328
335 329 switch (pseudo->type) {
336 330 case PSEUDO_VAL:
337 331 case PSEUDO_SYM:
338 332 return 1;
339 333
340 334 default:
341 335 in = find_storage_hash(pseudo, state->inputs);
342 336 if (in && in->storage->type != REG_REG)
343 337 return 1;
344 338 in = find_storage_hash(pseudo, state->internal);
345 339 if (in)
346 340 return 1;
347 341 }
348 342 return 0;
349 343 }
350 344
351 345 static void flush_one_pseudo(struct bb_state *state, struct hardreg *hardreg, pseudo_t pseudo)
352 346 {
353 347 struct storage_hash *out;
354 348 struct storage *storage;
355 349
356 350 if (can_regenerate(state, pseudo))
357 351 return;
358 352
359 353 output_comment(state, "flushing %s from %s", show_pseudo(pseudo), hardreg->name);
360 354 out = find_storage_hash(pseudo, state->internal);
361 355 if (!out) {
362 356 out = find_storage_hash(pseudo, state->outputs);
363 357 if (!out)
364 358 out = find_or_create_hash(pseudo, &state->internal);
365 359 }
366 360 storage = out->storage;
367 361 switch (storage->type) {
368 362 default:
369 363 /*
370 364 * Aieee - the next user wants it in a register, but we
371 365 * need to flush it to memory in between. Which means that
372 366 * we need to allocate an internal one, dammit..
373 367 */
374 368 out = find_or_create_hash(pseudo, &state->internal);
375 369 storage = out->storage;
376 370 /* Fall through */
377 371 case REG_UDEF:
378 372 alloc_stack(state, storage);
379 373 /* Fall through */
380 374 case REG_STACK:
381 375 output_insn(state, "movl %s,%s", hardreg->name, show_memop(storage));
382 376 break;
383 377 }
384 378 }
385 379
386 380 /* Flush a hardreg out to the storage it has.. */
↓ open down ↓ |
283 lines elided |
↑ open up ↑ |
387 381 static void flush_reg(struct bb_state *state, struct hardreg *reg)
388 382 {
389 383 pseudo_t pseudo;
390 384
391 385 if (reg->busy)
392 386 output_comment(state, "reg %s flushed while busy is %d!", reg->name, reg->busy);
393 387 if (!reg->contains)
394 388 return;
395 389 reg->dead = 0;
396 390 reg->used = 1;
397 - FOR_EACH_PTR(reg->contains, pseudo) {
391 + FOR_EACH_PTR_TAG(reg->contains, pseudo) {
398 392 if (CURRENT_TAG(pseudo) & TAG_DEAD)
399 393 continue;
400 394 if (!(CURRENT_TAG(pseudo) & TAG_DIRTY))
401 395 continue;
402 396 flush_one_pseudo(state, reg, pseudo);
403 397 } END_FOR_EACH_PTR(pseudo);
404 398 free_ptr_list(®->contains);
405 399 }
406 400
407 401 static struct storage_hash *find_pseudo_storage(struct bb_state *state, pseudo_t pseudo, struct hardreg *reg)
408 402 {
409 403 struct storage_hash *src;
410 404
411 405 src = find_storage_hash(pseudo, state->internal);
412 406 if (!src) {
413 407 src = find_storage_hash(pseudo, state->inputs);
414 408 if (!src) {
415 409 src = find_storage_hash(pseudo, state->outputs);
416 410 /* Undefined? Screw it! */
417 411 if (!src)
418 412 return NULL;
419 413
420 414 /*
421 415 * If we found output storage, it had better be local stack
422 416 * that we flushed to earlier..
423 417 */
424 418 if (src->storage->type != REG_STACK)
425 419 return NULL;
426 420 }
427 421 }
428 422
429 423 /*
430 424 * Incoming pseudo with out any pre-set storage allocation?
431 425 * We can make up our own, and obviously prefer to get it
432 426 * in the register we already selected (if it hasn't been
433 427 * used yet).
434 428 */
435 429 if (src->storage->type == REG_UDEF) {
436 430 if (reg && !reg->used) {
437 431 src->storage->type = REG_REG;
438 432 src->storage->regno = reg - hardregs;
439 433 return NULL;
↓ open down ↓ |
32 lines elided |
↑ open up ↑ |
440 434 }
441 435 alloc_stack(state, src->storage);
442 436 }
443 437 return src;
444 438 }
445 439
446 440 static void mark_reg_dead(struct bb_state *state, pseudo_t pseudo, struct hardreg *reg)
447 441 {
448 442 pseudo_t p;
449 443
450 - FOR_EACH_PTR(reg->contains, p) {
444 + FOR_EACH_PTR_TAG(reg->contains, p) {
451 445 if (p != pseudo)
452 446 continue;
453 447 if (CURRENT_TAG(p) & TAG_DEAD)
454 448 continue;
455 449 output_comment(state, "marking pseudo %s in reg %s dead", show_pseudo(pseudo), reg->name);
456 450 TAG_CURRENT(p, TAG_DEAD);
457 451 reg->dead++;
458 452 } END_FOR_EACH_PTR(p);
459 453 }
460 454
461 455 static void add_pseudo_reg(struct bb_state *state, pseudo_t pseudo, struct hardreg *reg)
462 456 {
463 457 output_comment(state, "added pseudo %s to reg %s", show_pseudo(pseudo), reg->name);
464 458 add_ptr_list_tag(®->contains, pseudo, TAG_DIRTY);
465 459 }
466 460
467 461 static struct hardreg *preferred_reg(struct bb_state *state, pseudo_t target)
468 462 {
469 463 struct storage_hash *dst;
470 464
471 465 dst = find_storage_hash(target, state->outputs);
472 466 if (dst) {
473 467 struct storage *storage = dst->storage;
474 468 if (storage->type == REG_REG)
475 469 return hardregs + storage->regno;
476 470 }
477 471 return NULL;
478 472 }
479 473
480 474 static struct hardreg *empty_reg(struct bb_state *state)
481 475 {
482 476 int i;
483 477 struct hardreg *reg = hardregs;
484 478
485 479 for (i = 0; i < REGNO; i++, reg++) {
486 480 if (!reg->contains)
487 481 return reg;
488 482 }
489 483 return NULL;
490 484 }
491 485
492 486 static struct hardreg *target_reg(struct bb_state *state, pseudo_t pseudo, pseudo_t target)
493 487 {
494 488 int i;
495 489 int unable_to_find_reg = 0;
496 490 struct hardreg *reg;
497 491
498 492 /* First, see if we have a preferred target register.. */
499 493 reg = preferred_reg(state, target);
500 494 if (reg && !reg->contains)
501 495 goto found;
502 496
503 497 reg = empty_reg(state);
504 498 if (reg)
505 499 goto found;
506 500
507 501 i = last_reg;
508 502 do {
509 503 i++;
510 504 if (i >= REGNO)
511 505 i = 0;
512 506 reg = hardregs + i;
513 507 if (!reg->busy) {
514 508 flush_reg(state, reg);
515 509 last_reg = i;
516 510 goto found;
517 511 }
518 512 } while (i != last_reg);
519 513 assert(unable_to_find_reg);
520 514
521 515 found:
522 516 add_pseudo_reg(state, pseudo, reg);
523 517 return reg;
524 518 }
↓ open down ↓ |
64 lines elided |
↑ open up ↑ |
525 519
526 520 static struct hardreg *find_in_reg(struct bb_state *state, pseudo_t pseudo)
527 521 {
528 522 int i;
529 523 struct hardreg *reg;
530 524
531 525 for (i = 0; i < REGNO; i++) {
532 526 pseudo_t p;
533 527
534 528 reg = hardregs + i;
535 - FOR_EACH_PTR(reg->contains, p) {
529 + FOR_EACH_PTR_TAG(reg->contains, p) {
536 530 if (p == pseudo) {
537 531 last_reg = i;
538 532 output_comment(state, "found pseudo %s in reg %s (busy=%d)", show_pseudo(pseudo), reg->name, reg->busy);
539 533 return reg;
540 534 }
541 535 } END_FOR_EACH_PTR(p);
542 536 }
543 537 return NULL;
544 538 }
545 539
546 540 static void flush_pseudo(struct bb_state *state, pseudo_t pseudo, struct storage *storage)
547 541 {
548 542 struct hardreg *reg = find_in_reg(state, pseudo);
549 543
550 544 if (reg)
551 545 flush_reg(state, reg);
552 546 }
553 547
554 548 static void flush_cc_cache_to_reg(struct bb_state *state, pseudo_t pseudo, struct hardreg *reg)
555 549 {
556 550 int opcode = state->cc_opcode;
557 551
558 552 state->cc_opcode = 0;
559 553 state->cc_target = NULL;
560 554 output_insn(state, "%s %s", opcodes[opcode], reg->name);
561 555 }
562 556
563 557 static void flush_cc_cache(struct bb_state *state)
564 558 {
565 559 pseudo_t pseudo = state->cc_target;
566 560
567 561 if (pseudo) {
568 562 struct hardreg *dst;
569 563
570 564 state->cc_target = NULL;
571 565
572 566 if (!state->cc_dead) {
573 567 dst = target_reg(state, pseudo, pseudo);
574 568 flush_cc_cache_to_reg(state, pseudo, dst);
575 569 }
576 570 }
577 571 }
578 572
579 573 static void add_cc_cache(struct bb_state *state, int opcode, pseudo_t pseudo)
580 574 {
581 575 assert(!state->cc_target);
582 576 state->cc_target = pseudo;
583 577 state->cc_opcode = opcode;
584 578 state->cc_dead = 0;
585 579 output_comment(state, "caching %s", opcodes[opcode]);
586 580 }
587 581
588 582 /* Fill a hardreg with the pseudo it has */
589 583 static struct hardreg *fill_reg(struct bb_state *state, struct hardreg *hardreg, pseudo_t pseudo)
590 584 {
591 585 struct storage_hash *src;
592 586 struct instruction *def;
593 587
594 588 if (state->cc_target == pseudo) {
595 589 flush_cc_cache_to_reg(state, pseudo, hardreg);
596 590 return hardreg;
597 591 }
598 592
599 593 switch (pseudo->type) {
600 594 case PSEUDO_VAL:
601 595 output_insn(state, "movl $%lld,%s", pseudo->value, hardreg->name);
602 596 break;
603 597 case PSEUDO_SYM:
604 598 src = find_pseudo_storage(state, pseudo, NULL);
605 599 /* Static thing? */
606 600 if (!src) {
607 601 output_insn(state, "movl $<%s>,%s", show_pseudo(pseudo), hardreg->name);
608 602 break;
609 603 }
610 604 switch (src->storage->type) {
611 605 case REG_REG:
612 606 /* Aiaiaiaiaii! Need to flush it to temporary memory */
613 607 src = find_or_create_hash(pseudo, &state->internal);
614 608 /* Fall through */
615 609 default:
616 610 alloc_stack(state, src->storage);
617 611 /* Fall through */
618 612 case REG_STACK:
619 613 case REG_FRAME:
620 614 flush_pseudo(state, pseudo, src->storage);
621 615 output_insn(state, "leal %s,%s", show_memop(src->storage), hardreg->name);
622 616 break;
623 617 }
624 618 break;
625 619 case PSEUDO_ARG:
626 620 case PSEUDO_REG:
627 621 def = pseudo->def;
628 622 if (def && def->opcode == OP_SETVAL) {
629 623 output_insn(state, "movl $<%s>,%s", show_pseudo(def->target), hardreg->name);
630 624 break;
631 625 }
632 626 src = find_pseudo_storage(state, pseudo, hardreg);
633 627 if (!src)
634 628 break;
635 629 if (src->flags & TAG_DEAD)
636 630 mark_reg_dead(state, pseudo, hardreg);
637 631 output_insn(state, "mov.%d %s,%s", 32, show_memop(src->storage), hardreg->name);
638 632 break;
639 633 default:
640 634 output_insn(state, "reload %s from %s", hardreg->name, show_pseudo(pseudo));
641 635 break;
642 636 }
643 637 return hardreg;
644 638 }
645 639
646 640 static struct hardreg *getreg(struct bb_state *state, pseudo_t pseudo, pseudo_t target)
647 641 {
648 642 struct hardreg *reg;
649 643
650 644 reg = find_in_reg(state, pseudo);
651 645 if (reg)
652 646 return reg;
653 647 reg = target_reg(state, pseudo, target);
654 648 return fill_reg(state, reg, pseudo);
655 649 }
656 650
657 651 static void move_reg(struct bb_state *state, struct hardreg *src, struct hardreg *dst)
658 652 {
659 653 output_insn(state, "movl %s,%s", src->name, dst->name);
660 654 }
661 655
662 656 static struct hardreg *copy_reg(struct bb_state *state, struct hardreg *src, pseudo_t target)
663 657 {
664 658 int i;
665 659 struct hardreg *reg;
666 660
667 661 /* If the container has been killed off, just re-use it */
668 662 if (!src->contains)
669 663 return src;
670 664
671 665 /* If "src" only has one user, and the contents are dead, we can re-use it */
672 666 if (src->busy == 1 && src->dead == 1)
673 667 return src;
674 668
675 669 reg = preferred_reg(state, target);
676 670 if (reg && !reg->contains) {
677 671 output_comment(state, "copying %s to preferred target %s", show_pseudo(target), reg->name);
678 672 move_reg(state, src, reg);
679 673 return reg;
680 674 }
681 675
682 676 for (i = 0; i < REGNO; i++) {
683 677 reg = hardregs + i;
684 678 if (!reg->contains) {
685 679 output_comment(state, "copying %s to %s", show_pseudo(target), reg->name);
686 680 output_insn(state, "movl %s,%s", src->name, reg->name);
687 681 return reg;
688 682 }
689 683 }
690 684
691 685 flush_reg(state, src);
692 686 return src;
693 687 }
694 688
695 689 static void put_operand(struct bb_state *state, struct operand *op)
696 690 {
697 691 switch (op->type) {
698 692 case OP_REG:
699 693 op->reg->busy--;
700 694 break;
701 695 case OP_ADDR:
702 696 case OP_MEM:
703 697 if (op->base)
704 698 op->base->busy--;
705 699 if (op->index)
706 700 op->index->busy--;
707 701 break;
708 702 default:
709 703 break;
710 704 }
711 705 }
712 706
713 707 static struct operand *alloc_op(void)
714 708 {
715 709 struct operand *op = malloc(sizeof(*op));
716 710 memset(op, 0, sizeof(*op));
717 711 return op;
718 712 }
719 713
720 714 static struct operand *get_register_operand(struct bb_state *state, pseudo_t pseudo, pseudo_t target)
721 715 {
722 716 struct operand *op = alloc_op();
723 717 op->type = OP_REG;
724 718 op->reg = getreg(state, pseudo, target);
725 719 op->reg->busy++;
726 720 return op;
727 721 }
728 722
729 723 static int get_sym_frame_offset(struct bb_state *state, pseudo_t pseudo)
730 724 {
731 725 int offset = pseudo->nr;
732 726 if (offset < 0) {
733 727 offset = alloc_stack_offset(4);
734 728 pseudo->nr = offset;
735 729 }
736 730 return offset;
737 731 }
738 732
739 733 static struct operand *get_generic_operand(struct bb_state *state, pseudo_t pseudo)
740 734 {
741 735 struct hardreg *reg;
742 736 struct storage *src;
743 737 struct storage_hash *hash;
744 738 struct operand *op = malloc(sizeof(*op));
745 739
746 740 memset(op, 0, sizeof(*op));
747 741 switch (pseudo->type) {
748 742 case PSEUDO_VAL:
749 743 op->type = OP_VAL;
750 744 op->value = pseudo->value;
751 745 break;
752 746
753 747 case PSEUDO_SYM: {
754 748 struct symbol *sym = pseudo->sym;
755 749 op->type = OP_ADDR;
756 750 if (sym->ctype.modifiers & MOD_NONLOCAL) {
757 751 op->sym = sym;
758 752 break;
759 753 }
760 754 op->base = hardregs + REG_EBP;
761 755 op->offset = get_sym_frame_offset(state, pseudo);
762 756 break;
763 757 }
764 758
765 759 default:
766 760 reg = find_in_reg(state, pseudo);
767 761 if (reg) {
768 762 op->type = OP_REG;
769 763 op->reg = reg;
770 764 reg->busy++;
771 765 break;
772 766 }
773 767 hash = find_pseudo_storage(state, pseudo, NULL);
774 768 if (!hash)
775 769 break;
776 770 src = hash->storage;
777 771 switch (src->type) {
778 772 case REG_REG:
779 773 op->type = OP_REG;
780 774 op->reg = hardregs + src->regno;
781 775 op->reg->busy++;
782 776 break;
783 777 case REG_FRAME:
784 778 op->type = OP_MEM;
785 779 op->offset = src->offset;
786 780 op->base = hardregs + REG_EBP;
787 781 break;
788 782 case REG_STACK:
789 783 op->type = OP_MEM;
790 784 op->offset = src->offset;
791 785 op->base = hardregs + REG_ESP;
792 786 break;
793 787 default:
794 788 break;
795 789 }
796 790 }
797 791 return op;
798 792 }
799 793
800 794 /* Callers should be made to use the proper "operand" formats */
801 795 static const char *generic(struct bb_state *state, pseudo_t pseudo)
802 796 {
803 797 struct hardreg *reg;
804 798 struct operand *op = get_generic_operand(state, pseudo);
805 799 static char buf[100];
806 800 const char *str;
807 801
808 802 switch (op->type) {
809 803 case OP_ADDR:
810 804 if (!op->offset && op->base && !op->sym)
811 805 return op->base->name;
812 806 if (op->sym && !op->base) {
813 807 int len = sprintf(buf, "$ %s", show_op(state, op));
814 808 if (op->offset)
815 809 sprintf(buf + len, " + %d", op->offset);
816 810 return buf;
817 811 }
818 812 str = show_op(state, op);
819 813 put_operand(state, op);
820 814 reg = target_reg(state, pseudo, NULL);
821 815 output_insn(state, "lea %s,%s", show_op(state, op), reg->name);
822 816 return reg->name;
823 817
824 818 default:
825 819 str = show_op(state, op);
826 820 }
827 821 put_operand(state, op);
828 822 return str;
829 823 }
830 824
831 825 static struct operand *get_address_operand(struct bb_state *state, struct instruction *memop)
832 826 {
833 827 struct hardreg *base;
834 828 struct operand *op = get_generic_operand(state, memop->src);
835 829
836 830 switch (op->type) {
837 831 case OP_ADDR:
838 832 op->offset += memop->offset;
839 833 break;
840 834 default:
841 835 put_operand(state, op);
842 836 base = getreg(state, memop->src, NULL);
843 837 op->type = OP_ADDR;
844 838 op->base = base;
845 839 base->busy++;
846 840 op->offset = memop->offset;
847 841 op->sym = NULL;
848 842 }
849 843 return op;
850 844 }
851 845
852 846 static const char *address(struct bb_state *state, struct instruction *memop)
853 847 {
854 848 struct operand *op = get_address_operand(state, memop);
855 849 const char *str = show_op(state, op);
856 850 put_operand(state, op);
857 851 return str;
858 852 }
859 853
860 854 static const char *reg_or_imm(struct bb_state *state, pseudo_t pseudo)
861 855 {
862 856 switch(pseudo->type) {
863 857 case PSEUDO_VAL:
864 858 return show_pseudo(pseudo);
↓ open down ↓ |
319 lines elided |
↑ open up ↑ |
865 859 default:
866 860 return getreg(state, pseudo, NULL)->name;
867 861 }
868 862 }
869 863
870 864 static void kill_dead_reg(struct hardreg *reg)
871 865 {
872 866 if (reg->dead) {
873 867 pseudo_t p;
874 868
875 - FOR_EACH_PTR(reg->contains, p) {
869 + FOR_EACH_PTR_TAG(reg->contains, p) {
876 870 if (CURRENT_TAG(p) & TAG_DEAD) {
877 871 DELETE_CURRENT_PTR(p);
878 872 reg->dead--;
879 873 }
880 874 } END_FOR_EACH_PTR(p);
881 875 PACK_PTR_LIST(®->contains);
882 876 assert(!reg->dead);
883 877 }
884 878 }
885 879
886 880 static struct hardreg *target_copy_reg(struct bb_state *state, struct hardreg *src, pseudo_t target)
887 881 {
888 882 kill_dead_reg(src);
889 883 return copy_reg(state, src, target);
890 884 }
891 885
892 886 static void do_binop(struct bb_state *state, struct instruction *insn, pseudo_t val1, pseudo_t val2)
893 887 {
894 888 const char *op = opcodes[insn->opcode];
895 889 struct operand *src = get_register_operand(state, val1, insn->target);
896 890 struct operand *src2 = get_generic_operand(state, val2);
897 891 struct hardreg *dst;
898 892
899 893 dst = target_copy_reg(state, src->reg, insn->target);
900 894 output_insn(state, "%s.%d %s,%s", op, insn->size, show_op(state, src2), dst->name);
901 895 put_operand(state, src);
902 896 put_operand(state, src2);
903 897 add_pseudo_reg(state, insn->target, dst);
904 898 }
↓ open down ↓ |
19 lines elided |
↑ open up ↑ |
905 899
906 900 static void generate_binop(struct bb_state *state, struct instruction *insn)
907 901 {
908 902 flush_cc_cache(state);
909 903 do_binop(state, insn, insn->src1, insn->src2);
910 904 }
911 905
912 906 static int is_dead_reg(struct bb_state *state, pseudo_t pseudo, struct hardreg *reg)
913 907 {
914 908 pseudo_t p;
915 - FOR_EACH_PTR(reg->contains, p) {
909 + FOR_EACH_PTR_TAG(reg->contains, p) {
916 910 if (p == pseudo)
917 911 return CURRENT_TAG(p) & TAG_DEAD;
918 912 } END_FOR_EACH_PTR(p);
919 913 return 0;
920 914 }
921 915
922 916 /*
923 917 * Commutative binops are much more flexible, since we can switch the
924 918 * sources around to satisfy the target register, or to avoid having
925 919 * to load one of them into a register..
926 920 */
927 921 static void generate_commutative_binop(struct bb_state *state, struct instruction *insn)
928 922 {
929 923 pseudo_t src1, src2;
930 924 struct hardreg *reg1, *reg2;
931 925
932 926 flush_cc_cache(state);
933 927 src1 = insn->src1;
934 928 src2 = insn->src2;
935 929 reg2 = find_in_reg(state, src2);
936 930 if (!reg2)
937 931 goto dont_switch;
938 932 reg1 = find_in_reg(state, src1);
939 933 if (!reg1)
940 934 goto do_switch;
941 935 if (!is_dead_reg(state, src2, reg2))
942 936 goto dont_switch;
943 937 if (!is_dead_reg(state, src1, reg1))
944 938 goto do_switch;
945 939
946 940 /* Both are dead. Is one preferable? */
947 941 if (reg2 != preferred_reg(state, insn->target))
948 942 goto dont_switch;
949 943
950 944 do_switch:
951 945 src1 = src2;
952 946 src2 = insn->src1;
953 947 dont_switch:
954 948 do_binop(state, insn, src1, src2);
955 949 }
956 950
957 951 /*
958 952 * This marks a pseudo dead. It still stays on the hardreg list (the hardreg
959 953 * still has its value), but it's scheduled to be killed after the next
960 954 * "sequence point" when we call "kill_read_pseudos()"
961 955 */
962 956 static void mark_pseudo_dead(struct bb_state *state, pseudo_t pseudo)
963 957 {
964 958 int i;
965 959 struct storage_hash *src;
966 960
967 961 if (state->cc_target == pseudo)
968 962 state->cc_dead = 1;
969 963 src = find_pseudo_storage(state, pseudo, NULL);
970 964 if (src)
971 965 src->flags |= TAG_DEAD;
972 966 for (i = 0; i < REGNO; i++)
973 967 mark_reg_dead(state, pseudo, hardregs + i);
974 968 }
975 969
976 970 static void kill_dead_pseudos(struct bb_state *state)
977 971 {
978 972 int i;
979 973
980 974 for (i = 0; i < REGNO; i++) {
981 975 kill_dead_reg(hardregs + i);
982 976 }
983 977 }
984 978
985 979 static void generate_store(struct instruction *insn, struct bb_state *state)
986 980 {
987 981 output_insn(state, "mov.%d %s,%s", insn->size, reg_or_imm(state, insn->target), address(state, insn));
988 982 }
989 983
990 984 static void generate_load(struct instruction *insn, struct bb_state *state)
991 985 {
992 986 const char *input = address(state, insn);
993 987 struct hardreg *dst;
994 988
995 989 kill_dead_pseudos(state);
996 990 dst = target_reg(state, insn->target, NULL);
997 991 output_insn(state, "mov.%d %s,%s", insn->size, input, dst->name);
998 992 }
999 993
↓ open down ↓ |
74 lines elided |
↑ open up ↑ |
1000 994 static void kill_pseudo(struct bb_state *state, pseudo_t pseudo)
1001 995 {
1002 996 int i;
1003 997 struct hardreg *reg;
1004 998
1005 999 output_comment(state, "killing pseudo %s", show_pseudo(pseudo));
1006 1000 for (i = 0; i < REGNO; i++) {
1007 1001 pseudo_t p;
1008 1002
1009 1003 reg = hardregs + i;
1010 - FOR_EACH_PTR(reg->contains, p) {
1004 + FOR_EACH_PTR_TAG(reg->contains, p) {
1011 1005 if (p != pseudo)
1012 1006 continue;
1013 1007 if (CURRENT_TAG(p) & TAG_DEAD)
1014 1008 reg->dead--;
1015 1009 output_comment(state, "removing pseudo %s from reg %s",
1016 1010 show_pseudo(pseudo), reg->name);
1017 1011 DELETE_CURRENT_PTR(p);
1018 1012 } END_FOR_EACH_PTR(p);
1019 1013 PACK_PTR_LIST(®->contains);
1020 1014 }
1021 1015 }
1022 1016
1023 1017 static void generate_copy(struct bb_state *state, struct instruction *insn)
1024 1018 {
1025 1019 struct hardreg *src = getreg(state, insn->src, insn->target);
1026 1020 kill_pseudo(state, insn->target);
1027 1021 add_pseudo_reg(state, insn->target, src);
1028 1022 }
1029 1023
1030 1024 static void generate_cast(struct bb_state *state, struct instruction *insn)
1031 1025 {
1032 1026 struct hardreg *src = getreg(state, insn->src, insn->target);
1033 1027 struct hardreg *dst;
1034 1028 unsigned int old = insn->orig_type ? insn->orig_type->bit_size : 0;
1035 1029 unsigned int new = insn->size;
1036 1030
1037 1031 /*
1038 1032 * Cast to smaller type? Ignore the high bits, we
1039 1033 * just keep both pseudos in the same register.
1040 1034 */
1041 1035 if (old >= new) {
1042 1036 add_pseudo_reg(state, insn->target, src);
1043 1037 return;
1044 1038 }
1045 1039
1046 1040 dst = target_copy_reg(state, src, insn->target);
1047 1041
1048 1042 if (insn->orig_type && (insn->orig_type->ctype.modifiers & MOD_SIGNED)) {
1049 1043 output_insn(state, "sext.%d.%d %s", old, new, dst->name);
1050 1044 } else {
1051 1045 unsigned long long mask;
1052 1046 mask = ~(~0ULL << old);
1053 1047 mask &= ~(~0ULL << new);
1054 1048 output_insn(state, "andl.%d $%#llx,%s", insn->size, mask, dst->name);
1055 1049 }
1056 1050 add_pseudo_reg(state, insn->target, dst);
1057 1051 }
1058 1052
1059 1053 static void generate_output_storage(struct bb_state *state);
1060 1054
1061 1055 static const char *conditional[] = {
1062 1056 [OP_SET_EQ] = "e",
1063 1057 [OP_SET_NE] = "ne",
1064 1058 [OP_SET_LE] = "le",
1065 1059 [OP_SET_GE] = "ge",
1066 1060 [OP_SET_LT] = "lt",
1067 1061 [OP_SET_GT] = "gt",
1068 1062 [OP_SET_B] = "b",
1069 1063 [OP_SET_A] = "a",
1070 1064 [OP_SET_BE] = "be",
1071 1065 [OP_SET_AE] = "ae"
1072 1066 };
1073 1067
1074 1068
1075 1069 static void generate_branch(struct bb_state *state, struct instruction *br)
1076 1070 {
1077 1071 const char *cond = "XXX";
1078 1072 struct basic_block *target;
1079 1073
1080 1074 if (br->cond) {
1081 1075 if (state->cc_target == br->cond) {
1082 1076 cond = conditional[state->cc_opcode];
1083 1077 } else {
1084 1078 struct hardreg *reg = getreg(state, br->cond, NULL);
1085 1079 output_insn(state, "testl %s,%s", reg->name, reg->name);
1086 1080 cond = "ne";
1087 1081 }
1088 1082 }
1089 1083 generate_output_storage(state);
1090 1084 target = br->bb_true;
1091 1085 if (br->cond) {
1092 1086 output_insn(state, "j%s .L%p", cond, target);
1093 1087 target = br->bb_false;
1094 1088 }
1095 1089 output_insn(state, "jmp .L%p", target);
1096 1090 }
1097 1091
1098 1092 /* We've made sure that there is a dummy reg live for the output */
1099 1093 static void generate_switch(struct bb_state *state, struct instruction *insn)
1100 1094 {
1101 1095 struct hardreg *reg = hardregs + SWITCH_REG;
1102 1096
1103 1097 generate_output_storage(state);
1104 1098 output_insn(state, "switch on %s", reg->name);
1105 1099 output_insn(state, "unimplemented: %s", show_instruction(insn));
1106 1100 }
1107 1101
1108 1102 static void generate_ret(struct bb_state *state, struct instruction *ret)
1109 1103 {
1110 1104 if (ret->src && ret->src != VOID) {
1111 1105 struct hardreg *wants = hardregs+0;
1112 1106 struct hardreg *reg = getreg(state, ret->src, NULL);
1113 1107 if (reg != wants)
1114 1108 output_insn(state, "movl %s,%s", reg->name, wants->name);
1115 1109 }
1116 1110 output_insn(state, "ret");
1117 1111 }
1118 1112
1119 1113 /*
1120 1114 * Fake "call" linearization just as a taster..
1121 1115 */
1122 1116 static void generate_call(struct bb_state *state, struct instruction *insn)
1123 1117 {
1124 1118 int offset = 0;
1125 1119 pseudo_t arg;
1126 1120
1127 1121 FOR_EACH_PTR(insn->arguments, arg) {
1128 1122 output_insn(state, "pushl %s", generic(state, arg));
1129 1123 offset += 4;
1130 1124 } END_FOR_EACH_PTR(arg);
1131 1125 flush_reg(state, hardregs+0);
1132 1126 flush_reg(state, hardregs+1);
1133 1127 flush_reg(state, hardregs+2);
1134 1128 output_insn(state, "call %s", show_pseudo(insn->func));
1135 1129 if (offset)
1136 1130 output_insn(state, "addl $%d,%%esp", offset);
1137 1131 if (insn->target && insn->target != VOID)
1138 1132 add_pseudo_reg(state, insn->target, hardregs+0);
1139 1133 }
1140 1134
1141 1135 static void generate_select(struct bb_state *state, struct instruction *insn)
1142 1136 {
1143 1137 const char *cond;
1144 1138 struct hardreg *src1, *src2, *dst;
1145 1139
1146 1140 src1 = getreg(state, insn->src2, NULL);
1147 1141 dst = copy_reg(state, src1, insn->target);
1148 1142 add_pseudo_reg(state, insn->target, dst);
1149 1143 src2 = getreg(state, insn->src3, insn->target);
1150 1144
1151 1145 if (state->cc_target == insn->src1) {
1152 1146 cond = conditional[state->cc_opcode];
1153 1147 } else {
1154 1148 struct hardreg *reg = getreg(state, insn->src1, NULL);
1155 1149 output_insn(state, "testl %s,%s", reg->name, reg->name);
1156 1150 cond = "ne";
1157 1151 }
1158 1152
1159 1153 output_insn(state, "sel%s %s,%s", cond, src2->name, dst->name);
1160 1154 }
1161 1155
1162 1156 struct asm_arg {
1163 1157 const struct ident *name;
1164 1158 const char *value;
1165 1159 pseudo_t pseudo;
1166 1160 struct hardreg *reg;
1167 1161 };
1168 1162
1169 1163 static void replace_asm_arg(char **dst_p, struct asm_arg *arg)
1170 1164 {
1171 1165 char *dst = *dst_p;
1172 1166 int len = strlen(arg->value);
1173 1167
1174 1168 memcpy(dst, arg->value, len);
1175 1169 *dst_p = dst + len;
1176 1170 }
1177 1171
1178 1172 static void replace_asm_percent(const char **src_p, char **dst_p, struct asm_arg *args, int nr)
1179 1173 {
1180 1174 const char *src = *src_p;
1181 1175 char c;
1182 1176 int index;
1183 1177
1184 1178 c = *src++;
1185 1179 switch (c) {
1186 1180 case '0' ... '9':
1187 1181 index = c - '0';
1188 1182 if (index < nr)
1189 1183 replace_asm_arg(dst_p, args+index);
1190 1184 break;
1191 1185 }
1192 1186 *src_p = src;
1193 1187 return;
1194 1188 }
1195 1189
1196 1190 static void replace_asm_named(const char **src_p, char **dst_p, struct asm_arg *args, int nr)
1197 1191 {
1198 1192 const char *src = *src_p;
1199 1193 const char *end = src;
1200 1194
1201 1195 for(;;) {
1202 1196 char c = *end++;
1203 1197 if (!c)
1204 1198 return;
1205 1199 if (c == ']') {
1206 1200 int i;
1207 1201
1208 1202 *src_p = end;
1209 1203 for (i = 0; i < nr; i++) {
1210 1204 const struct ident *ident = args[i].name;
1211 1205 int len;
1212 1206 if (!ident)
1213 1207 continue;
1214 1208 len = ident->len;
1215 1209 if (memcmp(src, ident->name, len))
1216 1210 continue;
1217 1211 replace_asm_arg(dst_p, args+i);
1218 1212 return;
1219 1213 }
1220 1214 }
1221 1215 }
1222 1216 }
1223 1217
1224 1218 static const char *replace_asm_args(const char *str, struct asm_arg *args, int nr)
1225 1219 {
1226 1220 static char buffer[1000];
1227 1221 char *p = buffer;
1228 1222
1229 1223 for (;;) {
1230 1224 char c = *str;
1231 1225 *p = c;
1232 1226 if (!c)
1233 1227 return buffer;
1234 1228 str++;
1235 1229 switch (c) {
1236 1230 case '%':
1237 1231 if (*str == '%') {
1238 1232 str++;
1239 1233 p++;
1240 1234 continue;
1241 1235 }
1242 1236 replace_asm_percent(&str, &p, args, nr);
1243 1237 continue;
1244 1238 case '[':
1245 1239 replace_asm_named(&str, &p, args, nr);
1246 1240 continue;
1247 1241 default:
1248 1242 break;
1249 1243 }
1250 1244 p++;
1251 1245 }
1252 1246 }
1253 1247
1254 1248 #define MAX_ASM_ARG (50)
1255 1249 static struct asm_arg asm_arguments[MAX_ASM_ARG];
1256 1250
1257 1251 static struct asm_arg *generate_asm_inputs(struct bb_state *state, struct asm_constraint_list *list, struct asm_arg *arg)
1258 1252 {
1259 1253 struct asm_constraint *entry;
1260 1254
1261 1255 FOR_EACH_PTR(list, entry) {
1262 1256 const char *constraint = entry->constraint;
1263 1257 pseudo_t pseudo = entry->pseudo;
1264 1258 struct hardreg *reg, *orig;
1265 1259 const char *string;
1266 1260 int index;
1267 1261
1268 1262 string = "undef";
1269 1263 switch (*constraint) {
1270 1264 case 'r':
1271 1265 string = getreg(state, pseudo, NULL)->name;
1272 1266 break;
1273 1267 case '0' ... '9':
1274 1268 index = *constraint - '0';
1275 1269 reg = asm_arguments[index].reg;
1276 1270 orig = find_in_reg(state, pseudo);
1277 1271 if (orig)
1278 1272 move_reg(state, orig, reg);
1279 1273 else
1280 1274 fill_reg(state, reg, pseudo);
1281 1275 string = reg->name;
1282 1276 break;
1283 1277 default:
1284 1278 string = generic(state, pseudo);
1285 1279 break;
1286 1280 }
1287 1281
1288 1282 output_insn(state, "# asm input \"%s\": %s : %s", constraint, show_pseudo(pseudo), string);
1289 1283
1290 1284 arg->name = entry->ident;
1291 1285 arg->value = string;
1292 1286 arg->pseudo = NULL;
1293 1287 arg->reg = NULL;
1294 1288 arg++;
1295 1289 } END_FOR_EACH_PTR(entry);
1296 1290 return arg;
1297 1291 }
1298 1292
1299 1293 static struct asm_arg *generate_asm_outputs(struct bb_state *state, struct asm_constraint_list *list, struct asm_arg *arg)
1300 1294 {
1301 1295 struct asm_constraint *entry;
1302 1296
1303 1297 FOR_EACH_PTR(list, entry) {
1304 1298 const char *constraint = entry->constraint;
1305 1299 pseudo_t pseudo = entry->pseudo;
1306 1300 struct hardreg *reg;
1307 1301 const char *string;
1308 1302
1309 1303 while (*constraint == '=' || *constraint == '+')
1310 1304 constraint++;
1311 1305
1312 1306 string = "undef";
1313 1307 switch (*constraint) {
1314 1308 case 'r':
1315 1309 default:
1316 1310 reg = target_reg(state, pseudo, NULL);
1317 1311 arg->pseudo = pseudo;
1318 1312 arg->reg = reg;
1319 1313 string = reg->name;
1320 1314 break;
1321 1315 }
1322 1316
1323 1317 output_insn(state, "# asm output \"%s\": %s : %s", constraint, show_pseudo(pseudo), string);
1324 1318
1325 1319 arg->name = entry->ident;
1326 1320 arg->value = string;
1327 1321 arg++;
1328 1322 } END_FOR_EACH_PTR(entry);
1329 1323 return arg;
1330 1324 }
1331 1325
1332 1326 static void generate_asm(struct bb_state *state, struct instruction *insn)
1333 1327 {
1334 1328 const char *str = insn->string;
1335 1329
1336 1330 if (insn->asm_rules->outputs || insn->asm_rules->inputs) {
1337 1331 struct asm_arg *arg;
1338 1332
1339 1333 arg = generate_asm_outputs(state, insn->asm_rules->outputs, asm_arguments);
1340 1334 arg = generate_asm_inputs(state, insn->asm_rules->inputs, arg);
1341 1335 str = replace_asm_args(str, asm_arguments, arg - asm_arguments);
1342 1336 }
1343 1337 output_insn(state, "%s", str);
1344 1338 }
1345 1339
1346 1340 static void generate_compare(struct bb_state *state, struct instruction *insn)
1347 1341 {
1348 1342 struct hardreg *src;
1349 1343 const char *src2;
1350 1344 int opcode;
1351 1345
1352 1346 flush_cc_cache(state);
1353 1347 opcode = insn->opcode;
1354 1348
1355 1349 /*
1356 1350 * We should try to switch these around if necessary,
1357 1351 * and update the opcode to match..
1358 1352 */
1359 1353 src = getreg(state, insn->src1, insn->target);
1360 1354 src2 = generic(state, insn->src2);
1361 1355
1362 1356 output_insn(state, "cmp.%d %s,%s", insn->size, src2, src->name);
1363 1357
1364 1358 add_cc_cache(state, opcode, insn->target);
1365 1359 }
1366 1360
1367 1361 static void generate_one_insn(struct instruction *insn, struct bb_state *state)
1368 1362 {
1369 1363 if (verbose)
1370 1364 output_comment(state, "%s", show_instruction(insn));
1371 1365
1372 1366 switch (insn->opcode) {
1373 1367 case OP_ENTRY: {
1374 1368 struct symbol *sym = insn->bb->ep->name;
1375 1369 const char *name = show_ident(sym->ident);
1376 1370 if (sym->ctype.modifiers & MOD_STATIC)
1377 1371 printf("\n\n%s:\n", name);
1378 1372 else
1379 1373 printf("\n\n.globl %s\n%s:\n", name, name);
1380 1374 break;
1381 1375 }
1382 1376
1383 1377 /*
1384 1378 * OP_SETVAL likewise doesn't actually generate any
1385 1379 * code. On use, the "def" of the pseudo will be
1386 1380 * looked up.
1387 1381 */
1388 1382 case OP_SETVAL:
1389 1383 break;
1390 1384
1391 1385 case OP_STORE:
1392 1386 generate_store(insn, state);
1393 1387 break;
1394 1388
1395 1389 case OP_LOAD:
1396 1390 generate_load(insn, state);
↓ open down ↓ |
376 lines elided |
↑ open up ↑ |
1397 1391 break;
1398 1392
1399 1393 case OP_DEATHNOTE:
1400 1394 mark_pseudo_dead(state, insn->target);
1401 1395 return;
1402 1396
1403 1397 case OP_COPY:
1404 1398 generate_copy(state, insn);
1405 1399 break;
1406 1400
1407 - case OP_ADD: case OP_MULU: case OP_MULS:
1401 + case OP_ADD: case OP_MUL:
1408 1402 case OP_AND: case OP_OR: case OP_XOR:
1409 - case OP_AND_BOOL: case OP_OR_BOOL:
1410 1403 generate_commutative_binop(state, insn);
1411 1404 break;
1412 1405
1413 1406 case OP_SUB: case OP_DIVU: case OP_DIVS:
1414 1407 case OP_MODU: case OP_MODS:
1415 1408 case OP_SHL: case OP_LSR: case OP_ASR:
1416 1409 generate_binop(state, insn);
1417 1410 break;
1418 1411
1419 1412 case OP_BINCMP ... OP_BINCMP_END:
1420 1413 generate_compare(state, insn);
1421 1414 break;
1422 1415
1423 - case OP_CAST: case OP_SCAST: case OP_FPCAST: case OP_PTRCAST:
1416 + case OP_SEXT: case OP_ZEXT:
1417 + case OP_TRUNC:
1418 + case OP_PTRCAST:
1419 + case OP_UTPTR:
1420 + case OP_PTRTU:
1421 + case OP_FCVTU: case OP_FCVTS:
1422 + case OP_UCVTF: case OP_SCVTF:
1423 + case OP_FCVTF:
1424 1424 generate_cast(state, insn);
1425 1425 break;
1426 1426
1427 1427 case OP_SEL:
1428 1428 generate_select(state, insn);
1429 1429 break;
1430 1430
1431 1431 case OP_BR:
1432 1432 case OP_CBR:
1433 1433 generate_branch(state, insn);
1434 1434 break;
1435 1435
1436 1436 case OP_SWITCH:
1437 1437 generate_switch(state, insn);
1438 1438 break;
1439 1439
1440 1440 case OP_CALL:
1441 1441 generate_call(state, insn);
1442 1442 break;
1443 1443
1444 1444 case OP_RET:
1445 1445 generate_ret(state, insn);
1446 1446 break;
1447 1447
1448 1448 case OP_ASM:
1449 1449 generate_asm(state, insn);
1450 1450 break;
1451 1451
1452 1452 case OP_PHI:
1453 1453 case OP_PHISOURCE:
1454 1454 default:
1455 1455 output_insn(state, "unimplemented: %s", show_instruction(insn));
1456 1456 break;
1457 1457 }
1458 1458 kill_dead_pseudos(state);
1459 1459 }
1460 1460
1461 1461 #define VERY_BUSY 1000
1462 1462 #define REG_FIXED 2000
1463 1463
1464 1464 static void write_reg_to_storage(struct bb_state *state, struct hardreg *reg, pseudo_t pseudo, struct storage *storage)
1465 1465 {
1466 1466 int i;
1467 1467 struct hardreg *out;
1468 1468
1469 1469 switch (storage->type) {
1470 1470 case REG_REG:
1471 1471 out = hardregs + storage->regno;
1472 1472 if (reg == out)
1473 1473 return;
1474 1474 output_insn(state, "movl %s,%s", reg->name, out->name);
1475 1475 return;
1476 1476 case REG_UDEF:
1477 1477 if (reg->busy < VERY_BUSY) {
1478 1478 storage->type = REG_REG;
1479 1479 storage->regno = reg - hardregs;
1480 1480 reg->busy = REG_FIXED;
1481 1481 return;
1482 1482 }
1483 1483
1484 1484 /* Try to find a non-busy register.. */
1485 1485 for (i = 0; i < REGNO; i++) {
1486 1486 out = hardregs + i;
1487 1487 if (out->contains)
1488 1488 continue;
1489 1489 output_insn(state, "movl %s,%s", reg->name, out->name);
1490 1490 storage->type = REG_REG;
1491 1491 storage->regno = i;
1492 1492 out->busy = REG_FIXED;
1493 1493 return;
1494 1494 }
1495 1495
1496 1496 /* Fall back on stack allocation ... */
1497 1497 alloc_stack(state, storage);
1498 1498 /* Fall through */
1499 1499 default:
1500 1500 output_insn(state, "movl %s,%s", reg->name, show_memop(storage));
1501 1501 return;
1502 1502 }
1503 1503 }
1504 1504
1505 1505 static void write_val_to_storage(struct bb_state *state, pseudo_t src, struct storage *storage)
1506 1506 {
1507 1507 struct hardreg *out;
1508 1508
1509 1509 switch (storage->type) {
1510 1510 case REG_UDEF:
1511 1511 alloc_stack(state, storage);
1512 1512 default:
1513 1513 output_insn(state, "movl %s,%s", show_pseudo(src), show_memop(storage));
1514 1514 break;
1515 1515 case REG_REG:
1516 1516 out = hardregs + storage->regno;
1517 1517 output_insn(state, "movl %s,%s", show_pseudo(src), out->name);
1518 1518 }
1519 1519 }
1520 1520
1521 1521 static void fill_output(struct bb_state *state, pseudo_t pseudo, struct storage *out)
1522 1522 {
1523 1523 int i;
1524 1524 struct storage_hash *in;
1525 1525 struct instruction *def;
1526 1526
1527 1527 /* Is that pseudo a constant value? */
1528 1528 switch (pseudo->type) {
1529 1529 case PSEUDO_VAL:
1530 1530 write_val_to_storage(state, pseudo, out);
1531 1531 return;
1532 1532 case PSEUDO_REG:
1533 1533 def = pseudo->def;
1534 1534 if (def && def->opcode == OP_SETVAL) {
1535 1535 write_val_to_storage(state, pseudo, out);
1536 1536 return;
↓ open down ↓ |
103 lines elided |
↑ open up ↑ |
1537 1537 }
1538 1538 default:
1539 1539 break;
1540 1540 }
1541 1541
1542 1542 /* See if we have that pseudo in a register.. */
1543 1543 for (i = 0; i < REGNO; i++) {
1544 1544 struct hardreg *reg = hardregs + i;
1545 1545 pseudo_t p;
1546 1546
1547 - FOR_EACH_PTR(reg->contains, p) {
1547 + FOR_EACH_PTR_TAG(reg->contains, p) {
1548 1548 if (p == pseudo) {
1549 1549 write_reg_to_storage(state, reg, pseudo, out);
1550 1550 return;
1551 1551 }
1552 1552 } END_FOR_EACH_PTR(p);
1553 1553 }
1554 1554
1555 1555 /* Do we have it in another storage? */
1556 1556 in = find_storage_hash(pseudo, state->internal);
1557 1557 if (!in) {
1558 1558 in = find_storage_hash(pseudo, state->inputs);
1559 1559 /* Undefined? */
1560 1560 if (!in)
1561 1561 return;
1562 1562 }
1563 1563 switch (out->type) {
1564 1564 case REG_UDEF:
1565 1565 *out = *in->storage;
1566 1566 break;
1567 1567 case REG_REG:
1568 1568 output_insn(state, "movl %s,%s", show_memop(in->storage), hardregs[out->regno].name);
1569 1569 break;
1570 1570 default:
1571 1571 if (out == in->storage)
1572 1572 break;
1573 1573 if ((out->type == in->storage->type) && (out->regno == in->storage->regno))
1574 1574 break;
1575 1575 output_insn(state, "movl %s,%s", show_memop(in->storage), show_memop(out));
1576 1576 break;
1577 1577 }
1578 1578 return;
1579 1579 }
1580 1580
1581 1581 static int final_pseudo_flush(struct bb_state *state, pseudo_t pseudo, struct hardreg *reg)
1582 1582 {
1583 1583 struct storage_hash *hash;
1584 1584 struct storage *out;
1585 1585 struct hardreg *dst;
1586 1586
1587 1587 /*
1588 1588 * Since this pseudo is live at exit, we'd better have output
1589 1589 * storage for it..
1590 1590 */
1591 1591 hash = find_storage_hash(pseudo, state->outputs);
1592 1592 if (!hash)
1593 1593 return 1;
1594 1594 out = hash->storage;
1595 1595
1596 1596 /* If the output is in a register, try to get it there.. */
1597 1597 if (out->type == REG_REG) {
1598 1598 dst = hardregs + out->regno;
1599 1599 /*
1600 1600 * Two good cases: nobody is using the right register,
1601 1601 * or we've already set it aside for output..
1602 1602 */
1603 1603 if (!dst->contains || dst->busy > VERY_BUSY)
1604 1604 goto copy_to_dst;
1605 1605
1606 1606 /* Aiee. Try to keep it in a register.. */
1607 1607 dst = empty_reg(state);
1608 1608 if (dst)
1609 1609 goto copy_to_dst;
1610 1610
1611 1611 return 0;
1612 1612 }
1613 1613
1614 1614 /* If the output is undefined, let's see if we can put it in a register.. */
1615 1615 if (out->type == REG_UDEF) {
1616 1616 dst = empty_reg(state);
1617 1617 if (dst) {
1618 1618 out->type = REG_REG;
1619 1619 out->regno = dst - hardregs;
1620 1620 goto copy_to_dst;
1621 1621 }
1622 1622 /* Uhhuh. Not so good. No empty registers right now */
1623 1623 return 0;
1624 1624 }
1625 1625
1626 1626 /* If we know we need to flush it, just do so already .. */
1627 1627 output_insn(state, "movl %s,%s", reg->name, show_memop(out));
1628 1628 return 1;
1629 1629
1630 1630 copy_to_dst:
1631 1631 if (reg == dst)
1632 1632 return 1;
1633 1633 output_insn(state, "movl %s,%s", reg->name, dst->name);
1634 1634 add_pseudo_reg(state, pseudo, dst);
1635 1635 return 1;
1636 1636 }
1637 1637
1638 1638 /*
1639 1639 * This tries to make sure that we put all the pseudos that are
1640 1640 * live on exit into the proper storage
1641 1641 */
1642 1642 static void generate_output_storage(struct bb_state *state)
1643 1643 {
1644 1644 struct storage_hash *entry;
↓ open down ↓ |
87 lines elided |
↑ open up ↑ |
1645 1645
1646 1646 /* Go through the fixed outputs, making sure we have those regs free */
1647 1647 FOR_EACH_PTR(state->outputs, entry) {
1648 1648 struct storage *out = entry->storage;
1649 1649 if (out->type == REG_REG) {
1650 1650 struct hardreg *reg = hardregs + out->regno;
1651 1651 pseudo_t p;
1652 1652 int flushme = 0;
1653 1653
1654 1654 reg->busy = REG_FIXED;
1655 - FOR_EACH_PTR(reg->contains, p) {
1655 + FOR_EACH_PTR_TAG(reg->contains, p) {
1656 1656 if (p == entry->pseudo) {
1657 1657 flushme = -100;
1658 1658 continue;
1659 1659 }
1660 1660 if (CURRENT_TAG(p) & TAG_DEAD)
1661 1661 continue;
1662 1662
1663 1663 /* Try to write back the pseudo to where it should go ... */
1664 1664 if (final_pseudo_flush(state, p, reg)) {
1665 1665 DELETE_CURRENT_PTR(p);
1666 1666 continue;
1667 1667 }
1668 1668 flushme++;
1669 1669 } END_FOR_EACH_PTR(p);
1670 1670 PACK_PTR_LIST(®->contains);
1671 1671 if (flushme > 0)
1672 1672 flush_reg(state, reg);
1673 1673 }
1674 1674 } END_FOR_EACH_PTR(entry);
1675 1675
1676 1676 FOR_EACH_PTR(state->outputs, entry) {
1677 1677 fill_output(state, entry->pseudo, entry->storage);
1678 1678 } END_FOR_EACH_PTR(entry);
1679 1679 }
1680 1680
1681 1681 static void generate(struct basic_block *bb, struct bb_state *state)
1682 1682 {
1683 1683 int i;
1684 1684 struct storage_hash *entry;
1685 1685 struct instruction *insn;
1686 1686
1687 1687 for (i = 0; i < REGNO; i++) {
1688 1688 free_ptr_list(&hardregs[i].contains);
1689 1689 hardregs[i].busy = 0;
1690 1690 hardregs[i].dead = 0;
1691 1691 hardregs[i].used = 0;
1692 1692 }
1693 1693
1694 1694 FOR_EACH_PTR(state->inputs, entry) {
1695 1695 struct storage *storage = entry->storage;
1696 1696 const char *name = show_storage(storage);
1697 1697 output_comment(state, "incoming %s in %s", show_pseudo(entry->pseudo), name);
1698 1698 if (storage->type == REG_REG) {
1699 1699 int regno = storage->regno;
1700 1700 add_pseudo_reg(state, entry->pseudo, hardregs + regno);
1701 1701 name = hardregs[regno].name;
1702 1702 }
1703 1703 } END_FOR_EACH_PTR(entry);
1704 1704
1705 1705 output_label(state, ".L%p", bb);
1706 1706 FOR_EACH_PTR(bb->insns, insn) {
1707 1707 if (!insn->bb)
1708 1708 continue;
1709 1709 generate_one_insn(insn, state);
1710 1710 } END_FOR_EACH_PTR(insn);
1711 1711
1712 1712 if (verbose) {
1713 1713 output_comment(state, "--- in ---");
1714 1714 FOR_EACH_PTR(state->inputs, entry) {
1715 1715 output_comment(state, "%s <- %s", show_pseudo(entry->pseudo), show_storage(entry->storage));
1716 1716 } END_FOR_EACH_PTR(entry);
1717 1717 output_comment(state, "--- spill ---");
1718 1718 FOR_EACH_PTR(state->internal, entry) {
1719 1719 output_comment(state, "%s <-> %s", show_pseudo(entry->pseudo), show_storage(entry->storage));
1720 1720 } END_FOR_EACH_PTR(entry);
1721 1721 output_comment(state, "--- out ---");
1722 1722 FOR_EACH_PTR(state->outputs, entry) {
1723 1723 output_comment(state, "%s -> %s", show_pseudo(entry->pseudo), show_storage(entry->storage));
1724 1724 } END_FOR_EACH_PTR(entry);
1725 1725 }
1726 1726 printf("\n");
1727 1727 }
1728 1728
1729 1729 static void generate_list(struct basic_block_list *list, unsigned long generation)
1730 1730 {
1731 1731 struct basic_block *bb;
1732 1732 FOR_EACH_PTR(list, bb) {
1733 1733 if (bb->generation == generation)
1734 1734 continue;
1735 1735 output_bb(bb, generation);
1736 1736 } END_FOR_EACH_PTR(bb);
1737 1737 }
1738 1738
1739 1739 /*
1740 1740 * Mark all the output registers of all the parents
1741 1741 * as being "used" - this does not mean that we cannot
1742 1742 * re-use them, but it means that we cannot ask the
1743 1743 * parents to pass in another pseudo in one of those
1744 1744 * registers that it already uses for another child.
1745 1745 */
1746 1746 static void mark_used_registers(struct basic_block *bb, struct bb_state *state)
1747 1747 {
1748 1748 struct basic_block *parent;
1749 1749
1750 1750 FOR_EACH_PTR(bb->parents, parent) {
1751 1751 struct storage_hash_list *outputs = gather_storage(parent, STOR_OUT);
1752 1752 struct storage_hash *entry;
1753 1753
1754 1754 FOR_EACH_PTR(outputs, entry) {
1755 1755 struct storage *s = entry->storage;
1756 1756 if (s->type == REG_REG) {
1757 1757 struct hardreg *reg = hardregs + s->regno;
1758 1758 reg->used = 1;
1759 1759 }
1760 1760 } END_FOR_EACH_PTR(entry);
1761 1761 } END_FOR_EACH_PTR(parent);
1762 1762 }
1763 1763
1764 1764 static void output_bb(struct basic_block *bb, unsigned long generation)
1765 1765 {
1766 1766 struct bb_state state;
1767 1767
1768 1768 bb->generation = generation;
1769 1769
1770 1770 /* Make sure all parents have been generated first */
1771 1771 generate_list(bb->parents, generation);
1772 1772
1773 1773 state.pos = bb->pos;
1774 1774 state.inputs = gather_storage(bb, STOR_IN);
1775 1775 state.outputs = gather_storage(bb, STOR_OUT);
1776 1776 state.internal = NULL;
1777 1777 state.cc_opcode = 0;
1778 1778 state.cc_target = NULL;
1779 1779
1780 1780 /* Mark incoming registers used */
1781 1781 mark_used_registers(bb, &state);
1782 1782
1783 1783 generate(bb, &state);
1784 1784
1785 1785 free_ptr_list(&state.inputs);
1786 1786 free_ptr_list(&state.outputs);
1787 1787
1788 1788 /* Generate all children... */
1789 1789 generate_list(bb->children, generation);
1790 1790 }
1791 1791
1792 1792 /*
1793 1793 * We should set up argument sources here..
1794 1794 *
1795 1795 * Things like "first three arguments in registers" etc
1796 1796 * are all for this place.
1797 1797 *
1798 1798 * On x86, we default to stack, unless it's a static
1799 1799 * function that doesn't have its address taken.
1800 1800 *
1801 1801 * I should implement the -mregparm=X cmd line option.
1802 1802 */
1803 1803 static void set_up_arch_entry(struct entrypoint *ep, struct instruction *entry)
1804 1804 {
1805 1805 pseudo_t arg;
1806 1806 struct symbol *sym, *argtype;
1807 1807 int i, offset, regparm;
1808 1808
1809 1809 sym = ep->name;
1810 1810 regparm = 0;
1811 1811 if (!(sym->ctype.modifiers & MOD_ADDRESSABLE))
1812 1812 regparm = 3;
1813 1813 sym = sym->ctype.base_type;
1814 1814 i = 0;
1815 1815 offset = 0;
1816 1816 PREPARE_PTR_LIST(sym->arguments, argtype);
1817 1817 FOR_EACH_PTR(entry->arg_list, arg) {
1818 1818 struct storage *in = lookup_storage(entry->bb, arg, STOR_IN);
1819 1819 if (!in) {
1820 1820 in = alloc_storage();
1821 1821 add_storage(in, entry->bb, arg, STOR_IN);
1822 1822 }
1823 1823 if (i < regparm) {
1824 1824 in->type = REG_REG;
1825 1825 in->regno = i;
1826 1826 } else {
1827 1827 int bits = argtype ? argtype->bit_size : 0;
1828 1828
1829 1829 if (bits < bits_in_int)
1830 1830 bits = bits_in_int;
1831 1831
1832 1832 in->type = REG_FRAME;
1833 1833 in->offset = offset;
1834 1834
1835 1835 offset += bits_to_bytes(bits);
1836 1836 }
1837 1837 i++;
1838 1838 NEXT_PTR_LIST(argtype);
1839 1839 } END_FOR_EACH_PTR(arg);
1840 1840 FINISH_PTR_LIST(argtype);
1841 1841 }
1842 1842
1843 1843 /*
1844 1844 * Set up storage information for "return"
1845 1845 *
1846 1846 * Not strictly necessary, since the code generator will
1847 1847 * certainly move the return value to the right register,
1848 1848 * but it can help register allocation if the allocator
1849 1849 * sees that the target register is going to return in %eax.
1850 1850 */
1851 1851 static void set_up_arch_exit(struct basic_block *bb, struct instruction *ret)
1852 1852 {
1853 1853 pseudo_t pseudo = ret->src;
1854 1854
1855 1855 if (pseudo && pseudo != VOID) {
1856 1856 struct storage *out = lookup_storage(bb, pseudo, STOR_OUT);
1857 1857 if (!out) {
1858 1858 out = alloc_storage();
1859 1859 add_storage(out, bb, pseudo, STOR_OUT);
1860 1860 }
1861 1861 out->type = REG_REG;
1862 1862 out->regno = 0;
1863 1863 }
1864 1864 }
1865 1865
1866 1866 /*
1867 1867 * Set up dummy/silly output storage information for a switch
1868 1868 * instruction. We need to make sure that a register is available
1869 1869 * when we generate code for switch, so force that by creating
1870 1870 * a dummy output rule.
1871 1871 */
1872 1872 static void set_up_arch_switch(struct basic_block *bb, struct instruction *insn)
1873 1873 {
1874 1874 pseudo_t pseudo = insn->cond;
1875 1875 struct storage *out = lookup_storage(bb, pseudo, STOR_OUT);
1876 1876 if (!out) {
1877 1877 out = alloc_storage();
1878 1878 add_storage(out, bb, pseudo, STOR_OUT);
1879 1879 }
1880 1880 out->type = REG_REG;
1881 1881 out->regno = SWITCH_REG;
1882 1882 }
1883 1883
1884 1884 static void arch_set_up_storage(struct entrypoint *ep)
1885 1885 {
1886 1886 struct basic_block *bb;
1887 1887
1888 1888 /* Argument storage etc.. */
1889 1889 set_up_arch_entry(ep, ep->entry);
1890 1890
1891 1891 FOR_EACH_PTR(ep->bbs, bb) {
1892 1892 struct instruction *insn = last_instruction(bb->insns);
1893 1893 if (!insn)
1894 1894 continue;
1895 1895 switch (insn->opcode) {
1896 1896 case OP_RET:
1897 1897 set_up_arch_exit(bb, insn);
1898 1898 break;
1899 1899 case OP_SWITCH:
1900 1900 set_up_arch_switch(bb, insn);
1901 1901 break;
1902 1902 default:
1903 1903 /* nothing */;
1904 1904 }
1905 1905 } END_FOR_EACH_PTR(bb);
1906 1906 }
1907 1907
1908 1908 static void output(struct entrypoint *ep)
1909 1909 {
1910 1910 unsigned long generation = ++bb_generation;
1911 1911
1912 1912 last_reg = -1;
1913 1913 stack_offset = 0;
1914 1914
1915 1915 /* Get rid of SSA form (phinodes etc) */
1916 1916 unssa(ep);
1917 1917
1918 1918 /* Set up initial inter-bb storage links */
1919 1919 set_up_storage(ep);
1920 1920
1921 1921 /* Architecture-specific storage rules.. */
1922 1922 arch_set_up_storage(ep);
1923 1923
1924 1924 /* Show the results ... */
1925 1925 output_bb(ep->entry->bb, generation);
1926 1926
1927 1927 /* Clear the storage hashes for the next function.. */
1928 1928 free_storage();
1929 1929 }
1930 1930
1931 1931 static int compile(struct symbol_list *list)
1932 1932 {
1933 1933 struct symbol *sym;
1934 1934 FOR_EACH_PTR(list, sym) {
1935 1935 struct entrypoint *ep;
1936 1936 expand_symbol(sym);
1937 1937 ep = linearize_symbol(sym);
1938 1938 if (ep)
1939 1939 output(ep);
1940 1940 } END_FOR_EACH_PTR(sym);
1941 1941
↓ open down ↓ |
276 lines elided |
↑ open up ↑ |
1942 1942 return 0;
1943 1943 }
1944 1944
1945 1945 int main(int argc, char **argv)
1946 1946 {
1947 1947 struct string_list *filelist = NULL;
1948 1948 char *file;
1949 1949
1950 1950 compile(sparse_initialize(argc, argv, &filelist));
1951 1951 dbg_dead = 1;
1952 - FOR_EACH_PTR_NOTAG(filelist, file) {
1952 + FOR_EACH_PTR(filelist, file) {
1953 1953 compile(sparse(file));
1954 - } END_FOR_EACH_PTR_NOTAG(file);
1954 + } END_FOR_EACH_PTR(file);
1955 1955 return 0;
1956 1956 }
1957 1957
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX