Skip to content

Commit

Permalink
Merge pull request #131 from nosba0957/master
Browse files Browse the repository at this point in the history
Fix bad logical-and implementation
  • Loading branch information
jserv authored Jul 7, 2024
2 parents c2afdc2 + 43f02a7 commit 7e49741
Show file tree
Hide file tree
Showing 8 changed files with 276 additions and 33 deletions.
10 changes: 0 additions & 10 deletions src/arm-codegen.c
Original file line number Diff line number Diff line change
Expand Up @@ -440,16 +440,6 @@ void emit_ph2_ir(ph2_ir_t *ph2_ir)
emit(__mov_i(__NE, rd, 0));
emit(__mov_i(__EQ, rd, 1));
return;
case OP_log_and:
/* TODO: short-circuit evaluation */
emit(__teq(rn));
emit(__mov_i(__NE, __r8, 1));
emit(__mov_i(__EQ, __r8, 0));
emit(__teq(rm));
emit(__mov_i(__NE, rd, 1));
emit(__mov_i(__EQ, rd, 0));
emit(__and_r(__AL, rd, rd, __r8));
return;
case OP_log_or:
emit(__or_r(__AL, rd, rn, rm));
emit(__teq(rd));
Expand Down
3 changes: 2 additions & 1 deletion src/defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
#define MAX_FUNC_TRIES 2160
#define MAX_BLOCKS 2048
#define MAX_TYPES 64
#define MAX_IR_INSTR 36864
#define MAX_IR_INSTR 40000
#define MAX_BB_PRED 128
#define MAX_BB_DOM_SUCC 64
#define MAX_GLOBAL_IR 256
Expand Down Expand Up @@ -175,6 +175,7 @@ struct var {
ref_block_list_t ref_block_list; /* blocks which kill variable */
int consumed;
bool is_ternary_ret;
bool is_log_and_ret;
bool is_const; /* whether a constant representaion or not */
};

Expand Down
176 changes: 170 additions & 6 deletions src/parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -662,6 +662,9 @@ void read_char_param(block_t *parent, basic_block_t *bb)
add_insn(parent, bb, OP_load_constant, ph1_ir->dest, NULL, NULL, 0, NULL);
}

void read_log_and_operation(block_t *parent,
basic_block_t **bb,
char *label_else);
void read_ternary_operation(block_t *parent, basic_block_t **bb);
void read_func_parameters(block_t *parent, basic_block_t **bb)
{
Expand Down Expand Up @@ -973,20 +976,37 @@ void read_expr_operand(block_t *parent, basic_block_t **bb)
}
}

void finalize_log_and(block_t *parent,
basic_block_t **bb,
char *label_else,
basic_block_t *else_bb);

void read_expr(block_t *parent, basic_block_t **bb)
{
ph1_ir_t *ph1_ir;
var_t *vd;
opcode_t oper_stack[10];
int oper_stack_idx = 0;

/* These variables used for parsing logical-and operation. False branch of
* each logical-and operand points to the same basic block.
*/
bool has_log_and = false;
basic_block_t *else_bb = bb_create(parent);
char land_else_label[MAX_VAR_LEN];
strcpy(land_else_label, gen_label());

read_expr_operand(parent, bb);

opcode_t op = get_operator();
if (op == OP_generic || op == OP_ternary)
return;

oper_stack[oper_stack_idx++] = op;
if (op == OP_log_and) {
bb_connect(*bb, else_bb, ELSE);
read_log_and_operation(parent, bb, land_else_label);
has_log_and = true;
} else
oper_stack[oper_stack_idx++] = op;
read_expr_operand(parent, bb);
op = get_operator();

Expand All @@ -1011,8 +1031,25 @@ void read_expr(block_t *parent, basic_block_t **bb)
same = 1;
} while (oper_stack_idx > 0 && same == 0);
}
if (op == OP_log_and) {
bb_connect(*bb, else_bb, ELSE);
read_log_and_operation(parent, bb, land_else_label);
has_log_and = true;
}
/* When encountering an operator with lower priority, conclude the
* current logical-and and create a new "else" basic block for next
* logical-and operator.
*/
if (has_log_and &&
get_operator_prio(op) < get_operator_prio(OP_log_and)) {
finalize_log_and(parent, bb, land_else_label, else_bb);
else_bb = bb_create(parent);
strcpy(land_else_label, gen_label());
has_log_and = false;
}
read_expr_operand(parent, bb);
oper_stack[oper_stack_idx++] = op;
if (op != OP_log_and)
oper_stack[oper_stack_idx++] = op;
op = get_operator();
}

