diff options
| author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2004-12-08 16:17:05 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-07 21:05:40 -0700 |
| commit | 14eb73dd7fb9fde72a9ae3d35e98f84b5d490f49 (patch) | |
| tree | 3236408c6115a15a2ea5eb624ae9cf4075318493 /example.c | |
| parent | 382087f40271921868ec1bf9c839e218b05d693b (diff) | |
| download | sparse-dev-14eb73dd7fb9fde72a9ae3d35e98f84b5d490f49.tar.gz | |
Generate "code" for binops.
It ain't pretty, but that's not the aim right now.
Diffstat (limited to 'example.c')
| -rw-r--r-- | example.c | 206 |
1 files changed, 171 insertions, 35 deletions
@@ -14,7 +14,8 @@ struct hardreg { const char *name; pseudo_t contains; - int busy; + unsigned busy:1, + dirty:1; }; static void output_bb(struct basic_block *bb, unsigned long generation); @@ -32,6 +33,7 @@ static struct hardreg hardregs[] = { struct bb_state { struct basic_block *bb; + unsigned long stack_offset; struct storage_hash_list *inputs; struct storage_hash_list *outputs; struct storage_hash_list *internal; @@ -60,13 +62,37 @@ static struct storage_hash *find_or_create_hash(pseudo_t pseudo, struct storage_ return entry; } +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); + break; + case REG_STACK: + sprintf(buffer, "%d(SP)", storage->offset); + break; + default: + return show_storage(storage); + } + return buffer; +} + +static void alloc_stack(struct bb_state *state, struct storage *storage) +{ + storage->type = REG_STACK; + storage->offset = state->stack_offset; + state->stack_offset += 4; +} + /* Flush a hardreg out to the storage it has.. */ static void flush_reg(struct bb_state *state, struct hardreg *hardreg) { pseudo_t pseudo; struct storage_hash *out; + struct storage *storage; - if (!hardreg->busy) + if (!hardreg->busy || !hardreg->dirty) return; pseudo = hardreg->contains; if (!pseudo) @@ -74,26 +100,31 @@ static void flush_reg(struct bb_state *state, struct hardreg *hardreg) if (pseudo->type != PSEUDO_REG && pseudo->type != PSEUDO_ARG) return; - out = find_storage_hash(pseudo, state->outputs); - if (!out) - out = find_or_create_hash(pseudo, &state->internal); - /* FIXME! Create a private storage for this pseudo for this bb!! */ -} - -static const char *show_memop(struct storage *storage) -{ - static char buffer[1000]; + out = find_storage_hash(pseudo, state->internal); + if (!out) { + out = find_storage_hash(pseudo, state->outputs); + if (!out) + out = find_or_create_hash(pseudo, &state->internal); + } + storage = out->storage; switch (storage->type) { - case REG_ARG: - sprintf(buffer, "%d(FP)", storage->regno * 4); - break; + default: + /* + * Aieee - the next user wants it in a register, but we + * need to flush it to memory in between. Which means that + * we need to allocate an internal one, dammit.. + */ + out = find_or_create_hash(pseudo, &state->internal); + storage = out->storage; + /* Fall through */ + case REG_UDEF: + alloc_stack(state, storage); + /* Fall through */ case REG_STACK: - sprintf(buffer, "%d(SP)", storage->offset); + printf("\tmovl %s,%s\n", hardreg->name, show_memop(storage)); break; - default: - return show_storage(storage); } - return buffer; + } /* Fill a hardreg with the pseudo it has */ @@ -150,35 +181,130 @@ static struct hardreg *getreg(struct bb_state *state, pseudo_t pseudo) return fill_reg(state, hardregs + i, pseudo); } -static struct hardreg *prepare_address(struct bb_state *state, pseudo_t addr) -{ - if (addr->type == PSEUDO_SYM) - return 0; - return getreg(state, addr); -} - -static const char *show_address(struct hardreg *base, struct instruction *memop) +static const char *address(struct bb_state *state, struct instruction *memop) { - static char buffer[1000]; + struct symbol *sym; + struct hardreg *base; + static char buffer[100]; + pseudo_t addr = memop->src; - if (!base) { - struct symbol *sym = memop->src->sym; + switch(addr->type) { + case PSEUDO_SYM: + sym = addr->sym; if (sym->ctype.modifiers & MOD_NONLOCAL) { sprintf(buffer, "%s+%d", show_ident(sym->ident), memop->offset); return buffer; } sprintf(buffer, "%d+%s(SP)", memop->offset, show_ident(sym->ident)); return buffer; + default: + base = getreg(state, addr); + sprintf(buffer, "%d(%s)", memop->offset, base->name); + return buffer; + } +} + +static const char *reg_or_imm(struct bb_state *state, pseudo_t pseudo) +{ + switch(pseudo->type) { + case PSEUDO_VAL: + return show_pseudo(pseudo); + default: + return getreg(state, pseudo)->name; } - sprintf(buffer, "%d(%s)", memop->offset, base->name); - return buffer; } static void generate_store(struct instruction *insn, struct bb_state *state) { - struct hardreg *value = getreg(state, insn->target); - struct hardreg *addr = prepare_address(state, insn->src); - printf("\tmov.%d %s,%s\n", insn->size, value->name, show_address(addr, insn)); + printf("\tmov.%d %s,%s\n", insn->size, reg_or_imm(state, insn->target), address(state, insn)); +} + +static const char* opcodes[] = { + [OP_BADOP] = "bad_op", + + /* Fn entrypoint */ + [OP_ENTRY] = "<entry-point>", + + /* Terminator */ + [OP_RET] = "ret", + [OP_BR] = "br", + [OP_SWITCH] = "switch", + [OP_INVOKE] = "invoke", + [OP_COMPUTEDGOTO] = "jmp *", + [OP_UNWIND] = "unwind", + + /* Binary */ + [OP_ADD] = "add", + [OP_SUB] = "sub", + [OP_MUL] = "mul", + [OP_DIV] = "div", + [OP_MOD] = "mod", + [OP_SHL] = "shl", + [OP_SHR] = "shr", + + /* Logical */ + [OP_AND] = "and", + [OP_OR] = "or", + [OP_XOR] = "xor", + [OP_AND_BOOL] = "and-bool", + [OP_OR_BOOL] = "or-bool", + + /* Binary comparison */ + [OP_SET_EQ] = "seteq", + [OP_SET_NE] = "setne", + [OP_SET_LE] = "setle", + [OP_SET_GE] = "setge", + [OP_SET_LT] = "setlt", + [OP_SET_GT] = "setgt", + [OP_SET_B] = "setb", + [OP_SET_A] = "seta", + [OP_SET_BE] = "setbe", + [OP_SET_AE] = "setae", + + /* Uni */ + [OP_NOT] = "not", + [OP_NEG] = "neg", + + /* Special three-input */ + [OP_SEL] = "select", + + /* Memory */ + [OP_MALLOC] = "malloc", + [OP_FREE] = "free", + [OP_ALLOCA] = "alloca", + [OP_LOAD] = "load", + [OP_STORE] = "store", + [OP_SETVAL] = "set", + [OP_GET_ELEMENT_PTR] = "getelem", + + /* Other */ + [OP_PHI] = "phi", + [OP_PHISOURCE] = "phisrc", + [OP_CAST] = "cast", + [OP_PTRCAST] = "ptrcast", + [OP_CALL] = "call", + [OP_VANEXT] = "va_next", + [OP_VAARG] = "va_arg", + [OP_SLICE] = "slice", + [OP_SNOP] = "snop", + [OP_LNOP] = "lnop", + [OP_NOP] = "nop", + [OP_DEATHNOTE] = "dead", + [OP_ASM] = "asm", + + /* Sparse tagging (line numbers, context, whatever) */ + [OP_CONTEXT] = "context", +}; + +static void generate_binop(struct bb_state *state, struct instruction *insn) +{ + const char *op = opcodes[insn->opcode]; + struct hardreg *reg = getreg(state, insn->src1); + flush_reg(state, reg); + printf("\t%s.%d %s,%s\n", op, insn->size, reg_or_imm(state, insn->src2), reg->name); + reg->contains = insn->target; + reg->busy = 1; + reg->dirty = 1; } static void mark_pseudo_dead(pseudo_t pseudo) @@ -186,8 +312,10 @@ static void mark_pseudo_dead(pseudo_t pseudo) int i; for (i = 0; i < REGNO; i++) { - if (hardregs[i].contains == pseudo) + if (hardregs[i].contains == pseudo) { hardregs[i].busy = 0; + hardregs[i].dirty = 0; + } } } @@ -226,6 +354,11 @@ static void generate_one_insn(struct instruction *insn, struct bb_state *state) mark_pseudo_dead(insn->target); break; + case OP_BINARY ... OP_BINARY_END: + case OP_BINCMP ... OP_BINCMP_END: + generate_binop(state, insn); + break; + default: show_instruction(insn); break; @@ -251,6 +384,7 @@ static void generate(struct basic_block *bb, struct bb_state *state) for (i = 0; i < REGNO; i++) { hardregs[i].contains = NULL; hardregs[i].busy = 0; + hardregs[i].dirty = 0; } FOR_EACH_PTR(state->inputs, entry) { @@ -260,6 +394,7 @@ static void generate(struct basic_block *bb, struct bb_state *state) int regno = storage->regno; hardregs[regno].contains = entry->pseudo; hardregs[regno].busy = 1; + hardregs[regno].dirty = 1; name = hardregs[regno].name; } printf("\t%s <- %s\n", show_pseudo(entry->pseudo), name); @@ -290,6 +425,7 @@ static void output_bb(struct basic_block *bb, unsigned long generation) state.inputs = gather_storage(bb, STOR_IN); state.outputs = gather_storage(bb, STOR_OUT); state.internal = NULL; + state.stack_offset = 0; generate(bb, &state); |
