package core.intrinsics.onyx
-__initialize :: (val: ^$T) -> void #intrinsic ---
+__initialize :: (val: ^$T) -> void #intrinsic ---
+__zero_value :: ($T: type_expr) -> T #intrinsic ---
ONYX_INTRINSIC_MEMORY_SIZE, ONYX_INTRINSIC_MEMORY_GROW,
ONYX_INTRINSIC_MEMORY_COPY, ONYX_INTRINSIC_MEMORY_FILL,
- ONYX_INTRINSIC_INITIALIZE,
+ ONYX_INTRINSIC_INITIALIZE, ONYX_INTRINSIC_ZERO_VALUE,
ONYX_INTRINSIC_I32_CLZ, ONYX_INTRINSIC_I32_CTZ, ONYX_INTRINSIC_I32_POPCNT,
ONYX_INTRINSIC_I32_AND, ONYX_INTRINSIC_I32_OR, ONYX_INTRINSIC_I32_XOR,
struct AstCall {
AstTyped_base;
+ Arguments original_args;
Arguments args;
union {
bh_arr(StructMember *) memarr; \
bh_arr(struct AstPolySolution) poly_sln; \
bh_arr(TypeWithOffset) linear_members; \
+ struct AstType *constructed_from; \
}) \
TYPE_KIND(Compound, struct { \
u32 count; \
u32 type_structlike_mem_count(Type* type);
u32 type_structlike_is_simple(Type* type);
b32 type_is_sl_constructable(Type* type);
+b32 type_struct_constructed_from_poly_struct(Type* struct_type, struct AstType* from);
#endif // #ifndef ONYX_TYPES
{ "memory_fill", ONYX_INTRINSIC_MEMORY_FILL },
{ "__initialize", ONYX_INTRINSIC_INITIALIZE },
+ { "__zero_value", ONYX_INTRINSIC_ZERO_VALUE },
{ "clz_i32", ONYX_INTRINSIC_I32_CLZ },
{ "ctz_i32", ONYX_INTRINSIC_I32_CTZ },
CHECK(expression, &call->callee);
check_arguments(&call->args);
+ // SPEED CLEANUP: Keeping an original copy for basically no reason except that sometimes you
+ // need to know the baked argument values in code generation.
+ arguments_clone(&call->original_args, &call->args);
+
if (call->callee->kind == Ast_Kind_Overloaded_Function) {
call->callee = find_matching_overload_by_arguments(((AstOverloadedFunction *) call->callee)->overloads, &call->args);
if (call->callee == NULL) {
bh_arr_free(slns);
if (!concrete) return NULL;
- return type_build_from_ast(alloc, (AstType *) concrete);
+ Type* struct_type = type_build_from_ast(alloc, (AstType *) concrete);
+ struct_type->Struct.constructed_from = (AstType *) ps_type;
+ return struct_type;
}
case Ast_Kind_Type_Compound: {
default: return 0;
}
}
+
+b32 type_struct_constructed_from_poly_struct(Type* struct_type, struct AstType* from) {
+ DEBUG_HERE;
+ if (struct_type->kind != Type_Kind_Struct) return 0;
+
+ return struct_type->Struct.constructed_from == from;
+}
EMIT_FUNC(stack_enter, u64 stacksize);
EMIT_FUNC(stack_leave, u32 unused);
EMIT_FUNC(zero_value, WasmType wt);
+EMIT_FUNC(zero_value_for_type, Type* type);
EMIT_FUNC(enter_structured_block, StructuredBlockType sbt);
EMIT_FUNC_NO_ARGS(leave_structured_block);
break;
}
+ case ONYX_INTRINSIC_ZERO_VALUE: {
+ // NOTE: This probably will not have to make an allocation.
+ Type* zero_type = type_build_from_ast(context.ast_alloc, (AstType *) ((AstArgument *) call->args.values[0])->value);
+ emit_zero_value_for_type(mod, &code, zero_type);
+ break;
+ }
+
case ONYX_INTRINSIC_I32_CLZ: WI(WI_I32_CLZ); break;
case ONYX_INTRINSIC_I32_CTZ: WI(WI_I32_CTZ); break;
case ONYX_INTRINSIC_I32_POPCNT: WI(WI_I32_POPCNT); break;
*pcode = code;
}
+EMIT_FUNC(zero_value_for_type, Type* type) {
+ bh_arr(WasmInstruction) code = *pcode;
+
+ if (type_is_structlike_strict(type)) {
+ i32 mem_count = type_linear_member_count(type);
+ TypeWithOffset two;
+
+ fori (i, 0, mem_count) {
+ type_linear_member_lookup(type, i, &two);
+ emit_zero_value_for_type(mod, &code, two.type);
+ }
+
+ } else {
+ WasmType wt = onyx_type_to_wasm_type(type);
+ emit_zero_value(mod, &code, wt);
+ }
+
+ *pcode = code;
+}
+
static i32 generate_type_idx(OnyxWasmModule* mod, Type* ft) {
if (ft->kind != Type_Kind_Function) return -1;