diff options
| author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2004-02-23 11:33:59 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-07 21:01:28 -0700 |
| commit | 8e3e7f9a8c1a6ea2532b383aacc76b49000a53d6 (patch) | |
| tree | 0f0a34fa75e65baf4baeb1e7658ed90da3c69cd1 /linearize.c | |
| parent | 48b2d8bb696a61b74661d5976365af0758d0f563 (diff) | |
| download | sparse-dev-8e3e7f9a8c1a6ea2532b383aacc76b49000a53d6.tar.gz | |
Linearize function calls. Kind-of.
(Btw - a number of the linearizations are pretty spotty,
and not doing the right thing in the details. It's more
concept thing).
Diffstat (limited to 'linearize.c')
| -rw-r--r-- | linearize.c | 77 |
1 files changed, 77 insertions, 0 deletions
diff --git a/linearize.c b/linearize.c index 652ff60b..b839f1fc 100644 --- a/linearize.c +++ b/linearize.c @@ -84,6 +84,15 @@ static void show_instruction(struct instruction *insn) case OP_MOVE: printf("\t%%r%d <- %%r%d\n", insn->target.nr, insn->src.nr); break; + case OP_ARGUMENT: + printf("\tpush %%r%d\n", insn->src.nr); + break; + case OP_CALL: + printf("\t%%r%d <- CALL %s\n", insn->target.nr, show_ident(insn->address->ident)); + break; + case OP_INDCALL: + printf("\t%%r%d <- CALL [%%r%d]\n", insn->target.nr, insn->src.nr); + break; case OP_UNOP ... OP_LASTUNOP: printf("\t%%r%d <- %c %%r%d\n", insn->target.nr, @@ -329,6 +338,71 @@ static pseudo_t linearize_assignment(struct entrypoint *ep, struct expression *e return value; } +static void push_argument(struct entrypoint *ep, struct expression *expr, pseudo_t pseudo) +{ + struct instruction *insn = alloc_instruction(OP_ARGUMENT, expr->ctype); + insn->src = pseudo; + add_one_insn(ep, expr->pos, insn); +} + +static pseudo_t linearize_direct_call(struct entrypoint *ep, struct expression *expr, struct symbol *direct) +{ + struct instruction *insn = alloc_instruction(OP_CALL, expr->ctype); + pseudo_t retval = alloc_pseudo(); + + insn->target = retval; + insn->address = direct; + add_one_insn(ep, expr->pos, insn); + return retval; +} + +static pseudo_t linearize_indirect_call(struct entrypoint *ep, struct expression *expr, pseudo_t pseudo) +{ + struct instruction *insn = alloc_instruction(OP_INDCALL, expr->ctype); + pseudo_t retval = alloc_pseudo(); + + insn->target = retval; + insn->src = pseudo; + add_one_insn(ep, expr->pos, insn); + return retval; +} + +static pseudo_t linearize_call_expression(struct entrypoint *ep, struct expression *expr) +{ + struct symbol *direct; + struct expression *arg, *fn; + pseudo_t retval; + + if (!expr->ctype) { + warn(expr->pos, "\tcall with no type!"); + return VOID; + } + + FOR_EACH_PTR_REVERSE(expr->args, arg) { + pseudo_t new = linearize_expression(ep, arg); + push_argument(ep, arg, new); + } END_FOR_EACH_PTR_REVERSE; + + fn = expr->fn; + + /* Remove dereference, if any */ + direct = NULL; + if (fn->type == EXPR_PREOP) { + if (fn->unop->type == EXPR_SYMBOL) { + struct symbol *sym = fn->unop->symbol; + if (sym->ctype.base_type->type == SYM_FN) + direct = sym; + } + } + if (direct) { + retval = linearize_direct_call(ep, expr, direct); + } else { + pseudo_t fncall = linearize_expression(ep, fn); + retval = linearize_indirect_call(ep, expr, fncall); + } + return retval; +} + static pseudo_t linearize_binop(struct entrypoint *ep, struct expression *expr) { pseudo_t src1, src2, result; @@ -403,6 +477,9 @@ pseudo_t linearize_expression(struct entrypoint *ep, struct expression *expr) case EXPR_STATEMENT: return linearize_statement(ep, expr->statement); + case EXPR_CALL: + return linearize_call_expression(ep, expr); + case EXPR_BINOP: return linearize_binop(ep, expr); |
