mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-05 15:18:49 +00:00
Refactor backend code for assignments; Refactor some statements into separate procedures
This commit is contained in:
+336
-400
@@ -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,6 +4943,321 @@ 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) {
|
||||||
|
for_array(i, vd->names) {
|
||||||
|
lbValue value = {};
|
||||||
|
if (vd->values.count > 0) {
|
||||||
|
GB_ASSERT(vd->names.count == vd->values.count);
|
||||||
|
Ast *ast_value = vd->values[i];
|
||||||
|
GB_ASSERT(ast_value->tav.mode == Addressing_Constant ||
|
||||||
|
ast_value->tav.mode == Addressing_Invalid);
|
||||||
|
|
||||||
|
bool allow_local = false;
|
||||||
|
value = lb_const_value(p->module, ast_value->tav.type, ast_value->tav.value, allow_local);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ast *ident = vd->names[i];
|
||||||
|
GB_ASSERT(!is_blank_ident(ident));
|
||||||
|
Entity *e = entity_of_node(ident);
|
||||||
|
GB_ASSERT(e->flags & EntityFlag_Static);
|
||||||
|
String name = e->token.string;
|
||||||
|
|
||||||
|
String mangled_name = {};
|
||||||
|
{
|
||||||
|
gbString str = gb_string_make_length(permanent_allocator(), p->name.text, p->name.len);
|
||||||
|
str = gb_string_appendc(str, "-");
|
||||||
|
str = gb_string_append_fmt(str, ".%.*s-%llu", LIT(name), cast(long long)e->id);
|
||||||
|
mangled_name.text = cast(u8 *)str;
|
||||||
|
mangled_name.len = gb_string_length(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *c_name = alloc_cstring(permanent_allocator(), mangled_name);
|
||||||
|
|
||||||
|
LLVMValueRef global = LLVMAddGlobal(p->module->mod, lb_type(p->module, e->type), c_name);
|
||||||
|
LLVMSetInitializer(global, LLVMConstNull(lb_type(p->module, e->type)));
|
||||||
|
if (value.value != nullptr) {
|
||||||
|
LLVMSetInitializer(global, value.value);
|
||||||
|
} else {
|
||||||
|
}
|
||||||
|
if (e->Variable.thread_local_model != "") {
|
||||||
|
LLVMSetThreadLocal(global, true);
|
||||||
|
|
||||||
|
String m = e->Variable.thread_local_model;
|
||||||
|
LLVMThreadLocalMode mode = LLVMGeneralDynamicTLSModel;
|
||||||
|
if (m == "default") {
|
||||||
|
mode = LLVMGeneralDynamicTLSModel;
|
||||||
|
} else if (m == "localdynamic") {
|
||||||
|
mode = LLVMLocalDynamicTLSModel;
|
||||||
|
} else if (m == "initialexec") {
|
||||||
|
mode = LLVMInitialExecTLSModel;
|
||||||
|
} else if (m == "localexec") {
|
||||||
|
mode = LLVMLocalExecTLSModel;
|
||||||
|
} else {
|
||||||
|
GB_PANIC("Unhandled thread local mode %.*s", LIT(m));
|
||||||
|
}
|
||||||
|
LLVMSetThreadLocalMode(global, mode);
|
||||||
|
} else {
|
||||||
|
LLVMSetLinkage(global, LLVMInternalLinkage);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
lbValue global_val = {global, alloc_type_pointer(e->type)};
|
||||||
|
lb_add_entity(p->module, e, 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto inits = array_make<lbValue>(permanent_allocator(), 0, lvals.count);
|
||||||
|
|
||||||
|
for_array(i, values) {
|
||||||
|
Ast *rhs = values[i];
|
||||||
|
if (is_type_tuple(type_of_expr(rhs))) {
|
||||||
|
lbValue init = lb_build_expr(p, rhs);
|
||||||
|
Type *t = init.type;
|
||||||
|
GB_ASSERT(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 {
|
||||||
|
auto prev_hint = lb_set_copy_elision_hint(p, lvals[inits.count], rhs);
|
||||||
|
lbValue init = lb_build_expr(p, rhs);
|
||||||
|
if (p->copy_elision_hint.used) {
|
||||||
|
lvals[inits.count] = {}; // zero lval
|
||||||
|
}
|
||||||
|
lb_reset_copy_elision_hint(p, prev_hint);
|
||||||
|
array_add(&inits, init);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GB_ASSERT(lvals.count == inits.count);
|
||||||
|
for_array(i, inits) {
|
||||||
|
lbAddr lval = lvals[i];
|
||||||
|
lbValue init = inits[i];
|
||||||
|
lb_addr_store(p, lval, init);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void lb_build_return_stmt(lbProcedure *p, AstReturnStmt *rs) {
|
||||||
|
lbValue res = {};
|
||||||
|
|
||||||
|
TypeTuple *tuple = &p->type->Proc.results->Tuple;
|
||||||
|
isize return_count = p->type->Proc.result_count;
|
||||||
|
isize res_count = rs->results.count;
|
||||||
|
|
||||||
|
if (return_count == 0) {
|
||||||
|
// No return values
|
||||||
|
|
||||||
|
lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr);
|
||||||
|
|
||||||
|
LLVMBuildRetVoid(p->builder);
|
||||||
|
return;
|
||||||
|
} else if (return_count == 1) {
|
||||||
|
Entity *e = tuple->variables[0];
|
||||||
|
if (res_count == 0) {
|
||||||
|
lbValue *found = map_get(&p->module->values, hash_entity(e));
|
||||||
|
GB_ASSERT(found);
|
||||||
|
res = lb_emit_load(p, *found);
|
||||||
|
} else {
|
||||||
|
res = lb_build_expr(p, rs->results[0]);
|
||||||
|
res = lb_emit_conv(p, res, e->type);
|
||||||
|
}
|
||||||
|
if (p->type->Proc.has_named_results) {
|
||||||
|
// NOTE(bill): store the named values before returning
|
||||||
|
if (e->token.string != "") {
|
||||||
|
lbValue *found = map_get(&p->module->values, hash_entity(e));
|
||||||
|
GB_ASSERT(found != nullptr);
|
||||||
|
lb_emit_store(p, *found, lb_emit_conv(p, res, e->type));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
auto results = array_make<lbValue>(permanent_allocator(), 0, return_count);
|
||||||
|
|
||||||
|
if (res_count != 0) {
|
||||||
|
for (isize res_index = 0; res_index < res_count; res_index++) {
|
||||||
|
lbValue res = lb_build_expr(p, rs->results[res_index]);
|
||||||
|
Type *t = res.type;
|
||||||
|
if (t->kind == Type_Tuple) {
|
||||||
|
for_array(i, t->Tuple.variables) {
|
||||||
|
Entity *e = t->Tuple.variables[i];
|
||||||
|
lbValue v = lb_emit_struct_ev(p, res, cast(i32)i);
|
||||||
|
array_add(&results, v);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
array_add(&results, res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (isize res_index = 0; res_index < return_count; res_index++) {
|
||||||
|
Entity *e = tuple->variables[res_index];
|
||||||
|
lbValue *found = map_get(&p->module->values, hash_entity(e));
|
||||||
|
GB_ASSERT(found);
|
||||||
|
lbValue res = lb_emit_load(p, *found);
|
||||||
|
array_add(&results, res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GB_ASSERT(results.count == return_count);
|
||||||
|
|
||||||
|
if (p->type->Proc.has_named_results) {
|
||||||
|
// NOTE(bill): store the named values before returning
|
||||||
|
for_array(i, p->type->Proc.results->Tuple.variables) {
|
||||||
|
Entity *e = p->type->Proc.results->Tuple.variables[i];
|
||||||
|
if (e->kind != Entity_Variable) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e->token.string == "") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
lbValue *found = map_get(&p->module->values, hash_entity(e));
|
||||||
|
GB_ASSERT(found != nullptr);
|
||||||
|
lb_emit_store(p, *found, lb_emit_conv(p, results[i], e->type));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Type *ret_type = p->type->Proc.results;
|
||||||
|
// NOTE(bill): Doesn't need to be zero because it will be initialized in the loops
|
||||||
|
res = lb_add_local_generated(p, ret_type, false).addr;
|
||||||
|
for_array(i, results) {
|
||||||
|
Entity *e = tuple->variables[i];
|
||||||
|
lbValue field = lb_emit_struct_ep(p, res, cast(i32)i);
|
||||||
|
lbValue val = lb_emit_conv(p, results[i], e->type);
|
||||||
|
lb_emit_store(p, field, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
res = lb_emit_load(p, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
lb_ensure_abi_function_type(p->module, p);
|
||||||
|
if (p->abi_function_type->ret.kind == lbArg_Indirect) {
|
||||||
|
if (res.value != nullptr) {
|
||||||
|
LLVMBuildStore(p->builder, res.value, p->return_ptr.addr.value);
|
||||||
|
} else {
|
||||||
|
LLVMBuildStore(p->builder, LLVMConstNull(p->abi_function_type->ret.type), p->return_ptr.addr.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr);
|
||||||
|
|
||||||
|
LLVMBuildRetVoid(p->builder);
|
||||||
|
} else {
|
||||||
|
LLVMValueRef ret_val = res.value;
|
||||||
|
ret_val = OdinLLVMBuildTransmute(p, ret_val, p->abi_function_type->ret.type);
|
||||||
|
if (p->abi_function_type->ret.cast_type != nullptr) {
|
||||||
|
ret_val = OdinLLVMBuildTransmute(p, ret_val, p->abi_function_type->ret.cast_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr);
|
||||||
|
LLVMBuildRet(p->builder, ret_val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void lb_build_if_stmt(lbProcedure *p, Ast *node) {
|
||||||
|
ast_node(is, IfStmt, node);
|
||||||
|
lb_open_scope(p, node->scope); // Scope #1
|
||||||
|
|
||||||
|
if (is->init != nullptr) {
|
||||||
|
// TODO(bill): Should this have a separate block to begin with?
|
||||||
|
#if 1
|
||||||
|
lbBlock *init = lb_create_block(p, "if.init");
|
||||||
|
lb_emit_jump(p, init);
|
||||||
|
lb_start_block(p, init);
|
||||||
|
#endif
|
||||||
|
lb_build_stmt(p, is->init);
|
||||||
|
}
|
||||||
|
lbBlock *then = lb_create_block(p, "if.then");
|
||||||
|
lbBlock *done = lb_create_block(p, "if.done");
|
||||||
|
lbBlock *else_ = done;
|
||||||
|
if (is->else_stmt != nullptr) {
|
||||||
|
else_ = lb_create_block(p, "if.else");
|
||||||
|
}
|
||||||
|
|
||||||
|
lb_build_cond(p, is->cond, then, else_);
|
||||||
|
lb_start_block(p, then);
|
||||||
|
|
||||||
|
if (is->label != nullptr) {
|
||||||
|
lbTargetList *tl = lb_push_target_list(p, is->label, done, nullptr, nullptr);
|
||||||
|
tl->is_block = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
lb_build_stmt(p, is->body);
|
||||||
|
|
||||||
|
lb_emit_jump(p, done);
|
||||||
|
|
||||||
|
if (is->else_stmt != nullptr) {
|
||||||
|
lb_start_block(p, else_);
|
||||||
|
|
||||||
|
lb_open_scope(p, is->else_stmt->scope);
|
||||||
|
lb_build_stmt(p, is->else_stmt);
|
||||||
|
lb_close_scope(p, lbDeferExit_Default, nullptr);
|
||||||
|
|
||||||
|
lb_emit_jump(p, done);
|
||||||
|
}
|
||||||
|
|
||||||
|
lb_start_block(p, done);
|
||||||
|
lb_close_scope(p, lbDeferExit_Default, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void lb_build_for_stmt(lbProcedure *p, Ast *node) {
|
||||||
|
ast_node(fs, ForStmt, node);
|
||||||
|
|
||||||
|
lb_open_scope(p, node->scope); // Open Scope here
|
||||||
|
|
||||||
|
if (fs->init != nullptr) {
|
||||||
|
#if 1
|
||||||
|
lbBlock *init = lb_create_block(p, "for.init");
|
||||||
|
lb_emit_jump(p, init);
|
||||||
|
lb_start_block(p, init);
|
||||||
|
#endif
|
||||||
|
lb_build_stmt(p, fs->init);
|
||||||
|
}
|
||||||
|
lbBlock *body = lb_create_block(p, "for.body");
|
||||||
|
lbBlock *done = lb_create_block(p, "for.done"); // NOTE(bill): Append later
|
||||||
|
lbBlock *loop = body;
|
||||||
|
if (fs->cond != nullptr) {
|
||||||
|
loop = lb_create_block(p, "for.loop");
|
||||||
|
}
|
||||||
|
lbBlock *post = loop;
|
||||||
|
if (fs->post != nullptr) {
|
||||||
|
post = lb_create_block(p, "for.post");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
lb_emit_jump(p, loop);
|
||||||
|
lb_start_block(p, loop);
|
||||||
|
|
||||||
|
if (loop != body) {
|
||||||
|
lb_build_cond(p, fs->cond, body, done);
|
||||||
|
lb_start_block(p, body);
|
||||||
|
}
|
||||||
|
|
||||||
|
lb_push_target_list(p, fs->label, done, post, nullptr);
|
||||||
|
|
||||||
|
lb_build_stmt(p, fs->body);
|
||||||
|
lb_close_scope(p, lbDeferExit_Default, nullptr);
|
||||||
|
|
||||||
|
lb_pop_target_list(p);
|
||||||
|
|
||||||
|
lb_emit_jump(p, post);
|
||||||
|
|
||||||
|
if (fs->post != nullptr) {
|
||||||
|
lb_start_block(p, post);
|
||||||
|
lb_build_stmt(p, fs->post);
|
||||||
|
lb_emit_jump(p, loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
lb_start_block(p, done);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void lb_build_stmt(lbProcedure *p, Ast *node) {
|
void lb_build_stmt(lbProcedure *p, Ast *node) {
|
||||||
Ast *prev_stmt = p->curr_stmt;
|
Ast *prev_stmt = p->curr_stmt;
|
||||||
@@ -5028,156 +5343,24 @@ void lb_build_stmt(lbProcedure *p, Ast *node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (is_static) {
|
if (is_static) {
|
||||||
for_array(i, vd->names) {
|
lb_build_static_variables(p, vd);
|
||||||
lbValue value = {};
|
|
||||||
if (vd->values.count > 0) {
|
|
||||||
GB_ASSERT(vd->names.count == vd->values.count);
|
|
||||||
Ast *ast_value = vd->values[i];
|
|
||||||
GB_ASSERT(ast_value->tav.mode == Addressing_Constant ||
|
|
||||||
ast_value->tav.mode == Addressing_Invalid);
|
|
||||||
|
|
||||||
bool allow_local = false;
|
|
||||||
value = lb_const_value(p->module, ast_value->tav.type, ast_value->tav.value, allow_local);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ast *ident = vd->names[i];
|
|
||||||
GB_ASSERT(!is_blank_ident(ident));
|
|
||||||
Entity *e = entity_of_node(ident);
|
|
||||||
GB_ASSERT(e->flags & EntityFlag_Static);
|
|
||||||
String name = e->token.string;
|
|
||||||
|
|
||||||
String mangled_name = {};
|
|
||||||
{
|
|
||||||
gbString str = gb_string_make_length(permanent_allocator(), p->name.text, p->name.len);
|
|
||||||
str = gb_string_appendc(str, "-");
|
|
||||||
str = gb_string_append_fmt(str, ".%.*s-%llu", LIT(name), cast(long long)e->id);
|
|
||||||
mangled_name.text = cast(u8 *)str;
|
|
||||||
mangled_name.len = gb_string_length(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
char *c_name = alloc_cstring(permanent_allocator(), mangled_name);
|
|
||||||
|
|
||||||
LLVMValueRef global = LLVMAddGlobal(p->module->mod, lb_type(p->module, e->type), c_name);
|
|
||||||
LLVMSetInitializer(global, LLVMConstNull(lb_type(p->module, e->type)));
|
|
||||||
if (value.value != nullptr) {
|
|
||||||
LLVMSetInitializer(global, value.value);
|
|
||||||
} else {
|
|
||||||
}
|
|
||||||
if (e->Variable.thread_local_model != "") {
|
|
||||||
LLVMSetThreadLocal(global, true);
|
|
||||||
|
|
||||||
String m = e->Variable.thread_local_model;
|
|
||||||
LLVMThreadLocalMode mode = LLVMGeneralDynamicTLSModel;
|
|
||||||
if (m == "default") {
|
|
||||||
mode = LLVMGeneralDynamicTLSModel;
|
|
||||||
} else if (m == "localdynamic") {
|
|
||||||
mode = LLVMLocalDynamicTLSModel;
|
|
||||||
} else if (m == "initialexec") {
|
|
||||||
mode = LLVMInitialExecTLSModel;
|
|
||||||
} else if (m == "localexec") {
|
|
||||||
mode = LLVMLocalExecTLSModel;
|
|
||||||
} else {
|
|
||||||
GB_PANIC("Unhandled thread local mode %.*s", LIT(m));
|
|
||||||
}
|
|
||||||
LLVMSetThreadLocalMode(global, mode);
|
|
||||||
} else {
|
|
||||||
LLVMSetLinkage(global, LLVMInternalLinkage);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
lbValue global_val = {global, alloc_type_pointer(e->type)};
|
|
||||||
lb_add_entity(p->module, e, global_val);
|
|
||||||
lb_add_member(p->module, mangled_name, global_val);
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (vd->values.count == 0) { // declared and zero-initialized
|
auto lvals = array_make<lbAddr>(permanent_allocator(), 0, vd->names.count);
|
||||||
for_array(i, vd->names) {
|
|
||||||
Ast *name = vd->names[i];
|
for_array(i, vd->names) {
|
||||||
if (!is_blank_ident(name)) {
|
Ast *name = vd->names[i];
|
||||||
Entity *e = entity_of_node(name);
|
lbAddr lval = {};
|
||||||
lb_add_local(p, e->type, e, true);
|
if (!is_blank_ident(name)) {
|
||||||
}
|
Entity *e = entity_of_node(name);
|
||||||
}
|
bool zero_init = true; // Zero always and optimize out later
|
||||||
} else if (vd->names.count == vd->values.count) {
|
lval = lb_add_local(p, e->type, e, zero_init);
|
||||||
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);
|
|
||||||
Type *t = init.type;
|
|
||||||
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) {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for_array(i, inits) {
|
|
||||||
lbAddr lval = lvals[i];
|
|
||||||
lbValue init = inits[i];
|
|
||||||
lb_addr_store(p, lval, init);
|
|
||||||
}
|
}
|
||||||
|
array_add(&lvals, lval);
|
||||||
}
|
}
|
||||||
|
lb_build_assignment(p, lvals, vd->values);
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
case_ast_node(as, AssignStmt, node);
|
case_ast_node(as, AssignStmt, node);
|
||||||
@@ -5192,54 +5375,10 @@ void lb_build_stmt(lbProcedure *p, Ast *node) {
|
|||||||
}
|
}
|
||||||
array_add(&lvals, lval);
|
array_add(&lvals, lval);
|
||||||
}
|
}
|
||||||
|
lb_build_assignment(p, lvals, as->rhs);
|
||||||
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);
|
|
||||||
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 {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for_array(i, inits) {
|
|
||||||
lbAddr lval = lvals[i];
|
|
||||||
lbValue init = inits[i];
|
|
||||||
lb_addr_store(p, lval, init);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
|
GB_ASSERT(as->lhs.count == 1);
|
||||||
|
GB_ASSERT(as->rhs.count == 1);
|
||||||
// NOTE(bill): Only 1 += 1 is allowed, no tuples
|
// NOTE(bill): Only 1 += 1 is allowed, no tuples
|
||||||
// +=, -=, etc
|
// +=, -=, etc
|
||||||
i32 op = cast(i32)as->op.kind;
|
i32 op = cast(i32)as->op.kind;
|
||||||
@@ -5270,222 +5409,19 @@ void lb_build_stmt(lbProcedure *p, Ast *node) {
|
|||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
case_ast_node(ds, DeferStmt, node);
|
case_ast_node(ds, DeferStmt, node);
|
||||||
isize scope_index = p->scope_index;
|
lb_add_defer_node(p, p->scope_index, ds->stmt);
|
||||||
lb_add_defer_node(p, scope_index, ds->stmt);
|
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
case_ast_node(rs, ReturnStmt, node);
|
case_ast_node(rs, ReturnStmt, node);
|
||||||
lbValue res = {};
|
lb_build_return_stmt(p, rs);
|
||||||
|
|
||||||
TypeTuple *tuple = &p->type->Proc.results->Tuple;
|
|
||||||
isize return_count = p->type->Proc.result_count;
|
|
||||||
isize res_count = rs->results.count;
|
|
||||||
|
|
||||||
if (return_count == 0) {
|
|
||||||
// No return values
|
|
||||||
|
|
||||||
lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr);
|
|
||||||
|
|
||||||
LLVMBuildRetVoid(p->builder);
|
|
||||||
return;
|
|
||||||
} else if (return_count == 1) {
|
|
||||||
Entity *e = tuple->variables[0];
|
|
||||||
if (res_count == 0) {
|
|
||||||
lbValue *found = map_get(&p->module->values, hash_entity(e));
|
|
||||||
GB_ASSERT(found);
|
|
||||||
res = lb_emit_load(p, *found);
|
|
||||||
} else {
|
|
||||||
res = lb_build_expr(p, rs->results[0]);
|
|
||||||
res = lb_emit_conv(p, res, e->type);
|
|
||||||
}
|
|
||||||
if (p->type->Proc.has_named_results) {
|
|
||||||
// NOTE(bill): store the named values before returning
|
|
||||||
if (e->token.string != "") {
|
|
||||||
lbValue *found = map_get(&p->module->values, hash_entity(e));
|
|
||||||
GB_ASSERT(found != nullptr);
|
|
||||||
lb_emit_store(p, *found, lb_emit_conv(p, res, e->type));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
auto results = array_make<lbValue>(permanent_allocator(), 0, return_count);
|
|
||||||
|
|
||||||
if (res_count != 0) {
|
|
||||||
for (isize res_index = 0; res_index < res_count; res_index++) {
|
|
||||||
lbValue res = lb_build_expr(p, rs->results[res_index]);
|
|
||||||
Type *t = res.type;
|
|
||||||
if (t->kind == Type_Tuple) {
|
|
||||||
for_array(i, t->Tuple.variables) {
|
|
||||||
Entity *e = t->Tuple.variables[i];
|
|
||||||
lbValue v = lb_emit_struct_ev(p, res, cast(i32)i);
|
|
||||||
array_add(&results, v);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
array_add(&results, res);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (isize res_index = 0; res_index < return_count; res_index++) {
|
|
||||||
Entity *e = tuple->variables[res_index];
|
|
||||||
lbValue *found = map_get(&p->module->values, hash_entity(e));
|
|
||||||
GB_ASSERT(found);
|
|
||||||
lbValue res = lb_emit_load(p, *found);
|
|
||||||
array_add(&results, res);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GB_ASSERT(results.count == return_count);
|
|
||||||
|
|
||||||
if (p->type->Proc.has_named_results) {
|
|
||||||
// NOTE(bill): store the named values before returning
|
|
||||||
for_array(i, p->type->Proc.results->Tuple.variables) {
|
|
||||||
Entity *e = p->type->Proc.results->Tuple.variables[i];
|
|
||||||
if (e->kind != Entity_Variable) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e->token.string == "") {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
lbValue *found = map_get(&p->module->values, hash_entity(e));
|
|
||||||
GB_ASSERT(found != nullptr);
|
|
||||||
lb_emit_store(p, *found, lb_emit_conv(p, results[i], e->type));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Type *ret_type = p->type->Proc.results;
|
|
||||||
// NOTE(bill): Doesn't need to be zero because it will be initialized in the loops
|
|
||||||
res = lb_add_local_generated(p, ret_type, false).addr;
|
|
||||||
for_array(i, results) {
|
|
||||||
Entity *e = tuple->variables[i];
|
|
||||||
lbValue field = lb_emit_struct_ep(p, res, cast(i32)i);
|
|
||||||
lbValue val = lb_emit_conv(p, results[i], e->type);
|
|
||||||
lb_emit_store(p, field, val);
|
|
||||||
}
|
|
||||||
|
|
||||||
res = lb_emit_load(p, res);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
lb_ensure_abi_function_type(p->module, p);
|
|
||||||
if (p->abi_function_type->ret.kind == lbArg_Indirect) {
|
|
||||||
if (res.value != nullptr) {
|
|
||||||
LLVMBuildStore(p->builder, res.value, p->return_ptr.addr.value);
|
|
||||||
} else {
|
|
||||||
LLVMBuildStore(p->builder, LLVMConstNull(p->abi_function_type->ret.type), p->return_ptr.addr.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr);
|
|
||||||
|
|
||||||
LLVMBuildRetVoid(p->builder);
|
|
||||||
} else {
|
|
||||||
LLVMValueRef ret_val = res.value;
|
|
||||||
ret_val = OdinLLVMBuildTransmute(p, ret_val, p->abi_function_type->ret.type);
|
|
||||||
if (p->abi_function_type->ret.cast_type != nullptr) {
|
|
||||||
ret_val = OdinLLVMBuildTransmute(p, ret_val, p->abi_function_type->ret.cast_type);
|
|
||||||
}
|
|
||||||
|
|
||||||
lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr);
|
|
||||||
LLVMBuildRet(p->builder, ret_val);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
case_ast_node(is, IfStmt, node);
|
case_ast_node(is, IfStmt, node);
|
||||||
lb_open_scope(p, node->scope); // Scope #1
|
lb_build_if_stmt(p, node);
|
||||||
|
|
||||||
if (is->init != nullptr) {
|
|
||||||
// TODO(bill): Should this have a separate block to begin with?
|
|
||||||
#if 1
|
|
||||||
lbBlock *init = lb_create_block(p, "if.init");
|
|
||||||
lb_emit_jump(p, init);
|
|
||||||
lb_start_block(p, init);
|
|
||||||
#endif
|
|
||||||
lb_build_stmt(p, is->init);
|
|
||||||
}
|
|
||||||
lbBlock *then = lb_create_block(p, "if.then");
|
|
||||||
lbBlock *done = lb_create_block(p, "if.done");
|
|
||||||
lbBlock *else_ = done;
|
|
||||||
if (is->else_stmt != nullptr) {
|
|
||||||
else_ = lb_create_block(p, "if.else");
|
|
||||||
}
|
|
||||||
|
|
||||||
lb_build_cond(p, is->cond, then, else_);
|
|
||||||
lb_start_block(p, then);
|
|
||||||
|
|
||||||
if (is->label != nullptr) {
|
|
||||||
lbTargetList *tl = lb_push_target_list(p, is->label, done, nullptr, nullptr);
|
|
||||||
tl->is_block = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
lb_build_stmt(p, is->body);
|
|
||||||
|
|
||||||
lb_emit_jump(p, done);
|
|
||||||
|
|
||||||
if (is->else_stmt != nullptr) {
|
|
||||||
lb_start_block(p, else_);
|
|
||||||
|
|
||||||
lb_open_scope(p, is->else_stmt->scope);
|
|
||||||
lb_build_stmt(p, is->else_stmt);
|
|
||||||
lb_close_scope(p, lbDeferExit_Default, nullptr);
|
|
||||||
|
|
||||||
lb_emit_jump(p, done);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
lb_start_block(p, done);
|
|
||||||
lb_close_scope(p, lbDeferExit_Default, nullptr);
|
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
case_ast_node(fs, ForStmt, node);
|
case_ast_node(fs, ForStmt, node);
|
||||||
lb_open_scope(p, node->scope); // Open Scope here
|
lb_build_for_stmt(p, node);
|
||||||
|
|
||||||
if (fs->init != nullptr) {
|
|
||||||
#if 1
|
|
||||||
lbBlock *init = lb_create_block(p, "for.init");
|
|
||||||
lb_emit_jump(p, init);
|
|
||||||
lb_start_block(p, init);
|
|
||||||
#endif
|
|
||||||
lb_build_stmt(p, fs->init);
|
|
||||||
}
|
|
||||||
lbBlock *body = lb_create_block(p, "for.body");
|
|
||||||
lbBlock *done = lb_create_block(p, "for.done"); // NOTE(bill): Append later
|
|
||||||
lbBlock *loop = body;
|
|
||||||
if (fs->cond != nullptr) {
|
|
||||||
loop = lb_create_block(p, "for.loop");
|
|
||||||
}
|
|
||||||
lbBlock *post = loop;
|
|
||||||
if (fs->post != nullptr) {
|
|
||||||
post = lb_create_block(p, "for.post");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
lb_emit_jump(p, loop);
|
|
||||||
lb_start_block(p, loop);
|
|
||||||
|
|
||||||
if (loop != body) {
|
|
||||||
lb_build_cond(p, fs->cond, body, done);
|
|
||||||
lb_start_block(p, body);
|
|
||||||
}
|
|
||||||
|
|
||||||
lb_push_target_list(p, fs->label, done, post, nullptr);
|
|
||||||
|
|
||||||
lb_build_stmt(p, fs->body);
|
|
||||||
lb_close_scope(p, lbDeferExit_Default, nullptr);
|
|
||||||
|
|
||||||
lb_pop_target_list(p);
|
|
||||||
|
|
||||||
lb_emit_jump(p, post);
|
|
||||||
|
|
||||||
if (fs->post != nullptr) {
|
|
||||||
lb_start_block(p, post);
|
|
||||||
lb_build_stmt(p, fs->post);
|
|
||||||
lb_emit_jump(p, loop);
|
|
||||||
}
|
|
||||||
|
|
||||||
lb_start_block(p, done);
|
|
||||||
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);
|
||||||
|
|||||||
Reference in New Issue
Block a user