Skip to content

Commit

Permalink
Support variable declaration in for loop setup
Browse files Browse the repository at this point in the history
This allows variables declare in the scope of for loop body, to
avoid loose variable liveness, in other word, variable can have
stricter scope liveness.
  • Loading branch information
ChAoSUnItY committed Mar 21, 2024
1 parent 6999393 commit 0dad658
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 24 deletions.
2 changes: 1 addition & 1 deletion src/defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
#define MAX_FIELDS 32
#define MAX_FUNCS 512
#define MAX_FUNC_TRIES 2160
#define MAX_BLOCKS 1150
#define MAX_BLOCKS 2048
#define MAX_TYPES 64
#define MAX_IR_INSTR 36864
#define MAX_BB_PRED 128
Expand Down
94 changes: 73 additions & 21 deletions src/parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -2326,60 +2326,110 @@ basic_block_t *read_body_statement(block_t *parent, basic_block_t *bb)

lex_expect(T_open_bracket);

/* synthesize for loop block */
block_t *blk = add_block(parent, parent->func, parent->macro);
add_ph1_ir(OP_block_start);

/* setup - execute once */
basic_block_t *setup = bb_create(blk);
bb_connect(bb, setup, NEXT);

if (!lex_accept(T_semicolon)) {
lex_peek(T_identifier, token);
read_body_assignment(token, parent, OP_generic, &bb);
if (!lex_peek(T_identifier, token))
error("Unexpected token");

int find_type_flag = lex_accept(T_struct) ? 2 : 1;
type = find_type(token, find_type_flag);
if (type) {
var = require_var(blk);
read_full_var_decl(var, 0, 0);
add_insn(blk, setup, OP_allocat, var, NULL, NULL, 0, NULL);
add_symbol(setup, var);
if (lex_accept(T_assign)) {
read_expr(blk, &setup);
read_ternary_operation(blk, &setup);

ph1_ir = add_ph1_ir(OP_assign);
ph1_ir->src0 = opstack_pop();
ph1_ir->dest = var;
add_insn(blk, setup, OP_assign, ph1_ir->dest, ph1_ir->src0,
NULL, 0, NULL);
}
while (lex_accept(T_comma)) {
var_t *nv;

/* add sequence point at T_comma */
perform_side_effect(blk, setup);

/* multiple (partial) declarations */
nv = require_var(blk);
read_partial_var_decl(nv, var); /* partial */
add_insn(blk, setup, OP_allocat, nv, NULL, NULL, 0, NULL);
add_symbol(setup, nv);
if (lex_accept(T_assign)) {
read_expr(blk, &setup);

ph1_ir = add_ph1_ir(OP_assign);
ph1_ir->src0 = opstack_pop();
ph1_ir->dest = nv;
add_insn(blk, setup, OP_assign, ph1_ir->dest,
ph1_ir->src0, NULL, 0, NULL);
}
}
} else {
read_body_assignment(token, blk, OP_generic, &setup);
}

lex_expect(T_semicolon);
}

basic_block_t *cond_ = bb_create(parent);
basic_block_t *cond_ = bb_create(blk);
basic_block_t *for_end = bb_create(parent);
break_bb[break_exit_idx] = for_end;
bb_connect(bb, cond_, NEXT);
bb_connect(setup, cond_, NEXT);
bb_connect(cond_, for_end, ELSE);

/* condition - check before the loop */
ph1_ir = add_ph1_ir(OP_label);
var_condition = require_var(parent);
var_condition = require_var(blk);
strcpy(var_condition->var_name, cond);
ph1_ir->src0 = var_condition;
if (!lex_accept(T_semicolon)) {
read_expr(parent, &cond_);
read_expr(blk, &cond_);
lex_expect(T_semicolon);
} else {
/* always true */
ph1_ir = add_ph1_ir(OP_load_constant);
vd = require_var(parent);
vd = require_var(blk);
vd->init_val = 1;
strcpy(vd->var_name, gen_name());
ph1_ir->dest = vd;
opstack_push(vd);
add_insn(parent, cond_, OP_load_constant, ph1_ir->dest, NULL, NULL,
0, NULL);
add_insn(blk, cond_, OP_load_constant, ph1_ir->dest, NULL, NULL, 0,
NULL);
}

