mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-24 00:17:54 +00:00
Merge branch 'odin-lang:master' into attr_error
This commit is contained in:
+28
-6
@@ -262,6 +262,7 @@ struct BuildContext {
|
||||
String microarch;
|
||||
BuildModeKind build_mode;
|
||||
bool generate_docs;
|
||||
bool custom_optimization_level;
|
||||
i32 optimization_level;
|
||||
bool show_timings;
|
||||
TimingsExportFormat export_timings_format;
|
||||
@@ -1272,6 +1273,12 @@ gb_internal void init_build_context(TargetMetrics *cross_target) {
|
||||
gb_exit(1);
|
||||
}
|
||||
|
||||
if (bc->ODIN_DEBUG && !bc->custom_optimization_level) {
|
||||
// NOTE(bill): when building with `-debug` but not specifying an optimization level
|
||||
// default to `-o:none` to improve the debug symbol generation by default
|
||||
bc->optimization_level = -1; // -o:none
|
||||
}
|
||||
|
||||
bc->optimization_level = gb_clamp(bc->optimization_level, -1, 2);
|
||||
|
||||
// ENFORCE DYNAMIC MAP CALLS
|
||||
@@ -1285,9 +1292,6 @@ gb_internal void init_build_context(TargetMetrics *cross_target) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#undef LINK_FLAG_X64
|
||||
#undef LINK_FLAG_386
|
||||
}
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
@@ -1497,13 +1501,23 @@ gb_internal bool init_build_paths(String init_filename) {
|
||||
} else if (is_arch_wasm()) {
|
||||
output_extension = STR_LIT("wasm");
|
||||
} else if (build_context.build_mode == BuildMode_Executable) {
|
||||
// By default use a .bin executable extension.
|
||||
output_extension = STR_LIT("bin");
|
||||
// By default use no executable extension.
|
||||
output_extension = make_string(nullptr, 0);
|
||||
String const single_file_extension = str_lit(".odin");
|
||||
|
||||
if (build_context.metrics.os == TargetOs_windows) {
|
||||
output_extension = STR_LIT("exe");
|
||||
} else if (build_context.cross_compiling && selected_target_metrics->metrics == &target_essence_amd64) {
|
||||
output_extension = make_string(nullptr, 0);
|
||||
// Do nothing: we don't want the .bin extension
|
||||
// when cross compiling
|
||||
} else if (path_is_directory(last_path_element(bc->build_paths[BuildPath_Main_Package].basename))) {
|
||||
// Add .bin extension to avoid collision
|
||||
// with package directory name
|
||||
output_extension = STR_LIT("bin");
|
||||
} else if (string_ends_with(init_filename, single_file_extension) && path_is_directory(remove_extension_from_path(init_filename))) {
|
||||
// Add bin extension if compiling single-file package
|
||||
// with same output name as a directory
|
||||
output_extension = STR_LIT("bin");
|
||||
}
|
||||
} else if (build_context.build_mode == BuildMode_DynamicLibrary) {
|
||||
// By default use a .so shared library extension.
|
||||
@@ -1615,6 +1629,14 @@ gb_internal bool init_build_paths(String init_filename) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!write_directory(bc->build_paths[BuildPath_Output].basename)) {
|
||||
String output_file = path_to_string(ha, bc->build_paths[BuildPath_Output]);
|
||||
defer (gb_free(ha, output_file.text));
|
||||
gb_printf_err("No write permissions for output path: %.*s\n", LIT(output_file));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (bc->target_features_string.len != 0) {
|
||||
enable_target_feature({}, bc->target_features_string);
|
||||
}
|
||||
|
||||
@@ -4843,6 +4843,89 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
}
|
||||
operand->mode = Addressing_Type;
|
||||
break;
|
||||
case BuiltinProc_type_merge:
|
||||
{
|
||||
operand->mode = Addressing_Type;
|
||||
operand->type = t_invalid;
|
||||
|
||||
Operand x = {};
|
||||
Operand y = {};
|
||||
check_expr_or_type(c, &x, ce->args[0]);
|
||||
check_expr_or_type(c, &y, ce->args[1]);
|
||||
if (x.mode != Addressing_Type) {
|
||||
error(x.expr, "Expected a type for '%.*s'", LIT(builtin_name));
|
||||
return false;
|
||||
}
|
||||
if (y.mode != Addressing_Type) {
|
||||
error(y.expr, "Expected a type for '%.*s'", LIT(builtin_name));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_type_polymorphic(x.type)) {
|
||||
gbString t = type_to_string(x.type);
|
||||
error(x.expr, "Expected a non-polymorphic type for '%.*s', got %s", LIT(builtin_name), t);
|
||||
gb_string_free(t);
|
||||
return false;
|
||||
}
|
||||
if (is_type_polymorphic(y.type)) {
|
||||
gbString t = type_to_string(y.type);
|
||||
error(y.expr, "Expected a non-polymorphic type for '%.*s', got %s", LIT(builtin_name), t);
|
||||
gb_string_free(t);
|
||||
return false;
|
||||
}
|
||||
if (!is_type_union(x.type)) {
|
||||
gbString t = type_to_string(x.type);
|
||||
error(x.expr, "Expected a union type for '%.*s', got %s", LIT(builtin_name), t);
|
||||
gb_string_free(t);
|
||||
return false;
|
||||
}
|
||||
if (!is_type_union(y.type)) {
|
||||
gbString t = type_to_string(y.type);
|
||||
error(x.expr, "Expected a union type for '%.*s', got %s", LIT(builtin_name), t);
|
||||
gb_string_free(t);
|
||||
return false;
|
||||
}
|
||||
Type *ux = base_type(x.type);
|
||||
Type *uy = base_type(y.type);
|
||||
GB_ASSERT(ux->kind == Type_Union);
|
||||
GB_ASSERT(uy->kind == Type_Union);
|
||||
|
||||
i64 custom_align = gb_max(ux->Union.custom_align, uy->Union.custom_align);
|
||||
if (ux->Union.kind != uy->Union.kind) {
|
||||
error(x.expr, "Union kinds must match, got %s vs %s", union_type_kind_strings[ux->Union.kind], union_type_kind_strings[uy->Union.kind]);
|
||||
}
|
||||
|
||||
Type *merged_union = alloc_type_union();
|
||||
|
||||
merged_union->Union.node = call;
|
||||
merged_union->Union.scope = create_scope(c->info, c->scope);
|
||||
merged_union->Union.kind = ux->Union.kind;
|
||||
merged_union->Union.custom_align = custom_align;
|
||||
|
||||
auto variants = array_make<Type *>(permanent_allocator(), 0, ux->Union.variants.count+uy->Union.variants.count);
|
||||
for (Type *t : ux->Union.variants) {
|
||||
array_add(&variants, t);
|
||||
}
|
||||
for (Type *t : uy->Union.variants) {
|
||||
bool ok = true;
|
||||
for (Type *other_t : ux->Union.variants) {
|
||||
if (are_types_identical(other_t, t)) {
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ok) {
|
||||
array_add(&variants, t);
|
||||
}
|
||||
|
||||
}
|
||||
merged_union->Union.variants = slice_from_array(variants);
|
||||
|
||||
operand->mode = Addressing_Type;
|
||||
operand->type = merged_union;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case BuiltinProc_type_is_boolean:
|
||||
case BuiltinProc_type_is_integer:
|
||||
|
||||
+14
-10
@@ -43,14 +43,20 @@ gb_internal Type *check_init_variable(CheckerContext *ctx, Entity *e, Operand *o
|
||||
}
|
||||
|
||||
if (operand->mode == Addressing_Type) {
|
||||
if (e->type != nullptr && is_type_typeid(e->type)) {
|
||||
if (e->type != nullptr && is_type_typeid(e->type) && !is_type_polymorphic(operand->type)) {
|
||||
add_type_info_type(ctx, operand->type);
|
||||
add_type_and_value(ctx, operand->expr, Addressing_Value, e->type, exact_value_typeid(operand->type));
|
||||
return e->type;
|
||||
} else {
|
||||
ERROR_BLOCK();
|
||||
|
||||
gbString t = type_to_string(operand->type);
|
||||
defer (gb_string_free(t));
|
||||
error(operand->expr, "Cannot assign a type '%s' to variable '%.*s'", t, LIT(e->token.string));
|
||||
if (is_type_polymorphic(operand->type)) {
|
||||
error(operand->expr, "Cannot assign a non-specialized polymorphic type '%s' to variable '%.*s'", t, LIT(e->token.string));
|
||||
} else {
|
||||
error(operand->expr, "Cannot assign a type '%s' to variable '%.*s'", t, LIT(e->token.string));
|
||||
}
|
||||
if (e->type == nullptr) {
|
||||
error_line("\tThe type of the variable '%.*s' cannot be inferred as a type does not have a default type\n", LIT(e->token.string));
|
||||
}
|
||||
@@ -59,20 +65,17 @@ gb_internal Type *check_init_variable(CheckerContext *ctx, Entity *e, Operand *o
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (e->type == nullptr) {
|
||||
|
||||
// NOTE(bill): Use the type of the operand
|
||||
Type *t = operand->type;
|
||||
if (is_type_untyped(t)) {
|
||||
if (t == t_invalid || is_type_untyped_nil(t)) {
|
||||
error(e->token, "Invalid use of untyped nil in %.*s", LIT(context_name));
|
||||
if (is_type_untyped_uninit(t)) {
|
||||
error(e->token, "Invalid use of --- in %.*s", LIT(context_name));
|
||||
e->type = t_invalid;
|
||||
return nullptr;
|
||||
}
|
||||
if (t == t_invalid || is_type_untyped_undef(t)) {
|
||||
error(e->token, "Invalid use of --- in %.*s", LIT(context_name));
|
||||
} else if (t == t_invalid || is_type_untyped_nil(t)) {
|
||||
error(e->token, "Invalid use of untyped nil in %.*s", LIT(context_name));
|
||||
e->type = t_invalid;
|
||||
return nullptr;
|
||||
}
|
||||
@@ -119,7 +122,7 @@ gb_internal void check_init_variables(CheckerContext *ctx, Entity **lhs, isize l
|
||||
// an extra allocation
|
||||
TEMPORARY_ALLOCATOR_GUARD();
|
||||
auto operands = array_make<Operand>(temporary_allocator(), 0, 2*lhs_count);
|
||||
check_unpack_arguments(ctx, lhs, lhs_count, &operands, inits, true, false);
|
||||
check_unpack_arguments(ctx, lhs, lhs_count, &operands, inits, UnpackFlag_AllowOk|UnpackFlag_AllowUndef);
|
||||
|
||||
isize rhs_count = operands.count;
|
||||
isize max = gb_min(lhs_count, rhs_count);
|
||||
@@ -947,6 +950,7 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
|
||||
|
||||
if (ac.require_declaration) {
|
||||
e->flags |= EntityFlag_Require;
|
||||
pl->inlining = ProcInlining_no_inline;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+53
-31
@@ -646,11 +646,8 @@ gb_internal i64 check_distance_between_types(CheckerContext *c, Operand *operand
|
||||
Type *src = base_type(s);
|
||||
Type *dst = base_type(type);
|
||||
|
||||
if (is_type_untyped_undef(src)) {
|
||||
if (type_has_undef(dst)) {
|
||||
return 1;
|
||||
}
|
||||
return -1;
|
||||
if (is_type_untyped_uninit(src)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (is_type_untyped_nil(src)) {
|
||||
@@ -993,13 +990,13 @@ gb_internal void check_assignment(CheckerContext *c, Operand *operand, Type *typ
|
||||
if (is_type_untyped(operand->type)) {
|
||||
Type *target_type = type;
|
||||
if (type == nullptr || is_type_any(type)) {
|
||||
if (type == nullptr && is_type_untyped_nil(operand->type)) {
|
||||
error(operand->expr, "Use of untyped nil in %.*s", LIT(context_name));
|
||||
if (type == nullptr && is_type_untyped_uninit(operand->type)) {
|
||||
error(operand->expr, "Use of --- in %.*s", LIT(context_name));
|
||||
operand->mode = Addressing_Invalid;
|
||||
return;
|
||||
}
|
||||
if (type == nullptr && is_type_untyped_undef(operand->type)) {
|
||||
error(operand->expr, "Use of --- in %.*s", LIT(context_name));
|
||||
if (type == nullptr && is_type_untyped_nil(operand->type)) {
|
||||
error(operand->expr, "Use of untyped nil in %.*s", LIT(context_name));
|
||||
operand->mode = Addressing_Invalid;
|
||||
return;
|
||||
}
|
||||
@@ -1067,7 +1064,7 @@ gb_internal void check_assignment(CheckerContext *c, Operand *operand, Type *typ
|
||||
|
||||
if (check_is_assignable_to(c, operand, type)) {
|
||||
if (operand->mode == Addressing_Type && is_type_typeid(type)) {
|
||||
add_type_info_type(c, operand->type);
|
||||
add_type_info_type(c, operand->type);
|
||||
add_type_and_value(c, operand->expr, Addressing_Value, type, exact_value_typeid(operand->type));
|
||||
}
|
||||
} else {
|
||||
@@ -3969,7 +3966,7 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar
|
||||
|
||||
|
||||
case Type_Union:
|
||||
if (!is_operand_nil(*operand) && !is_operand_undef(*operand)) {
|
||||
if (!is_operand_nil(*operand) && !is_operand_uninit(*operand)) {
|
||||
TEMPORARY_ALLOCATOR_GUARD();
|
||||
|
||||
isize count = t->Union.variants.count;
|
||||
@@ -4036,8 +4033,8 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar
|
||||
error_line("\n\n");
|
||||
|
||||
return;
|
||||
} else if (is_type_untyped_undef(operand->type) && type_has_undef(target_type)) {
|
||||
target_type = t_untyped_undef;
|
||||
} else if (is_type_untyped_uninit(operand->type)) {
|
||||
target_type = t_untyped_uninit;
|
||||
} else if (!is_type_untyped_nil(operand->type) || !type_has_nil(target_type)) {
|
||||
begin_error_block();
|
||||
defer (end_error_block());
|
||||
@@ -4070,8 +4067,8 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar
|
||||
|
||||
|
||||
default:
|
||||
if (is_type_untyped_undef(operand->type) && type_has_undef(target_type)) {
|
||||
target_type = t_untyped_undef;
|
||||
if (is_type_untyped_uninit(operand->type)) {
|
||||
target_type = t_untyped_uninit;
|
||||
} else if (is_type_untyped_nil(operand->type) && type_has_nil(target_type)) {
|
||||
target_type = t_untyped_nil;
|
||||
} else {
|
||||
@@ -4083,8 +4080,8 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar
|
||||
}
|
||||
|
||||
if (is_type_any(target_type) && is_type_untyped(operand->type)) {
|
||||
if (is_type_untyped_nil(operand->type) && is_type_untyped_undef(operand->type)) {
|
||||
|
||||
if (is_type_untyped_nil(operand->type) && is_type_untyped_uninit(operand->type)) {
|
||||
|
||||
} else {
|
||||
target_type = default_type(operand->type);
|
||||
}
|
||||
@@ -5144,8 +5141,20 @@ gb_internal bool check_assignment_arguments(CheckerContext *ctx, Array<Operand>
|
||||
}
|
||||
|
||||
|
||||
typedef u32 UnpackFlags;
|
||||
enum UnpackFlag : u32 {
|
||||
UnpackFlag_None = 0,
|
||||
UnpackFlag_AllowOk = 1<<0,
|
||||
UnpackFlag_IsVariadic = 1<<1,
|
||||
UnpackFlag_AllowUndef = 1<<2,
|
||||
};
|
||||
|
||||
|
||||
gb_internal bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize lhs_count, Array<Operand> *operands, Slice<Ast *> const &rhs, UnpackFlags flags) {
|
||||
bool allow_ok = (flags & UnpackFlag_AllowOk) != 0;
|
||||
bool is_variadic = (flags & UnpackFlag_IsVariadic) != 0;
|
||||
bool allow_undef = (flags & UnpackFlag_AllowUndef) != 0;
|
||||
|
||||
gb_internal bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize lhs_count, Array<Operand> *operands, Slice<Ast *> const &rhs, bool allow_ok, bool is_variadic) {
|
||||
bool optional_ok = false;
|
||||
isize tuple_index = 0;
|
||||
for_array(i, rhs) {
|
||||
@@ -5184,7 +5193,16 @@ gb_internal bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize
|
||||
}
|
||||
}
|
||||
|
||||
check_expr_base(c, &o, rhs[i], type_hint);
|
||||
Ast *rhs_expr = unparen_expr(rhs[i]);
|
||||
if (allow_undef && rhs_expr != nullptr && rhs_expr->kind == Ast_Uninit) {
|
||||
// NOTE(bill): Just handle this very specific logic here
|
||||
o.type = t_untyped_uninit;
|
||||
o.mode = Addressing_Value;
|
||||
o.expr = rhs[i];
|
||||
add_type_and_value(c, rhs[i], o.mode, o.type, o.value);
|
||||
} else {
|
||||
check_expr_base(c, &o, rhs[i], type_hint);
|
||||
}
|
||||
if (o.mode == Addressing_NoValue) {
|
||||
error_operand_no_value(&o);
|
||||
o.mode = Addressing_Invalid;
|
||||
@@ -5968,7 +5986,7 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op
|
||||
lhs = populate_proc_parameter_list(c, proc_type, &lhs_count, &is_variadic);
|
||||
}
|
||||
if (operand->mode != Addressing_ProcGroup) {
|
||||
check_unpack_arguments(c, lhs, lhs_count, &operands, args, false, is_variadic);
|
||||
check_unpack_arguments(c, lhs, lhs_count, &operands, args, is_variadic ? UnpackFlag_IsVariadic : UnpackFlag_None);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6025,7 +6043,7 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op
|
||||
isize lhs_count = -1;
|
||||
bool is_variadic = false;
|
||||
lhs = populate_proc_parameter_list(c, e->type, &lhs_count, &is_variadic);
|
||||
check_unpack_arguments(c, lhs, lhs_count, &operands, args, false, is_variadic);
|
||||
check_unpack_arguments(c, lhs, lhs_count, &operands, args, is_variadic ? UnpackFlag_IsVariadic : UnpackFlag_None);
|
||||
|
||||
CallArgumentData data = {};
|
||||
CallArgumentError err = call_checker(c, call, e->type, e, operands, CallArgumentMode_ShowErrors, &data);
|
||||
@@ -6101,7 +6119,7 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op
|
||||
}
|
||||
|
||||
|
||||
check_unpack_arguments(c, lhs, lhs_count, &operands, args, false, false);
|
||||
check_unpack_arguments(c, lhs, lhs_count, &operands, args, UnpackFlag_None);
|
||||
|
||||
if (lhs != nullptr) {
|
||||
gb_free(heap_allocator(), lhs);
|
||||
@@ -6462,7 +6480,7 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O
|
||||
lhs_count = params->variables.count;
|
||||
}
|
||||
|
||||
check_unpack_arguments(c, lhs, lhs_count, &operands, ce->args, false, false);
|
||||
check_unpack_arguments(c, lhs, lhs_count, &operands, ce->args, UnpackFlag_None);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -7146,11 +7164,11 @@ gb_internal bool check_set_index_data(Operand *o, Type *t, bool indirection, i64
|
||||
}
|
||||
|
||||
gb_internal bool ternary_compare_types(Type *x, Type *y) {
|
||||
if (is_type_untyped_undef(x) && type_has_undef(y)) {
|
||||
if (is_type_untyped_uninit(x)) {
|
||||
return true;
|
||||
} else if (is_type_untyped_nil(x) && type_has_nil(y)) {
|
||||
return true;
|
||||
} else if (is_type_untyped_undef(y) && type_has_undef(x)) {
|
||||
} else if (is_type_untyped_uninit(y)) {
|
||||
return true;
|
||||
} else if (is_type_untyped_nil(y) && type_has_nil(x)) {
|
||||
return true;
|
||||
@@ -7687,7 +7705,7 @@ gb_internal ExprKind check_ternary_if_expr(CheckerContext *c, Operand *o, Ast *n
|
||||
}
|
||||
|
||||
o->type = x.type;
|
||||
if (is_type_untyped_nil(o->type) || is_type_untyped_undef(o->type)) {
|
||||
if (is_type_untyped_nil(o->type) || is_type_untyped_uninit(o->type)) {
|
||||
o->type = y.type;
|
||||
}
|
||||
|
||||
@@ -7887,8 +7905,11 @@ gb_internal ExprKind check_or_return_expr(CheckerContext *c, Operand *o, Ast *no
|
||||
rhs.type = right_type;
|
||||
rhs.mode = Addressing_Value;
|
||||
|
||||
// TODO(bill): better error message
|
||||
if (!check_is_assignable_to(c, &rhs, end_type)) {
|
||||
if (is_type_boolean(right_type) && is_type_boolean(end_type)) {
|
||||
// NOTE(bill): allow implicit conversion between boolean types
|
||||
// within 'or_return' to improve the experience using third-party code
|
||||
} else if (!check_is_assignable_to(c, &rhs, end_type)) {
|
||||
// TODO(bill): better error message
|
||||
gbString a = type_to_string(right_type);
|
||||
gbString b = type_to_string(end_type);
|
||||
gbString ret_type = type_to_string(result_type);
|
||||
@@ -9577,9 +9598,10 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast
|
||||
check_ident(c, o, node, nullptr, type_hint, false);
|
||||
case_end;
|
||||
|
||||
case_ast_node(u, Undef, node);
|
||||
case_ast_node(u, Uninit, node);
|
||||
o->mode = Addressing_Value;
|
||||
o->type = t_untyped_undef;
|
||||
o->type = t_untyped_uninit;
|
||||
error(node, "Use of --- outside of variable declaration");
|
||||
case_end;
|
||||
|
||||
|
||||
@@ -10142,7 +10164,7 @@ gb_internal gbString write_expr_to_string(gbString str, Ast *node, bool shorthan
|
||||
str = string_append_string(str, bd->name.string);
|
||||
case_end;
|
||||
|
||||
case_ast_node(ud, Undef, node);
|
||||
case_ast_node(ud, Uninit, node);
|
||||
str = gb_string_appendc(str, "---");
|
||||
case_end;
|
||||
|
||||
|
||||
+26
-2
@@ -402,6 +402,12 @@ gb_internal Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, O
|
||||
|
||||
Type *assignment_type = lhs->type;
|
||||
|
||||
if (rhs->mode == Addressing_Type && is_type_polymorphic(rhs->type)) {
|
||||
gbString t = type_to_string(rhs->type);
|
||||
error(rhs->expr, "Invalid use of a non-specialized polymorphic type '%s'", t);
|
||||
gb_string_free(t);
|
||||
}
|
||||
|
||||
switch (lhs->mode) {
|
||||
case Addressing_Invalid:
|
||||
return nullptr;
|
||||
@@ -1455,6 +1461,7 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags)
|
||||
bool is_map = false;
|
||||
bool use_by_reference_for_value = false;
|
||||
bool is_soa = false;
|
||||
bool is_reverse = rs->reverse;
|
||||
|
||||
Ast *expr = unparen_expr(rs->expr);
|
||||
|
||||
@@ -1470,6 +1477,10 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags)
|
||||
}
|
||||
array_add(&vals, x.type);
|
||||
array_add(&vals, t_int);
|
||||
|
||||
if (is_reverse) {
|
||||
error(node, "#reverse for is not supported with ranges, prefer an explicit for loop with init, condition, and post arguments");
|
||||
}
|
||||
} else {
|
||||
Operand operand = {Addressing_Invalid};
|
||||
check_expr_base(ctx, &operand, expr, nullptr);
|
||||
@@ -1482,6 +1493,9 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags)
|
||||
gb_string_free(t);
|
||||
goto skip_expr_range_stmt;
|
||||
} else {
|
||||
if (is_reverse) {
|
||||
error(node, "#reverse for is not supported for enum types");
|
||||
}
|
||||
array_add(&vals, operand.type);
|
||||
array_add(&vals, t_int);
|
||||
add_type_info_type(ctx, operand.type);
|
||||
@@ -1495,7 +1509,11 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags)
|
||||
if (is_type_string(t) && t->Basic.kind != Basic_cstring) {
|
||||
array_add(&vals, t_rune);
|
||||
array_add(&vals, t_int);
|
||||
add_package_dependency(ctx, "runtime", "string_decode_rune");
|
||||
if (is_reverse) {
|
||||
add_package_dependency(ctx, "runtime", "string_decode_last_rune");
|
||||
} else {
|
||||
add_package_dependency(ctx, "runtime", "string_decode_rune");
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1528,6 +1546,9 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags)
|
||||
is_map = true;
|
||||
array_add(&vals, t->Map.key);
|
||||
array_add(&vals, t->Map.value);
|
||||
if (is_reverse) {
|
||||
error(node, "#reverse for is not supported for map types, as maps are unordered");
|
||||
}
|
||||
break;
|
||||
|
||||
case Type_Tuple:
|
||||
@@ -1564,6 +1585,9 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags)
|
||||
break;
|
||||
}
|
||||
|
||||
if (is_reverse) {
|
||||
error(node, "#reverse for is not supported for multiple return valued parameters");
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -2170,7 +2194,7 @@ gb_internal void check_return_stmt(CheckerContext *ctx, Ast *node) {
|
||||
auto operands = array_make<Operand>(heap_allocator(), 0, 2*rs->results.count);
|
||||
defer (array_free(&operands));
|
||||
|
||||
check_unpack_arguments(ctx, result_entities, result_count, &operands, rs->results, true, false);
|
||||
check_unpack_arguments(ctx, result_entities, result_count, &operands, rs->results, UnpackFlag_AllowOk);
|
||||
|
||||
if (result_count == 0 && rs->results.count > 0) {
|
||||
error(rs->results[0], "No return values expected");
|
||||
|
||||
+3
-3
@@ -135,7 +135,7 @@ gb_internal void check_struct_fields(CheckerContext *ctx, Ast *node, Slice<Entit
|
||||
type = t_invalid;
|
||||
}
|
||||
if (is_type_untyped(type)) {
|
||||
if (is_type_untyped_undef(type)) {
|
||||
if (is_type_untyped_uninit(type)) {
|
||||
error(params[i], "Cannot determine parameter type from ---");
|
||||
} else {
|
||||
error(params[i], "Cannot determine parameter type from a nil");
|
||||
@@ -473,7 +473,7 @@ gb_internal Type *check_record_polymorphic_params(CheckerContext *ctx, Ast *poly
|
||||
type = t_invalid;
|
||||
}
|
||||
if (is_type_untyped(type)) {
|
||||
if (is_type_untyped_undef(type)) {
|
||||
if (is_type_untyped_uninit(type)) {
|
||||
error(params[i], "Cannot determine parameter type from ---");
|
||||
} else {
|
||||
error(params[i], "Cannot determine parameter type from a nil");
|
||||
@@ -1528,7 +1528,7 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para
|
||||
type = t_invalid;
|
||||
}
|
||||
if (is_type_untyped(type)) {
|
||||
if (is_type_untyped_undef(type)) {
|
||||
if (is_type_untyped_uninit(type)) {
|
||||
error(param, "Cannot determine parameter type from ---");
|
||||
} else {
|
||||
error(param, "Cannot determine parameter type from a nil");
|
||||
|
||||
+2
-2
@@ -27,8 +27,8 @@ gb_internal bool is_operand_value(Operand o) {
|
||||
gb_internal bool is_operand_nil(Operand o) {
|
||||
return o.mode == Addressing_Value && o.type == t_untyped_nil;
|
||||
}
|
||||
gb_internal bool is_operand_undef(Operand o) {
|
||||
return o.mode == Addressing_Value && o.type == t_untyped_undef;
|
||||
gb_internal bool is_operand_uninit(Operand o) {
|
||||
return o.mode == Addressing_Value && o.type == t_untyped_uninit;
|
||||
}
|
||||
|
||||
gb_internal bool check_rtti_type_disallowed(Token const &token, Type *type, char const *format) {
|
||||
|
||||
@@ -203,6 +203,7 @@ BuiltinProc__type_begin,
|
||||
BuiltinProc_type_elem_type,
|
||||
|
||||
BuiltinProc_type_convert_variants_to_pointers,
|
||||
BuiltinProc_type_merge,
|
||||
|
||||
BuiltinProc__type_simple_boolean_begin,
|
||||
BuiltinProc_type_is_boolean,
|
||||
@@ -501,6 +502,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
|
||||
{STR_LIT("type_core_type"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_elem_type"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_convert_variants_to_pointers"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_merge"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
|
||||
{STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_is_boolean"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
|
||||
+68
-12
@@ -30,6 +30,7 @@ struct OdinDocWriter {
|
||||
PtrMap<AstPackage *, OdinDocPkgIndex> pkg_cache;
|
||||
PtrMap<Entity *, OdinDocEntityIndex> entity_cache;
|
||||
PtrMap<Type *, OdinDocTypeIndex> type_cache;
|
||||
PtrMap<Type *, Type *> stable_type_cache;
|
||||
|
||||
OdinDocWriterItemTracker<OdinDocFile> files;
|
||||
OdinDocWriterItemTracker<OdinDocPkg> pkgs;
|
||||
@@ -51,6 +52,7 @@ gb_internal void odin_doc_writer_item_tracker_init(OdinDocWriterItemTracker<T> *
|
||||
|
||||
|
||||
gb_internal void odin_doc_writer_prepare(OdinDocWriter *w) {
|
||||
debugf("odin_doc_writer_prepare\n");
|
||||
w->state = OdinDocWriterState_Preparing;
|
||||
|
||||
string_map_init(&w->string_cache);
|
||||
@@ -59,6 +61,7 @@ gb_internal void odin_doc_writer_prepare(OdinDocWriter *w) {
|
||||
map_init(&w->pkg_cache);
|
||||
map_init(&w->entity_cache);
|
||||
map_init(&w->type_cache);
|
||||
map_init(&w->stable_type_cache);
|
||||
|
||||
odin_doc_writer_item_tracker_init(&w->files, 1);
|
||||
odin_doc_writer_item_tracker_init(&w->pkgs, 1);
|
||||
@@ -70,6 +73,7 @@ gb_internal void odin_doc_writer_prepare(OdinDocWriter *w) {
|
||||
|
||||
|
||||
gb_internal void odin_doc_writer_destroy(OdinDocWriter *w) {
|
||||
debugf("odin_doc_writer_destroy\n");
|
||||
gb_free(heap_allocator(), w->data);
|
||||
|
||||
string_map_destroy(&w->string_cache);
|
||||
@@ -77,6 +81,7 @@ gb_internal void odin_doc_writer_destroy(OdinDocWriter *w) {
|
||||
map_destroy(&w->pkg_cache);
|
||||
map_destroy(&w->entity_cache);
|
||||
map_destroy(&w->type_cache);
|
||||
map_destroy(&w->stable_type_cache);
|
||||
}
|
||||
|
||||
|
||||
@@ -102,6 +107,7 @@ gb_internal isize odin_doc_writer_calc_total_size(OdinDocWriter *w) {
|
||||
}
|
||||
|
||||
gb_internal void odin_doc_writer_start_writing(OdinDocWriter *w) {
|
||||
debugf("odin_doc_writer_start_writing\n");
|
||||
w->state = OdinDocWriterState_Writing;
|
||||
|
||||
string_map_clear(&w->string_cache);
|
||||
@@ -138,6 +144,7 @@ gb_internal void odin_doc_writer_assign_tracker(OdinDocArray<T> *array, OdinDocW
|
||||
|
||||
|
||||
gb_internal void odin_doc_writer_end_writing(OdinDocWriter *w) {
|
||||
debugf("odin_doc_writer_end_writing\n");
|
||||
OdinDocHeader *h = w->header;
|
||||
|
||||
gb_memmove(h->base.magic, OdinDocHeader_MagicString, gb_strlen(OdinDocHeader_MagicString));
|
||||
@@ -471,22 +478,60 @@ gb_internal OdinDocArray<OdinDocEntityIndex> odin_doc_add_entity_as_slice(OdinDo
|
||||
return odin_write_item_as_slice(w, index);
|
||||
}
|
||||
|
||||
|
||||
|
||||
gb_internal OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type) {
|
||||
if (type == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Type **mapped_type = map_get(&w->stable_type_cache, type); // may map to itself
|
||||
// if (mapped_type && *mapped_type) {
|
||||
// type = *mapped_type;
|
||||
// }
|
||||
|
||||
OdinDocTypeIndex *found = map_get(&w->type_cache, type);
|
||||
if (found) {
|
||||
return *found;
|
||||
}
|
||||
for (auto const &entry : w->type_cache) {
|
||||
// NOTE(bill): THIS IS SLOW
|
||||
Type *other = entry.key;
|
||||
if (are_types_identical_unique_tuples(type, other)) {
|
||||
OdinDocTypeIndex index = entry.value;
|
||||
map_set(&w->type_cache, type, index);
|
||||
return index;
|
||||
Type *x = type;
|
||||
Type *y = entry.key;
|
||||
|
||||
if (x == y) {
|
||||
goto do_set;
|
||||
}
|
||||
|
||||
if (!x | !y) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (x->kind == Type_Named) {
|
||||
Entity *e = x->Named.type_name;
|
||||
if (e->TypeName.is_type_alias) {
|
||||
x = x->Named.base;
|
||||
}
|
||||
}
|
||||
if (y->kind == Type_Named) {
|
||||
Entity *e = y->Named.type_name;
|
||||
if (e->TypeName.is_type_alias) {
|
||||
y = y->Named.base;
|
||||
}
|
||||
}
|
||||
if (x->kind != y->kind) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!are_types_identical_internal(x, y, true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
do_set:
|
||||
OdinDocTypeIndex index = entry.value;
|
||||
map_set(&w->type_cache, type, index);
|
||||
map_set(&w->stable_type_cache, type, entry.key);
|
||||
return index;
|
||||
}
|
||||
|
||||
|
||||
@@ -495,6 +540,7 @@ gb_internal OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type) {
|
||||
OdinDocTypeIndex type_index = 0;
|
||||
type_index = odin_doc_write_item(w, &w->types, &doc_type, &dst);
|
||||
map_set(&w->type_cache, type, type_index);
|
||||
map_set(&w->stable_type_cache, type, type);
|
||||
|
||||
switch (type->kind) {
|
||||
case Type_Basic:
|
||||
@@ -856,13 +902,12 @@ gb_internal OdinDocEntityIndex odin_doc_add_entity(OdinDocWriter *w, Entity *e)
|
||||
break;
|
||||
}
|
||||
|
||||
if (e->flags & EntityFlag_Param) {
|
||||
if (e->flags & EntityFlag_Using) { flags |= OdinDocEntityFlag_Param_Using; }
|
||||
if (e->flags & EntityFlag_ConstInput) { flags |= OdinDocEntityFlag_Param_Const; }
|
||||
if (e->flags & EntityFlag_Ellipsis) { flags |= OdinDocEntityFlag_Param_Ellipsis; }
|
||||
if (e->flags & EntityFlag_NoAlias) { flags |= OdinDocEntityFlag_Param_NoAlias; }
|
||||
if (e->flags & EntityFlag_AnyInt) { flags |= OdinDocEntityFlag_Param_AnyInt; }
|
||||
}
|
||||
if (e->flags & EntityFlag_Using) { flags |= OdinDocEntityFlag_Param_Using; }
|
||||
if (e->flags & EntityFlag_ConstInput) { flags |= OdinDocEntityFlag_Param_Const; }
|
||||
if (e->flags & EntityFlag_Ellipsis) { flags |= OdinDocEntityFlag_Param_Ellipsis; }
|
||||
if (e->flags & EntityFlag_NoAlias) { flags |= OdinDocEntityFlag_Param_NoAlias; }
|
||||
if (e->flags & EntityFlag_AnyInt) { flags |= OdinDocEntityFlag_Param_AnyInt; }
|
||||
|
||||
if (e->scope && (e->scope->flags & (ScopeFlag_File|ScopeFlag_Pkg)) && !is_entity_exported(e)) {
|
||||
flags |= OdinDocEntityFlag_Private;
|
||||
}
|
||||
@@ -910,6 +955,8 @@ gb_internal OdinDocEntityIndex odin_doc_add_entity(OdinDocWriter *w, Entity *e)
|
||||
}
|
||||
|
||||
gb_internal void odin_doc_update_entities(OdinDocWriter *w) {
|
||||
debugf("odin_doc_update_entities %s\n", w->state ? "preparing" : "writing");
|
||||
|
||||
{
|
||||
// NOTE(bill): Double pass, just in case entities are created on odin_doc_type
|
||||
auto entities = array_make<Entity *>(heap_allocator(), 0, w->entity_cache.count);
|
||||
@@ -974,6 +1021,8 @@ gb_internal OdinDocArray<OdinDocScopeEntry> odin_doc_add_pkg_entries(OdinDocWrit
|
||||
return {};
|
||||
}
|
||||
|
||||
debugf("odin_doc_add_pkg_entries %s -> package %.*s\n", w->state ? "preparing" : "writing", LIT(pkg->name));
|
||||
|
||||
auto entries = array_make<OdinDocScopeEntry>(heap_allocator(), 0, w->entity_cache.count);
|
||||
defer (array_free(&entries));
|
||||
|
||||
@@ -1017,6 +1066,8 @@ gb_internal OdinDocArray<OdinDocScopeEntry> odin_doc_add_pkg_entries(OdinDocWrit
|
||||
|
||||
|
||||
gb_internal void odin_doc_write_docs(OdinDocWriter *w) {
|
||||
debugf("odin_doc_write_docs %s", w->state ? "preparing" : "writing");
|
||||
|
||||
auto pkgs = array_make<AstPackage *>(heap_allocator(), 0, w->info->packages.count);
|
||||
defer (array_free(&pkgs));
|
||||
for (auto const &entry : w->info->packages) {
|
||||
@@ -1032,6 +1083,7 @@ gb_internal void odin_doc_write_docs(OdinDocWriter *w) {
|
||||
}
|
||||
}
|
||||
|
||||
debugf("odin_doc_update_entities sort pkgs %s\n", w->state ? "preparing" : "writing");
|
||||
gb_sort_array(pkgs.data, pkgs.count, cmp_ast_package_by_name);
|
||||
|
||||
for_array(i, pkgs) {
|
||||
@@ -1092,6 +1144,7 @@ gb_internal void odin_doc_write_docs(OdinDocWriter *w) {
|
||||
|
||||
|
||||
gb_internal void odin_doc_write_to_file(OdinDocWriter *w, char const *filename) {
|
||||
debugf("odin_doc_write_to_file %s\n", filename);
|
||||
gbFile f = {};
|
||||
gbFileError err = gb_file_open_mode(&f, gbFileMode_Write, filename);
|
||||
if (err != gbFileError_None) {
|
||||
@@ -1102,6 +1155,7 @@ gb_internal void odin_doc_write_to_file(OdinDocWriter *w, char const *filename)
|
||||
defer (gb_file_close(&f));
|
||||
if (gb_file_write(&f, w->data, w->data_len)) {
|
||||
err = gb_file_truncate(&f, w->data_len);
|
||||
debugf("Wrote .odin-doc file to: %s\n", filename);
|
||||
gb_printf("Wrote .odin-doc file to: %s\n", filename);
|
||||
}
|
||||
}
|
||||
@@ -1112,6 +1166,8 @@ gb_internal void odin_doc_write(CheckerInfo *info, char const *filename) {
|
||||
defer (odin_doc_writer_destroy(w));
|
||||
w->info = info;
|
||||
|
||||
debugf("odin_doc_write %s\n", filename);
|
||||
|
||||
odin_doc_writer_prepare(w);
|
||||
odin_doc_write_docs(w);
|
||||
|
||||
|
||||
+14
-3
@@ -8,8 +8,9 @@ struct ErrorCollector {
|
||||
BlockingMutex string_mutex;
|
||||
RecursiveMutex block_mutex;
|
||||
|
||||
Array<u8> error_buffer;
|
||||
Array<String> errors;
|
||||
RecursiveMutex error_buffer_mutex;
|
||||
Array<u8> error_buffer;
|
||||
Array<String> errors;
|
||||
};
|
||||
|
||||
gb_global ErrorCollector global_error_collector;
|
||||
@@ -119,6 +120,7 @@ gb_internal void begin_error_block(void) {
|
||||
}
|
||||
|
||||
gb_internal void end_error_block(void) {
|
||||
mutex_lock(&global_error_collector.error_buffer_mutex);
|
||||
isize n = global_error_collector.error_buffer.count;
|
||||
if (n > 0) {
|
||||
u8 *text = global_error_collector.error_buffer.data;
|
||||
@@ -150,11 +152,16 @@ gb_internal void end_error_block(void) {
|
||||
text = gb_alloc_array(permanent_allocator(), u8, n+1);
|
||||
gb_memmove(text, global_error_collector.error_buffer.data, n);
|
||||
text[n] = 0;
|
||||
|
||||
|
||||
mutex_lock(&global_error_collector.error_out_mutex);
|
||||
String s = {text, n};
|
||||
array_add(&global_error_collector.errors, s);
|
||||
mutex_unlock(&global_error_collector.error_out_mutex);
|
||||
|
||||
global_error_collector.error_buffer.count = 0;
|
||||
}
|
||||
|
||||
mutex_unlock(&global_error_collector.error_buffer_mutex);
|
||||
global_error_collector.in_block.store(false);
|
||||
mutex_unlock(&global_error_collector.block_mutex);
|
||||
}
|
||||
@@ -172,11 +179,15 @@ gb_internal ERROR_OUT_PROC(default_error_out_va) {
|
||||
isize len = gb_snprintf_va(buf, gb_size_of(buf), fmt, va);
|
||||
isize n = len-1;
|
||||
if (global_error_collector.in_block) {
|
||||
mutex_lock(&global_error_collector.error_buffer_mutex);
|
||||
|
||||
isize cap = global_error_collector.error_buffer.count + n;
|
||||
array_reserve(&global_error_collector.error_buffer, cap);
|
||||
u8 *data = global_error_collector.error_buffer.data + global_error_collector.error_buffer.count;
|
||||
gb_memmove(data, buf, n);
|
||||
global_error_collector.error_buffer.count += n;
|
||||
|
||||
mutex_unlock(&global_error_collector.error_buffer_mutex);
|
||||
} else {
|
||||
mutex_lock(&global_error_collector.error_out_mutex);
|
||||
{
|
||||
|
||||
+27
-10
@@ -1179,7 +1179,11 @@ namespace lbAbiArm64 {
|
||||
if (is_register(type)) {
|
||||
args[i] = non_struct(c, type);
|
||||
} else if (is_homogenous_aggregate(c, type, &homo_base_type, &homo_member_count)) {
|
||||
args[i] = lb_arg_type_direct(type, LLVMArrayType(homo_base_type, homo_member_count), nullptr, nullptr);
|
||||
if (is_homogenous_aggregate_small_enough(homo_base_type, homo_member_count)) {
|
||||
args[i] = lb_arg_type_direct(type, LLVMArrayType(homo_base_type, homo_member_count), nullptr, nullptr);
|
||||
} else {
|
||||
args[i] = lb_arg_type_indirect(type, nullptr);;
|
||||
}
|
||||
} else {
|
||||
i64 size = lb_sizeof(type);
|
||||
if (size <= 16) {
|
||||
@@ -1213,7 +1217,7 @@ namespace lbAbiWasm {
|
||||
The approach taken optimizes for passing things in multiple
|
||||
registers/arguments if possible rather than by pointer.
|
||||
*/
|
||||
gb_internal Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count);
|
||||
gb_internal Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count, ProcCallingConvention calling_convention);
|
||||
gb_internal LB_ABI_COMPUTE_RETURN_TYPE(compute_return_type);
|
||||
|
||||
enum {MAX_DIRECT_STRUCT_SIZE = 32};
|
||||
@@ -1221,7 +1225,7 @@ namespace lbAbiWasm {
|
||||
gb_internal LB_ABI_INFO(abi_info) {
|
||||
lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType);
|
||||
ft->ctx = c;
|
||||
ft->args = compute_arg_types(c, arg_types, arg_count);
|
||||
ft->args = compute_arg_types(c, arg_types, arg_count, calling_convention);
|
||||
ft->ret = compute_return_type(ft, c, return_type, return_is_defined, return_is_tuple);
|
||||
ft->calling_convention = calling_convention;
|
||||
return ft;
|
||||
@@ -1258,13 +1262,26 @@ namespace lbAbiWasm {
|
||||
return false;
|
||||
}
|
||||
|
||||
gb_internal bool type_can_be_direct(LLVMTypeRef type) {
|
||||
gb_internal bool type_can_be_direct(LLVMTypeRef type, ProcCallingConvention calling_convention) {
|
||||
LLVMTypeKind kind = LLVMGetTypeKind(type);
|
||||
i64 sz = lb_sizeof(type);
|
||||
if (sz == 0) {
|
||||
return false;
|
||||
}
|
||||
if (sz <= MAX_DIRECT_STRUCT_SIZE) {
|
||||
if (calling_convention == ProcCC_CDecl) {
|
||||
// WASM Basic C ABI:
|
||||
// https://github.com/WebAssembly/tool-conventions/blob/main/BasicCABI.md#function-signatures
|
||||
if (kind == LLVMArrayTypeKind) {
|
||||
return false;
|
||||
} else if (kind == LLVMStructTypeKind) {
|
||||
unsigned count = LLVMCountStructElementTypes(type);
|
||||
if (count == 1) {
|
||||
return type_can_be_direct(LLVMStructGetTypeAtIndex(type, 0), calling_convention);
|
||||
}
|
||||
} else if (is_basic_register_type(type)) {
|
||||
return true;
|
||||
}
|
||||
} else if (sz <= MAX_DIRECT_STRUCT_SIZE) {
|
||||
if (kind == LLVMArrayTypeKind) {
|
||||
if (is_basic_register_type(OdinLLVMGetArrayElementType(type))) {
|
||||
return true;
|
||||
@@ -1284,7 +1301,7 @@ namespace lbAbiWasm {
|
||||
return false;
|
||||
}
|
||||
|
||||
gb_internal lbArgType is_struct(LLVMContextRef c, LLVMTypeRef type) {
|
||||
gb_internal lbArgType is_struct(LLVMContextRef c, LLVMTypeRef type, ProcCallingConvention calling_convention) {
|
||||
LLVMTypeKind kind = LLVMGetTypeKind(type);
|
||||
GB_ASSERT(kind == LLVMArrayTypeKind || kind == LLVMStructTypeKind);
|
||||
|
||||
@@ -1292,21 +1309,21 @@ namespace lbAbiWasm {
|
||||
if (sz == 0) {
|
||||
return lb_arg_type_ignore(type);
|
||||
}
|
||||
if (type_can_be_direct(type)) {
|
||||
if (type_can_be_direct(type, calling_convention)) {
|
||||
return lb_arg_type_direct(type);
|
||||
}
|
||||
return lb_arg_type_indirect(type, nullptr);
|
||||
}
|
||||
|
||||
|
||||
gb_internal Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count) {
|
||||
gb_internal Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count, ProcCallingConvention calling_convention) {
|
||||
auto args = array_make<lbArgType>(lb_function_type_args_allocator(), arg_count);
|
||||
|
||||
for (unsigned i = 0; i < arg_count; i++) {
|
||||
LLVMTypeRef t = arg_types[i];
|
||||
LLVMTypeKind kind = LLVMGetTypeKind(t);
|
||||
if (kind == LLVMStructTypeKind || kind == LLVMArrayTypeKind) {
|
||||
args[i] = is_struct(c, t);
|
||||
args[i] = is_struct(c, t, calling_convention);
|
||||
} else {
|
||||
args[i] = non_struct(c, t, false);
|
||||
}
|
||||
@@ -1318,7 +1335,7 @@ namespace lbAbiWasm {
|
||||
if (!return_is_defined) {
|
||||
return lb_arg_type_direct(LLVMVoidTypeInContext(c));
|
||||
} else if (lb_is_type_kind(return_type, LLVMStructTypeKind) || lb_is_type_kind(return_type, LLVMArrayTypeKind)) {
|
||||
if (type_can_be_direct(return_type)) {
|
||||
if (type_can_be_direct(return_type, ft->calling_convention)) {
|
||||
return lb_arg_type_direct(return_type);
|
||||
}
|
||||
|
||||
|
||||
+26
-15
@@ -720,6 +720,7 @@ gb_internal lbValue lb_map_set_proc_for_type(lbModule *m, Type *type) {
|
||||
lbBlock *check_grow_block = lb_create_block(p, "check-grow");
|
||||
lbBlock *grow_fail_block = lb_create_block(p, "grow-fail");
|
||||
lbBlock *insert_block = lb_create_block(p, "insert");
|
||||
lbBlock *rehash_block = lb_create_block(p, "rehash");
|
||||
|
||||
lb_emit_if(p, lb_emit_comp_against_nil(p, Token_NotEq, found_ptr), found_block, check_grow_block);
|
||||
lb_start_block(p, found_block);
|
||||
@@ -737,12 +738,19 @@ gb_internal lbValue lb_map_set_proc_for_type(lbModule *m, Type *type) {
|
||||
args[0] = lb_emit_conv(p, map_ptr, t_rawptr);
|
||||
args[1] = map_info;
|
||||
args[2] = lb_emit_load(p, location_ptr);
|
||||
lbValue grow_err = lb_emit_runtime_call(p, "__dynamic_map_check_grow", args);
|
||||
lbValue grow_err_and_has_grown = lb_emit_runtime_call(p, "__dynamic_map_check_grow", args);
|
||||
lbValue grow_err = lb_emit_struct_ev(p, grow_err_and_has_grown, 0);
|
||||
lbValue has_grown = lb_emit_struct_ev(p, grow_err_and_has_grown, 1);
|
||||
|
||||
lb_emit_if(p, lb_emit_comp_against_nil(p, Token_NotEq, grow_err), grow_fail_block, insert_block);
|
||||
|
||||
lb_start_block(p, grow_fail_block);
|
||||
LLVMBuildRet(p->builder, LLVMConstNull(lb_type(m, t_rawptr)));
|
||||
|
||||
lb_emit_if(p, has_grown, grow_fail_block, rehash_block);
|
||||
lb_start_block(p, rehash_block);
|
||||
lbValue key = lb_emit_load(p, key_ptr);
|
||||
hash = lb_gen_map_key_hash(p, map_ptr, key, nullptr);
|
||||
}
|
||||
|
||||
lb_start_block(p, insert_block);
|
||||
@@ -916,7 +924,7 @@ gb_internal lbValue lb_const_hash(lbModule *m, lbValue key, Type *key_type) {
|
||||
return hashed_key;
|
||||
}
|
||||
|
||||
gb_internal lbValue lb_gen_map_key_hash(lbProcedure *p, lbValue key, Type *key_type, lbValue *key_ptr_) {
|
||||
gb_internal lbValue lb_gen_map_key_hash(lbProcedure *p, lbValue const &map_ptr, lbValue key, lbValue *key_ptr_) {
|
||||
TEMPORARY_ALLOCATOR_GUARD();
|
||||
|
||||
lbValue key_ptr = lb_address_from_load_or_generate_local(p, key);
|
||||
@@ -924,13 +932,22 @@ gb_internal lbValue lb_gen_map_key_hash(lbProcedure *p, lbValue key, Type *key_t
|
||||
|
||||
if (key_ptr_) *key_ptr_ = key_ptr;
|
||||
|
||||
Type* key_type = base_type(type_deref(map_ptr.type))->Map.key;
|
||||
|
||||
lbValue hashed_key = lb_const_hash(p->module, key, key_type);
|
||||
if (hashed_key.value == nullptr) {
|
||||
lbValue hasher = lb_hasher_proc_for_type(p->module, key_type);
|
||||
|
||||
lbValue seed = {};
|
||||
{
|
||||
auto args = array_make<lbValue>(temporary_allocator(), 1);
|
||||
args[0] = lb_map_data_uintptr(p, lb_emit_load(p, map_ptr));
|
||||
seed = lb_emit_runtime_call(p, "map_seed_from_map_data", args);
|
||||
}
|
||||
|
||||
auto args = array_make<lbValue>(temporary_allocator(), 2);
|
||||
args[0] = key_ptr;
|
||||
args[1] = lb_const_int(p->module, t_uintptr, 0);
|
||||
args[1] = seed;
|
||||
hashed_key = lb_emit_call(p, hasher, args);
|
||||
}
|
||||
|
||||
@@ -945,7 +962,7 @@ gb_internal lbValue lb_internal_dynamic_map_get_ptr(lbProcedure *p, lbValue cons
|
||||
|
||||
lbValue ptr = {};
|
||||
lbValue key_ptr = {};
|
||||
lbValue hash = lb_gen_map_key_hash(p, key, map_type->Map.key, &key_ptr);
|
||||
lbValue hash = lb_gen_map_key_hash(p, map_ptr, key, &key_ptr);
|
||||
|
||||
if (build_context.dynamic_map_calls) {
|
||||
auto args = array_make<lbValue>(temporary_allocator(), 4);
|
||||
@@ -976,7 +993,7 @@ gb_internal void lb_internal_dynamic_map_set(lbProcedure *p, lbValue const &map_
|
||||
GB_ASSERT(map_type->kind == Type_Map);
|
||||
|
||||
lbValue key_ptr = {};
|
||||
lbValue hash = lb_gen_map_key_hash(p, map_key, map_type->Map.key, &key_ptr);
|
||||
lbValue hash = lb_gen_map_key_hash(p, map_ptr, map_key, &key_ptr);
|
||||
|
||||
lbValue v = lb_emit_conv(p, map_value, map_type->Map.value);
|
||||
lbValue value_ptr = lb_address_from_load_or_generate_local(p, v);
|
||||
@@ -1129,12 +1146,7 @@ gb_internal lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProc
|
||||
lbValue init = lb_build_expr(p, init_expr);
|
||||
if (init.value == nullptr) {
|
||||
LLVMTypeRef global_type = llvm_addr_type(p->module, var.var);
|
||||
if (is_type_untyped_undef(init.type)) {
|
||||
// LLVMSetInitializer(var.var.value, LLVMGetUndef(global_type));
|
||||
LLVMSetInitializer(var.var.value, LLVMConstNull(global_type));
|
||||
var.is_initialized = true;
|
||||
continue;
|
||||
} else if (is_type_untyped_nil(init.type)) {
|
||||
if (is_type_untyped_nil(init.type)) {
|
||||
LLVMSetInitializer(var.var.value, LLVMConstNull(global_type));
|
||||
var.is_initialized = true;
|
||||
continue;
|
||||
@@ -1365,7 +1377,7 @@ gb_internal WORKER_TASK_PROC(lb_llvm_emit_worker_proc) {
|
||||
|
||||
gb_internal void lb_llvm_function_pass_per_function_internal(lbModule *module, lbProcedure *p, lbFunctionPassManagerKind pass_manager_kind = lbFunctionPassManager_default) {
|
||||
LLVMPassManagerRef pass_manager = module->function_pass_managers[pass_manager_kind];
|
||||
lb_run_function_pass_manager(pass_manager, p);
|
||||
lb_run_function_pass_manager(pass_manager, p, pass_manager_kind);
|
||||
}
|
||||
|
||||
gb_internal WORKER_TASK_PROC(lb_llvm_function_pass_per_module) {
|
||||
@@ -1899,7 +1911,7 @@ gb_internal lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *star
|
||||
LLVMVerifyFunction(p->value, LLVMAbortProcessAction);
|
||||
}
|
||||
|
||||
lb_run_function_pass_manager(default_function_pass_manager, p);
|
||||
lb_run_function_pass_manager(default_function_pass_manager, p, lbFunctionPassManager_default);
|
||||
return p;
|
||||
}
|
||||
|
||||
@@ -2363,8 +2375,7 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!var.is_initialized &&
|
||||
(is_type_untyped_nil(tav.type) || is_type_untyped_undef(tav.type))) {
|
||||
if (!var.is_initialized && is_type_untyped_nil(tav.type)) {
|
||||
var.is_initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -477,7 +477,7 @@ gb_internal String lb_get_const_string(lbModule *m, lbValue value);
|
||||
|
||||
gb_internal lbValue lb_generate_local_array(lbProcedure *p, Type *elem_type, i64 count, bool zero_init=true);
|
||||
gb_internal lbValue lb_generate_global_array(lbModule *m, Type *elem_type, i64 count, String prefix, i64 id);
|
||||
gb_internal lbValue lb_gen_map_key_hash(lbProcedure *p, lbValue key, Type *key_type, lbValue *key_ptr_);
|
||||
gb_internal lbValue lb_gen_map_key_hash(lbProcedure *p, lbValue const &map_ptr, lbValue key, lbValue *key_ptr_);
|
||||
gb_internal lbValue lb_gen_map_cell_info_ptr(lbModule *m, Type *type);
|
||||
gb_internal lbValue lb_gen_map_info_ptr(lbModule *m, Type *map_type);
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
gb_internal bool lb_is_const(lbValue value) {
|
||||
LLVMValueRef v = value.value;
|
||||
if (is_type_untyped_nil(value.type) || is_type_untyped_undef(value.type)) {
|
||||
if (is_type_untyped_nil(value.type)) {
|
||||
// TODO(bill): Is this correct behaviour?
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -282,7 +282,7 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) {
|
||||
case Basic_UntypedString: GB_PANIC("Basic_UntypedString"); break;
|
||||
case Basic_UntypedRune: GB_PANIC("Basic_UntypedRune"); break;
|
||||
case Basic_UntypedNil: GB_PANIC("Basic_UntypedNil"); break;
|
||||
case Basic_UntypedUndef: GB_PANIC("Basic_UntypedUndef"); break;
|
||||
case Basic_UntypedUninit: GB_PANIC("Basic_UntypedUninit"); break;
|
||||
|
||||
default: GB_PANIC("Basic Unhandled"); break;
|
||||
}
|
||||
|
||||
+48
-58
@@ -1,20 +1,18 @@
|
||||
gb_internal lbValue lb_emit_arith_matrix(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type, bool component_wise);
|
||||
|
||||
gb_internal lbValue lb_emit_logical_binary_expr(lbProcedure *p, TokenKind op, Ast *left, Ast *right, Type *type) {
|
||||
gb_internal lbValue lb_emit_logical_binary_expr(lbProcedure *p, TokenKind op, Ast *left, Ast *right, Type *final_type) {
|
||||
lbModule *m = p->module;
|
||||
|
||||
lbBlock *rhs = lb_create_block(p, "logical.cmp.rhs");
|
||||
lbBlock *done = lb_create_block(p, "logical.cmp.done");
|
||||
|
||||
type = default_type(type);
|
||||
|
||||
lbValue short_circuit = {};
|
||||
if (op == Token_CmpAnd) {
|
||||
lb_build_cond(p, left, rhs, done);
|
||||
short_circuit = lb_const_bool(m, type, false);
|
||||
short_circuit = lb_const_bool(m, t_llvm_bool, false);
|
||||
} else if (op == Token_CmpOr) {
|
||||
lb_build_cond(p, left, done, rhs);
|
||||
short_circuit = lb_const_bool(m, type, true);
|
||||
short_circuit = lb_const_bool(m, t_llvm_bool, true);
|
||||
}
|
||||
|
||||
if (rhs->preds.count == 0) {
|
||||
@@ -25,7 +23,7 @@ gb_internal lbValue lb_emit_logical_binary_expr(lbProcedure *p, TokenKind op, As
|
||||
if (done->preds.count == 0) {
|
||||
lb_start_block(p, rhs);
|
||||
if (lb_is_expr_untyped_const(right)) {
|
||||
return lb_expr_untyped_const_to_typed(m, right, type);
|
||||
return lb_expr_untyped_const_to_typed(m, right, default_type(final_type));
|
||||
}
|
||||
return lb_build_expr(p, right);
|
||||
}
|
||||
@@ -43,10 +41,11 @@ gb_internal lbValue lb_emit_logical_binary_expr(lbProcedure *p, TokenKind op, As
|
||||
lb_start_block(p, rhs);
|
||||
lbValue edge = {};
|
||||
if (lb_is_expr_untyped_const(right)) {
|
||||
edge = lb_expr_untyped_const_to_typed(m, right, type);
|
||||
edge = lb_expr_untyped_const_to_typed(m, right, t_llvm_bool);
|
||||
} else {
|
||||
edge = lb_build_expr(p, right);
|
||||
edge = lb_emit_conv(p, lb_build_expr(p, right), t_llvm_bool);
|
||||
}
|
||||
GB_ASSERT(edge.type == t_llvm_bool);
|
||||
|
||||
incoming_values[done->preds.count] = edge.value;
|
||||
incoming_blocks[done->preds.count] = p->curr_block->block;
|
||||
@@ -54,7 +53,7 @@ gb_internal lbValue lb_emit_logical_binary_expr(lbProcedure *p, TokenKind op, As
|
||||
lb_emit_jump(p, done);
|
||||
lb_start_block(p, done);
|
||||
|
||||
LLVMTypeRef dst_type = lb_type(m, type);
|
||||
LLVMTypeRef dst_type = lb_type(m, t_llvm_bool);
|
||||
LLVMValueRef phi = nullptr;
|
||||
|
||||
GB_ASSERT(incoming_values.count == incoming_blocks.count);
|
||||
@@ -67,48 +66,36 @@ gb_internal lbValue lb_emit_logical_binary_expr(lbProcedure *p, TokenKind op, As
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
lbValue res = {};
|
||||
|
||||
if (phi_type == nullptr) {
|
||||
phi = LLVMBuildPhi(p->builder, dst_type, "");
|
||||
LLVMAddIncoming(phi, incoming_values.data, incoming_blocks.data, cast(unsigned)incoming_values.count);
|
||||
lbValue res = {};
|
||||
res.type = type;
|
||||
res.value = phi;
|
||||
return res;
|
||||
}
|
||||
|
||||
for_array(i, incoming_values) {
|
||||
LLVMValueRef incoming_value = incoming_values[i];
|
||||
LLVMTypeRef incoming_type = LLVMTypeOf(incoming_value);
|
||||
|
||||
if (phi_type != incoming_type) {
|
||||
GB_ASSERT_MSG(LLVMIsConstant(incoming_value), "%s vs %s", LLVMPrintTypeToString(phi_type), LLVMPrintTypeToString(incoming_type));
|
||||
bool ok = !!LLVMConstIntGetZExtValue(incoming_value);
|
||||
incoming_values[i] = LLVMConstInt(phi_type, ok, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
phi = LLVMBuildPhi(p->builder, phi_type, "");
|
||||
LLVMAddIncoming(phi, incoming_values.data, incoming_blocks.data, cast(unsigned)incoming_values.count);
|
||||
|
||||
LLVMTypeRef i1 = LLVMInt1TypeInContext(m->ctx);
|
||||
if ((phi_type == i1) ^ (dst_type == i1)) {
|
||||
if (phi_type == i1) {
|
||||
phi = LLVMBuildZExt(p->builder, phi, dst_type, "");
|
||||
} else {
|
||||
phi = LLVMBuildTruncOrBitCast(p->builder, phi, dst_type, "");
|
||||
}
|
||||
} else if (lb_sizeof(phi_type) < lb_sizeof(dst_type)) {
|
||||
phi = LLVMBuildZExt(p->builder, phi, dst_type, "");
|
||||
res.type = t_llvm_bool;
|
||||
} else {
|
||||
phi = LLVMBuildTruncOrBitCast(p->builder, phi, dst_type, "");
|
||||
}
|
||||
|
||||
lbValue res = {};
|
||||
res.type = type;
|
||||
res.value = phi;
|
||||
return res;
|
||||
for_array(i, incoming_values) {
|
||||
LLVMValueRef incoming_value = incoming_values[i];
|
||||
LLVMTypeRef incoming_type = LLVMTypeOf(incoming_value);
|
||||
|
||||
if (phi_type != incoming_type) {
|
||||
GB_ASSERT_MSG(LLVMIsConstant(incoming_value), "%s vs %s", LLVMPrintTypeToString(phi_type), LLVMPrintTypeToString(incoming_type));
|
||||
bool ok = !!LLVMConstIntGetZExtValue(incoming_value);
|
||||
incoming_values[i] = LLVMConstInt(phi_type, ok, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// NOTE(bill): this now only uses i1 for the logic to prevent issues with corrupted booleans which are not of value 0 or 1 (e.g. 2)
|
||||
// Doing this may produce slightly worse code as a result but it will be correct behaviour
|
||||
|
||||
phi = LLVMBuildPhi(p->builder, phi_type, "");
|
||||
LLVMAddIncoming(phi, incoming_values.data, incoming_blocks.data, cast(unsigned)incoming_values.count);
|
||||
res.value = phi;
|
||||
res.type = t_llvm_bool;
|
||||
}
|
||||
return lb_emit_conv(p, res, default_type(final_type));
|
||||
}
|
||||
|
||||
|
||||
@@ -1499,12 +1486,12 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
|
||||
GB_ASSERT(src != nullptr);
|
||||
GB_ASSERT(dst != nullptr);
|
||||
|
||||
if (is_type_untyped_uninit(src)) {
|
||||
return lb_const_undef(m, t);
|
||||
}
|
||||
if (is_type_untyped_nil(src)) {
|
||||
return lb_const_nil(m, t);
|
||||
}
|
||||
if (is_type_untyped_undef(src)) {
|
||||
return lb_const_undef(m, t);
|
||||
}
|
||||
|
||||
if (LLVMIsConstant(value.value)) {
|
||||
if (is_type_any(dst)) {
|
||||
@@ -1566,7 +1553,7 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
|
||||
// bool <-> llvm bool
|
||||
if (is_type_boolean(src) && dst == t_llvm_bool) {
|
||||
lbValue res = {};
|
||||
res.value = LLVMBuildTrunc(p->builder, value.value, lb_type(m, dst), "");
|
||||
res.value = LLVMBuildICmp(p->builder, LLVMIntNE, value.value, LLVMConstNull(lb_type(m, src)), "");
|
||||
res.type = t;
|
||||
return res;
|
||||
}
|
||||
@@ -2083,10 +2070,12 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
|
||||
Type *elem = base_array_type(dst);
|
||||
lbValue e = lb_emit_conv(p, value, elem);
|
||||
lbAddr v = lb_add_local_generated(p, t, false);
|
||||
for (i64 i = 0; i < dst->Matrix.row_count; i++) {
|
||||
isize j = cast(isize)i;
|
||||
lbValue ptr = lb_emit_matrix_epi(p, v.addr, j, j);
|
||||
lb_emit_store(p, ptr, e);
|
||||
lbValue zero = lb_const_value(p->module, elem, exact_value_i64(0), true);
|
||||
for (i64 j = 0; j < dst->Matrix.column_count; j++) {
|
||||
for (i64 i = 0; i < dst->Matrix.row_count; i++) {
|
||||
lbValue ptr = lb_emit_matrix_epi(p, v.addr, i, j);
|
||||
lb_emit_store(p, ptr, i == j ? e : zero);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2143,12 +2132,12 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
|
||||
|
||||
|
||||
if (is_type_any(dst)) {
|
||||
if (is_type_untyped_uninit(src)) {
|
||||
return lb_const_undef(p->module, t);
|
||||
}
|
||||
if (is_type_untyped_nil(src)) {
|
||||
return lb_const_nil(p->module, t);
|
||||
}
|
||||
if (is_type_untyped_undef(src)) {
|
||||
return lb_const_undef(p->module, t);
|
||||
}
|
||||
|
||||
lbAddr result = lb_add_local_generated(p, t, true);
|
||||
|
||||
@@ -3147,11 +3136,11 @@ gb_internal lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) {
|
||||
return lb_addr_load(p, lb_build_addr(p, expr));
|
||||
case_end;
|
||||
|
||||
case_ast_node(u, Undef, expr)
|
||||
case_ast_node(u, Uninit, expr)
|
||||
lbValue res = {};
|
||||
if (is_type_untyped(type)) {
|
||||
res.value = nullptr;
|
||||
res.type = t_untyped_undef;
|
||||
res.type = t_untyped_uninit;
|
||||
} else {
|
||||
res.value = LLVMGetUndef(lb_type(m, type));
|
||||
res.type = type;
|
||||
@@ -3781,6 +3770,7 @@ gb_internal lbAddr lb_build_addr_index_expr(lbProcedure *p, Ast *expr) {
|
||||
multi_ptr = lb_emit_load(p, multi_ptr);
|
||||
}
|
||||
lbValue index = lb_build_expr(p, ie->index);
|
||||
index = lb_emit_conv(p, index, t_int);
|
||||
lbValue v = {};
|
||||
|
||||
LLVMValueRef indices[1] = {index.value};
|
||||
|
||||
@@ -677,7 +677,7 @@ gb_internal void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value) {
|
||||
return;
|
||||
}
|
||||
GB_ASSERT(value.type != nullptr);
|
||||
if (is_type_untyped_undef(value.type)) {
|
||||
if (is_type_untyped_uninit(value.type)) {
|
||||
Type *t = lb_addr_type(addr);
|
||||
value.type = t;
|
||||
value.value = LLVMGetUndef(lb_type(p->module, t));
|
||||
@@ -1828,7 +1828,7 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
|
||||
case Basic_UntypedString: GB_PANIC("Basic_UntypedString"); break;
|
||||
case Basic_UntypedRune: GB_PANIC("Basic_UntypedRune"); break;
|
||||
case Basic_UntypedNil: GB_PANIC("Basic_UntypedNil"); break;
|
||||
case Basic_UntypedUndef: GB_PANIC("Basic_UntypedUndef"); break;
|
||||
case Basic_UntypedUninit: GB_PANIC("Basic_UntypedUninit"); break;
|
||||
}
|
||||
break;
|
||||
case Type_Named:
|
||||
|
||||
@@ -370,11 +370,21 @@ gb_internal void lb_run_remove_dead_instruction_pass(lbProcedure *p) {
|
||||
}
|
||||
|
||||
|
||||
gb_internal void lb_run_function_pass_manager(LLVMPassManagerRef fpm, lbProcedure *p) {
|
||||
gb_internal void lb_run_function_pass_manager(LLVMPassManagerRef fpm, lbProcedure *p, lbFunctionPassManagerKind pass_manager_kind) {
|
||||
if (p == nullptr) {
|
||||
return;
|
||||
}
|
||||
LLVMRunFunctionPassManager(fpm, p->value);
|
||||
switch (pass_manager_kind) {
|
||||
case lbFunctionPassManager_none:
|
||||
return;
|
||||
case lbFunctionPassManager_default:
|
||||
case lbFunctionPassManager_default_without_memcpy:
|
||||
if (build_context.optimization_level < 0) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// NOTE(bill): LLVMAddDCEPass doesn't seem to be exported in the official DLL's for LLVM
|
||||
// which means we cannot rely upon it
|
||||
// This is also useful for read the .ll for debug purposes because a lot of instructions
|
||||
|
||||
@@ -3218,10 +3218,10 @@ gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) {
|
||||
Entity *e = params->variables[i];
|
||||
if (args[i].type == nullptr) {
|
||||
continue;
|
||||
} else if (is_type_untyped_uninit(args[i].type)) {
|
||||
args[i] = lb_const_undef(m, e->type);
|
||||
} else if (is_type_untyped_nil(args[i].type)) {
|
||||
args[i] = lb_const_nil(m, e->type);
|
||||
} else if (is_type_untyped_undef(args[i].type)) {
|
||||
args[i] = lb_const_undef(m, e->type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3409,10 +3409,10 @@ gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) {
|
||||
Entity *e = param_tuple->variables[i];
|
||||
if (args[i].type == nullptr) {
|
||||
continue;
|
||||
} else if (is_type_untyped_uninit(args[i].type)) {
|
||||
args[i] = lb_const_undef(m, e->type);
|
||||
} else if (is_type_untyped_nil(args[i].type)) {
|
||||
args[i] = lb_const_nil(m, e->type);
|
||||
} else if (is_type_untyped_undef(args[i].type)) {
|
||||
args[i] = lb_const_undef(m, e->type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+211
-51
@@ -249,7 +249,8 @@ gb_internal void lb_build_when_stmt(lbProcedure *p, AstWhenStmt *ws) {
|
||||
|
||||
|
||||
gb_internal void lb_build_range_indexed(lbProcedure *p, lbValue expr, Type *val_type, lbValue count_ptr,
|
||||
lbValue *val_, lbValue *idx_, lbBlock **loop_, lbBlock **done_) {
|
||||
lbValue *val_, lbValue *idx_, lbBlock **loop_, lbBlock **done_,
|
||||
bool is_reverse) {
|
||||
lbModule *m = p->module;
|
||||
|
||||
lbValue count = {};
|
||||
@@ -266,25 +267,78 @@ gb_internal void lb_build_range_indexed(lbProcedure *p, lbValue expr, Type *val_
|
||||
lbBlock *done = nullptr;
|
||||
lbBlock *body = nullptr;
|
||||
|
||||
|
||||
lbAddr index = lb_add_local_generated(p, t_int, false);
|
||||
lb_addr_store(p, index, lb_const_int(m, t_int, cast(u64)-1));
|
||||
|
||||
loop = lb_create_block(p, "for.index.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(m, t_int, 1), t_int);
|
||||
lb_addr_store(p, index, incr);
|
||||
|
||||
body = lb_create_block(p, "for.index.body");
|
||||
done = lb_create_block(p, "for.index.done");
|
||||
if (count.value == nullptr) {
|
||||
GB_ASSERT(count_ptr.value != nullptr);
|
||||
count = lb_emit_load(p, count_ptr);
|
||||
|
||||
lbAddr index = lb_add_local_generated(p, t_int, false);
|
||||
|
||||
if (!is_reverse) {
|
||||
/*
|
||||
for x, i in array {
|
||||
...
|
||||
}
|
||||
|
||||
i := -1
|
||||
for {
|
||||
i += 1
|
||||
if !(i < len(array)) {
|
||||
break
|
||||
}
|
||||
#no_bounds_check x := array[i]
|
||||
...
|
||||
}
|
||||
*/
|
||||
|
||||
lb_addr_store(p, index, lb_const_int(m, t_int, cast(u64)-1));
|
||||
|
||||
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(m, t_int, 1), t_int);
|
||||
lb_addr_store(p, index, incr);
|
||||
|
||||
if (count.value == nullptr) {
|
||||
GB_ASSERT(count_ptr.value != nullptr);
|
||||
count = lb_emit_load(p, count_ptr);
|
||||
}
|
||||
lbValue cond = lb_emit_comp(p, Token_Lt, incr, count);
|
||||
lb_emit_if(p, cond, body, done);
|
||||
} else {
|
||||
// NOTE(bill): REVERSED LOGIC
|
||||
/*
|
||||
#reverse for x, i in array {
|
||||
...
|
||||
}
|
||||
|
||||
i := len(array)
|
||||
for {
|
||||
i -= 1
|
||||
if i < 0 {
|
||||
break
|
||||
}
|
||||
#no_bounds_check x := array[i]
|
||||
...
|
||||
}
|
||||
*/
|
||||
|
||||
if (count.value == nullptr) {
|
||||
GB_ASSERT(count_ptr.value != nullptr);
|
||||
count = lb_emit_load(p, count_ptr);
|
||||
}
|
||||
count = lb_emit_conv(p, count, t_int);
|
||||
lb_addr_store(p, index, count);
|
||||
|
||||
lb_emit_jump(p, loop);
|
||||
lb_start_block(p, loop);
|
||||
|
||||
lbValue incr = lb_emit_arith(p, Token_Sub, lb_addr_load(p, index), lb_const_int(m, t_int, 1), t_int);
|
||||
lb_addr_store(p, index, incr);
|
||||
|
||||
lbValue anti_cond = lb_emit_comp(p, Token_Lt, incr, lb_const_int(m, t_int, 0));
|
||||
lb_emit_if(p, anti_cond, done, body);
|
||||
}
|
||||
lbValue cond = lb_emit_comp(p, Token_Lt, incr, count);
|
||||
lb_emit_if(p, cond, body, done);
|
||||
|
||||
lb_start_block(p, body);
|
||||
|
||||
idx = lb_addr_load(p, index);
|
||||
@@ -452,7 +506,8 @@ gb_internal void lb_build_range_map(lbProcedure *p, lbValue expr, Type *val_type
|
||||
|
||||
|
||||
gb_internal void lb_build_range_string(lbProcedure *p, lbValue expr, Type *val_type,
|
||||
lbValue *val_, lbValue *idx_, lbBlock **loop_, lbBlock **done_) {
|
||||
lbValue *val_, lbValue *idx_, lbBlock **loop_, lbBlock **done_,
|
||||
bool is_reverse) {
|
||||
lbModule *m = p->module;
|
||||
lbValue count = lb_const_int(m, t_int, 0);
|
||||
Type *expr_type = base_type(expr.type);
|
||||
@@ -471,35 +526,88 @@ gb_internal void lb_build_range_string(lbProcedure *p, lbValue expr, Type *val_t
|
||||
lbBlock *done = nullptr;
|
||||
lbBlock *body = nullptr;
|
||||
|
||||
|
||||
lbAddr offset_ = lb_add_local_generated(p, t_int, false);
|
||||
lb_addr_store(p, offset_, lb_const_int(m, t_int, 0));
|
||||
|
||||
loop = lb_create_block(p, "for.string.loop");
|
||||
lb_emit_jump(p, loop);
|
||||
lb_start_block(p, loop);
|
||||
|
||||
|
||||
|
||||
body = lb_create_block(p, "for.string.body");
|
||||
done = lb_create_block(p, "for.string.done");
|
||||
|
||||
lbValue offset = lb_addr_load(p, offset_);
|
||||
lbValue cond = lb_emit_comp(p, Token_Lt, offset, count);
|
||||
lbAddr offset_ = lb_add_local_generated(p, t_int, false);
|
||||
lbValue offset = {};
|
||||
lbValue cond = {};
|
||||
|
||||
if (!is_reverse) {
|
||||
/*
|
||||
for c, offset in str {
|
||||
...
|
||||
}
|
||||
|
||||
offset := 0
|
||||
for offset < len(str) {
|
||||
c, _w := string_decode_rune(str[offset:])
|
||||
...
|
||||
offset += _w
|
||||
}
|
||||
*/
|
||||
lb_addr_store(p, offset_, lb_const_int(m, t_int, 0));
|
||||
|
||||
lb_emit_jump(p, loop);
|
||||
lb_start_block(p, loop);
|
||||
|
||||
|
||||
offset = lb_addr_load(p, offset_);
|
||||
cond = lb_emit_comp(p, Token_Lt, offset, count);
|
||||
} else {
|
||||
// NOTE(bill): REVERSED LOGIC
|
||||
/*
|
||||
#reverse for c, offset in str {
|
||||
...
|
||||
}
|
||||
|
||||
offset := len(str)
|
||||
for offset > 0 {
|
||||
c, _w := string_decode_last_rune(str[:offset])
|
||||
offset -= _w
|
||||
...
|
||||
}
|
||||
*/
|
||||
lb_addr_store(p, offset_, count);
|
||||
|
||||
lb_emit_jump(p, loop);
|
||||
lb_start_block(p, loop);
|
||||
|
||||
offset = lb_addr_load(p, offset_);
|
||||
cond = lb_emit_comp(p, Token_Gt, offset, lb_const_int(m, t_int, 0));
|
||||
}
|
||||
lb_emit_if(p, cond, body, done);
|
||||
lb_start_block(p, body);
|
||||
|
||||
|
||||
lbValue str_elem = lb_emit_ptr_offset(p, lb_string_elem(p, expr), offset);
|
||||
lbValue str_len = lb_emit_arith(p, Token_Sub, count, offset, t_int);
|
||||
auto args = array_make<lbValue>(permanent_allocator(), 1);
|
||||
args[0] = lb_emit_string(p, str_elem, str_len);
|
||||
lbValue rune_and_len = lb_emit_runtime_call(p, "string_decode_rune", args);
|
||||
lbValue len = lb_emit_struct_ev(p, rune_and_len, 1);
|
||||
lb_addr_store(p, offset_, lb_emit_arith(p, Token_Add, offset, len, t_int));
|
||||
lbValue rune_and_len = {};
|
||||
if (!is_reverse) {
|
||||
lbValue str_elem = lb_emit_ptr_offset(p, lb_string_elem(p, expr), offset);
|
||||
lbValue str_len = lb_emit_arith(p, Token_Sub, count, offset, t_int);
|
||||
auto args = array_make<lbValue>(permanent_allocator(), 1);
|
||||
args[0] = lb_emit_string(p, str_elem, str_len);
|
||||
|
||||
rune_and_len = lb_emit_runtime_call(p, "string_decode_rune", args);
|
||||
lbValue len = lb_emit_struct_ev(p, rune_and_len, 1);
|
||||
lb_addr_store(p, offset_, lb_emit_arith(p, Token_Add, offset, len, t_int));
|
||||
|
||||
idx = offset;
|
||||
} else {
|
||||
// NOTE(bill): REVERSED LOGIC
|
||||
lbValue str_elem = lb_string_elem(p, expr);
|
||||
lbValue str_len = offset;
|
||||
auto args = array_make<lbValue>(permanent_allocator(), 1);
|
||||
args[0] = lb_emit_string(p, str_elem, str_len);
|
||||
|
||||
rune_and_len = lb_emit_runtime_call(p, "string_decode_last_rune", args);
|
||||
lbValue len = lb_emit_struct_ev(p, rune_and_len, 1);
|
||||
lb_addr_store(p, offset_, lb_emit_arith(p, Token_Sub, offset, len, t_int));
|
||||
|
||||
idx = lb_addr_load(p, offset_);
|
||||
}
|
||||
|
||||
|
||||
idx = offset;
|
||||
if (val_type != nullptr) {
|
||||
val = lb_emit_struct_ev(p, rune_and_len, 0);
|
||||
}
|
||||
@@ -702,6 +810,8 @@ gb_internal void lb_build_range_stmt_struct_soa(lbProcedure *p, AstRangeStmt *rs
|
||||
lbBlock *body = nullptr;
|
||||
lbBlock *done = nullptr;
|
||||
|
||||
bool is_reverse = rs->reverse;
|
||||
|
||||
lb_open_scope(p, scope);
|
||||
|
||||
|
||||
@@ -723,20 +833,70 @@ gb_internal void lb_build_range_stmt_struct_soa(lbProcedure *p, AstRangeStmt *rs
|
||||
|
||||
|
||||
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);
|
||||
if (!is_reverse) {
|
||||
/*
|
||||
for x, i in array {
|
||||
...
|
||||
}
|
||||
|
||||
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);
|
||||
i := -1
|
||||
for {
|
||||
i += 1
|
||||
if !(i < len(array)) {
|
||||
break
|
||||
}
|
||||
x := array[i] // but #soa-ified
|
||||
...
|
||||
}
|
||||
*/
|
||||
|
||||
body = lb_create_block(p, "for.soa.body");
|
||||
done = lb_create_block(p, "for.soa.done");
|
||||
lb_addr_store(p, index, lb_const_int(p->module, t_int, cast(u64)-1));
|
||||
|
||||
lbValue cond = lb_emit_comp(p, Token_Lt, incr, count);
|
||||
lb_emit_if(p, cond, body, done);
|
||||
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);
|
||||
} else {
|
||||
// NOTE(bill): REVERSED LOGIC
|
||||
/*
|
||||
#reverse for x, i in array {
|
||||
...
|
||||
}
|
||||
|
||||
i := len(array)
|
||||
for {
|
||||
i -= 1
|
||||
if i < 0 {
|
||||
break
|
||||
}
|
||||
#no_bounds_check x := array[i] // but #soa-ified
|
||||
...
|
||||
}
|
||||
*/
|
||||
lb_addr_store(p, index, count);
|
||||
|
||||
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_Sub, 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, lb_const_int(p->module, t_int, 0));
|
||||
lb_emit_if(p, cond, done, body);
|
||||
}
|
||||
lb_start_block(p, body);
|
||||
|
||||
|
||||
@@ -820,7 +980,7 @@ gb_internal void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *sc
|
||||
}
|
||||
lbAddr count_ptr = lb_add_local_generated(p, t_int, false);
|
||||
lb_addr_store(p, count_ptr, lb_const_int(p->module, t_int, et->Array.count));
|
||||
lb_build_range_indexed(p, array, val0_type, count_ptr.addr, &val, &key, &loop, &done);
|
||||
lb_build_range_indexed(p, array, val0_type, count_ptr.addr, &val, &key, &loop, &done, rs->reverse);
|
||||
break;
|
||||
}
|
||||
case Type_EnumeratedArray: {
|
||||
@@ -830,7 +990,7 @@ gb_internal void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *sc
|
||||
}
|
||||
lbAddr count_ptr = lb_add_local_generated(p, t_int, false);
|
||||
lb_addr_store(p, count_ptr, lb_const_int(p->module, t_int, et->EnumeratedArray.count));
|
||||
lb_build_range_indexed(p, array, val0_type, count_ptr.addr, &val, &key, &loop, &done);
|
||||
lb_build_range_indexed(p, array, val0_type, count_ptr.addr, &val, &key, &loop, &done, rs->reverse);
|
||||
break;
|
||||
}
|
||||
case Type_DynamicArray: {
|
||||
@@ -840,7 +1000,7 @@ gb_internal void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *sc
|
||||
array = lb_emit_load(p, array);
|
||||
}
|
||||
count_ptr = lb_emit_struct_ep(p, array, 1);
|
||||
lb_build_range_indexed(p, array, val0_type, count_ptr, &val, &key, &loop, &done);
|
||||
lb_build_range_indexed(p, array, val0_type, count_ptr, &val, &key, &loop, &done, rs->reverse);
|
||||
break;
|
||||
}
|
||||
case Type_Slice: {
|
||||
@@ -853,7 +1013,7 @@ gb_internal void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *sc
|
||||
count_ptr = lb_add_local_generated(p, t_int, false).addr;
|
||||
lb_emit_store(p, count_ptr, lb_slice_len(p, slice));
|
||||
}
|
||||
lb_build_range_indexed(p, slice, val0_type, count_ptr, &val, &key, &loop, &done);
|
||||
lb_build_range_indexed(p, slice, val0_type, count_ptr, &val, &key, &loop, &done, rs->reverse);
|
||||
break;
|
||||
}
|
||||
case Type_Basic: {
|
||||
@@ -868,7 +1028,7 @@ gb_internal void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *sc
|
||||
}
|
||||
Type *t = base_type(string.type);
|
||||
GB_ASSERT(!is_type_cstring(t));
|
||||
lb_build_range_string(p, string, val0_type, &val, &key, &loop, &done);
|
||||
lb_build_range_string(p, string, val0_type, &val, &key, &loop, &done, rs->reverse);
|
||||
break;
|
||||
}
|
||||
case Type_Tuple:
|
||||
|
||||
@@ -1035,12 +1035,16 @@ gb_internal bool parse_build_flags(Array<String> args) {
|
||||
case BuildFlag_OptimizationMode: {
|
||||
GB_ASSERT(value.kind == ExactValue_String);
|
||||
if (value.value_string == "none") {
|
||||
build_context.custom_optimization_level = true;
|
||||
build_context.optimization_level = -1;
|
||||
} else if (value.value_string == "minimal") {
|
||||
build_context.custom_optimization_level = true;
|
||||
build_context.optimization_level = 0;
|
||||
} else if (value.value_string == "size") {
|
||||
build_context.custom_optimization_level = true;
|
||||
build_context.optimization_level = 1;
|
||||
} else if (value.value_string == "speed") {
|
||||
build_context.custom_optimization_level = true;
|
||||
build_context.optimization_level = 2;
|
||||
} else {
|
||||
gb_printf_err("Invalid optimization mode for -o:<string>, got %.*s\n", LIT(value.value_string));
|
||||
|
||||
+31
-10
@@ -115,7 +115,7 @@ gb_internal Ast *clone_ast(Ast *node, AstFile *f) {
|
||||
n->Ident.entity = nullptr;
|
||||
break;
|
||||
case Ast_Implicit: break;
|
||||
case Ast_Undef: break;
|
||||
case Ast_Uninit: break;
|
||||
case Ast_BasicLit: break;
|
||||
case Ast_BasicDirective: break;
|
||||
|
||||
@@ -646,9 +646,9 @@ gb_internal Ast *ast_implicit(AstFile *f, Token token) {
|
||||
result->Implicit = token;
|
||||
return result;
|
||||
}
|
||||
gb_internal Ast *ast_undef(AstFile *f, Token token) {
|
||||
Ast *result = alloc_ast_node(f, Ast_Undef);
|
||||
result->Undef = token;
|
||||
gb_internal Ast *ast_uninit(AstFile *f, Token token) {
|
||||
Ast *result = alloc_ast_node(f, Ast_Uninit);
|
||||
result->Uninit = token;
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -2092,8 +2092,8 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) {
|
||||
case Token_Ident:
|
||||
return parse_ident(f);
|
||||
|
||||
case Token_Undef:
|
||||
return ast_undef(f, expect_token(f, Token_Undef));
|
||||
case Token_Uninit:
|
||||
return ast_uninit(f, expect_token(f, Token_Uninit));
|
||||
|
||||
case Token_context:
|
||||
return ast_implicit(f, expect_token(f, Token_context));
|
||||
@@ -2292,7 +2292,7 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) {
|
||||
|
||||
skip_possible_newline_for_literal(f);
|
||||
|
||||
if (allow_token(f, Token_Undef)) {
|
||||
if (allow_token(f, Token_Uninit)) {
|
||||
if (where_token.kind != Token_Invalid) {
|
||||
syntax_error(where_token, "'where' clauses are not allowed on procedure literals without a defined body (replaced with ---)");
|
||||
}
|
||||
@@ -2462,7 +2462,7 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) {
|
||||
}
|
||||
is_raw_union = true;
|
||||
} else if (tag.string == "no_copy") {
|
||||
if (is_packed) {
|
||||
if (no_copy) {
|
||||
syntax_error(tag, "Duplicate struct tag '#%.*s'", LIT(tag.string));
|
||||
}
|
||||
no_copy = true;
|
||||
@@ -3744,8 +3744,18 @@ gb_internal bool allow_field_separator(AstFile *f) {
|
||||
if (allow_token(f, Token_Comma)) {
|
||||
return true;
|
||||
}
|
||||
if (ALLOW_NEWLINE && token.kind == Token_Semicolon) {
|
||||
if (!token_is_newline(token)) {
|
||||
if (token.kind == Token_Semicolon) {
|
||||
bool ok = false;
|
||||
if (ALLOW_NEWLINE && token_is_newline(token)) {
|
||||
TokenKind next = peek_token(f).kind;
|
||||
switch (next) {
|
||||
case Token_CloseBrace:
|
||||
case Token_CloseParen:
|
||||
ok = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!ok) {
|
||||
String p = token_to_string(token);
|
||||
syntax_error(token_end_of_line(f, f->prev_token), "Expected a comma, got a %.*s", LIT(p));
|
||||
}
|
||||
@@ -4749,6 +4759,17 @@ gb_internal Ast *parse_stmt(AstFile *f) {
|
||||
return stmt;
|
||||
} else if (tag == "unroll") {
|
||||
return parse_unrolled_for_loop(f, name);
|
||||
} else if (tag == "reverse") {
|
||||
Ast *for_stmt = parse_for_stmt(f);
|
||||
if (for_stmt->kind == Ast_RangeStmt) {
|
||||
if (for_stmt->RangeStmt.reverse) {
|
||||
syntax_error(token, "#reverse already applied to a 'for in' statement");
|
||||
}
|
||||
for_stmt->RangeStmt.reverse = true;
|
||||
} else {
|
||||
syntax_error(token, "#reverse can only be applied to a 'for in' statement");
|
||||
}
|
||||
return for_stmt;
|
||||
} else if (tag == "include") {
|
||||
syntax_error(token, "#include is not a valid import declaration kind. Did you mean 'import'?");
|
||||
s = ast_bad_stmt(f, token, f->curr_token);
|
||||
|
||||
+11
-1
@@ -356,6 +356,15 @@ enum UnionTypeKind : u8 {
|
||||
UnionType_Normal = 0,
|
||||
UnionType_no_nil = 2,
|
||||
UnionType_shared_nil = 3,
|
||||
|
||||
UnionType_COUNT
|
||||
};
|
||||
|
||||
gb_global char const *union_type_kind_strings[UnionType_COUNT] = {
|
||||
"(normal)",
|
||||
"#maybe",
|
||||
"#no_nil",
|
||||
"#shared_nil",
|
||||
};
|
||||
|
||||
#define AST_KINDS \
|
||||
@@ -364,7 +373,7 @@ enum UnionTypeKind : u8 {
|
||||
Entity *entity; \
|
||||
}) \
|
||||
AST_KIND(Implicit, "implicit", Token) \
|
||||
AST_KIND(Undef, "undef", Token) \
|
||||
AST_KIND(Uninit, "uninitialized value", Token) \
|
||||
AST_KIND(BasicLit, "basic literal", struct { \
|
||||
Token token; \
|
||||
}) \
|
||||
@@ -520,6 +529,7 @@ AST_KIND(_ComplexStmtBegin, "", bool) \
|
||||
Token in_token; \
|
||||
Ast *expr; \
|
||||
Ast *body; \
|
||||
bool reverse; \
|
||||
}) \
|
||||
AST_KIND(UnrollRangeStmt, "#unroll range statement", struct { \
|
||||
Scope *scope; \
|
||||
|
||||
+2
-2
@@ -2,7 +2,7 @@ gb_internal Token ast_token(Ast *node) {
|
||||
switch (node->kind) {
|
||||
case Ast_Ident: return node->Ident.token;
|
||||
case Ast_Implicit: return node->Implicit;
|
||||
case Ast_Undef: return node->Undef;
|
||||
case Ast_Uninit: return node->Uninit;
|
||||
case Ast_BasicLit: return node->BasicLit.token;
|
||||
case Ast_BasicDirective: return node->BasicDirective.token;
|
||||
case Ast_ProcGroup: return node->ProcGroup.token;
|
||||
@@ -137,7 +137,7 @@ Token ast_end_token(Ast *node) {
|
||||
return empty_token;
|
||||
case Ast_Ident: return node->Ident.token;
|
||||
case Ast_Implicit: return node->Implicit;
|
||||
case Ast_Undef: return node->Undef;
|
||||
case Ast_Uninit: return node->Uninit;
|
||||
case Ast_BasicLit: return node->BasicLit.token;
|
||||
case Ast_BasicDirective: return node->BasicDirective.token;
|
||||
case Ast_ProcGroup: return node->ProcGroup.close;
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
/*
|
||||
Path handling utilities.
|
||||
*/
|
||||
#if !defined(GB_SYSTEM_WINDOWS)
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
gb_internal String remove_extension_from_path(String const &s) {
|
||||
if (s.len != 0 && s.text[s.len-1] == '.') {
|
||||
return s;
|
||||
@@ -25,6 +29,29 @@ gb_internal String remove_directory_from_path(String const &s) {
|
||||
return substring(s, s.len-len, s.len);
|
||||
}
|
||||
|
||||
|
||||
// NOTE(Mark Naughton): getcwd as String
|
||||
#if !defined(GB_SYSTEM_WINDOWS)
|
||||
gb_internal String get_current_directory(void) {
|
||||
char cwd[256];
|
||||
getcwd(cwd, 256);
|
||||
|
||||
return make_string_c(cwd);
|
||||
}
|
||||
|
||||
#else
|
||||
gb_internal String get_current_directory(void) {
|
||||
gbAllocator a = heap_allocator();
|
||||
|
||||
wchar_t cwd[256];
|
||||
GetCurrentDirectoryW(256, cwd);
|
||||
|
||||
String16 wstr = make_string16_c(cwd);
|
||||
|
||||
return string16_to_string(a, wstr);
|
||||
}
|
||||
#endif
|
||||
|
||||
gb_internal bool path_is_directory(String path);
|
||||
|
||||
gb_internal String directory_from_path(String const &s) {
|
||||
@@ -392,7 +419,43 @@ gb_internal ReadDirectoryError read_directory(String path, Array<FileInfo> *fi)
|
||||
|
||||
return ReadDirectory_None;
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
#error Implement read_directory
|
||||
#endif
|
||||
|
||||
#if !defined(GB_SYSTEM_WINDOWS)
|
||||
gb_internal bool write_directory(String path) {
|
||||
char const *pathname = (char *) path.text;
|
||||
|
||||
if (access(pathname, W_OK) < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
gb_internal bool write_directory(String path) {
|
||||
String16 wstr = string_to_string16(heap_allocator(), path);
|
||||
LPCWSTR wdirectory_name = wstr.text;
|
||||
|
||||
HANDLE directory = CreateFileW(wdirectory_name,
|
||||
GENERIC_WRITE,
|
||||
0,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_BACKUP_SEMANTICS,
|
||||
NULL);
|
||||
|
||||
if (directory == INVALID_HANDLE_VALUE) {
|
||||
DWORD error_code = GetLastError();
|
||||
if (error_code == ERROR_ACCESS_DENIED) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
CloseHandle(directory);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
+1
-1
@@ -47,7 +47,7 @@ gb_internal gb_inline u32 ptr_map_hash_key(uintptr key) {
|
||||
key = key ^ (key << 28);
|
||||
res = cast(u32)key;
|
||||
#elif defined(GB_ARCH_32_BIT)
|
||||
u32 state = ((u32)key) * 747796405u + 2891336453u;
|
||||
u32 state = (cast(u32)key) * 747796405u + 2891336453u;
|
||||
u32 word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u;
|
||||
res = (word >> 22u) ^ word;
|
||||
#endif
|
||||
|
||||
+3
-3
@@ -54,7 +54,7 @@ TOKEN_KIND(Token__AssignOpEnd, ""), \
|
||||
TOKEN_KIND(Token_Increment, "++"), \
|
||||
TOKEN_KIND(Token_Decrement, "--"), \
|
||||
TOKEN_KIND(Token_ArrowRight,"->"), \
|
||||
TOKEN_KIND(Token_Undef, "---"), \
|
||||
TOKEN_KIND(Token_Uninit, "---"), \
|
||||
\
|
||||
TOKEN_KIND(Token__ComparisonBegin, ""), \
|
||||
TOKEN_KIND(Token_CmpEq, "=="), \
|
||||
@@ -917,7 +917,7 @@ gb_internal void tokenizer_get_token(Tokenizer *t, Token *token, int repeat=0) {
|
||||
token->kind = Token_Decrement;
|
||||
if (t->curr_rune == '-') {
|
||||
advance_to_next_rune(t);
|
||||
token->kind = Token_Undef;
|
||||
token->kind = Token_Uninit;
|
||||
}
|
||||
break;
|
||||
case '>':
|
||||
@@ -1078,7 +1078,7 @@ semicolon_check:;
|
||||
case Token_Imag:
|
||||
case Token_Rune:
|
||||
case Token_String:
|
||||
case Token_Undef:
|
||||
case Token_Uninit:
|
||||
/*fallthrough*/
|
||||
case Token_Question:
|
||||
case Token_Pointer:
|
||||
|
||||
+19
-12
@@ -83,7 +83,7 @@ enum BasicKind {
|
||||
Basic_UntypedString,
|
||||
Basic_UntypedRune,
|
||||
Basic_UntypedNil,
|
||||
Basic_UntypedUndef,
|
||||
Basic_UntypedUninit,
|
||||
|
||||
Basic_COUNT,
|
||||
|
||||
@@ -515,7 +515,7 @@ gb_global Type basic_types[] = {
|
||||
{Type_Basic, {Basic_UntypedString, BasicFlag_String | BasicFlag_Untyped, 0, STR_LIT("untyped string")}},
|
||||
{Type_Basic, {Basic_UntypedRune, BasicFlag_Integer | BasicFlag_Untyped, 0, STR_LIT("untyped rune")}},
|
||||
{Type_Basic, {Basic_UntypedNil, BasicFlag_Untyped, 0, STR_LIT("untyped nil")}},
|
||||
{Type_Basic, {Basic_UntypedUndef, BasicFlag_Untyped, 0, STR_LIT("untyped undefined")}},
|
||||
{Type_Basic, {Basic_UntypedUninit, BasicFlag_Untyped, 0, STR_LIT("untyped uninitialized")}},
|
||||
};
|
||||
|
||||
// gb_global Type basic_type_aliases[] = {
|
||||
@@ -589,7 +589,7 @@ gb_global Type *t_untyped_quaternion = &basic_types[Basic_UntypedQuaternion];
|
||||
gb_global Type *t_untyped_string = &basic_types[Basic_UntypedString];
|
||||
gb_global Type *t_untyped_rune = &basic_types[Basic_UntypedRune];
|
||||
gb_global Type *t_untyped_nil = &basic_types[Basic_UntypedNil];
|
||||
gb_global Type *t_untyped_undef = &basic_types[Basic_UntypedUndef];
|
||||
gb_global Type *t_untyped_uninit = &basic_types[Basic_UntypedUninit];
|
||||
|
||||
|
||||
|
||||
@@ -1866,14 +1866,15 @@ gb_internal bool is_type_typeid(Type *t) {
|
||||
}
|
||||
gb_internal bool is_type_untyped_nil(Type *t) {
|
||||
t = base_type(t);
|
||||
return (t->kind == Type_Basic && t->Basic.kind == Basic_UntypedNil);
|
||||
// NOTE(bill): checking for `nil` or `---` at once is just to improve the error handling
|
||||
return (t->kind == Type_Basic && (t->Basic.kind == Basic_UntypedNil || t->Basic.kind == Basic_UntypedUninit));
|
||||
}
|
||||
gb_internal bool is_type_untyped_undef(Type *t) {
|
||||
gb_internal bool is_type_untyped_uninit(Type *t) {
|
||||
t = base_type(t);
|
||||
return (t->kind == Type_Basic && t->Basic.kind == Basic_UntypedUndef);
|
||||
// NOTE(bill): checking for `nil` or `---` at once is just to improve the error handling
|
||||
return (t->kind == Type_Basic && t->Basic.kind == Basic_UntypedUninit);
|
||||
}
|
||||
|
||||
|
||||
gb_internal bool is_type_empty_union(Type *t) {
|
||||
t = base_type(t);
|
||||
return t->kind == Type_Union && t->Union.variants.count == 0;
|
||||
@@ -2206,10 +2207,6 @@ gb_internal bool is_type_polymorphic(Type *t, bool or_specialized=false) {
|
||||
}
|
||||
|
||||
|
||||
gb_internal gb_inline bool type_has_undef(Type *t) {
|
||||
return true;
|
||||
}
|
||||
|
||||
gb_internal bool type_has_nil(Type *t) {
|
||||
t = base_type(t);
|
||||
switch (t->kind) {
|
||||
@@ -2769,13 +2766,23 @@ gb_internal Type *default_type(Type *type) {
|
||||
return type;
|
||||
}
|
||||
|
||||
gb_internal bool union_variant_index_types_equal(Type *v, Type *vt) {
|
||||
if (are_types_identical(v, vt)) {
|
||||
return true;
|
||||
}
|
||||
if (is_type_proc(v) && is_type_proc(vt)) {
|
||||
return are_types_identical(base_type(v), base_type(vt));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
gb_internal i64 union_variant_index(Type *u, Type *v) {
|
||||
u = base_type(u);
|
||||
GB_ASSERT(u->kind == Type_Union);
|
||||
|
||||
for_array(i, u->Union.variants) {
|
||||
Type *vt = u->Union.variants[i];
|
||||
if (are_types_identical(v, vt)) {
|
||||
if (union_variant_index_types_equal(v, vt)) {
|
||||
if (u->Union.kind == UnionType_no_nil) {
|
||||
return cast(i64)(i+0);
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user