Expand All @@ -1027,6 +1064,9 @@ void read_expr(block_t *parent, basic_block_t **bb)
add_insn(parent, *bb, ph1_ir->op, ph1_ir->dest, ph1_ir->src0,
ph1_ir->src1, 0, NULL);
}
if (has_log_and) {
finalize_log_and(parent, bb, land_else_label, else_bb);
}
}

/* Return the address that an expression points to, or evaluate its value.
Expand Down Expand Up @@ -1343,6 +1383,127 @@ void read_lvalue(lvalue_t *lvalue,
}
}

void read_log_and_operation(block_t *parent,
basic_block_t **bb,
char *label_else)
{
char label_true[MAX_VAR_LEN];
var_t *vd;
ph1_ir_t *ph1_ir;
strcpy(label_true, gen_label());

/* test the operand before the logical-and operator */
ph1_ir = add_ph1_ir(OP_branch);
ph1_ir->dest = opstack_pop();
vd = require_var(parent);
strcpy(vd->var_name, label_true);
ph1_ir->src0 = vd;
vd = require_var(parent);
strcpy(vd->var_name, label_else);
ph1_ir->src1 = vd;
add_insn(parent, *bb, OP_branch, NULL, ph1_ir->dest, NULL, 0, NULL);

/* true branch label */
ph1_ir = add_ph1_ir(OP_label);
vd = require_var(parent);
strcpy(vd->var_name, label_true);
ph1_ir->src0 = vd;

basic_block_t *then_ = bb_create(parent);
bb_connect(*bb, then_, THEN);

bb[0] = then_;
}

void finalize_log_and(block_t *parent,
basic_block_t **bb,
char *label_else,
basic_block_t *else_bb)
{
basic_block_t *then_next_ = bb_create(parent);
basic_block_t *end_ = bb_create(parent);
bb_connect(*bb, then_next_, THEN);
bb_connect(*bb, else_bb, ELSE);
bb_connect(then_next_, end_, NEXT);
bb_connect(else_bb, end_, NEXT);
char label_and_true[MAX_VAR_LEN], label_end[MAX_VAR_LEN];
strcpy(label_and_true, gen_label());
strcpy(label_end, gen_label());
var_t *and_res;

/* create branch instruction for final logical-and operand */
ph1_ir_t *ph1_ir = add_ph1_ir(OP_branch);
var_t *vd = opstack_pop();
ph1_ir->dest = vd;
vd = require_var(parent);
strcpy(vd->var_name, label_and_true);
ph1_ir->src0 = vd;
vd = require_var(parent);
strcpy(vd->var_name, label_else);
ph1_ir->src1 = vd;
add_insn(parent, *bb, OP_branch, NULL, ph1_ir->dest, NULL, 0, NULL);

/* true branch of the logical-and operation */
ph1_ir = add_ph1_ir(OP_label);
vd = require_var(parent);
strcpy(vd->var_name, label_and_true);
ph1_ir->dest = vd;

ph1_ir = add_ph1_ir(OP_load_constant);
vd = require_var(parent);
strcpy(vd->var_name, gen_name());
vd->init_val = 1;
ph1_ir->dest = vd;
add_insn(parent, then_next_, OP_load_constant, ph1_ir->dest, NULL, NULL, 0,
NULL);

ph1_ir = add_ph1_ir(OP_assign);
and_res = require_var(parent);
strcpy(and_res->var_name, gen_name());
ph1_ir->dest = and_res;
ph1_ir->src0 = vd;
add_insn(parent, then_next_, OP_assign, ph1_ir->dest, ph1_ir->src0, NULL, 0,
NULL);

/* end of true branch, jump over the false branch */
ph1_ir = add_ph1_ir(OP_jump);
vd = require_var(parent);
strcpy(vd->var_name, label_end);
ph1_ir->dest = vd;

/* false branch of logical-and operation */
ph1_ir = add_ph1_ir(OP_label);
vd = require_var(parent);
strcpy(vd->var_name, label_else);
ph1_ir->src0 = vd;

ph1_ir = add_ph1_ir(OP_load_constant);
vd = require_var(parent);
strcpy(vd->var_name, gen_name());
vd->init_val = 0;
ph1_ir->dest = vd;
add_insn(parent, else_bb, OP_load_constant, ph1_ir->dest, NULL, NULL, 0,
NULL);

/* final basic block to retrieve the value from one of previous basic block
*/
ph1_ir = add_ph1_ir(OP_assign);
ph1_ir->dest = and_res;
ph1_ir->src0 = vd;
add_insn(parent, else_bb, OP_assign, ph1_ir->dest, ph1_ir->src0, NULL, 0,
NULL);

ph1_ir = add_ph1_ir(OP_label);
vd = require_var(parent);
strcpy(vd->var_name, label_end);
ph1_ir->src0 = vd;

and_res->is_log_and_ret = true;
opstack_push(and_res);

bb[0] = end_;
}

