mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-14 07:01:25 -07:00
Merge remote-tracking branch 'offical/master'
This commit is contained in:
+212
-8
@@ -155,6 +155,11 @@ gb_internal bool does_require_msgSend_stret(Type *return_type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// No objc here so this doesn't matter, right?
|
||||
if (build_context.metrics.arch == TargetArch_riscv64) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// if (build_context.metrics.arch == TargetArch_arm32) {
|
||||
// i64 struct_limit = type_size_of(t_uintptr);
|
||||
// // NOTE(bill): This is technically wrong
|
||||
@@ -470,8 +475,8 @@ gb_internal bool check_builtin_simd_operation(CheckerContext *c, Operand *operan
|
||||
}
|
||||
|
||||
// Integer only
|
||||
case BuiltinProc_simd_add_sat:
|
||||
case BuiltinProc_simd_sub_sat:
|
||||
case BuiltinProc_simd_saturating_add:
|
||||
case BuiltinProc_simd_saturating_sub:
|
||||
case BuiltinProc_simd_bit_and:
|
||||
case BuiltinProc_simd_bit_or:
|
||||
case BuiltinProc_simd_bit_xor:
|
||||
@@ -501,8 +506,8 @@ gb_internal bool check_builtin_simd_operation(CheckerContext *c, Operand *operan
|
||||
Type *elem = base_array_type(x.type);
|
||||
|
||||
switch (id) {
|
||||
case BuiltinProc_simd_add_sat:
|
||||
case BuiltinProc_simd_sub_sat:
|
||||
case BuiltinProc_simd_saturating_add:
|
||||
case BuiltinProc_simd_saturating_sub:
|
||||
if (!is_type_integer(elem)) {
|
||||
gbString xs = type_to_string(x.type);
|
||||
error(x.expr, "'%.*s' expected a #simd type with an integer element, got '%s'", LIT(builtin_name), xs);
|
||||
@@ -663,6 +668,91 @@ gb_internal bool check_builtin_simd_operation(CheckerContext *c, Operand *operan
|
||||
return true;
|
||||
}
|
||||
|
||||
case BuiltinProc_simd_gather:
|
||||
case BuiltinProc_simd_scatter:
|
||||
case BuiltinProc_simd_masked_load:
|
||||
case BuiltinProc_simd_masked_store:
|
||||
case BuiltinProc_simd_masked_expand_load:
|
||||
case BuiltinProc_simd_masked_compress_store:
|
||||
{
|
||||
// gather (ptr: #simd[N]rawptr, values: #simd[N]T, mask: #simd[N]int_or_bool) -> #simd[N]T
|
||||
// scatter(ptr: #simd[N]rawptr, values: #simd[N]T, mask: #simd[N]int_or_bool)
|
||||
|
||||
// masked_load (ptr: rawptr, values: #simd[N]T, mask: #simd[N]int_or_bool) -> #simd[N]T
|
||||
// masked_store(ptr: rawptr, values: #simd[N]T, mask: #simd[N]int_or_bool)
|
||||
// masked_expand_load (ptr: rawptr, values: #simd[N]T, mask: #simd[N]int_or_bool) -> #simd[N]T
|
||||
// masked_compress_store(ptr: rawptr, values: #simd[N]T, mask: #simd[N]int_or_bool)
|
||||
|
||||
Operand ptr = {};
|
||||
Operand values = {};
|
||||
Operand mask = {};
|
||||
check_expr(c, &ptr, ce->args[0]); if (ptr.mode == Addressing_Invalid) return false;
|
||||
check_expr(c, &values, ce->args[1]); if (values.mode == Addressing_Invalid) return false;
|
||||
check_expr(c, &mask, ce->args[2]); if (mask.mode == Addressing_Invalid) return false;
|
||||
if (!is_type_simd_vector(values.type)) { error(values.expr, "'%.*s' expected a simd vector type", LIT(builtin_name)); return false; }
|
||||
if (!is_type_simd_vector(mask.type)) { error(mask.expr, "'%.*s' expected a simd vector type", LIT(builtin_name)); return false; }
|
||||
|
||||
if (id == BuiltinProc_simd_gather || id == BuiltinProc_simd_scatter) {
|
||||
if (!is_type_simd_vector(ptr.type)) { error(ptr.expr, "'%.*s' expected a simd vector type", LIT(builtin_name)); return false; }
|
||||
Type *ptr_elem = base_array_type(ptr.type);
|
||||
if (!is_type_rawptr(ptr_elem)) {
|
||||
gbString s = type_to_string(ptr.type);
|
||||
error(ptr.expr, "Expected a simd vector of 'rawptr' for the addresses, got %s", s);
|
||||
gb_string_free(s);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!is_type_pointer(ptr.type)) {
|
||||
gbString s = type_to_string(ptr.type);
|
||||
error(ptr.expr, "Expected a pointer type for the address, got %s", s);
|
||||
gb_string_free(s);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Type *mask_elem = base_array_type(mask.type);
|
||||
|
||||
if (!is_type_integer(mask_elem) && !is_type_boolean(mask_elem)) {
|
||||
gbString s = type_to_string(mask.type);
|
||||
error(mask.expr, "Expected a simd vector of integers or booleans for the mask, got %s", s);
|
||||
gb_string_free(s);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (id == BuiltinProc_simd_gather || id == BuiltinProc_simd_scatter) {
|
||||
i64 ptr_count = get_array_type_count(ptr.type);
|
||||
i64 values_count = get_array_type_count(values.type);
|
||||
i64 mask_count = get_array_type_count(mask.type);
|
||||
if (ptr_count != values_count ||
|
||||
values_count != mask_count ||
|
||||
mask_count != ptr_count) {
|
||||
gbString s = type_to_string(mask.type);
|
||||
error(mask.expr, "All simd vectors must be of the same length, got %lld vs %lld vs %lld", cast(long long)ptr_count, cast(long long)values_count, cast(long long)mask_count);
|
||||
gb_string_free(s);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
i64 values_count = get_array_type_count(values.type);
|
||||
i64 mask_count = get_array_type_count(mask.type);
|
||||
if (values_count != mask_count) {
|
||||
gbString s = type_to_string(mask.type);
|
||||
error(mask.expr, "All simd vectors must be of the same length, got %lld vs %lld", cast(long long)values_count, cast(long long)mask_count);
|
||||
gb_string_free(s);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (id == BuiltinProc_simd_gather ||
|
||||
id == BuiltinProc_simd_masked_load ||
|
||||
id == BuiltinProc_simd_masked_expand_load) {
|
||||
operand->mode = Addressing_Value;
|
||||
operand->type = values.type;
|
||||
} else {
|
||||
operand->mode = Addressing_NoValue;
|
||||
operand->type = nullptr;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
case BuiltinProc_simd_extract:
|
||||
{
|
||||
Operand x = {};
|
||||
@@ -775,6 +865,29 @@ gb_internal bool check_builtin_simd_operation(CheckerContext *c, Operand *operan
|
||||
return true;
|
||||
}
|
||||
|
||||
case BuiltinProc_simd_reduce_any:
|
||||
case BuiltinProc_simd_reduce_all:
|
||||
{
|
||||
Operand x = {};
|
||||
check_expr(c, &x, ce->args[0]); if (x.mode == Addressing_Invalid) return false;
|
||||
|
||||
if (!is_type_simd_vector(x.type)) {
|
||||
error(x.expr, "'%.*s' expected a simd vector type", LIT(builtin_name));
|
||||
return false;
|
||||
}
|
||||
Type *elem = base_array_type(x.type);
|
||||
if (!is_type_boolean(elem)) {
|
||||
gbString xs = type_to_string(x.type);
|
||||
error(x.expr, "'%.*s' expected a #simd type with a boolean element, got '%s'", LIT(builtin_name), xs);
|
||||
gb_string_free(xs);
|
||||
return false;
|
||||
}
|
||||
|
||||
operand->mode = Addressing_Value;
|
||||
operand->type = t_untyped_bool;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
case BuiltinProc_simd_shuffle:
|
||||
{
|
||||
@@ -1679,7 +1792,10 @@ gb_internal bool check_builtin_procedure_directive(CheckerContext *c, Operand *o
|
||||
error(call, "'#assert' expects either 1 or 2 arguments, got %td", ce->args.count);
|
||||
return false;
|
||||
}
|
||||
if (!is_type_boolean(operand->type) || operand->mode != Addressing_Constant) {
|
||||
|
||||
// operand->type can be nil if the condition is a procedure, for example: #assert(assert())
|
||||
// So let's check it before we use it, so we get the same error as if we wrote `#exists(assert())
|
||||
if (operand->type == nullptr || !is_type_boolean(operand->type) || operand->mode != Addressing_Constant) {
|
||||
gbString str = expr_to_string(ce->args[0]);
|
||||
error(call, "'%s' is not a constant boolean", str);
|
||||
gb_string_free(str);
|
||||
@@ -1949,6 +2065,14 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
return ok;
|
||||
}
|
||||
|
||||
if (BuiltinProc__atomic_begin < id && id < BuiltinProc__atomic_end) {
|
||||
if (build_context.metrics.arch == TargetArch_riscv64) {
|
||||
if (!check_target_feature_is_enabled(str_lit("a"), nullptr)) {
|
||||
error(call, "missing required target feature \"a\" for atomics, enable it by setting a different -microarch or explicitly adding it through -target-features");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (id) {
|
||||
default:
|
||||
GB_PANIC("Implement built-in procedure: %.*s", LIT(builtin_name));
|
||||
@@ -2474,7 +2598,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
arg_count++;
|
||||
}
|
||||
|
||||
if (arg_count > max_count) {
|
||||
if (false && arg_count > max_count) {
|
||||
error(call, "Too many 'swizzle' indices, %td > %td", arg_count, max_count);
|
||||
return false;
|
||||
} else if (arg_count < 2) {
|
||||
@@ -3885,6 +4009,23 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
break;
|
||||
}
|
||||
|
||||
case BuiltinProc_constant_log2: {
|
||||
Operand o = {};
|
||||
check_expr(c, &o, ce->args[0]);
|
||||
|
||||
if (!is_type_integer(o.type) && (o.mode != Addressing_Constant)) {
|
||||
error(ce->args[0], "Expected a constant integer for '%.*s'", LIT(builtin_name));
|
||||
return false;
|
||||
}
|
||||
|
||||
int log2 = big_int_log2(&o.value.value_integer);
|
||||
|
||||
operand->mode = Addressing_Constant;
|
||||
operand->value = exact_value_i64(cast(i64)log2);
|
||||
operand->type = t_untyped_integer;
|
||||
break;
|
||||
}
|
||||
|
||||
case BuiltinProc_soa_struct: {
|
||||
Operand x = {};
|
||||
Operand y = {};
|
||||
@@ -4316,8 +4457,8 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
}
|
||||
break;
|
||||
|
||||
case BuiltinProc_add_sat:
|
||||
case BuiltinProc_sub_sat:
|
||||
case BuiltinProc_saturating_add:
|
||||
case BuiltinProc_saturating_sub:
|
||||
{
|
||||
Operand x = {};
|
||||
Operand y = {};
|
||||
@@ -5076,6 +5217,16 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sz >= 64) {
|
||||
if (is_type_unsigned(x.type)) {
|
||||
add_package_dependency(c, "runtime", "umodti3", true);
|
||||
add_package_dependency(c, "runtime", "udivti3", true);
|
||||
} else {
|
||||
add_package_dependency(c, "runtime", "modti3", true);
|
||||
add_package_dependency(c, "runtime", "divti3", true);
|
||||
}
|
||||
}
|
||||
|
||||
operand->type = x.type;
|
||||
operand->mode = Addressing_Value;
|
||||
}
|
||||
@@ -5549,6 +5700,59 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case BuiltinProc_type_has_shared_fields:
|
||||
{
|
||||
Type *u = check_type(c, ce->args[0]);
|
||||
Type *ut = base_type(u);
|
||||
if (ut == nullptr || ut == t_invalid) {
|
||||
error(ce->args[0], "Expected a type for '%.*s'", LIT(builtin_name));
|
||||
return false;
|
||||
}
|
||||
if (ut->kind != Type_Struct || ut->Struct.soa_kind != StructSoa_None) {
|
||||
gbString t = type_to_string(ut);
|
||||
error(ce->args[0], "Expected a struct type for '%.*s', got %s", LIT(builtin_name), t);
|
||||
gb_string_free(t);
|
||||
return false;
|
||||
}
|
||||
|
||||
Type *v = check_type(c, ce->args[1]);
|
||||
Type *vt = base_type(v);
|
||||
if (vt == nullptr || vt == t_invalid) {
|
||||
error(ce->args[1], "Expected a type for '%.*s'", LIT(builtin_name));
|
||||
return false;
|
||||
}
|
||||
if (vt->kind != Type_Struct || vt->Struct.soa_kind != StructSoa_None) {
|
||||
gbString t = type_to_string(vt);
|
||||
error(ce->args[1], "Expected a struct type for '%.*s', got %s", LIT(builtin_name), t);
|
||||
gb_string_free(t);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool is_shared = true;
|
||||
|
||||
for (Entity *v_field : vt->Struct.fields) {
|
||||
bool found = false;
|
||||
for (Entity *u_field : ut->Struct.fields) {
|
||||
if (v_field->token.string == u_field->token.string &&
|
||||
are_types_identical(v_field->type, u_field->type)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
is_shared = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
operand->mode = Addressing_Constant;
|
||||
operand->value = exact_value_bool(is_shared);
|
||||
operand->type = t_untyped_bool;
|
||||
break;
|
||||
}
|
||||
|
||||
case BuiltinProc_type_field_type:
|
||||
{
|
||||
Operand op = {};
|
||||
|
||||
Reference in New Issue
Block a user