mirror of
https://github.com/odin-lang/Odin.git
synced 2025-12-29 17:34:34 +00:00
SOA Struct support intrinsics.soa_struct
This commit is contained in:
@@ -3216,7 +3216,7 @@ Entity *check_selector(CheckerContext *c, Operand *operand, Ast *node, Type *typ
|
||||
}
|
||||
} else if (operand->mode == Addressing_MapIndex) {
|
||||
operand->mode = Addressing_Value;
|
||||
} else if (sel.indirect || operand->mode != Addressing_Value) {
|
||||
} else if (sel.indirect || operand->mode != Addressing_Value || operand->mode == Addressing_SoaVariable) {
|
||||
operand->mode = Addressing_Variable;
|
||||
} else {
|
||||
operand->mode = Addressing_Value;
|
||||
@@ -4735,6 +4735,81 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
break;
|
||||
}
|
||||
|
||||
case BuiltinProc_soa_struct: {
|
||||
Operand x = {};
|
||||
Operand y = {};
|
||||
x = *operand;
|
||||
if (!is_type_integer(x.type) || x.mode != Addressing_Constant) {
|
||||
error(call, "Expected a constant integer for 'intrinsics.soa_struct'");
|
||||
operand->mode = Addressing_Type;
|
||||
operand->type = t_invalid;
|
||||
return false;
|
||||
}
|
||||
if (x.value.value_integer.neg) {
|
||||
error(call, "Negative array element length");
|
||||
operand->mode = Addressing_Type;
|
||||
operand->type = t_invalid;
|
||||
return false;
|
||||
}
|
||||
i64 count = big_int_to_i64(&x.value.value_integer);
|
||||
|
||||
check_expr_or_type(c, &y, ce->args[1]);
|
||||
if (y.mode != Addressing_Type) {
|
||||
error(call, "Expected a type 'intrinsics.soa_struct'");
|
||||
operand->mode = Addressing_Type;
|
||||
operand->type = t_invalid;
|
||||
return false;
|
||||
}
|
||||
Type *elem = y.type;
|
||||
if (!is_type_struct(elem) && !is_type_raw_union(elem)) {
|
||||
gbString str = type_to_string(elem);
|
||||
error(call, "Invalid type for 'intrinsics.soa_struct', expected a struct, got '%s'", str);
|
||||
gb_string_free(str);
|
||||
operand->mode = Addressing_Type;
|
||||
operand->type = t_invalid;
|
||||
return false;
|
||||
}
|
||||
|
||||
operand->mode = Addressing_Type;
|
||||
|
||||
Type *old_struct = base_type(elem);
|
||||
Type *soa_struct = alloc_type_struct();
|
||||
soa_struct->Struct.fields = array_make<Entity *>(heap_allocator(), old_struct->Struct.fields.count);
|
||||
soa_struct->Struct.tags = array_make<String>(heap_allocator(), old_struct->Struct.tags.count);
|
||||
soa_struct->Struct.node = operand->expr;
|
||||
soa_struct->Struct.is_soa = true;
|
||||
soa_struct->Struct.soa_elem = elem;
|
||||
soa_struct->Struct.soa_count = count;
|
||||
|
||||
Scope *scope = create_scope(old_struct->Struct.scope->parent, c->allocator);
|
||||
soa_struct->Struct.scope = scope;
|
||||
|
||||
for_array(i, old_struct->Struct.fields) {
|
||||
Entity *old_field = old_struct->Struct.fields[i];
|
||||
if (old_field->kind == Entity_Variable) {
|
||||
Type *array_type = alloc_type_array(old_field->type, count);
|
||||
Entity *new_field = alloc_entity_field(scope, old_field->token, array_type, false, old_field->Variable.field_src_index);
|
||||
soa_struct->Struct.fields[i] = new_field;
|
||||
add_entity(c->checker, scope, nullptr, new_field);
|
||||
} else {
|
||||
soa_struct->Struct.fields[i] = old_field;
|
||||
}
|
||||
|
||||
soa_struct->Struct.tags[i] = old_struct->Struct.tags[i];
|
||||
}
|
||||
|
||||
|
||||
Token token = {};
|
||||
token.string = str_lit("Base_Type");
|
||||
Entity *base_type_entity = alloc_entity_type_name(scope, token, elem, EntityState_Resolved);
|
||||
add_entity(c->checker, scope, nullptr, base_type_entity);
|
||||
|
||||
add_type_info_type(c, soa_struct);
|
||||
|
||||
operand->type = soa_struct;
|
||||
break;
|
||||
}
|
||||
|
||||
case BuiltinProc_atomic_fence:
|
||||
case BuiltinProc_atomic_fence_acq:
|
||||
case BuiltinProc_atomic_fence_rel:
|
||||
@@ -6640,6 +6715,18 @@ bool check_set_index_data(Operand *o, Type *t, bool indirection, i64 *max_count)
|
||||
o->mode = Addressing_Variable;
|
||||
}
|
||||
return true;
|
||||
case Type_Struct:
|
||||
if (t->Struct.is_soa) {
|
||||
*max_count = t->Struct.soa_count;
|
||||
o->type = t->Struct.soa_elem;
|
||||
if (o->mode == Addressing_SoaVariable || o->mode == Addressing_Variable) {
|
||||
o->mode = Addressing_SoaVariable;
|
||||
} else {
|
||||
o->mode = Addressing_Value;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -293,6 +293,9 @@ Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, Operand *rhs)
|
||||
break;
|
||||
}
|
||||
|
||||
case Addressing_SoaVariable:
|
||||
break;
|
||||
|
||||
default: {
|
||||
if (lhs->expr->kind == Ast_SelectorExpr) {
|
||||
// NOTE(bill): Extra error checks
|
||||
|
||||
@@ -13,6 +13,7 @@ bool is_operand_value(Operand o) {
|
||||
case Addressing_Constant:
|
||||
case Addressing_MapIndex:
|
||||
case Addressing_OptionalOk:
|
||||
case Addressing_SoaVariable:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -1255,6 +1256,9 @@ void add_type_info_type(CheckerContext *c, Type *t) {
|
||||
break;
|
||||
case Type_Basic:
|
||||
switch (bt->Basic.kind) {
|
||||
case Basic_cstring:
|
||||
add_type_info_type(c, t_u8_ptr);
|
||||
break;
|
||||
case Basic_string:
|
||||
add_type_info_type(c, t_u8_ptr);
|
||||
add_type_info_type(c, t_int);
|
||||
@@ -1274,6 +1278,14 @@ void add_type_info_type(CheckerContext *c, Type *t) {
|
||||
add_type_info_type(c, t_type_info_float);
|
||||
add_type_info_type(c, t_f64);
|
||||
break;
|
||||
case Basic_quaternion128:
|
||||
add_type_info_type(c, t_type_info_float);
|
||||
add_type_info_type(c, t_f32);
|
||||
break;
|
||||
case Basic_quaternion256:
|
||||
add_type_info_type(c, t_type_info_float);
|
||||
add_type_info_type(c, t_f64);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1328,7 +1340,11 @@ void add_type_info_type(CheckerContext *c, Type *t) {
|
||||
if (bt->Struct.scope != nullptr) {
|
||||
for_array(i, bt->Struct.scope->elements.entries) {
|
||||
Entity *e = bt->Struct.scope->elements.entries[i].value;
|
||||
add_type_info_type(c, e->type);
|
||||
if (bt->Struct.is_soa) {
|
||||
add_type_info_type(c, alloc_type_pointer(e->type));
|
||||
} else {
|
||||
add_type_info_type(c, e->type);
|
||||
}
|
||||
}
|
||||
}
|
||||
for_array(i, bt->Struct.fields) {
|
||||
|
||||
@@ -34,6 +34,7 @@ enum BuiltinProcId {
|
||||
|
||||
// "Intrinsics"
|
||||
BuiltinProc_vector,
|
||||
BuiltinProc_soa_struct,
|
||||
|
||||
BuiltinProc_atomic_fence,
|
||||
BuiltinProc_atomic_fence_acq,
|
||||
@@ -159,6 +160,7 @@ BuiltinProc__type_begin,
|
||||
|
||||
BuiltinProc__type_end,
|
||||
|
||||
|
||||
BuiltinProc_COUNT,
|
||||
};
|
||||
gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
|
||||
@@ -195,7 +197,8 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
|
||||
|
||||
|
||||
// "Intrinsics"
|
||||
{STR_LIT("vector"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, // Type
|
||||
{STR_LIT("vector"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, // Type
|
||||
{STR_LIT("soa_struct"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, // Type
|
||||
|
||||
{STR_LIT("atomic_fence"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("atomic_fence_acq"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
|
||||
|
||||
101
src/ir.cpp
101
src/ir.cpp
@@ -483,6 +483,7 @@ enum irAddrKind {
|
||||
irAddr_Map,
|
||||
irAddr_BitField,
|
||||
irAddr_Context,
|
||||
irAddr_SoaVariable,
|
||||
};
|
||||
|
||||
struct irAddr {
|
||||
@@ -500,6 +501,10 @@ struct irAddr {
|
||||
struct {
|
||||
Selection sel;
|
||||
} ctx;
|
||||
struct {
|
||||
irValue *index;
|
||||
Ast *index_expr;
|
||||
} soa;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -530,6 +535,14 @@ irAddr ir_addr_bit_field(irValue *addr, i32 bit_field_value_index) {
|
||||
return v;
|
||||
}
|
||||
|
||||
irAddr ir_addr_soa_variable(irValue *addr, irValue *index, Ast *index_expr) {
|
||||
irAddr v = {irAddr_SoaVariable, addr};
|
||||
v.soa.index = index;
|
||||
v.soa.index_expr = index_expr;
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
enum irDebugEncoding {
|
||||
irDebugBasicEncoding_Invalid = 0,
|
||||
|
||||
@@ -3397,6 +3410,8 @@ irValue *ir_emit_source_code_location(irProcedure *proc, Ast *node);
|
||||
irValue *ir_emit_ptr_offset(irProcedure *proc, irValue *ptr, irValue *offset);
|
||||
irValue *ir_emit_arith(irProcedure *proc, TokenKind op, irValue *left, irValue *right, Type *type);
|
||||
irValue *ir_emit_deep_field_gep(irProcedure *proc, irValue *e, Selection sel);
|
||||
void ir_emit_bounds_check(irProcedure *proc, Token token, irValue *index, irValue *len);
|
||||
|
||||
|
||||
irValue *ir_insert_dynamic_map_key_and_value(irProcedure *proc, irValue *addr, Type *map_type,
|
||||
irValue *map_key, irValue *map_value) {
|
||||
@@ -3532,6 +3547,28 @@ void ir_addr_store(irProcedure *proc, irAddr const &addr, irValue *value) {
|
||||
ir_emit_store(proc, lhs, rhs);
|
||||
}
|
||||
|
||||
return;
|
||||
} else if (addr.kind == irAddr_SoaVariable) {
|
||||
Type *t = type_deref(ir_type(addr.addr));
|
||||
t = base_type(t);
|
||||
GB_ASSERT(t->kind == Type_Struct && t->Struct.is_soa);
|
||||
value = ir_emit_conv(proc, value, t->Struct.soa_elem);
|
||||
|
||||
irValue *index = addr.soa.index;
|
||||
if (index->kind != irValue_Constant) {
|
||||
Type *t = base_type(type_deref(ir_type(addr.addr)));
|
||||
GB_ASSERT(t->kind == Type_Struct && t->Struct.is_soa);
|
||||
i64 count = t->Struct.soa_count;
|
||||
irValue *len = ir_const_int(count);
|
||||
ir_emit_bounds_check(proc, ast_token(addr.soa.index_expr), index, len);
|
||||
}
|
||||
|
||||
for_array(i, t->Struct.fields) {
|
||||
irValue *dst = ir_emit_struct_ep(proc, addr.addr, cast(i32)i);
|
||||
dst = ir_emit_array_ep(proc, dst, index);
|
||||
irValue *src = ir_emit_struct_ev(proc, value, cast(i32)i);
|
||||
ir_emit_store(proc, dst, src);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -3642,6 +3679,35 @@ irValue *ir_addr_load(irProcedure *proc, irAddr const &addr) {
|
||||
irValue *b = ir_emit_deep_field_gep(proc, a, addr.ctx.sel);
|
||||
return ir_emit_load(proc, b);
|
||||
}
|
||||
} else if (addr.kind == irAddr_SoaVariable) {
|
||||
Type *t = type_deref(ir_type(addr.addr));
|
||||
t = base_type(t);
|
||||
GB_ASSERT(t->kind == Type_Struct && t->Struct.is_soa);
|
||||
Type *elem = t->Struct.soa_elem;;
|
||||
i32 count = cast(i32)t->Struct.soa_count;
|
||||
|
||||
irValue *res = ir_add_local_generated(proc, elem, true);
|
||||
|
||||
if (addr.soa.index->kind != irValue_Constant) {
|
||||
irValue *len = ir_const_int(count);
|
||||
ir_emit_bounds_check(proc, ast_token(addr.soa.index_expr), addr.soa.index, len);
|
||||
}
|
||||
|
||||
for_array(i, t->Struct.fields) {
|
||||
Entity *field = t->Struct.fields[i];
|
||||
Type *base_type = field->type;
|
||||
GB_ASSERT(base_type->kind == Type_Array);
|
||||
Type *elem = base_type->Array.elem;
|
||||
|
||||
|
||||
irValue *dst = ir_emit_struct_ep(proc, res, cast(i32)i);
|
||||
irValue *src_ptr = ir_emit_struct_ep(proc, addr.addr, cast(i32)i);
|
||||
src_ptr = ir_emit_array_ep(proc, src_ptr, addr.soa.index);
|
||||
irValue *src = ir_emit_load(proc, src_ptr);
|
||||
ir_emit_store(proc, dst, src);
|
||||
}
|
||||
|
||||
return ir_emit_load(proc, res);
|
||||
}
|
||||
|
||||
Type *t = base_type(ir_type(addr.addr));
|
||||
@@ -7459,6 +7525,28 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
|
||||
addr.ctx.sel = sel;
|
||||
|
||||
return addr;
|
||||
} else if (addr.kind == irAddr_SoaVariable) {
|
||||
irValue *index = addr.soa.index;
|
||||
i32 first_index = sel.index[0];
|
||||
Selection sub_sel = sel;
|
||||
sub_sel.index.data += 1;
|
||||
sub_sel.index.count -= 1;
|
||||
|
||||
irValue *arr = ir_emit_struct_ep(proc, addr.addr, first_index);
|
||||
|
||||
if (addr.soa.index->kind != irValue_Constant) {
|
||||
Type *t = base_type(type_deref(ir_type(addr.addr)));
|
||||
GB_ASSERT(t->kind == Type_Struct && t->Struct.is_soa);
|
||||
i64 count = t->Struct.soa_count;
|
||||
irValue *len = ir_const_int(count);
|
||||
ir_emit_bounds_check(proc, ast_token(addr.soa.index_expr), addr.soa.index, len);
|
||||
}
|
||||
|
||||
irValue *item = ir_emit_array_ep(proc, arr, index);
|
||||
if (sub_sel.index.count > 0) {
|
||||
item = ir_emit_deep_field_gep(proc, item, sub_sel);
|
||||
}
|
||||
return ir_addr(item);
|
||||
}
|
||||
irValue *a = ir_addr_get_ptr(proc, addr);
|
||||
a = ir_emit_deep_field_gep(proc, a, sel);
|
||||
@@ -7515,6 +7603,19 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
|
||||
|
||||
bool deref = is_type_pointer(t);
|
||||
t = base_type(type_deref(t));
|
||||
if (t->kind == Type_Struct && t->Struct.is_soa) {
|
||||
// SOA STRUCTURES!!!!
|
||||
Type *elem = t->Struct.soa_elem;
|
||||
|
||||
irValue *val = ir_build_addr_ptr(proc, ie->expr);
|
||||
if (deref) {
|
||||
val = ir_emit_load(proc, val);
|
||||
}
|
||||
|
||||
irValue *index = ir_build_expr(proc, ie->index);
|
||||
return ir_addr_soa_variable(val, index, ie->index);
|
||||
}
|
||||
|
||||
GB_ASSERT_MSG(is_type_indexable(t), "%s %s", type_to_string(t), expr_to_string(expr));
|
||||
|
||||
if (is_type_map(t)) {
|
||||
|
||||
@@ -21,6 +21,7 @@ enum AddressingMode {
|
||||
// lhs: acts like a Variable
|
||||
// rhs: acts like OptionalOk
|
||||
Addressing_OptionalOk, // rhs: acts like a value with an optional boolean part (for existence check)
|
||||
Addressing_SoaVariable, // Struct-Of-Arrays indexed variable
|
||||
};
|
||||
|
||||
struct TypeAndValue {
|
||||
|
||||
@@ -129,6 +129,9 @@ struct TypeStruct {
|
||||
bool is_raw_union;
|
||||
bool is_polymorphic;
|
||||
bool is_poly_specialized;
|
||||
bool is_soa;
|
||||
Type *soa_elem;
|
||||
i64 soa_count;
|
||||
};
|
||||
|
||||
struct TypeUnion {
|
||||
|
||||
Reference in New Issue
Block a user