Refactor backend code for assignments; Refactor some statements into separate procedures

This commit is contained in:
gingerBill
2021-05-24 22:09:21 +01:00
parent d35a9e65b6
commit 3f156bcb4b
+190 -254
View File
@@ -4425,7 +4425,7 @@ void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *scope) {
lb_start_block(p, done); lb_start_block(p, done);
} }
void lb_build_inline_range_stmt(lbProcedure *p, AstUnrollRangeStmt *rs, Scope *scope) { void lb_build_unroll_range_stmt(lbProcedure *p, AstUnrollRangeStmt *rs, Scope *scope) {
lbModule *m = p->module; lbModule *m = p->module;
lb_open_scope(p, scope); // Open scope here lb_open_scope(p, scope); // Open scope here
@@ -4943,91 +4943,7 @@ void lb_reset_copy_elision_hint(lbProcedure *p, lbCopyElisionHint prev_hint) {
p->copy_elision_hint = prev_hint; p->copy_elision_hint = prev_hint;
} }
void lb_build_static_variables(lbProcedure *p, AstValueDecl *vd) {
void lb_build_stmt(lbProcedure *p, Ast *node) {
Ast *prev_stmt = p->curr_stmt;
defer (p->curr_stmt = prev_stmt);
p->curr_stmt = node;
if (p->curr_block != nullptr) {
LLVMValueRef last_instr = LLVMGetLastInstruction(p->curr_block->block);
if (lb_is_instr_terminating(last_instr)) {
return;
}
}
LLVMMetadataRef prev_debug_location = nullptr;
if (p->debug_info != nullptr) {
prev_debug_location = LLVMGetCurrentDebugLocation2(p->builder);
LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_ast(p, node));
}
defer (if (prev_debug_location != nullptr) {
LLVMSetCurrentDebugLocation2(p->builder, prev_debug_location);
});
u16 prev_state_flags = p->state_flags;
defer (p->state_flags = prev_state_flags);
if (node->state_flags != 0) {
u16 in = node->state_flags;
u16 out = p->state_flags;
if (in & StateFlag_bounds_check) {
out |= StateFlag_bounds_check;
out &= ~StateFlag_no_bounds_check;
} else if (in & StateFlag_no_bounds_check) {
out |= StateFlag_no_bounds_check;
out &= ~StateFlag_bounds_check;
}
p->state_flags = out;
}
switch (node->kind) {
case_ast_node(bs, EmptyStmt, node);
case_end;
case_ast_node(us, UsingStmt, node);
case_end;
case_ast_node(ws, WhenStmt, node);
lb_build_when_stmt(p, ws);
case_end;
case_ast_node(bs, BlockStmt, node);
lbBlock *done = nullptr;
if (bs->label != nullptr) {
done = lb_create_block(p, "block.done");
lbTargetList *tl = lb_push_target_list(p, bs->label, done, nullptr, nullptr);
tl->is_block = true;
}
lb_open_scope(p, node->scope);
lb_build_stmt_list(p, bs->stmts);
lb_close_scope(p, lbDeferExit_Default, nullptr);
if (done != nullptr) {
lb_emit_jump(p, done);
lb_start_block(p, done);
}
case_end;
case_ast_node(vd, ValueDecl, node);
if (!vd->is_mutable) {
return;
}
bool is_static = false;
if (vd->names.count > 0) {
Entity *e = entity_of_node(vd->names[0]);
if (e->flags & EntityFlag_Static) {
// NOTE(bill): If one of the entities is static, they all are
is_static = true;
}
}
if (is_static) {
for_array(i, vd->names) { for_array(i, vd->names) {
lbValue value = {}; lbValue value = {};
if (vd->values.count > 0) { if (vd->values.count > 0) {
@@ -5089,192 +5005,47 @@ void lb_build_stmt(lbProcedure *p, Ast *node) {
lb_add_entity(p->module, e, global_val); lb_add_entity(p->module, e, global_val);
lb_add_member(p->module, mangled_name, global_val); lb_add_member(p->module, mangled_name, global_val);
} }
}
void lb_build_assignment(lbProcedure *p, Array<lbAddr> &lvals, Slice<Ast *> const &values) {
if (values.count == 0) {
return; return;
} }
auto inits = array_make<lbValue>(permanent_allocator(), 0, lvals.count);
if (vd->values.count == 0) { // declared and zero-initialized for_array(i, values) {
for_array(i, vd->names) { Ast *rhs = values[i];
Ast *name = vd->names[i]; if (is_type_tuple(type_of_expr(rhs))) {
if (!is_blank_ident(name)) {
Entity *e = entity_of_node(name);
lb_add_local(p, e->type, e, true);
}
}
} else if (vd->names.count == vd->values.count) {
auto lvals = array_make<lbAddr>(permanent_allocator(), 0, vd->names.count);
auto inits = array_make<lbValue>(permanent_allocator(), 0, vd->names.count);
for_array(i, vd->names) {
Ast *name = vd->names[i];
lbAddr lval = {};
if (!is_blank_ident(name)) {
Entity *e = entity_of_node(name);
bool zero_init = true;
if (vd->names.count == vd->values.count) {
// Possibly uses copy elision
// Make the caller mem zero
zero_init = true;
}
lval = lb_add_local(p, e->type, e, zero_init);
}
array_add(&lvals, lval);
}
for_array(i, vd->values) {
Ast *rhs = unparen_expr(vd->values[i]);
auto prev_hint = lb_set_copy_elision_hint(p, lvals[i], rhs);
lbValue init = lb_build_expr(p, rhs); lbValue init = lb_build_expr(p, rhs);
Type *t = init.type; Type *t = init.type;
GB_ASSERT(t->kind != Type_Tuple); GB_ASSERT(t->kind == Type_Tuple);
array_add(&inits, init);
if (p->copy_elision_hint.used) {
lvals[i] = {}; // zero lval
}
lb_reset_copy_elision_hint(p, prev_hint);
}
for_array(i, inits) {
lbAddr lval = lvals[i];
lbValue init = inits[i];
lb_addr_store(p, lval, init);
}
} else { // Tuple(s)
auto lvals = array_make<lbAddr>(permanent_allocator(), 0, vd->names.count);
auto inits = array_make<lbValue>(permanent_allocator(), 0, vd->names.count);
for_array(i, vd->names) {
Ast *name = vd->names[i];
lbAddr lval = {};
if (!is_blank_ident(name)) {
Entity *e = entity_of_node(name);
bool zero_init = false;
lval = lb_add_local(p, e->type, e, zero_init);
}
array_add(&lvals, lval);
}
for_array(i, vd->values) {
Ast *rhs = unparen_expr(vd->values[i]);
lbValue init = lb_build_expr(p, rhs);
Type *t = init.type;
if (t->kind == Type_Tuple) {
for_array(i, t->Tuple.variables) { for_array(i, t->Tuple.variables) {
Entity *e = t->Tuple.variables[i]; Entity *e = t->Tuple.variables[i];
lbValue v = lb_emit_struct_ev(p, init, cast(i32)i); lbValue v = lb_emit_struct_ev(p, init, cast(i32)i);
array_add(&inits, v); array_add(&inits, v);
} }
} else { } else {
array_add(&inits, init); auto prev_hint = lb_set_copy_elision_hint(p, lvals[inits.count], rhs);
}
}
for_array(i, inits) {
lbAddr lval = lvals[i];
lbValue init = inits[i];
lb_addr_store(p, lval, init);
}
}
case_end;
case_ast_node(as, AssignStmt, node);
if (as->op.kind == Token_Eq) {
auto lvals = array_make<lbAddr>(permanent_allocator(), 0, as->lhs.count);
for_array(i, as->lhs) {
Ast *lhs = as->lhs[i];
lbAddr lval = {};
if (!is_blank_ident(lhs)) {
lval = lb_build_addr(p, lhs);
}
array_add(&lvals, lval);
}
if (as->lhs.count == as->rhs.count) {
auto inits = array_make<lbValue>(permanent_allocator(), 0, lvals.count);
for_array(i, as->rhs) {
Ast *rhs = unparen_expr(as->rhs[i]);
auto prev_hint = lb_set_copy_elision_hint(p, lvals[i], rhs);
lbValue init = lb_build_expr(p, rhs); lbValue init = lb_build_expr(p, rhs);
array_add(&inits, init);
if (p->copy_elision_hint.used) { if (p->copy_elision_hint.used) {
lvals[i] = {}; // zero lval lvals[inits.count] = {}; // zero lval
} }
lb_reset_copy_elision_hint(p, prev_hint); lb_reset_copy_elision_hint(p, prev_hint);
}
for_array(i, inits) {
lbAddr lval = lvals[i];
lbValue init = inits[i];
lb_addr_store(p, lval, init);
}
} else {
auto inits = array_make<lbValue>(permanent_allocator(), 0, lvals.count);
for_array(i, as->rhs) {
lbValue init = lb_build_expr(p, as->rhs[i]);
Type *t = init.type;
// TODO(bill): refactor for code reuse as this is repeated a bit
if (t->kind == Type_Tuple) {
for_array(i, t->Tuple.variables) {
Entity *e = t->Tuple.variables[i];
lbValue v = lb_emit_struct_ev(p, init, cast(i32)i);
array_add(&inits, v);
}
} else {
array_add(&inits, init); array_add(&inits, init);
} }
} }
GB_ASSERT(lvals.count == inits.count);
for_array(i, inits) { for_array(i, inits) {
lbAddr lval = lvals[i]; lbAddr lval = lvals[i];
lbValue init = inits[i]; lbValue init = inits[i];
lb_addr_store(p, lval, init); lb_addr_store(p, lval, init);
} }
} }
} else {
// NOTE(bill): Only 1 += 1 is allowed, no tuples
// +=, -=, etc
i32 op = cast(i32)as->op.kind;
op += Token_Add - Token_AddEq; // Convert += to +
if (op == Token_CmpAnd || op == Token_CmpOr) {
Type *type = as->lhs[0]->tav.type;
lbValue new_value = lb_emit_logical_binary_expr(p, cast(TokenKind)op, as->lhs[0], as->rhs[0], type);
lbAddr lhs = lb_build_addr(p, as->lhs[0]); void lb_build_return_stmt(lbProcedure *p, AstReturnStmt *rs) {
lb_addr_store(p, lhs, new_value);
} else {
lbAddr lhs = lb_build_addr(p, as->lhs[0]);
lbValue value = lb_build_expr(p, as->rhs[0]);
lbValue old_value = lb_addr_load(p, lhs);
Type *type = old_value.type;
lbValue change = lb_emit_conv(p, value, type);
lbValue new_value = lb_emit_arith(p, cast(TokenKind)op, old_value, change, type);
lb_addr_store(p, lhs, new_value);
}
return;
}
case_end;
case_ast_node(es, ExprStmt, node);
lb_build_expr(p, es->expr);
case_end;
case_ast_node(ds, DeferStmt, node);
isize scope_index = p->scope_index;
lb_add_defer_node(p, scope_index, ds->stmt);
case_end;
case_ast_node(rs, ReturnStmt, node);
lbValue res = {}; lbValue res = {};
TypeTuple *tuple = &p->type->Proc.results->Tuple; TypeTuple *tuple = &p->type->Proc.results->Tuple;
@@ -5388,12 +5159,10 @@ void lb_build_stmt(lbProcedure *p, Ast *node) {
lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr); lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr);
LLVMBuildRet(p->builder, ret_val); LLVMBuildRet(p->builder, ret_val);
} }
}
void lb_build_if_stmt(lbProcedure *p, Ast *node) {
ast_node(is, IfStmt, node);
case_end;
case_ast_node(is, IfStmt, node);
lb_open_scope(p, node->scope); // Scope #1 lb_open_scope(p, node->scope); // Scope #1
if (is->init != nullptr) { if (is->init != nullptr) {
@@ -5434,12 +5203,13 @@ void lb_build_stmt(lbProcedure *p, Ast *node) {
lb_emit_jump(p, done); lb_emit_jump(p, done);
} }
lb_start_block(p, done); lb_start_block(p, done);
lb_close_scope(p, lbDeferExit_Default, nullptr); lb_close_scope(p, lbDeferExit_Default, nullptr);
case_end; }
void lb_build_for_stmt(lbProcedure *p, Ast *node) {
ast_node(fs, ForStmt, node);
case_ast_node(fs, ForStmt, node);
lb_open_scope(p, node->scope); // Open Scope here lb_open_scope(p, node->scope); // Open Scope here
if (fs->init != nullptr) { if (fs->init != nullptr) {
@@ -5486,6 +5256,172 @@ void lb_build_stmt(lbProcedure *p, Ast *node) {
} }
lb_start_block(p, done); lb_start_block(p, done);
}
void lb_build_stmt(lbProcedure *p, Ast *node) {
Ast *prev_stmt = p->curr_stmt;
defer (p->curr_stmt = prev_stmt);
p->curr_stmt = node;
if (p->curr_block != nullptr) {
LLVMValueRef last_instr = LLVMGetLastInstruction(p->curr_block->block);
if (lb_is_instr_terminating(last_instr)) {
return;
}
}
LLVMMetadataRef prev_debug_location = nullptr;
if (p->debug_info != nullptr) {
prev_debug_location = LLVMGetCurrentDebugLocation2(p->builder);
LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_ast(p, node));
}
defer (if (prev_debug_location != nullptr) {
LLVMSetCurrentDebugLocation2(p->builder, prev_debug_location);
});
u16 prev_state_flags = p->state_flags;
defer (p->state_flags = prev_state_flags);
if (node->state_flags != 0) {
u16 in = node->state_flags;
u16 out = p->state_flags;
if (in & StateFlag_bounds_check) {
out |= StateFlag_bounds_check;
out &= ~StateFlag_no_bounds_check;
} else if (in & StateFlag_no_bounds_check) {
out |= StateFlag_no_bounds_check;
out &= ~StateFlag_bounds_check;
}
p->state_flags = out;
}
switch (node->kind) {
case_ast_node(bs, EmptyStmt, node);
case_end;
case_ast_node(us, UsingStmt, node);
case_end;
case_ast_node(ws, WhenStmt, node);
lb_build_when_stmt(p, ws);
case_end;
case_ast_node(bs, BlockStmt, node);
lbBlock *done = nullptr;
if (bs->label != nullptr) {
done = lb_create_block(p, "block.done");
lbTargetList *tl = lb_push_target_list(p, bs->label, done, nullptr, nullptr);
tl->is_block = true;
}
lb_open_scope(p, node->scope);
lb_build_stmt_list(p, bs->stmts);
lb_close_scope(p, lbDeferExit_Default, nullptr);
if (done != nullptr) {
lb_emit_jump(p, done);
lb_start_block(p, done);
}
case_end;
case_ast_node(vd, ValueDecl, node);
if (!vd->is_mutable) {
return;
}
bool is_static = false;
if (vd->names.count > 0) {
Entity *e = entity_of_node(vd->names[0]);
if (e->flags & EntityFlag_Static) {
// NOTE(bill): If one of the entities is static, they all are
is_static = true;
}
}
if (is_static) {
lb_build_static_variables(p, vd);
return;
}
auto lvals = array_make<lbAddr>(permanent_allocator(), 0, vd->names.count);
for_array(i, vd->names) {
Ast *name = vd->names[i];
lbAddr lval = {};
if (!is_blank_ident(name)) {
Entity *e = entity_of_node(name);
bool zero_init = true; // Zero always and optimize out later
lval = lb_add_local(p, e->type, e, zero_init);
}
array_add(&lvals, lval);
}
lb_build_assignment(p, lvals, vd->values);
case_end;
case_ast_node(as, AssignStmt, node);
if (as->op.kind == Token_Eq) {
auto lvals = array_make<lbAddr>(permanent_allocator(), 0, as->lhs.count);
for_array(i, as->lhs) {
Ast *lhs = as->lhs[i];
lbAddr lval = {};
if (!is_blank_ident(lhs)) {
lval = lb_build_addr(p, lhs);
}
array_add(&lvals, lval);
}
lb_build_assignment(p, lvals, as->rhs);
} else {
GB_ASSERT(as->lhs.count == 1);
GB_ASSERT(as->rhs.count == 1);
// NOTE(bill): Only 1 += 1 is allowed, no tuples
// +=, -=, etc
i32 op = cast(i32)as->op.kind;
op += Token_Add - Token_AddEq; // Convert += to +
if (op == Token_CmpAnd || op == Token_CmpOr) {
Type *type = as->lhs[0]->tav.type;
lbValue new_value = lb_emit_logical_binary_expr(p, cast(TokenKind)op, as->lhs[0], as->rhs[0], type);
lbAddr lhs = lb_build_addr(p, as->lhs[0]);
lb_addr_store(p, lhs, new_value);
} else {
lbAddr lhs = lb_build_addr(p, as->lhs[0]);
lbValue value = lb_build_expr(p, as->rhs[0]);
lbValue old_value = lb_addr_load(p, lhs);
Type *type = old_value.type;
lbValue change = lb_emit_conv(p, value, type);
lbValue new_value = lb_emit_arith(p, cast(TokenKind)op, old_value, change, type);
lb_addr_store(p, lhs, new_value);
}
return;
}
case_end;
case_ast_node(es, ExprStmt, node);
lb_build_expr(p, es->expr);
case_end;
case_ast_node(ds, DeferStmt, node);
lb_add_defer_node(p, p->scope_index, ds->stmt);
case_end;
case_ast_node(rs, ReturnStmt, node);
lb_build_return_stmt(p, rs);
case_end;
case_ast_node(is, IfStmt, node);
lb_build_if_stmt(p, node);
case_end;
case_ast_node(fs, ForStmt, node);
lb_build_for_stmt(p, node);
case_end; case_end;
case_ast_node(rs, RangeStmt, node); case_ast_node(rs, RangeStmt, node);
@@ -5493,7 +5429,7 @@ void lb_build_stmt(lbProcedure *p, Ast *node) {
case_end; case_end;
case_ast_node(rs, UnrollRangeStmt, node); case_ast_node(rs, UnrollRangeStmt, node);
lb_build_inline_range_stmt(p, rs, node->scope); lb_build_unroll_range_stmt(p, rs, node->scope);
case_end; case_end;
case_ast_node(ss, SwitchStmt, node); case_ast_node(ss, SwitchStmt, node);