From df0d922cd9181d2fa3a54eee99350ee008b8fb33 Mon Sep 17 00:00:00 2001 From: tyfkda Date: Thu, 27 Jul 2023 09:15:39 +0900 Subject: [PATCH] Unnest function calls If function call is used for function argument, physical register usage may conflict in compiled code. To make complex function arguments simple, precompute and store it to temporary variable. And refer it in outer function call. --- src/cc/codegen_expr.c | 92 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/src/cc/codegen_expr.c b/src/cc/codegen_expr.c index 1936c206a..fb934c05a 100644 --- a/src/cc/codegen_expr.c +++ b/src/cc/codegen_expr.c @@ -340,6 +340,92 @@ typedef struct { #endif } ArgInfo; +// If an argument is complex expression, +// precalculate it and make function argument simple. +static Expr *simplify_funarg(Expr *arg) { + switch (arg->kind) { + default: assert(false); break; + + case EX_ASSIGN: + case EX_TERNARY: + case EX_FUNCALL: + case EX_BLOCK: + { + // Precalculate expr and store the result to temporary variable. + Type *type = arg->type; + if (type->kind == TY_STRUCT) + type = ptrof(type); + Scope *scope = curscope; + const Name *name = alloc_label(); + VarInfo *varinfo = scope_add(scope, name, type, 0); + varinfo->local.reg = gen_expr(arg); + // Replace the argument to temporary variable reference. + return new_expr_variable(name, type, NULL, scope); + } + + case EX_COMPLIT: + // Precalculate compound literal, and returns its stored variable name. + gen_expr(arg); + return arg->complit.var; + + case EX_COMMA: + // Precalculate first expression in comma. + gen_expr(arg->bop.lhs); + return simplify_funarg(arg->bop.rhs); + + // Binary operators + case EX_ADD: + case EX_SUB: + case EX_MUL: + case EX_DIV: + case EX_MOD: + case EX_BITAND: + case EX_BITOR: + case EX_BITXOR: + case EX_LSHIFT: + case EX_RSHIFT: + case EX_EQ: + case EX_NE: + case EX_LT: + case EX_LE: + case EX_GE: + case EX_GT: + case EX_LOGAND: + case EX_LOGIOR: + arg->bop.lhs = simplify_funarg(arg->bop.lhs); + arg->bop.rhs = simplify_funarg(arg->bop.rhs); + break; + + // Unary operators + case EX_POS: + case EX_NEG: + case EX_BITNOT: + case EX_PREINC: + case EX_PREDEC: + case EX_POSTINC: + case EX_POSTDEC: + case EX_REF: + case EX_DEREF: + case EX_CAST: + arg->unary.sub = simplify_funarg(arg->unary.sub); + break; + + case EX_MEMBER: + arg->member.target = simplify_funarg(arg->member.target); + break; + + // Literals + case EX_FIXNUM: +#ifndef __NO_FLONUM + case EX_FLONUM: +#endif + case EX_STR: + case EX_VAR: + break; + } + return arg; +} + static VReg *gen_funcall(Expr *expr) { Expr *func = expr->funcall.func; if (func->kind == EX_VAR && is_global_scope(func->var.scope)) { @@ -352,6 +438,12 @@ static VReg *gen_funcall(Expr *expr) { Vector *args = expr->funcall.args; int arg_count = args->len; + // To avoid nested funcall, + // simplify funargs and precalculate complex expression before funcall. + for (int i = 0; i < arg_count; ++i) { + Expr *arg = args->data[i]; + args->data[i] = simplify_funarg(arg); + } int offset = 0;