Skip to content

Commit

Permalink
Fix to detect whether stack frame is required
Browse files Browse the repository at this point in the history
It should be checked after
function body is generated.

  * There are stack variables
  * Function register parameters overflow
  * Variable arguments
  * `alloca` is used

Degraded in 6fd61fa
  • Loading branch information
tyfkda committed Dec 9, 2023
1 parent c9df76f commit c66fb61
Showing 1 changed file with 23 additions and 21 deletions.
44 changes: 23 additions & 21 deletions src/cc/backend/codegen.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,6 @@ static VarInfo *prepare_retvar(Function *func) {
static void alloc_variable_registers(Function *func) {
assert(func->type->kind == TY_FUNC);

bool require_stack_frame = (func->flag & FUNCF_STACK_MODIFIED) != 0;

for (int i = 0; i < func->scopes->len; ++i) {
Scope *scope = func->scopes->data[i];
if (scope->vars == NULL)
Expand All @@ -97,7 +95,6 @@ static void alloc_variable_registers(Function *func) {
FrameInfo *fi = malloc_or_die(sizeof(*fi));
fi->offset = 0;
varinfo->local.frameinfo = fi;
require_stack_frame = true;
continue;
}

Expand All @@ -106,47 +103,41 @@ static void alloc_variable_registers(Function *func) {
vreg->flag |= VRF_REF;
varinfo->local.vreg = vreg;
varinfo->local.frameinfo = &vreg->frame;
require_stack_frame = true;
}
}

// Handle if return value is on the stack.
struct {
struct RegSet {
int index;
int max;
} regparams[2] = {
{.index = 0, .max = MAX_REG_ARGS},
{.index = 0, .max = MAX_FREG_ARGS},
};
enum { IREG = 0, FREG = 1 };
enum RegKind { IREG = 0, FREG = 1 };

// Handle if return value is on the stack.
if (is_stack_param(func->type->func.ret)) {
prepare_retvar(func);
++regparams[IREG].index;
}

// Add flag to parameters.
// Count register parameters, or set flag.
const Vector *params = func->params;
if (params != NULL) {
for (int i = 0; i < params->len; ++i) {
VarInfo *varinfo = params->data[i];
VReg *vreg = varinfo->local.vreg;
if (vreg != NULL) {
vreg->flag |= VRF_PARAM;
int k = (vreg->flag & VRF_FLONUM) ? FREG : IREG;
if (regparams[k].index < regparams[k].max) {
vreg->reg_param_index = regparams[k].index++;
} else {
vreg->flag |= VRF_SPILLED | VRF_STACK_PARAM;
require_stack_frame = true;
}
enum RegKind k = (vreg->flag & VRF_FLONUM) ? FREG : IREG;
struct RegSet *p = &regparams[k];
if (p->index < p->max)
vreg->reg_param_index = p->index++;
else
vreg->flag |= VRF_STACK_PARAM;
}
}
}

if (require_stack_frame) {
FuncBackend *fnbe = func->extra;
fnbe->ra->flag |= RAF_STACK_FRAME;
}
}

void enumerate_register_params(
Expand Down Expand Up @@ -673,6 +664,8 @@ void gen_stmt(Stmt *stmt) {
////////////////////////////////////////////////

void prepare_register_allocation(Function *func) {
bool require_stack_frame = func->type->func.vaargs || (func->flag & FUNCF_STACK_MODIFIED) != 0;

for (int i = 0; i < func->scopes->len; ++i) {
Scope *scope = (Scope*)func->scopes->data[i];
if (scope->vars == NULL)
Expand All @@ -685,15 +678,24 @@ void prepare_register_allocation(Function *func) {
VReg *vreg = varinfo->local.vreg;
if (vreg == NULL) {
assert(!is_prim_type(varinfo->type));
// Whether it is a parameter or local variable defined in a function,
// it is needed to access relative to base pointer.
require_stack_frame = true;
continue;
}

assert(is_prim_type(varinfo->type));
if (vreg->flag & VRF_REF) {
if (vreg->flag & (VRF_REF | VRF_STACK_PARAM)) {
spill_vreg(vreg);
require_stack_frame = true;
}
}
}

if (require_stack_frame) {
FuncBackend *fnbe = func->extra;
fnbe->ra->flag |= RAF_STACK_FRAME;
}
}

void map_virtual_to_physical_registers(RegAlloc *ra) {
Expand Down

0 comments on commit c66fb61

Please sign in to comment.