mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 15:48:51 +00:00
Refactor backend code for assignments; Refactor some statements into separate procedures
This commit is contained in:
+190
-254
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user