SSA Phi Node Support

This commit is contained in:
Ginger Bill
2016-10-08 22:03:40 +01:00
parent b705fa7f22
commit e299c3693e
4 changed files with 260 additions and 143 deletions

View File

@@ -1,6 +1,6 @@
#import "fmt.odin"
main :: proc() {
x := ?123
fmt.println(123)
}

View File

@@ -69,7 +69,6 @@ String ssa_mangle_name(ssaGen *s, String path, String name) {
void ssa_gen_tree(ssaGen *s) {
ssaModule *m = &s->module;
CheckerInfo *info = m->info;
gbAllocator a = m->allocator;
@@ -677,12 +676,7 @@ void ssa_gen_tree(ssaGen *s) {
ssa_build_proc(m->procs[i], m->procs[i]->Proc.parent);
}
// m->layout = make_string("e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64");
}

View File

@@ -500,8 +500,12 @@ void ssa_print_exact_value(ssaFileBuffer *f, ssaModule *m, ExactValue value, Typ
}
void ssa_print_block_name(ssaFileBuffer *f, ssaBlock *b) {
ssa_print_escape_string(f, b->label, false);
ssa_fprintf(f, "-%d", b->id);
if (b != NULL) {
ssa_print_escape_string(f, b->label, false);
ssa_fprintf(f, "-%td", b->index);
} else {
ssa_fprintf(f, "<INVALID-BLOCK>");
}
}
void ssa_print_value(ssaFileBuffer *f, ssaModule *m, ssaValue *value, Type *type_hint) {
@@ -648,6 +652,32 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) {
ssa_fprintf(f, "\n");
} break;
case ssaInstr_Phi: {
ssa_fprintf(f, "%%%d = phi ", value->id);
ssa_print_type(f, m, instr->Phi.type);
ssa_fprintf(f, " ", value->id);
for (isize i = 0; i < instr->Phi.edges.count; i++) {
ssaValue *edge = instr->Phi.edges[i];
if (i > 0) {
ssa_fprintf(f, ", ");
}
ssaBlock *block = NULL;
if (instr->parent != NULL &&
i < instr->parent->preds.count) {
block = instr->parent->preds[i];
}
ssa_fprintf(f, "[ ");
ssa_print_value(f, m, edge, instr->Phi.type);
ssa_fprintf(f, ", %%");
ssa_print_block_name(f, block);
ssa_fprintf(f, " ]");
}
ssa_fprintf(f, "\n");
} break;
case ssaInstr_ExtractValue: {
Type *et = instr->ExtractValue.elem_type;
ssa_fprintf(f, "%%%d = extractvalue ", value->id);
@@ -721,12 +751,12 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) {
ssa_fprintf(f, "%%%d = ", value->id);
if (gb_is_between(bo->op.kind, Token__ComparisonBegin+1, Token__ComparisonEnd-1)) {
if (gb_is_between(bo->op, Token__ComparisonBegin+1, Token__ComparisonEnd-1)) {
if (is_type_string(elem_type)) {
ssa_fprintf(f, "call ");
ssa_print_type(f, m, t_bool);
char *runtime_proc = "";
switch (bo->op.kind) {
switch (bo->op) {
case Token_CmpEq: runtime_proc = "__string_eq"; break;
case Token_NotEq: runtime_proc = "__string_ne"; break;
case Token_Lt: runtime_proc = "__string_lt"; break;
@@ -750,7 +780,7 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) {
} else if (is_type_float(elem_type)) {
ssa_fprintf(f, "fcmp ");
switch (bo->op.kind) {
switch (bo->op) {
case Token_CmpEq: ssa_fprintf(f, "oeq"); break;
case Token_NotEq: ssa_fprintf(f, "one"); break;
case Token_Lt: ssa_fprintf(f, "olt"); break;
@@ -760,15 +790,15 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) {
}
} else {
ssa_fprintf(f, "icmp ");
if (bo->op.kind != Token_CmpEq &&
bo->op.kind != Token_NotEq) {
if (bo->op != Token_CmpEq &&
bo->op != Token_NotEq) {
if (is_type_unsigned(elem_type)) {
ssa_fprintf(f, "u");
} else {
ssa_fprintf(f, "s");
}
}
switch (bo->op.kind) {
switch (bo->op) {
case Token_CmpEq: ssa_fprintf(f, "eq"); break;
case Token_NotEq: ssa_fprintf(f, "ne"); break;
case Token_Lt: ssa_fprintf(f, "lt"); break;
@@ -781,7 +811,7 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) {
if (is_type_float(elem_type))
ssa_fprintf(f, "f");
switch (bo->op.kind) {
switch (bo->op) {
case Token_Add: ssa_fprintf(f, "add"); break;
case Token_Sub: ssa_fprintf(f, "sub"); break;
case Token_And: ssa_fprintf(f, "and"); break;
@@ -800,7 +830,7 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) {
else ssa_fprintf(f, "s");
}
switch (bo->op.kind) {
switch (bo->op) {
case Token_Quo: ssa_fprintf(f, "div"); break;
case Token_Mod: ssa_fprintf(f, "rem"); break;
}

View File

@@ -69,7 +69,7 @@ struct ssaModule {
struct ssaBlock {
i32 id;
isize index;
AstNode *node;
Scope *scope;
isize scope_index;
@@ -266,12 +266,12 @@ struct ssaInstr {
ssaValue *false_value;
} Select;
struct {
String comment;
Array<ssaValue *> edges;
Type *type;
} Phi;
struct {
Type *type;
Token op;
TokenKind op;
ssaValue *left, *right;
} BinaryOp;
struct {
@@ -513,6 +513,8 @@ Type *ssa_type(ssaInstr *instr) {
return instr->Load.type;
case ssaInstr_GetElementPtr:
return instr->GetElementPtr.result_type;
case ssaInstr_Phi:
return instr->Phi.type;
case ssaInstr_ExtractValue:
return instr->ExtractValue.result_type;
case ssaInstr_InsertValue:
@@ -742,7 +744,7 @@ ssaValue *ssa_make_instr_insert_value(ssaProcedure *p, ssaValue *value, ssaValue
}
ssaValue *ssa_make_instr_binary_op(ssaProcedure *p, Token op, ssaValue *left, ssaValue *right, Type *type) {
ssaValue *ssa_make_instr_binary_op(ssaProcedure *p, TokenKind op, ssaValue *left, ssaValue *right, Type *type) {
ssaValue *v = ssa_alloc_instr(p, ssaInstr_BinaryOp);
ssaInstr *i = &v->Instr;
i->BinaryOp.op = op;
@@ -761,6 +763,14 @@ ssaValue *ssa_make_instr_br(ssaProcedure *p, ssaValue *cond, ssaBlock *true_bloc
return v;
}
ssaValue *ssa_make_instr_phi(ssaProcedure *p, Array<ssaValue *> edges, Type *type) {
ssaValue *v = ssa_alloc_instr(p, ssaInstr_Phi);
ssaInstr *i = &v->Instr;
i->Phi.edges = edges;
i->Phi.type = type;
return v;
}
ssaValue *ssa_make_instr_unreachable(ssaProcedure *p) {
ssaValue *v = ssa_alloc_instr(p, ssaInstr_Unreachable);
return v;
@@ -1065,7 +1075,7 @@ Type *ssa_addr_type(ssaAddr lval) {
return NULL;
}
ssaBlock *ssa__make_block(ssaProcedure *proc, AstNode *node, String label) {
ssaBlock *ssa_add_block(ssaProcedure *proc, AstNode *node, char *label) {
Scope *scope = NULL;
if (node != NULL) {
Scope **found = map_get(&proc->module->info->scopes, hash_pointer(node));
@@ -1076,12 +1086,8 @@ ssaBlock *ssa__make_block(ssaProcedure *proc, AstNode *node, String label) {
}
}
ssaValue *block = ssa_make_value_block(proc, node, scope, label);
return &block->Block;
}
ssaBlock *ssa_add_block(ssaProcedure *proc, AstNode *node, String label) {
ssaBlock *block = ssa__make_block(proc, node, label);
ssaValue *value = ssa_make_value_block(proc, node, scope, make_string(label));
ssaBlock *block = &value->Block;
array_add(&proc->blocks, block);
return block;
}
@@ -1091,13 +1097,12 @@ void ssa_emit_no_op(ssaProcedure *proc);
void ssa_emit_jump(ssaProcedure *proc, ssaBlock *block);
void ssa_build_defer_stmt(ssaProcedure *proc, ssaDefer d) {
ssaBlock *b = ssa__make_block(proc, NULL, make_string("defer"));
ssaBlock *b = ssa_add_block(proc, NULL, "defer");
// NOTE(bill): The prev block may defer injection before it's terminator
ssaInstr *last_instr = ssa_get_last_instr(proc->curr_block);
if (last_instr == NULL || !ssa_is_instr_terminating(last_instr)) {
ssa_emit_jump(proc, b);
}
array_add(&proc->blocks, b);
proc->curr_block = b;
ssa_emit_comment(proc, make_string("defer"));
if (d.kind == ssaDefer_Node) {
@@ -1228,8 +1233,8 @@ void ssa_begin_procedure_body(ssaProcedure *proc) {
array_init(&proc->defer_stmts, gb_heap_allocator());
array_init(&proc->children, gb_heap_allocator());
proc->decl_block = ssa_add_block(proc, proc->type_expr, make_string("decls"));
proc->entry_block = ssa_add_block(proc, proc->type_expr, make_string("entry"));
proc->decl_block = ssa_add_block(proc, proc->type_expr, "decls");
proc->entry_block = ssa_add_block(proc, proc->type_expr, "entry");
proc->curr_block = proc->entry_block;
if (proc->type->Proc.params != NULL) {
@@ -1241,6 +1246,92 @@ void ssa_begin_procedure_body(ssaProcedure *proc) {
}
}
void ssa_remove_pred(ssaBlock *a, ssaBlock *b) {
}
void ssa_remove_dead_blocks(ssaProcedure *proc) {
isize j = 0;
for_array(i, proc->blocks) {
ssaBlock *b = proc->blocks[i];
if (b != NULL) {
// NOTE(bill): Swap order
b->index = j;
proc->blocks[j] = b;
j++;
}
}
proc->blocks.count = j;
}
void ssa_mark_reachable(ssaBlock *b) {
isize const WHITE = 0;
isize const BLACK = -1;
b->index = BLACK;
for_array(i, b->succs) {
ssaBlock *succ = b->succs[i];
if (succ->index == WHITE) {
ssa_mark_reachable(succ);
}
}
}
void ssa_remove_unreachable_blocks(ssaProcedure *proc) {
isize const WHITE = 0;
isize const BLACK = -1;
for_array(i, proc->blocks) {
proc->blocks[i]->index = WHITE;
}
ssa_mark_reachable(proc->blocks[0]);
for_array(i, proc->blocks) {
ssaBlock *b = proc->blocks[i];
if (b->index == WHITE) {
for_array(j, b->succs) {
ssaBlock *c = b->succs[j];
if (c->index == BLACK) {
// ssa_remove_pred(c, b);
}
}
// NOTE(bill): Mark as empty but don't actually free it
// As it's been allocated with an arena
proc->blocks[i] = NULL;
}
}
ssa_remove_dead_blocks(proc);
}
void ssa_optimize_blocks(ssaProcedure *proc) {
ssa_remove_unreachable_blocks(proc);
#if 0
b32 changed = false;
do {
for_array(i, proc->blocks) {
ssaBlock *b = proc->blocks[i];
if (b == NULL) {
continue;
}
// if (ssa_fuse_blocks(proc, b)) {
// changed = true;
// }
if (ssa_jump_threading(proc, b)) {
// x -> y -> z becomes x -> z if y is just a jump
changed = true;
continue;
}
}
} while (changed);
#endif
ssa_remove_dead_blocks(proc);
}
void ssa_end_procedure_body(ssaProcedure *proc) {
if (proc->type->Proc.result_count == 0) {
ssa_emit_ret(proc, NULL);
@@ -1253,12 +1344,13 @@ void ssa_end_procedure_body(ssaProcedure *proc) {
proc->curr_block = proc->decl_block;
ssa_emit_jump(proc, proc->entry_block);
ssa_optimize_blocks(proc);
// Number blocks and registers
i32 reg_id = 0;
for_array(i, proc->blocks) {
ssaBlock *b = proc->blocks[i];
b->id = i;
for_array(j, b->instrs) {
ssaValue *value = b->instrs[j];
GB_ASSERT(value->kind == ssaValue_Instr);
@@ -1300,17 +1392,17 @@ void ssa_pop_target_list(ssaProcedure *proc) {
ssaValue *ssa_emit_arith(ssaProcedure *proc, Token op, ssaValue *left, ssaValue *right, Type *type) {
switch (op.kind) {
ssaValue *ssa_emit_arith(ssaProcedure *proc, TokenKind op, ssaValue *left, ssaValue *right, Type *type) {
switch (op) {
case Token_AndNot: {
// NOTE(bill): x &~ y == x & (~y) == x & (y ~ -1)
// NOTE(bill): "not" `x` == `x` "xor" `-1`
ssaValue *neg = ssa_add_module_constant(proc->module, type, make_exact_value_integer(-1));
op.kind = Token_Xor;
op = Token_Xor;
right = ssa_emit_arith(proc, op, right, neg, type);
GB_ASSERT(right->Instr.kind == ssaInstr_BinaryOp);
right->Instr.BinaryOp.type = type;
op.kind = Token_And;
op = Token_And;
} /* fallthrough */
case Token_Add:
case Token_Sub:
@@ -1328,7 +1420,7 @@ ssaValue *ssa_emit_arith(ssaProcedure *proc, Token op, ssaValue *left, ssaValue
return ssa_emit(proc, ssa_make_instr_binary_op(proc, op, left, right, type));
}
ssaValue *ssa_emit_comp(ssaProcedure *proc, Token op, ssaValue *left, ssaValue *right) {
ssaValue *ssa_emit_comp(ssaProcedure *proc, TokenKind op_kind, ssaValue *left, ssaValue *right) {
Type *a = base_type(ssa_type(left));
Type *b = base_type(ssa_type(right));
@@ -1344,7 +1436,7 @@ ssaValue *ssa_emit_comp(ssaProcedure *proc, Token op, ssaValue *left, ssaValue *
if (is_type_vector(a)) {
result = make_type_vector(proc->module->allocator, t_bool, a->Vector.count);
}
return ssa_emit(proc, ssa_make_instr_binary_op(proc, op, left, right, result));
return ssa_emit(proc, ssa_make_instr_binary_op(proc, op_kind, left, right, result));
}
ssaValue *ssa_emit_ptr_offset(ssaProcedure *proc, ssaValue *ptr, ssaValue *offset) {
@@ -1601,9 +1693,8 @@ ssaValue *ssa_add_local_slice(ssaProcedure *proc, Type *slice_type, ssaValue *ba
}
GB_ASSERT(max != NULL);
Token op_sub = {Token_Sub};
ssaValue *len = ssa_emit_arith(proc, op_sub, high, low, t_int);
ssaValue *cap = ssa_emit_arith(proc, op_sub, max, low, t_int);
ssaValue *len = ssa_emit_arith(proc, Token_Sub, high, low, t_int);
ssaValue *cap = ssa_emit_arith(proc, Token_Sub, max, low, t_int);
ssaValue *elem = NULL;
switch (bt->kind) {
@@ -1779,8 +1870,7 @@ ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *t, b32 is_arg
// integer -> boolean
if (is_type_integer(src) && is_type_boolean(dst)) {
Token op = {Token_NotEq};
return ssa_emit_comp(proc, op, value, v_zero);
return ssa_emit_comp(proc, Token_NotEq, value, v_zero);
}
@@ -2013,9 +2103,10 @@ void ssa_build_cond(ssaProcedure *proc, AstNode *cond, ssaBlock *true_block, ssa
ssaValue *ssa_emit_logical_binary_expr(ssaProcedure *proc, AstNode *expr) {
ast_node(be, BinaryExpr, expr);
ssaBlock *true_ = ssa_add_block(proc, NULL, make_string("logical.cmp.true"));
ssaBlock *false_ = ssa_add_block(proc, NULL, make_string("logical.cmp.false"));
ssaBlock *done = ssa__make_block(proc, NULL, make_string("logical.cmp.done"));
#if 0
ssaBlock *true_ = ssa_add_block(proc, NULL, "logical.cmp.true");
ssaBlock *false_ = ssa_add_block(proc, NULL, "logical.cmp.false");
ssaBlock *done = ssa_add_block(proc, NULL, "logical.cmp.done");
ssaValue *result = ssa_add_local_generated(proc, t_bool);
ssa_build_cond(proc, expr, true_, false_);
@@ -2028,10 +2119,48 @@ ssaValue *ssa_emit_logical_binary_expr(ssaProcedure *proc, AstNode *expr) {
ssa_emit_store(proc, result, v_false);
ssa_emit_jump(proc, done);
array_add(&proc->blocks, done);
proc->curr_block = done;
return ssa_emit_load(proc, result);
#else
ssaBlock *rhs = ssa_add_block(proc, NULL, "logical.cmp.rhs");
ssaBlock *done = ssa_add_block(proc, NULL, "logical.cmp.done");
Type *type = type_of_expr(proc->module->info, expr);
type = default_type(type);
ssaValue *short_circuit = NULL;
if (be->op.kind == Token_CmpAnd) {
ssa_build_cond(proc, be->left, rhs, done);
short_circuit = v_false;
} else if (be->op.kind == Token_CmpOr) {
ssa_build_cond(proc, be->left, done, rhs);
short_circuit = v_true;
}
if (rhs->preds.count == 0) {
proc->curr_block = done;
return short_circuit;
}
if (done->preds.count == 0) {
proc->curr_block = rhs;
return ssa_build_expr(proc, be->right);
}
Array<ssaValue *> edges = {};
array_init(&edges, proc->module->allocator, done->preds.count+1);
for_array(i, done->preds) {
array_add(&edges, short_circuit);
}
proc->curr_block = rhs;
array_add(&edges, ssa_build_expr(proc, be->right));
ssa_emit_jump(proc, done);
proc->curr_block = done;
return ssa_emit(proc, ssa_make_instr_phi(proc, edges, type));
#endif
}
@@ -2125,14 +2254,14 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
return ssa_build_expr(proc, ue->expr);
case Token_Sub: // NOTE(bill): -`x` == 0 - `x`
return ssa_emit_arith(proc, ue->op, v_zero, ssa_build_expr(proc, ue->expr), tv->type);
return ssa_emit_arith(proc, ue->op.kind, v_zero, ssa_build_expr(proc, ue->expr), tv->type);
case Token_Not: // Boolean not
case Token_Xor: { // Bitwise not
// NOTE(bill): "not" `x` == `x` "xor" `-1`
ssaValue *left = ssa_build_expr(proc, ue->expr);
ssaValue *right = ssa_add_module_constant(proc->module, tv->type, make_exact_value_integer(-1));
return ssa_emit_arith(proc, ue->op,
return ssa_emit_arith(proc, ue->op.kind,
left, right,
tv->type);
} break;
@@ -2152,7 +2281,7 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
case Token_AndNot:
case Token_Shl:
case Token_Shr:
return ssa_emit_arith(proc, be->op,
return ssa_emit_arith(proc, be->op.kind,
ssa_build_expr(proc, be->left),
ssa_build_expr(proc, be->right),
tv->type);
@@ -2167,7 +2296,7 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
ssaValue *left = ssa_build_expr(proc, be->left);
ssaValue *right = ssa_build_expr(proc, be->right);
ssaValue *cmp = ssa_emit_comp(proc, be->op, left, right);
ssaValue *cmp = ssa_emit_comp(proc, be->op.kind, left, right);
return ssa_emit_conv(proc, cmp, default_type(tv->type));
} break;
@@ -2420,8 +2549,7 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
ssa_slice_bounds_check(proc, ast_node_token(ce->args[1]), v_zero, len, cap, false);
Token mul = {Token_Mul};
ssaValue *slice_size = ssa_emit_arith(proc, mul, elem_size, cap, t_int);
ssaValue *slice_size = ssa_emit_arith(proc, Token_Mul, elem_size, cap, t_int);
ssaValue **args = gb_alloc_array(allocator, ssaValue *, 2);
args[0] = slice_size;
@@ -2445,10 +2573,9 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
ssaValue *cond = ssa_build_expr(proc, ce->args[0]);
GB_ASSERT(is_type_boolean(ssa_type(cond)));
Token eq = {Token_CmpEq};
cond = ssa_emit_comp(proc, eq, cond, v_false);
ssaBlock *err = ssa_add_block(proc, NULL, make_string("builtin.assert.err"));
ssaBlock *done = ssa__make_block(proc, NULL, make_string("builtin.assert.done"));
cond = ssa_emit_comp(proc, Token_CmpEq, cond, v_false);
ssaBlock *err = ssa_add_block(proc, NULL, "builtin.assert.err");
ssaBlock *done = ssa_add_block(proc, NULL, "builtin.assert.done");
ssa_emit_if(proc, cond, err, done);
proc->curr_block = err;
@@ -2471,7 +2598,6 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
ssa_emit_global_call(proc, "__assert", args, 4);
ssa_emit_jump(proc, done);
array_add(&proc->blocks, done);
proc->curr_block = done;
return NULL;
@@ -2515,12 +2641,11 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
ssaValue *len_dst = ssa_slice_len(proc, dst_slice);
ssaValue *len_src = ssa_slice_len(proc, src_slice);
Token lt = {Token_Lt};
ssaValue *cond = ssa_emit_comp(proc, lt, len_dst, len_src);
ssaValue *cond = ssa_emit_comp(proc, Token_Lt, len_dst, len_src);
ssaValue *len = ssa_emit_select(proc, cond, len_dst, len_src);
Token mul = {Token_Mul};
ssaValue *elem_size = ssa_make_const_int(proc->module->allocator, size_of_elem);
ssaValue *byte_count = ssa_emit_arith(proc, mul, len, elem_size, t_int);
ssaValue *byte_count = ssa_emit_arith(proc, Token_Mul, len, elem_size, t_int);
ssaValue **args = gb_alloc_array(proc->module->allocator, ssaValue *, 3);
args[0] = dst;
@@ -2553,10 +2678,9 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
// NOTE(bill): Check if can append is possible
Token lt = {Token_Lt};
ssaValue *cond = ssa_emit_comp(proc, lt, len, cap);
ssaBlock *able = ssa_add_block(proc, NULL, make_string("builtin.append.able"));
ssaBlock *done = ssa__make_block(proc, NULL, make_string("builtin.append.done"));
ssaValue *cond = ssa_emit_comp(proc, Token_Lt, len, cap);
ssaBlock *able = ssa_add_block(proc, NULL, "builtin.append.able");
ssaBlock *done = ssa_add_block(proc, NULL, "builtin.append.done");
ssa_emit_if(proc, cond, able, done);
proc->curr_block = able;
@@ -2579,13 +2703,11 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
ssa_emit_global_call(proc, "__mem_copy", args, 3);
// Increment slice length
Token add = {Token_Add};
ssaValue *new_len = ssa_emit_arith(proc, add, len, v_one, t_int);
ssaValue *new_len = ssa_emit_arith(proc, Token_Add, len, v_one, t_int);
ssaValue *gep = ssa_emit_struct_gep(proc, slice_ptr, v_one32, t_int);
ssa_emit_store(proc, gep, new_len);
ssa_emit_jump(proc, done);
array_add(&proc->blocks, done);
proc->curr_block = done;
return ssa_emit_conv(proc, cond, t_bool, true);
@@ -2627,12 +2749,11 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
Type *ptr_type = base_type(ssa_type(ptr_a));
GB_ASSERT(ptr_type->kind == Type_Pointer);
isize elem_size = type_size_of(proc->module->sizes, proc->module->allocator, ptr_type->Pointer.elem);
Token sub = {Token_Sub};
ssaValue *v = ssa_emit_arith(proc, sub, ptr_a, ptr_b, t_int);
ssaValue *v = ssa_emit_arith(proc, Token_Sub, ptr_a, ptr_b, t_int);
if (elem_size > 1) {
Token quo = {Token_Quo};
ssaValue *ez = ssa_make_const_int(proc->module->allocator, elem_size);
v = ssa_emit_arith(proc, quo, v, ez, t_int);
v = ssa_emit_arith(proc, Token_Quo, v, ez, t_int);
}
return v;
@@ -2665,8 +2786,7 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
ssaValue *x = ssa_build_expr(proc, ce->args[0]);
ssaValue *y = ssa_build_expr(proc, ce->args[1]);
Type *t = base_type(ssa_type(x));
Token lt = {Token_Lt};
ssaValue *cond = ssa_emit_comp(proc, lt, x, y);
ssaValue *cond = ssa_emit_comp(proc, Token_Lt, x, y);
return ssa_emit_select(proc, cond, x, y);
} break;
@@ -2675,21 +2795,18 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
ssaValue *x = ssa_build_expr(proc, ce->args[0]);
ssaValue *y = ssa_build_expr(proc, ce->args[1]);
Type *t = base_type(ssa_type(x));
Token gt = {Token_Gt};
ssaValue *cond = ssa_emit_comp(proc, gt, x, y);
ssaValue *cond = ssa_emit_comp(proc, Token_Gt, x, y);
return ssa_emit_select(proc, cond, x, y);
} break;
case BuiltinProc_abs: {
ssa_emit_comment(proc, make_string("abs"));
Token lt = {Token_Lt};
Token sub = {Token_Sub};
ssaValue *x = ssa_build_expr(proc, ce->args[0]);
Type *t = ssa_type(x);
ssaValue *neg_x = ssa_emit_arith(proc, sub, v_zero, x, t);
ssaValue *cond = ssa_emit_comp(proc, lt, x, v_zero);
ssaValue *neg_x = ssa_emit_arith(proc, Token_Sub, v_zero, x, t);
ssaValue *cond = ssa_emit_comp(proc, Token_Lt, x, v_zero);
return ssa_emit_select(proc, cond, neg_x, x);
} break;
@@ -3117,10 +3234,9 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
ssa_slice_bounds_check(proc, se->open, low, high, max, false);
Token op_sub = {Token_Sub};
ssaValue *elem = ssa_slice_elem(proc, base);
ssaValue *len = ssa_emit_arith(proc, op_sub, high, low, t_int);
ssaValue *cap = ssa_emit_arith(proc, op_sub, max, low, t_int);
ssaValue *len = ssa_emit_arith(proc, Token_Sub, high, low, t_int);
ssaValue *cap = ssa_emit_arith(proc, Token_Sub, max, low, t_int);
ssaValue *slice = ssa_add_local_generated(proc, slice_type);
ssaValue *gep0 = ssa_emit_struct_gep(proc, slice, v_zero32, ssa_type(elem));
@@ -3142,10 +3258,9 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
ssa_slice_bounds_check(proc, se->open, low, high, max, false);
Token op_sub = {Token_Sub};
ssaValue *elem = ssa_array_elem(proc, addr);
ssaValue *len = ssa_emit_arith(proc, op_sub, high, low, t_int);
ssaValue *cap = ssa_emit_arith(proc, op_sub, max, low, t_int);
ssaValue *len = ssa_emit_arith(proc, Token_Sub, high, low, t_int);
ssaValue *cap = ssa_emit_arith(proc, Token_Sub, max, low, t_int);
ssaValue *slice = ssa_add_local_generated(proc, slice_type);
ssaValue *gep0 = ssa_emit_struct_gep(proc, slice, v_zero32, ssa_type(elem));
@@ -3166,9 +3281,8 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
ssa_slice_bounds_check(proc, se->open, low, high, high, true);
Token op_sub = {Token_Sub};
ssaValue *elem, *len;
len = ssa_emit_arith(proc, op_sub, high, low, t_int);
len = ssa_emit_arith(proc, Token_Sub, high, low, t_int);
elem = ssa_string_elem(proc, base);
elem = ssa_emit_ptr_offset(proc, elem, low);
@@ -3231,7 +3345,7 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
return ssa_make_addr(NULL, NULL);
}
void ssa_build_assign_op(ssaProcedure *proc, ssaAddr lhs, ssaValue *value, Token op) {
void ssa_build_assign_op(ssaProcedure *proc, ssaAddr lhs, ssaValue *value, TokenKind op) {
ssaValue *old_value = ssa_lvalue_load(proc, lhs);
Type *type = ssa_type(old_value);
ssaValue *change = ssa_emit_conv(proc, value, type);
@@ -3255,13 +3369,13 @@ void ssa_build_cond(ssaProcedure *proc, AstNode *cond, ssaBlock *true_block, ssa
case_ast_node(be, BinaryExpr, cond);
if (be->op.kind == Token_CmpAnd) {
ssaBlock *block = ssa_add_block(proc, NULL, make_string("cmp.and"));
ssaBlock *block = ssa_add_block(proc, NULL, "cmp.and");
ssa_build_cond(proc, be->left, block, false_block);
proc->curr_block = block;
ssa_build_cond(proc, be->right, true_block, false_block);
return;
} else if (be->op.kind == Token_CmpOr) {
ssaBlock *block = ssa_add_block(proc, NULL, make_string("cmp.or"));
ssaBlock *block = ssa_add_block(proc, NULL, "cmp.or");
ssa_build_cond(proc, be->left, true_block, block);
proc->curr_block = block;
ssa_build_cond(proc, be->right, true_block, false_block);
@@ -3497,11 +3611,11 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
case_ast_node(ids, IncDecStmt, node);
ssa_emit_comment(proc, make_string("IncDecStmt"));
Token op = ids->op;
if (op.kind == Token_Increment) {
op.kind = Token_Add;
} else if (op.kind == Token_Decrement) {
op.kind = Token_Sub;
TokenKind op = ids->op.kind;
if (op == Token_Increment) {
op = Token_Add;
} else if (op == Token_Decrement) {
op = Token_Sub;
}
ssaAddr lval = ssa_build_addr(proc, ids->expr);
ssaValue *one = ssa_emit_conv(proc, v_one, ssa_addr_type(lval));
@@ -3577,13 +3691,11 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
default: {
// NOTE(bill): Only 1 += 1 is allowed, no tuples
// +=, -=, etc
Token op = as->op;
i32 kind = op.kind;
kind += Token_Add - Token_AddEq; // Convert += to +
op.kind = cast(TokenKind)kind;
i32 op = cast(i32)as->op.kind;
op += Token_Add - Token_AddEq; // Convert += to +
ssaAddr lhs = ssa_build_addr(proc, as->lhs[0]);
ssaValue *value = ssa_build_expr(proc, as->rhs[0]);
ssa_build_assign_op(proc, lhs, value, op);
ssa_build_assign_op(proc, lhs, value, cast(TokenKind)op);
} break;
}
case_end;
@@ -3658,16 +3770,16 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
case_ast_node(is, IfStmt, node);
ssa_emit_comment(proc, make_string("IfStmt"));
if (is->init != NULL) {
ssaBlock *init = ssa_add_block(proc, node, make_string("if.init"));
ssaBlock *init = ssa_add_block(proc, node, "if.init");
ssa_emit_jump(proc, init);
proc->curr_block = init;
ssa_build_stmt(proc, is->init);
}
ssaBlock *then = ssa_add_block(proc, node, make_string("if.then"));
ssaBlock *done = ssa__make_block(proc, node, make_string("if.done")); // NOTE(bill): Append later
ssaBlock *then = ssa_add_block(proc, node, "if.then");
ssaBlock *done = ssa_add_block(proc, node, "if.done"); // NOTE(bill): Append later
ssaBlock *else_ = done;
if (is->else_stmt != NULL) {
else_ = ssa_add_block(proc, is->else_stmt, make_string("if.else"));
else_ = ssa_add_block(proc, is->else_stmt, "if.else");
}
ssa_build_cond(proc, is->cond, then, else_);
@@ -3688,29 +3800,28 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
ssa_emit_jump(proc, done);
}
array_add(&proc->blocks, done);
proc->curr_block = done;
case_end;
case_ast_node(fs, ForStmt, node);
ssa_emit_comment(proc, make_string("ForStmt"));
if (fs->init != NULL) {
ssaBlock *init = ssa_add_block(proc, node, make_string("for.init"));
ssaBlock *init = ssa_add_block(proc, node, "for.init");
ssa_emit_jump(proc, init);
proc->curr_block = init;
ssa_build_stmt(proc, fs->init);
}
ssaBlock *body = ssa_add_block(proc, node, make_string("for.body"));
ssaBlock *done = ssa__make_block(proc, node, make_string("for.done")); // NOTE(bill): Append later
ssaBlock *body = ssa_add_block(proc, node, "for.body");
ssaBlock *done = ssa_add_block(proc, node, "for.done"); // NOTE(bill): Append later
ssaBlock *loop = body;
if (fs->cond != NULL) {
loop = ssa_add_block(proc, node, make_string("for.loop"));
loop = ssa_add_block(proc, node, "for.loop");
}
ssaBlock *cont = loop;
if (fs->post != NULL) {
cont = ssa_add_block(proc, node, make_string("for.post"));
cont = ssa_add_block(proc, node, "for.post");
}
ssa_emit_jump(proc, loop);
@@ -3736,7 +3847,6 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
}
array_add(&proc->blocks, done);
proc->curr_block = done;
case_end;
@@ -3750,11 +3860,10 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
if (ms->tag != NULL) {
tag = ssa_build_expr(proc, ms->tag);
}
ssaBlock *done = ssa__make_block(proc, node, make_string("match.done")); // NOTE(bill): Append later
ssaBlock *done = ssa_add_block(proc, node, "match.done"); // NOTE(bill): Append later
ast_node(body, BlockStmt, ms->body);
AstNodeArray default_stmts = {};
ssaBlock *default_fall = NULL;
ssaBlock *default_block = NULL;
@@ -3766,28 +3875,24 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
for_array(i, body->stmts) {
AstNode *clause = body->stmts[i];
ssaBlock *body = fall;
b32 append_body = false;
ast_node(cc, CaseClause, clause);
if (body == NULL) {
append_body = true;
if (cc->list.count == 0) {
body = ssa__make_block(proc, clause, make_string("match.dflt.body"));
body = ssa_add_block(proc, clause, "match.dflt.body");
} else {
body = ssa__make_block(proc, clause, make_string("match.case.body"));
body = ssa_add_block(proc, clause, "match.case.body");
}
}
if (append_fall && body == fall) {
append_fall = false;
append_body = true;
}
fall = done;
if (i+1 < case_count) {
append_fall = true;
fall = ssa__make_block(proc, clause, make_string("match.fall.body"));
fall = ssa_add_block(proc, clause, "match.fall.body");
}
if (cc->list.count == 0) {
@@ -3799,19 +3904,14 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
}
ssaBlock *next_cond = NULL;
Token eq = {Token_CmpEq};
for_array(j, cc->list) {
AstNode *expr = cc->list[j];
next_cond = ssa__make_block(proc, clause, make_string("match.case.next"));
next_cond = ssa_add_block(proc, clause, "match.case.next");
ssaValue *cond = ssa_emit_comp(proc, eq, tag, ssa_build_expr(proc, expr));
ssaValue *cond = ssa_emit_comp(proc, Token_CmpEq, tag, ssa_build_expr(proc, expr));
ssa_emit_if(proc, cond, body, next_cond);
array_add(&proc->blocks, next_cond);
proc->curr_block = next_cond;
}
if (append_body) {
array_add(&proc->blocks, body);
}
proc->curr_block = body;
ssa_push_target_list(proc, done, NULL, fall);
@@ -3826,7 +3926,6 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
if (default_block != NULL) {
ssa_emit_jump(proc, default_block);
array_add(&proc->blocks, default_block);
proc->curr_block = default_block;
ssa_push_target_list(proc, done, NULL, default_fall);
@@ -3837,7 +3936,6 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
}
ssa_emit_jump(proc, done);
array_add(&proc->blocks, done);
proc->curr_block = done;
case_end;
@@ -3856,11 +3954,11 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
ssaValue *data = ssa_emit_conv(proc, parent, t_rawptr);
ssaBlock *start_block = ssa_add_block(proc, node, make_string("type-match.case.first"));
ssaBlock *start_block = ssa_add_block(proc, node, "type-match.case.first");
ssa_emit_jump(proc, start_block);
proc->curr_block = start_block;
ssaBlock *done = ssa__make_block(proc, node, make_string("type-match.done")); // NOTE(bill): Append later
ssaBlock *done = ssa_add_block(proc, node, "type-match.done"); // NOTE(bill): Append later
ast_node(body, BlockStmt, ms->body);
@@ -3878,12 +3976,12 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
if (cc->list.count == 0) {
// default case
default_stmts = cc->stmts;
default_block = ssa__make_block(proc, clause, make_string("type-match.dflt.body"));
default_block = ssa_add_block(proc, clause, "type-match.dflt.body");
continue;
}
ssaBlock *body = ssa__make_block(proc, clause, make_string("type-match.case.body"));
ssaBlock *body = ssa_add_block(proc, clause, "type-match.case.body");
Scope *scope = *map_get(&proc->module->info->scopes, hash_pointer(clause));
Entity *tag_var_entity = current_scope_lookup_entity(scope, tag_var_name);
@@ -3907,14 +4005,11 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
}
GB_ASSERT(index != NULL);
ssaBlock *next_cond = ssa__make_block(proc, clause, make_string("type-match.case.next"));
Token eq = {Token_CmpEq};
ssaValue *cond = ssa_emit_comp(proc, eq, tag_index, index);
ssaBlock *next_cond = ssa_add_block(proc, clause, "type-match.case.next");
ssaValue *cond = ssa_emit_comp(proc, Token_CmpEq, tag_index, index);
ssa_emit_if(proc, cond, body, next_cond);
array_add(&proc->blocks, next_cond);
proc->curr_block = next_cond;
array_add(&proc->blocks, body);
proc->curr_block = body;
ssa_push_target_list(proc, done, NULL, NULL);
@@ -3929,7 +4024,6 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
if (default_block != NULL) {
ssa_emit_jump(proc, default_block);
array_add(&proc->blocks, default_block);
proc->curr_block = default_block;
ssa_push_target_list(proc, done, NULL, NULL);
@@ -3940,7 +4034,6 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
}
ssa_emit_jump(proc, done);
array_add(&proc->blocks, done);
proc->curr_block = done;
case_end;