ph1_ir = add_ph1_ir(OP_branch);
ph1_ir->dest = opstack_pop();
vd = require_var(parent);
vd = require_var(blk);
strcpy(vd->var_name, body);
ph1_ir->src0 = vd;
vd = require_var(parent);
vd = require_var(blk);
strcpy(vd->var_name, end);
ph1_ir->src1 = vd;
add_insn(parent, cond_, OP_branch, NULL, ph1_ir->dest, NULL, 0, NULL);
add_insn(blk, cond_, OP_branch, NULL, ph1_ir->dest, NULL, 0, NULL);

var_break = require_var(parent);
var_break = require_var(blk);
strcpy(var_break->var_name, end);

break_exit[break_exit_idx++] = var_break;

basic_block_t *inc_ = bb_create(parent);
basic_block_t *inc_ = bb_create(blk);
continue_bb[continue_pos_idx] = inc_;

/* increment after each loop */
ph1_ir = add_ph1_ir(OP_label);
var_inc = require_var(parent);
var_inc = require_var(blk);
strcpy(var_inc->var_name, inc);
ph1_ir->src0 = var_inc;

Expand All @@ -2391,25 +2441,25 @@ basic_block_t *read_body_statement(block_t *parent, basic_block_t *bb)
else if (lex_accept(T_decrement))
prefix_op = OP_sub;
lex_peek(T_identifier, token);
read_body_assignment(token, parent, prefix_op, &inc_);
read_body_assignment(token, blk, prefix_op, &inc_);
lex_expect(T_close_bracket);
}

/* jump back to condition */
ph1_ir = add_ph1_ir(OP_jump);
vd = require_var(parent);
vd = require_var(blk);
strcpy(vd->var_name, cond);
ph1_ir->dest = vd;

/* loop body */
ph1_ir = add_ph1_ir(OP_label);
vd = require_var(parent);
vd = require_var(blk);
strcpy(vd->var_name, body);
ph1_ir->src0 = vd;

basic_block_t *body_ = bb_create(parent);
basic_block_t *body_ = bb_create(blk);
bb_connect(cond_, body_, THEN);
body_ = read_body_statement(parent, body_);
body_ = read_body_statement(blk, body_);

if (body_) {
bb_connect(body_, inc_, NEXT);
Expand All @@ -2420,7 +2470,7 @@ basic_block_t *read_body_statement(block_t *parent, basic_block_t *bb)

/* jump to increment */
ph1_ir = add_ph1_ir(OP_jump);
vd = require_var(parent);
vd = require_var(blk);
strcpy(vd->var_name, inc);
ph1_ir->dest = vd;

Expand All @@ -2431,6 +2481,7 @@ basic_block_t *read_body_statement(block_t *parent, basic_block_t *bb)

continue_pos_idx--;
break_exit_idx--;
add_ph1_ir(OP_block_end);
return for_end;
}

Expand Down Expand Up @@ -2504,6 +2555,7 @@ basic_block_t *read_body_statement(block_t *parent, basic_block_t *bb)

continue_pos_idx--;
break_exit_idx--;
add_ph1_ir(OP_block_end);
return do_while_end;
}

Expand Down
12 changes: 12 additions & 0 deletions tests/driver.sh
Original file line number Diff line number Diff line change
Expand Up @@ -580,4 +580,16 @@ int main()
}
EOF

# Variables can be declared within a for-loop iteration
try_ 120 << EOF
int main()
{
int fac = 1;
for (int i = 1; i <= 5; i++) {
fac = fac * i;
}
return fac;
}
EOF

echo OK
2 changes: 1 addition & 1 deletion tests/snapshots/fib.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion tests/snapshots/hello.json

Large diffs are not rendered by default.

0 comments on commit 0dad658

Please sign in to comment.