void read_ternary_operation(block_t *parent, basic_block_t **bb)
{
char true_label[MAX_VAR_LEN], false_label[MAX_VAR_LEN];
Expand Down Expand Up @@ -2074,6 +2235,8 @@ basic_block_t *read_body_statement(block_t *parent, basic_block_t *bb)
strcpy(var_break->var_name, label_end);
break_exit[break_exit_idx++] = var_break;

basic_block_t *cond = bb_create(parent);
cond = bb;
lex_expect(T_open_bracket);
read_expr(parent, &bb);
lex_expect(T_close_bracket);
Expand Down Expand Up @@ -2118,7 +2281,7 @@ basic_block_t *read_body_statement(block_t *parent, basic_block_t *bb)

/* return, break, continue */
if (body_)
bb_connect(body_, bb, NEXT);
bb_connect(body_, cond, NEXT);

return else_;
}
Expand Down Expand Up @@ -2365,9 +2528,9 @@ basic_block_t *read_body_statement(block_t *parent, basic_block_t *bb)

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

/* condition - check before the loop */
ph1_ir = add_ph1_ir(OP_label);
Expand All @@ -2388,6 +2551,7 @@ basic_block_t *read_body_statement(block_t *parent, basic_block_t *bb)
add_insn(blk, cond_, OP_load_constant, ph1_ir->dest, NULL, NULL, 0,
NULL);
}
bb_connect(cond_, for_end, ELSE);

ph1_ir = add_ph1_ir(OP_branch);
ph1_ir->dest = opstack_pop();
Expand Down Expand Up @@ -2443,7 +2607,7 @@ basic_block_t *read_body_statement(block_t *parent, basic_block_t *bb)

if (body_) {
bb_connect(body_, inc_, NEXT);
bb_connect(inc_, cond_, NEXT);
bb_connect(inc_, cond_start, NEXT);
} else {
/* TODO: Release dangling inc basic block */
}
Expand Down
9 changes: 0 additions & 9 deletions src/riscv-codegen.c
Original file line number Diff line number Diff line change
Expand Up @@ -412,15 +412,6 @@ void emit_ph2_ir(ph2_ir_t *ph2_ir)
emit(__sltu(rd, __zero, rs1));
emit(__xori(rd, rd, 1));
return;
case OP_log_and:
/* TODO: short-circuit evaluation */
emit(__xor(__t0, rs1, rs2));
emit(__sub(rd, __t0, rs1));
emit(__sub(__t0, __t0, rs2));
emit(__sltu(rd, __zero, rd));
emit(__sltu(__t0, __zero, __t0));
emit(__and(rd, rd, __t0));
return;
case OP_log_or:
emit(__or(rd, rs1, rs2));
emit(__sltu(rd, __zero, rd));
Expand Down
14 changes: 9 additions & 5 deletions src/ssa.c
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,7 @@ bool insert_phi_insn(basic_block_t *bb, var_t *var)
bb->insn_list.head = n;
bb->insn_list.tail = n;
} else {
head->prev = n;
n->next = head;
bb->insn_list.head = n;
}
Expand Down Expand Up @@ -455,13 +456,14 @@ void solve_phi_insertion()
if (insert_phi_insn(df, var)) {
bool found = false;

/* Restrict phi insertion of ternary operation.
/* Restrict phi insertion of ternary operation and
* logical-and operation.
*
* The ternary operation doesn't create new scope, so
* prevent temporary variable from propagating through
* the dominance tree.
* The ternary and logical-and operation doesn't create
* new scope, so prevent temporary variable from
* propagating through the dominance tree.
*/
if (var->is_ternary_ret)
if (var->is_ternary_ret || var->is_log_and_ret)
continue;

for (int l = 0; l < work_list_idx; l++)
Expand Down Expand Up @@ -665,6 +667,8 @@ void bb_unwind_phi(fn_t *fn, basic_block_t *bb)
bb->insn_list.head = insn;
if (!insn)
bb->insn_list.tail = NULL;
else
insn->prev = NULL;
}

void unwind_phi()
Expand Down
Loading

0 comments on commit 7e49741

Please sign in to comment.