mirror of
https://github.com/odin-lang/Odin.git
synced 2026-04-19 13:00:28 +00:00
Support #soa array iteration in a for in loop for -llvm-api backend only
This commit is contained in:
@@ -1661,6 +1661,7 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
|
||||
auto entities = array_make<Entity *>(temporary_allocator(), 0, 2);
|
||||
bool is_map = false;
|
||||
bool use_by_reference_for_value = false;
|
||||
bool is_soa = false;
|
||||
|
||||
Ast *expr = unparen_expr(rs->expr);
|
||||
|
||||
@@ -1775,7 +1776,12 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
|
||||
|
||||
case Type_Struct:
|
||||
if (t->Struct.soa_kind != StructSoa_None) {
|
||||
error(operand.expr, "#soa structures do not yet support for in loop iteration");
|
||||
is_soa = true;
|
||||
array_add(&vals, t->Struct.soa_elem);
|
||||
array_add(&vals, t_int);
|
||||
if (!build_context.use_llvm_api) {
|
||||
error(operand.expr, "#soa structures do not yet support for in loop iteration");
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1836,6 +1842,11 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
|
||||
entity->flags &= ~EntityFlag_Value;
|
||||
}
|
||||
}
|
||||
if (is_soa) {
|
||||
if (i == 0) {
|
||||
entity->flags |= EntityFlag_SoaPtrField;
|
||||
}
|
||||
}
|
||||
|
||||
add_entity_definition(&ctx->checker->info, name, entity);
|
||||
} else {
|
||||
|
||||
@@ -416,7 +416,9 @@ void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value) {
|
||||
Type *t = base_type(type_deref(addr.addr.type));
|
||||
GB_ASSERT(t->kind == Type_Struct && t->Struct.soa_kind != StructSoa_None);
|
||||
lbValue len = lb_soa_struct_len(p, addr.addr);
|
||||
lb_emit_bounds_check(p, ast_token(addr.soa.index_expr), index, len);
|
||||
if (addr.soa.index_expr != nullptr) {
|
||||
lb_emit_bounds_check(p, ast_token(addr.soa.index_expr), index, len);
|
||||
}
|
||||
}
|
||||
|
||||
isize field_count = 0;
|
||||
@@ -640,7 +642,7 @@ lbValue lb_addr_load(lbProcedure *p, lbAddr const &addr) {
|
||||
|
||||
lbAddr res = lb_add_local_generated(p, elem, true);
|
||||
|
||||
if (!lb_is_const(addr.soa.index) || t->Struct.soa_kind != StructSoa_Fixed) {
|
||||
if (addr.soa.index_expr != nullptr && (!lb_is_const(addr.soa.index) || t->Struct.soa_kind != StructSoa_Fixed)) {
|
||||
lb_emit_bounds_check(p, ast_token(addr.soa.index_expr), addr.soa.index, len);
|
||||
}
|
||||
|
||||
@@ -671,8 +673,8 @@ lbValue lb_addr_load(lbProcedure *p, lbAddr const &addr) {
|
||||
|
||||
lbValue dst = lb_emit_struct_ep(p, res.addr, cast(i32)i);
|
||||
lbValue src_ptr = lb_emit_struct_ep(p, addr.addr, cast(i32)i);
|
||||
src_ptr = lb_emit_ptr_offset(p, src_ptr, addr.soa.index);
|
||||
lbValue src = lb_emit_load(p, src_ptr);
|
||||
src = lb_emit_ptr_offset(p, src, addr.soa.index);
|
||||
src = lb_emit_load(p, src);
|
||||
lb_emit_store(p, dst, src);
|
||||
}
|
||||
@@ -3673,6 +3675,11 @@ void lb_build_range_indexed(lbProcedure *p, lbValue expr, Type *val_type, lbValu
|
||||
|
||||
break;
|
||||
}
|
||||
case Type_Struct: {
|
||||
GB_ASSERT(is_type_soa_struct(expr_type));
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
GB_PANIC("Cannot do range_indexed of %s", type_to_string(expr_type));
|
||||
break;
|
||||
@@ -3884,7 +3891,87 @@ void lb_build_range_tuple(lbProcedure *p, Ast *expr, Type *val0_type, Type *val1
|
||||
if (done_) *done_ = done;
|
||||
}
|
||||
|
||||
void lb_build_range_stmt_struct_soa(lbProcedure *p, AstRangeStmt *rs, Scope *scope) {
|
||||
Ast *expr = unparen_expr(rs->expr);
|
||||
TypeAndValue tav = type_and_value_of_expr(expr);
|
||||
|
||||
lbBlock *loop = nullptr;
|
||||
lbBlock *body = nullptr;
|
||||
lbBlock *done = nullptr;
|
||||
|
||||
lb_open_scope(p, scope);
|
||||
|
||||
|
||||
Type *val_types[2] = {};
|
||||
if (rs->vals.count > 0 && rs->vals[0] != nullptr && !is_blank_ident(rs->vals[0])) {
|
||||
val_types[0] = type_of_expr(rs->vals[0]);
|
||||
}
|
||||
if (rs->vals.count > 1 && rs->vals[1] != nullptr && !is_blank_ident(rs->vals[1])) {
|
||||
val_types[1] = type_of_expr(rs->vals[1]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
lbAddr array = lb_build_addr(p, expr);
|
||||
if (is_type_pointer(type_deref(lb_addr_type(array)))) {
|
||||
array = lb_addr(lb_addr_load(p, array));
|
||||
}
|
||||
lbValue count = lb_soa_struct_len(p, lb_addr_load(p, array));
|
||||
|
||||
|
||||
lbAddr index = lb_add_local_generated(p, t_int, false);
|
||||
lb_addr_store(p, index, lb_const_int(p->module, t_int, cast(u64)-1));
|
||||
|
||||
loop = lb_create_block(p, "for.soa.loop");
|
||||
lb_emit_jump(p, loop);
|
||||
lb_start_block(p, loop);
|
||||
|
||||
lbValue incr = lb_emit_arith(p, Token_Add, lb_addr_load(p, index), lb_const_int(p->module, t_int, 1), t_int);
|
||||
lb_addr_store(p, index, incr);
|
||||
|
||||
body = lb_create_block(p, "for.soa.body");
|
||||
done = lb_create_block(p, "for.soa.done");
|
||||
|
||||
lbValue cond = lb_emit_comp(p, Token_Lt, incr, count);
|
||||
lb_emit_if(p, cond, body, done);
|
||||
lb_start_block(p, body);
|
||||
|
||||
|
||||
if (val_types[0]) {
|
||||
Entity *e = entity_of_node(rs->vals[0]);
|
||||
if (e != nullptr) {
|
||||
lbAddr soa_val = lb_addr_soa_variable(array.addr, lb_addr_load(p, index), nullptr);
|
||||
map_set(&p->module->soa_values, hash_entity(e), soa_val);
|
||||
}
|
||||
}
|
||||
if (val_types[1]) {
|
||||
lb_store_range_stmt_val(p, rs->vals[1], lb_addr_load(p, index));
|
||||
}
|
||||
|
||||
|
||||
lb_push_target_list(p, rs->label, done, loop, nullptr);
|
||||
|
||||
lb_build_stmt(p, rs->body);
|
||||
|
||||
lb_close_scope(p, lbDeferExit_Default, nullptr);
|
||||
lb_pop_target_list(p);
|
||||
lb_emit_jump(p, loop);
|
||||
lb_start_block(p, done);
|
||||
|
||||
}
|
||||
|
||||
void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *scope) {
|
||||
Ast *expr = unparen_expr(rs->expr);
|
||||
|
||||
Type *expr_type = type_of_expr(expr);
|
||||
if (expr_type != nullptr) {
|
||||
Type *et = base_type(type_deref(expr_type));
|
||||
if (is_type_soa_struct(et)) {
|
||||
lb_build_range_stmt_struct_soa(p, rs, scope);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
lb_open_scope(p, scope);
|
||||
|
||||
Type *val0_type = nullptr;
|
||||
@@ -3909,11 +3996,10 @@ void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *scope) {
|
||||
lbValue key = {};
|
||||
lbBlock *loop = nullptr;
|
||||
lbBlock *done = nullptr;
|
||||
Ast *expr = unparen_expr(rs->expr);
|
||||
bool is_map = false;
|
||||
|
||||
TypeAndValue tav = type_and_value_of_expr(expr);
|
||||
|
||||
|
||||
if (is_ast_range(expr)) {
|
||||
lb_build_range_interval(p, &expr->BinaryExpr, val0_type, &val, &key, &loop, &done);
|
||||
} else if (tav.mode == Addressing_Type) {
|
||||
@@ -10622,6 +10708,11 @@ lbValue lb_build_expr(lbProcedure *p, Ast *expr) {
|
||||
return {};
|
||||
}
|
||||
|
||||
lbAddr lb_get_soa_variable_addr(lbProcedure *p, Entity *e) {
|
||||
lbAddr *found = map_get(&p->module->soa_values, hash_entity(e));
|
||||
GB_ASSERT(found != nullptr);
|
||||
return *found;
|
||||
}
|
||||
lbValue lb_get_using_variable(lbProcedure *p, Entity *e) {
|
||||
GB_ASSERT(e->kind == Entity_Variable && e->flags & EntityFlag_Using);
|
||||
String name = e->token.string;
|
||||
@@ -10661,6 +10752,8 @@ lbAddr lb_build_addr_from_entity(lbProcedure *p, Entity *e, Ast *expr) {
|
||||
} else if (e->kind == Entity_Variable && e->flags & EntityFlag_Using) {
|
||||
// NOTE(bill): Calculate the using variable every time
|
||||
v = lb_get_using_variable(p, e);
|
||||
} else if (e->flags & EntityFlag_SoaPtrField) {
|
||||
return lb_get_soa_variable_addr(p, e);
|
||||
}
|
||||
|
||||
if (v.value == nullptr) {
|
||||
@@ -10901,7 +10994,7 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) {
|
||||
GB_ASSERT(is_type_soa_struct(t));
|
||||
|
||||
// TODO(bill): Bounds check
|
||||
if (!lb_is_const(addr.soa.index) || t->Struct.soa_kind != StructSoa_Fixed) {
|
||||
if (addr.soa.index_expr != nullptr && (!lb_is_const(addr.soa.index) || t->Struct.soa_kind != StructSoa_Fixed)) {
|
||||
lbValue len = lb_soa_struct_len(p, addr.addr);
|
||||
lb_emit_bounds_check(p, ast_token(addr.soa.index_expr), addr.soa.index, len);
|
||||
}
|
||||
@@ -10911,7 +11004,7 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) {
|
||||
if (t->Struct.soa_kind == StructSoa_Fixed) {
|
||||
item = lb_emit_array_ep(p, arr, index);
|
||||
} else {
|
||||
item = lb_emit_load(p, lb_emit_ptr_offset(p, arr, index));
|
||||
item = lb_emit_ptr_offset(p, lb_emit_load(p, arr), index);
|
||||
}
|
||||
if (sub_sel.index.count > 0) {
|
||||
item = lb_emit_deep_field_gep(p, item, sub_sel);
|
||||
@@ -12005,6 +12098,7 @@ void lb_init_module(lbModule *m, Checker *c) {
|
||||
map_init(&m->types, a);
|
||||
map_init(&m->llvm_types, a);
|
||||
map_init(&m->values, a);
|
||||
map_init(&m->soa_values, a);
|
||||
string_map_init(&m->members, a);
|
||||
map_init(&m->procedure_values, a);
|
||||
string_map_init(&m->procedures, a);
|
||||
|
||||
@@ -98,6 +98,7 @@ struct lbModule {
|
||||
i32 internal_type_level;
|
||||
|
||||
Map<lbValue> values; // Key: Entity *
|
||||
Map<lbAddr> soa_values; // Key: Entity *
|
||||
StringMap<lbValue> members;
|
||||
StringMap<lbProcedure *> procedures;
|
||||
Map<Entity *> procedure_values; // Key: LLVMValueRef
|
||||
|
||||
Reference in New Issue
Block a user