diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2004-12-10 18:55:20 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-07 21:05:58 -0700 |
commit | 594e014153ed63ae04bbdf2c24a5da7b147006be (patch) | |
tree | 127a34f2c4a80049d3b3ec9c36062578ea133e03 /example.c | |
parent | Add the argument pseudos to the "enter" instruction (diff) | |
download | sparse-594e014153ed63ae04bbdf2c24a5da7b147006be.tar.gz sparse-594e014153ed63ae04bbdf2c24a5da7b147006be.tar.bz2 sparse-594e014153ed63ae04bbdf2c24a5da7b147006be.zip |
Add support for various arch-specific storage allocation
issues:
- argument passign setup
- return value storage
- silly switch register hack.
Diffstat (limited to 'example.c')
-rw-r--r-- | example.c | 118 |
1 files changed, 116 insertions, 2 deletions
@@ -23,6 +23,9 @@ struct hardreg { #define TAG_DEAD 1 #define TAG_DIRTY 2 +/* Our "switch" generation is very very stupid. */ +#define SWITCH_REG (1) + static void output_bb(struct basic_block *bb, unsigned long generation); /* @@ -122,8 +125,8 @@ static const char *show_memop(struct storage *storage) { static char buffer[1000]; switch (storage->type) { - case REG_ARG: - sprintf(buffer, "%d(FP)", storage->regno * 4); + case REG_FRAME: + sprintf(buffer, "%d(FP)", storage->offset); break; case REG_STACK: sprintf(buffer, "%d(SP)", storage->offset); @@ -685,6 +688,16 @@ static void generate_branch(struct bb_state *state, struct instruction *br) output_insn(state, "jmp .L%p", br->bb_true); } +/* We've made sure that there is a dummy reg live for the output */ +static void generate_switch(struct bb_state *state, struct instruction *insn) +{ + struct hardreg *reg = hardregs + SWITCH_REG; + + generate_output_storage(state); + output_insn(state, "switch on %s", reg->name); + output_insn(state, "unimplemented: %s", show_instruction(insn)); +} + static void generate_ret(struct bb_state *state, struct instruction *ret) { if (ret->src && ret->src != VOID) { @@ -795,6 +808,10 @@ static void generate_one_insn(struct instruction *insn, struct bb_state *state) generate_branch(state, insn); break; + case OP_SWITCH: + generate_switch(state, insn); + break; + case OP_CALL: generate_call(state, insn); break; @@ -1109,6 +1126,100 @@ static void output_bb(struct basic_block *bb, unsigned long generation) generate_list(bb->children, generation); } +static void set_up_arch_entry(struct entrypoint *ep, struct instruction *entry) +{ + int i; + pseudo_t arg; + + /* + * We should set up argument sources here.. + * + * Things like "first three arguments in registers" etc + * are all for this place. + */ + i = 0; + FOR_EACH_PTR(entry->arg_list, arg) { + struct storage *in = lookup_storage(entry->bb, arg, STOR_IN); + if (!in) { + in = alloc_storage(); + add_storage(in, entry->bb, arg, STOR_IN); + } + if (i < 3) { + in->type = REG_REG; + in->regno = i; + } else { + in->type = REG_FRAME; + in->offset = (i-3)*4; + } + i++; + } END_FOR_EACH_PTR(arg); +} + +/* + * Set up storage information for "return" + * + * Not strictly necessary, since the code generator will + * certainly move the return value to the right register, + * but it can help register allocation if the allocator + * sees that the target register is going to return in %eax. + */ +static void set_up_arch_exit(struct basic_block *bb, struct instruction *ret) +{ + pseudo_t pseudo = ret->src; + + if (pseudo && pseudo != VOID) { + struct storage *out = lookup_storage(bb, pseudo, STOR_OUT); + if (!out) { + out = alloc_storage(); + add_storage(out, bb, pseudo, STOR_OUT); + } + out->type = REG_REG; + out->regno = 0; + } +} + +/* + * Set up dummy/silly output storage information for a switch + * instruction. We need to make sure that a register is available + * when we generate code for switch, so force that by creating + * a dummy output rule. + */ +static void set_up_arch_switch(struct basic_block *bb, struct instruction *insn) +{ + pseudo_t pseudo = insn->cond; + struct storage *out = lookup_storage(bb, pseudo, STOR_OUT); + if (!out) { + out = alloc_storage(); + add_storage(out, bb, pseudo, STOR_OUT); + } + out->type = REG_REG; + out->regno = SWITCH_REG; +} + +static void arch_set_up_storage(struct entrypoint *ep) +{ + struct basic_block *bb; + + /* Argument storage etc.. */ + set_up_arch_entry(ep, ep->entry); + + FOR_EACH_PTR(ep->bbs, bb) { + struct instruction *insn = last_instruction(bb->insns); + if (!insn) + continue; + switch (insn->opcode) { + case OP_RET: + set_up_arch_exit(bb, insn); + break; + case OP_SWITCH: + set_up_arch_switch(bb, insn); + break; + default: + /* nothing */; + } + } END_FOR_EACH_PTR(bb); +} + static void output(struct entrypoint *ep) { unsigned long generation = ++bb_generation; @@ -1118,6 +1229,9 @@ static void output(struct entrypoint *ep) /* Set up initial inter-bb storage links */ set_up_storage(ep); + /* Architecture-specific storage rules.. */ + arch_set_up_storage(ep); + /* Show the results ... */ output_bb(ep->entry->bb, generation); |