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

View File

@@ -4425,7 +4425,7 @@ void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *scope) {
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;
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;
}
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) {
Ast *prev_stmt = p->curr_stmt;
@@ -5028,156 +5343,24 @@ void lb_build_stmt(lbProcedure *p, Ast *node) {
}
if (is_static) {
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);
}
lb_build_static_variables(p, vd);
return;
}
if (vd->values.count == 0) { // declared and zero-initialized
for_array(i, vd->names) {
Ast *name = vd->names[i];
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);
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);
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);
@@ -5192,54 +5375,10 @@ void lb_build_stmt(lbProcedure *p, Ast *node) {
}
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);
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);
}
}
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;
@@ -5270,222 +5409,19 @@ void lb_build_stmt(lbProcedure *p, Ast *node) {
case_end;
case_ast_node(ds, DeferStmt, node);
isize scope_index = p->scope_index;
lb_add_defer_node(p, scope_index, ds->stmt);
lb_add_defer_node(p, p->scope_index, ds->stmt);
case_end;
case_ast_node(rs, ReturnStmt, node);
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);
}
lb_build_return_stmt(p, rs);
case_end;
case_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);
lb_build_if_stmt(p, node);
case_end;
case_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);
lb_build_for_stmt(p, node);
case_end;
case_ast_node(rs, RangeStmt, node);
@@ -5493,7 +5429,7 @@ void lb_build_stmt(lbProcedure *p, Ast *node) {
case_end;
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_ast_node(ss, SwitchStmt, node);