2 * Example of how to write a compiler with sparse
10 #include "expression.h"
11 #include "linearize.h"
17 struct pseudo_list
*contains
;
25 static void output_bb(struct basic_block
*bb
, unsigned long generation
);
28 * We only know about the caller-clobbered registers
31 static struct hardreg hardregs
[] = {
39 #define REGNO (sizeof(hardregs)/sizeof(struct hardreg))
42 struct basic_block
*bb
;
43 unsigned long stack_offset
;
44 struct storage_hash_list
*inputs
;
45 struct storage_hash_list
*outputs
;
46 struct storage_hash_list
*internal
;
49 static struct storage_hash
*find_storage_hash(pseudo_t pseudo
, struct storage_hash_list
*list
)
51 struct storage_hash
*entry
;
52 FOR_EACH_PTR(list
, entry
) {
53 if (entry
->pseudo
== pseudo
)
55 } END_FOR_EACH_PTR(entry
);
59 static struct storage_hash
*find_or_create_hash(pseudo_t pseudo
, struct storage_hash_list
**listp
)
61 struct storage_hash
*entry
;
63 entry
= find_storage_hash(pseudo
, *listp
);
65 entry
= alloc_storage_hash(alloc_storage());
66 entry
->pseudo
= pseudo
;
67 add_ptr_list(listp
, entry
);
72 /* Eventually we should just build it up in memory */
73 static void output_line(struct bb_state
*state
, const char *fmt
, ...)
82 static void output_label(struct bb_state
*state
, const char *fmt
, ...)
84 static char buffer
[512];
88 vsnprintf(buffer
, sizeof(buffer
), fmt
, args
);
91 output_line(state
, "%s:\n", buffer
);
94 static void output_insn(struct bb_state
*state
, const char *fmt
, ...)
96 static char buffer
[512];
100 vsnprintf(buffer
, sizeof(buffer
), fmt
, args
);
103 output_line(state
, "\t%s\n", buffer
);
106 static void output_comment(struct bb_state
*state
, const char *fmt
, ...)
108 static char buffer
[512];
114 vsnprintf(buffer
, sizeof(buffer
), fmt
, args
);
117 output_line(state
, "\t# %s\n", buffer
);
120 static const char *show_memop(struct storage
*storage
)
122 static char buffer
[1000];
123 switch (storage
->type
) {
125 sprintf(buffer
, "%d(FP)", storage
->regno
* 4);
128 sprintf(buffer
, "%d(SP)", storage
->offset
);
131 return hardregs
[storage
->regno
].name
;
133 return show_storage(storage
);
138 static void alloc_stack(struct bb_state
*state
, struct storage
*storage
)
140 storage
->type
= REG_STACK
;
141 storage
->offset
= state
->stack_offset
;
142 state
->stack_offset
+= 4;
146 * Can we re-generate the pseudo, so that we don't need to
147 * flush it to memory? We can regenerate:
148 * - immediates and symbol addresses
149 * - pseudos we got as input in non-registers
150 * - pseudos we've already saved off earlier..
152 static int can_regenerate(struct bb_state
*state
, pseudo_t pseudo
)
154 struct storage_hash
*in
;
156 switch (pseudo
->type
) {
162 in
= find_storage_hash(pseudo
, state
->inputs
);
163 if (in
&& in
->storage
->type
!= REG_REG
)
165 in
= find_storage_hash(pseudo
, state
->internal
);
172 static void flush_one_pseudo(struct bb_state
*state
, struct hardreg
*hardreg
, pseudo_t pseudo
)
174 struct storage_hash
*out
;
175 struct storage
*storage
;
177 if (can_regenerate(state
, pseudo
))
180 output_comment(state
, "flushing %s from %s", show_pseudo(pseudo
), hardreg
->name
);
181 out
= find_storage_hash(pseudo
, state
->internal
);
183 out
= find_storage_hash(pseudo
, state
->outputs
);
185 out
= find_or_create_hash(pseudo
, &state
->internal
);
187 storage
= out
->storage
;
188 switch (storage
->type
) {
191 * Aieee - the next user wants it in a register, but we
192 * need to flush it to memory in between. Which means that
193 * we need to allocate an internal one, dammit..
195 out
= find_or_create_hash(pseudo
, &state
->internal
);
196 storage
= out
->storage
;
199 alloc_stack(state
, storage
);
202 output_insn(state
, "movl %s,%s", hardreg
->name
, show_memop(storage
));
207 /* Flush a hardreg out to the storage it has.. */
208 static void flush_reg(struct bb_state
*state
, struct hardreg
*hardreg
)
216 FOR_EACH_PTR(hardreg
->contains
, pseudo
) {
217 if (CURRENT_TAG(pseudo
) & TAG_DEAD
)
219 if (!(CURRENT_TAG(pseudo
) & TAG_DIRTY
))
221 flush_one_pseudo(state
, hardreg
, pseudo
);
222 } END_FOR_EACH_PTR(pseudo
);
223 free_ptr_list(&hardreg
->contains
);
226 /* Fill a hardreg with the pseudo it has */
227 static struct hardreg
*fill_reg(struct bb_state
*state
, struct hardreg
*hardreg
, pseudo_t pseudo
)
229 struct storage_hash
*src
;
230 struct instruction
*def
;
232 switch (pseudo
->type
) {
234 output_insn(state
, "movl $%lld,%s", pseudo
->value
, hardreg
->name
);
237 output_insn(state
, "movl $<%s>,%s", show_pseudo(pseudo
), hardreg
->name
);
242 if (def
->opcode
== OP_SETVAL
) {
243 output_insn(state
, "movl $<%s>,%s", show_pseudo(def
->symbol
), hardreg
->name
);
246 src
= find_storage_hash(pseudo
, state
->internal
);
248 src
= find_storage_hash(pseudo
, state
->inputs
);
250 src
= find_storage_hash(pseudo
, state
->outputs
);
251 /* Undefined? Screw it! */
253 output_insn(state
, "undef %s ??", show_pseudo(pseudo
));
258 * If we found output storage, it had better be local stack
259 * that we flushed to earlier..
261 if (src
->storage
->type
!= REG_STACK
) {
262 output_insn(state
, "fill_reg on undef storage %s ??", show_pseudo(pseudo
));
269 * Incoming pseudo with out any pre-set storage allocation?
270 * We can make up our own, and obviously prefer to get it
271 * in the register we already selected (if it hasn't been
274 if (src
->storage
->type
== REG_UDEF
) {
275 if (!hardreg
->used
) {
276 src
->storage
->type
= REG_REG
;
277 src
->storage
->regno
= hardreg
- hardregs
;
280 alloc_stack(state
, src
->storage
);
282 output_insn(state
, "mov.%d %s,%s", 32, show_memop(src
->storage
), hardreg
->name
);
285 output_insn(state
, "reload %s from %s", hardreg
->name
, show_pseudo(pseudo
));
291 static void add_pseudo_reg(struct bb_state
*state
, pseudo_t pseudo
, struct hardreg
*reg
)
293 output_comment(state
, "added pseudo %s to reg %s", show_pseudo(pseudo
), reg
->name
);
294 add_ptr_list_tag(®
->contains
, pseudo
, TAG_DIRTY
);
300 static struct hardreg
*preferred_reg(struct bb_state
*state
, pseudo_t target
)
302 struct storage_hash
*dst
;
304 dst
= find_storage_hash(target
, state
->outputs
);
306 struct storage
*storage
= dst
->storage
;
307 if (storage
->type
== REG_REG
)
308 return hardregs
+ storage
->regno
;
313 static struct hardreg
*empty_reg(struct bb_state
*state
)
316 struct hardreg
*reg
= hardregs
;
318 for (i
= 0; i
< REGNO
; i
++, reg
++) {
325 static struct hardreg
*target_reg(struct bb_state
*state
, pseudo_t pseudo
, pseudo_t target
)
330 /* First, see if we have a preferred target register.. */
331 reg
= preferred_reg(state
, target
);
332 if (reg
&& !reg
->busy
)
340 flush_reg(state
, reg
);
343 add_pseudo_reg(state
, pseudo
, reg
);
347 static struct hardreg
*getreg(struct bb_state
*state
, pseudo_t pseudo
, pseudo_t target
)
352 for (i
= 0; i
< REGNO
; i
++) {
356 FOR_EACH_PTR(reg
->contains
, p
) {
359 output_comment(state
, "found pseudo %s in reg %s", show_pseudo(pseudo
), reg
->name
);
362 } END_FOR_EACH_PTR(p
);
364 reg
= target_reg(state
, pseudo
, target
);
365 return fill_reg(state
, reg
, pseudo
);
368 static struct hardreg
*copy_reg(struct bb_state
*state
, struct hardreg
*src
, pseudo_t target
)
376 reg
= preferred_reg(state
, target
);
377 if (reg
&& !reg
->busy
) {
378 output_comment(state
, "copying %s to preferred target %s", show_pseudo(target
), reg
->name
);
379 output_insn(state
, "movl %s,%s", src
->name
, reg
->name
);
383 for (i
= 0; i
< REGNO
; i
++) {
384 struct hardreg
*reg
= hardregs
+ i
;
386 output_comment(state
, "copying %s to %s", show_pseudo(target
), reg
->name
);
387 output_insn(state
, "movl %s,%s", src
->name
, reg
->name
);
392 flush_reg(state
, src
);
396 static const char *generic(struct bb_state
*state
, pseudo_t pseudo
)
400 switch (pseudo
->type
) {
403 return show_pseudo(pseudo
);
405 reg
= getreg(state
, pseudo
, NULL
);
410 static const char *address(struct bb_state
*state
, struct instruction
*memop
)
413 struct hardreg
*base
;
414 static char buffer
[100];
415 pseudo_t addr
= memop
->src
;
420 if (sym
->ctype
.modifiers
& MOD_NONLOCAL
) {
421 sprintf(buffer
, "%s+%d", show_ident(sym
->ident
), memop
->offset
);
424 sprintf(buffer
, "%d+%s(SP)", memop
->offset
, show_ident(sym
->ident
));
427 base
= getreg(state
, addr
, NULL
);
428 sprintf(buffer
, "%d(%s)", memop
->offset
, base
->name
);
433 static const char *reg_or_imm(struct bb_state
*state
, pseudo_t pseudo
)
435 switch(pseudo
->type
) {
437 return show_pseudo(pseudo
);
439 return getreg(state
, pseudo
, NULL
)->name
;
443 static void generate_store(struct instruction
*insn
, struct bb_state
*state
)
445 output_insn(state
, "mov.%d %s,%s", insn
->size
, reg_or_imm(state
, insn
->target
), address(state
, insn
));
448 static void generate_load(struct instruction
*insn
, struct bb_state
*state
)
450 const char *input
= address(state
, insn
);
451 output_insn(state
, "mov.%d %s,%s", insn
->size
, input
, target_reg(state
, insn
->target
, NULL
)->name
);
454 static const char* opcodes
[] = {
455 [OP_BADOP
] = "bad_op",
458 [OP_ENTRY
] = "<entry-point>",
463 [OP_SWITCH
] = "switch",
464 [OP_INVOKE
] = "invoke",
465 [OP_COMPUTEDGOTO
] = "jmp *",
466 [OP_UNWIND
] = "unwind",
481 [OP_AND_BOOL
] = "and-bool",
482 [OP_OR_BOOL
] = "or-bool",
484 /* Binary comparison */
485 [OP_SET_EQ
] = "seteq",
486 [OP_SET_NE
] = "setne",
487 [OP_SET_LE
] = "setle",
488 [OP_SET_GE
] = "setge",
489 [OP_SET_LT
] = "setlt",
490 [OP_SET_GT
] = "setgt",
493 [OP_SET_BE
] = "setbe",
494 [OP_SET_AE
] = "setae",
500 /* Special three-input */
504 [OP_MALLOC
] = "malloc",
506 [OP_ALLOCA
] = "alloca",
508 [OP_STORE
] = "store",
510 [OP_GET_ELEMENT_PTR
] = "getelem",
514 [OP_PHISOURCE
] = "phisrc",
516 [OP_PTRCAST
] = "ptrcast",
518 [OP_VANEXT
] = "va_next",
519 [OP_VAARG
] = "va_arg",
520 [OP_SLICE
] = "slice",
524 [OP_DEATHNOTE
] = "dead",
527 /* Sparse tagging (line numbers, context, whatever) */
528 [OP_CONTEXT
] = "context",
531 static void generate_binop(struct bb_state
*state
, struct instruction
*insn
)
533 const char *op
= opcodes
[insn
->opcode
];
534 struct hardreg
*src
= getreg(state
, insn
->src1
, insn
->target
);
535 struct hardreg
*dst
= copy_reg(state
, src
, insn
->target
);
537 output_insn(state
, "%s.%d %s,%s", op
, insn
->size
, reg_or_imm(state
, insn
->src2
), dst
->name
);
538 add_pseudo_reg(state
, insn
->target
, dst
);
541 static void mark_pseudo_dead(struct bb_state
*state
, pseudo_t pseudo
)
545 for (i
= 0; i
< REGNO
; i
++) {
547 struct hardreg
*reg
= hardregs
+ i
;
548 FOR_EACH_PTR(reg
->contains
, p
) {
551 if (CURRENT_TAG(p
) & TAG_DEAD
)
553 output_comment(state
, "marking pseudo %s in reg %s dead", show_pseudo(pseudo
), reg
->name
);
554 TAG_CURRENT(p
, TAG_DEAD
);
556 } END_FOR_EACH_PTR(p
);
561 * A PHI source can define a pseudo that we already
562 * have in another register. We need to invalidate the
563 * old register so that we don't end up with the same
564 * pseudo in "two places".
566 static void remove_pseudo_reg(struct bb_state
*state
, pseudo_t pseudo
)
570 output_comment(state
, "pseudo %s died", show_pseudo(pseudo
));
571 for (i
= 0; i
< REGNO
; i
++) {
572 struct hardreg
*reg
= hardregs
+ i
;
573 if (remove_pseudo(®
->contains
, pseudo
))
574 output_comment(state
, "removed pseudo %s from reg %s", show_pseudo(pseudo
), reg
->name
);
578 static void generate_phisource(struct instruction
*insn
, struct bb_state
*state
)
580 struct instruction
*user
;
583 /* Mark all the target pseudos dead first */
584 FOR_EACH_PTR(insn
->phi_users
, user
) {
585 mark_pseudo_dead(state
, user
->target
);
586 } END_FOR_EACH_PTR(user
);
589 FOR_EACH_PTR(insn
->phi_users
, user
) {
591 reg
= getreg(state
, insn
->phi_src
, user
->target
);
592 remove_pseudo_reg(state
, user
->target
);
593 add_pseudo_reg(state
, user
->target
, reg
);
594 } END_FOR_EACH_PTR(user
);
597 static void generate_output_storage(struct bb_state
*state
);
599 static void generate_branch(struct bb_state
*state
, struct instruction
*br
)
602 struct hardreg
*reg
= getreg(state
, br
->cond
, NULL
);
603 output_insn(state
, "testl %s,%s", reg
->name
, reg
->name
);
605 generate_output_storage(state
);
607 output_insn(state
, "je .L%p", br
->bb_false
);
608 output_insn(state
, "jmp .L%p", br
->bb_true
);
611 static void generate_ret(struct bb_state
*state
, struct instruction
*ret
)
613 if (ret
->src
&& ret
->src
!= VOID
) {
614 struct hardreg
*wants
= hardregs
+0;
615 struct hardreg
*reg
= getreg(state
, ret
->src
, NULL
);
617 output_insn(state
, "movl %s,%s", reg
->name
, wants
->name
);
619 output_insn(state
, "ret");
623 * Fake "call" linearization just as a taster..
625 static void generate_call(struct bb_state
*state
, struct instruction
*insn
)
630 FOR_EACH_PTR(insn
->arguments
, arg
) {
631 output_insn(state
, "pushl %s", generic(state
, arg
));
633 } END_FOR_EACH_PTR(arg
);
634 flush_reg(state
, hardregs
+0);
635 flush_reg(state
, hardregs
+1);
636 flush_reg(state
, hardregs
+2);
637 output_insn(state
, "call %s", show_pseudo(insn
->func
));
639 output_insn(state
, "addl $%d,%%esp", offset
);
640 add_pseudo_reg(state
, insn
->target
, hardregs
+0);
643 static void generate_one_insn(struct instruction
*insn
, struct bb_state
*state
)
646 output_comment(state
, "%s", show_instruction(insn
));
648 switch (insn
->opcode
) {
650 struct symbol
*sym
= insn
->bb
->ep
->name
;
651 const char *name
= show_ident(sym
->ident
);
652 if (sym
->ctype
.modifiers
& MOD_STATIC
)
653 printf("\n\n%s:\n", name
);
655 printf("\n\n.globl %s\n%s:\n", name
, name
);
660 * OP_PHI doesn't actually generate any code. It has been
661 * done by the storage allocator and the OP_PHISOURCE.
667 generate_phisource(insn
, state
);
671 * OP_SETVAL likewise doesn't actually generate any
672 * code. On use, the "def" of the pseudo will be
679 generate_store(insn
, state
);
683 generate_load(insn
, state
);
687 mark_pseudo_dead(state
, insn
->target
);
690 case OP_BINARY
... OP_BINARY_END
:
691 case OP_BINCMP
... OP_BINCMP_END
:
692 generate_binop(state
, insn
);
696 generate_branch(state
, insn
);
700 generate_call(state
, insn
);
704 generate_ret(state
, insn
);
708 output_insn(state
, "unimplemented: %s", show_instruction(insn
));
713 #define VERY_BUSY 1000
714 #define REG_FIXED 2000
716 static void write_reg_to_storage(struct bb_state
*state
, struct hardreg
*reg
, pseudo_t pseudo
, struct storage
*storage
)
721 switch (storage
->type
) {
723 out
= hardregs
+ storage
->regno
;
726 output_insn(state
, "movl %s,%s", reg
->name
, out
->name
);
729 if (reg
->busy
< VERY_BUSY
) {
730 storage
->type
= REG_REG
;
731 storage
->regno
= reg
- hardregs
;
732 reg
->busy
= REG_FIXED
;
736 /* Try to find a non-busy register.. */
737 for (i
= 0; i
< REGNO
; i
++) {
741 output_insn(state
, "movl %s,%s", reg
->name
, out
->name
);
742 storage
->type
= REG_REG
;
744 reg
->busy
= REG_FIXED
;
748 /* Fall back on stack allocation ... */
749 alloc_stack(state
, storage
);
752 output_insn(state
, "movl %s,%s", reg
->name
, show_memop(storage
));
757 static void write_val_to_storage(struct bb_state
*state
, pseudo_t src
, struct storage
*storage
)
761 switch (storage
->type
) {
763 alloc_stack(state
, storage
);
765 output_insn(state
, "movl %s,%s", show_pseudo(src
), show_memop(storage
));
768 out
= hardregs
+ storage
->regno
;
769 output_insn(state
, "movl %s,%s", show_pseudo(src
), out
->name
);
773 static void fill_output(struct bb_state
*state
, pseudo_t pseudo
, struct storage
*out
)
776 struct storage_hash
*in
;
777 struct instruction
*def
;
779 /* Is that pseudo a constant value? */
780 switch (pseudo
->type
) {
782 write_val_to_storage(state
, pseudo
, out
);
786 if (def
->opcode
== OP_SETVAL
) {
787 write_val_to_storage(state
, def
->symbol
, out
);
794 /* See if we have that pseudo in a register.. */
795 for (i
= 0; i
< REGNO
; i
++) {
796 struct hardreg
*reg
= hardregs
+ i
;
799 FOR_EACH_PTR(reg
->contains
, p
) {
801 write_reg_to_storage(state
, reg
, pseudo
, out
);
804 } END_FOR_EACH_PTR(p
);
807 /* Do we have it in another storage? */
808 in
= find_storage_hash(pseudo
, state
->internal
);
810 in
= find_storage_hash(pseudo
, state
->inputs
);
820 output_insn(state
, "movl %s,%s", show_memop(in
->storage
), hardregs
[out
->regno
].name
);
823 output_insn(state
, "movl %s,tmp", show_memop(in
->storage
));
824 output_insn(state
, "movl tmp,%s", show_memop(out
));
830 static int final_pseudo_flush(struct bb_state
*state
, pseudo_t pseudo
, struct hardreg
*reg
)
832 struct storage_hash
*hash
;
837 * Since this pseudo is live at exit, we'd better have output
840 hash
= find_storage_hash(pseudo
, state
->outputs
);
845 /* If the output is in a register, try to get it there.. */
846 if (out
->type
== REG_REG
) {
847 dst
= hardregs
+ out
->regno
;
849 * Two good cases: nobody is using the right register,
850 * or we've already set it aside for output..
852 if (!dst
->busy
|| dst
->busy
> VERY_BUSY
)
855 /* Aiee. Try to keep it in a register.. */
856 dst
= empty_reg(state
);
863 /* If the output is undefined, let's see if we can put it in a register.. */
864 if (out
->type
== REG_UDEF
) {
865 dst
= empty_reg(state
);
868 out
->regno
= dst
- hardregs
;
871 /* Uhhuh. Not so good. No empty registers right now */
875 /* If we know we need to flush it, just do so already .. */
876 output_insn(state
, "movl %s,%s", reg
->name
, show_memop(out
));
882 output_insn(state
, "movl %s,%s", reg
->name
, dst
->name
);
883 add_pseudo_reg(state
, pseudo
, dst
);
888 * This tries to make sure that we put all the pseudos that are
889 * live on exit into the proper storage
891 static void generate_output_storage(struct bb_state
*state
)
893 struct storage_hash
*entry
;
895 /* Go through the fixed outputs, making sure we have those regs free */
896 FOR_EACH_PTR(state
->outputs
, entry
) {
897 struct storage
*out
= entry
->storage
;
898 if (out
->type
== REG_REG
) {
899 struct hardreg
*reg
= hardregs
+ out
->regno
;
903 reg
->busy
= REG_FIXED
;
904 FOR_EACH_PTR(reg
->contains
, p
) {
905 if (p
== entry
->pseudo
) {
909 if (CURRENT_TAG(p
) & TAG_DEAD
)
912 /* Try to write back the pseudo to where it should go ... */
913 if (final_pseudo_flush(state
, p
, reg
)) {
914 DELETE_CURRENT_PTR(p
);
919 } END_FOR_EACH_PTR(p
);
920 PACK_PTR_LIST(®
->contains
);
922 flush_reg(state
, reg
);
924 } END_FOR_EACH_PTR(entry
);
926 FOR_EACH_PTR(state
->outputs
, entry
) {
927 fill_output(state
, entry
->pseudo
, entry
->storage
);
928 } END_FOR_EACH_PTR(entry
);
931 static void generate(struct basic_block
*bb
, struct bb_state
*state
)
934 struct storage_hash
*entry
;
935 struct instruction
*insn
;
937 for (i
= 0; i
< REGNO
; i
++) {
938 free_ptr_list(&hardregs
[i
].contains
);
939 hardregs
[i
].busy
= 0;
940 hardregs
[i
].used
= 0;
943 FOR_EACH_PTR(state
->inputs
, entry
) {
944 struct storage
*storage
= entry
->storage
;
945 const char *name
= show_storage(storage
);
946 if (storage
->type
== REG_REG
) {
947 int regno
= storage
->regno
;
948 add_pseudo_reg(state
, entry
->pseudo
, hardregs
+ regno
);
949 name
= hardregs
[regno
].name
;
951 } END_FOR_EACH_PTR(entry
);
953 output_label(state
, ".L%p", bb
);
954 FOR_EACH_PTR(bb
->insns
, insn
) {
957 generate_one_insn(insn
, state
);
958 } END_FOR_EACH_PTR(insn
);
961 output_comment(state
, "--- in ---");
962 FOR_EACH_PTR(state
->inputs
, entry
) {
963 output_comment(state
, "%s <- %s", show_pseudo(entry
->pseudo
), show_storage(entry
->storage
));
964 } END_FOR_EACH_PTR(entry
);
965 output_comment(state
, "--- spill ---");
966 FOR_EACH_PTR(state
->internal
, entry
) {
967 output_comment(state
, "%s <-> %s", show_pseudo(entry
->pseudo
), show_storage(entry
->storage
));
968 } END_FOR_EACH_PTR(entry
);
969 output_comment(state
, "--- out ---");
970 FOR_EACH_PTR(state
->outputs
, entry
) {
971 output_comment(state
, "%s -> %s", show_pseudo(entry
->pseudo
), show_storage(entry
->storage
));
972 } END_FOR_EACH_PTR(entry
);
977 static void generate_list(struct basic_block_list
*list
, unsigned long generation
)
979 struct basic_block
*bb
;
980 FOR_EACH_PTR(list
, bb
) {
981 if (bb
->generation
== generation
)
983 output_bb(bb
, generation
);
984 } END_FOR_EACH_PTR(bb
);
987 static void output_bb(struct basic_block
*bb
, unsigned long generation
)
989 struct bb_state state
;
991 bb
->generation
= generation
;
993 /* Make sure all parents have been generated first */
994 generate_list(bb
->parents
, generation
);
996 state
.inputs
= gather_storage(bb
, STOR_IN
);
997 state
.outputs
= gather_storage(bb
, STOR_OUT
);
998 state
.internal
= NULL
;
999 state
.stack_offset
= 0;
1001 generate(bb
, &state
);
1003 free_ptr_list(&state
.inputs
);
1004 free_ptr_list(&state
.outputs
);
1006 /* Generate all children... */
1007 generate_list(bb
->children
, generation
);
1010 static void output(struct entrypoint
*ep
)
1012 unsigned long generation
= ++bb_generation
;
1016 /* Set up initial inter-bb storage links */
1019 /* Show the results ... */
1020 output_bb(ep
->entry
->bb
, generation
);
1022 /* Clear the storage hashes for the next function.. */
1026 static int compile(struct symbol_list
*list
)
1029 FOR_EACH_PTR(list
, sym
) {
1030 struct entrypoint
*ep
;
1032 ep
= linearize_symbol(sym
);
1035 } END_FOR_EACH_PTR(sym
);
1040 int main(int argc
, char **argv
)
1042 return compile(sparse(argc
, argv
));