mirror of
https://github.com/Ed94/Odin.git
synced 2026-06-20 20:54:59 -07:00
Merge branch 'master' into parser-experiments
This commit is contained in:
+87
-2
@@ -43,11 +43,96 @@ template <typename T> void array_set_capacity (Array<T> *array, isize capac
|
||||
template <typename T> Array<T> array_slice (Array<T> const &array, isize lo, isize hi);
|
||||
template <typename T> Array<T> array_clone (gbAllocator const &a, Array<T> const &array);
|
||||
|
||||
|
||||
|
||||
template <typename T> void array_ordered_remove (Array<T> *array, isize index);
|
||||
template <typename T> void array_unordered_remove(Array<T> *array, isize index);
|
||||
|
||||
template <typename T> void array_copy(Array<T> *array, Array<T> const &data, isize offset);
|
||||
template <typename T> void array_copy(Array<T> *array, Array<T> const &data, isize offset, isize count);
|
||||
|
||||
template <typename T> T *array_end_ptr(Array<T> *array);
|
||||
|
||||
|
||||
template <typename T>
|
||||
struct Slice {
|
||||
T *data;
|
||||
isize count;
|
||||
|
||||
T &operator[](isize index) {
|
||||
#if !defined(NO_ARRAY_BOUNDS_CHECK)
|
||||
GB_ASSERT_MSG(0 <= index && index < count, "Index %td is out of bounds ranges 0..<%td", index, count);
|
||||
#endif
|
||||
return data[index];
|
||||
}
|
||||
|
||||
T const &operator[](isize index) const {
|
||||
#if !defined(NO_ARRAY_BOUNDS_CHECK)
|
||||
GB_ASSERT_MSG(0 <= index && index < count, "Index %td is out of bounds ranges 0..<%td", index, count);
|
||||
#endif
|
||||
return data[index];
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T> Slice<T> slice_from_array(Array<T> const &a);
|
||||
|
||||
|
||||
|
||||
template <typename T>
|
||||
Slice<T> slice_make(gbAllocator const &allocator, isize count) {
|
||||
Slice<T> s = {};
|
||||
s.data = gb_alloc_array(allocator, T, count);
|
||||
s.count = count;
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
Slice<T> slice_from_array(Array<T> const &a) {
|
||||
return {a.data, a.count};
|
||||
}
|
||||
template <typename T>
|
||||
Slice<T> slice_clone(gbAllocator const &allocator, Slice<T> const &a) {
|
||||
T *data = cast(T *)gb_alloc_copy_align(allocator, a.data, a.count*gb_size_of(T), gb_align_of(T));
|
||||
return {data, a.count};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Slice<T> slice_clone_from_array(gbAllocator const &allocator, Array<T> const &a) {
|
||||
auto c = array_clone(allocator, a);
|
||||
return {c.data, c.count};
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
void slice_copy(Slice<T> *slice, Slice<T> const &data, isize offset) {
|
||||
gb_memmove(slice->data+offset, data.data, gb_size_of(T)*data.count);
|
||||
}
|
||||
template <typename T>
|
||||
void slice_copy(Slice<T> *slice, Slice<T> const &data, isize offset, isize count) {
|
||||
gb_memmove(slice->data+offset, data.data, gb_size_of(T)*gb_min(data.count, count));
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <typename T>
|
||||
void slice_ordered_remove(Slice<T> *array, isize index) {
|
||||
GB_ASSERT(0 <= index && index < array->count);
|
||||
|
||||
isize bytes = gb_size_of(T) * (array->count-(index+1));
|
||||
gb_memmove(array->data+index, array->data+index+1, bytes);
|
||||
array->count -= 1;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void slice_unordered_remove(Slice<T> *array, isize index) {
|
||||
GB_ASSERT(0 <= index && index < array->count);
|
||||
|
||||
isize n = array->count-1;
|
||||
if (index != n) {
|
||||
gb_memmove(array->data+index, array->data+n, gb_size_of(T));
|
||||
}
|
||||
array->count -= 1;
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
void array_copy(Array<T> *array, Array<T> const &data, isize offset) {
|
||||
|
||||
@@ -104,6 +104,37 @@ enum BuildModeKind {
|
||||
BuildMode_Assembly,
|
||||
};
|
||||
|
||||
enum CommandKind : u32 {
|
||||
Command_run = 1<<0,
|
||||
Command_build = 1<<1,
|
||||
Command_check = 1<<3,
|
||||
Command_query = 1<<4,
|
||||
Command_doc = 1<<5,
|
||||
Command_version = 1<<6,
|
||||
Command_test = 1<<7,
|
||||
|
||||
Command__does_check = Command_run|Command_build|Command_check|Command_query|Command_doc|Command_test,
|
||||
Command__does_build = Command_run|Command_build|Command_test,
|
||||
Command_all = ~(u32)0,
|
||||
};
|
||||
|
||||
char const *odin_command_strings[32] = {
|
||||
"run",
|
||||
"build",
|
||||
"check",
|
||||
"query",
|
||||
"doc",
|
||||
"version",
|
||||
};
|
||||
|
||||
|
||||
|
||||
enum CmdDocFlag : u32 {
|
||||
CmdDocFlag_Short = 1<<0,
|
||||
CmdDocFlag_AllPackages = 1<<1,
|
||||
};
|
||||
|
||||
|
||||
|
||||
// This stores the information for the specify architecture of this build
|
||||
struct BuildContext {
|
||||
@@ -124,6 +155,7 @@ struct BuildContext {
|
||||
i64 word_size; // Size of a pointer, must be >= 4
|
||||
i64 max_align; // max alignment, must be >= 1 (and typically >= word_size)
|
||||
|
||||
CommandKind command_kind;
|
||||
String command;
|
||||
|
||||
TargetMetrics metrics;
|
||||
@@ -143,6 +175,8 @@ struct BuildContext {
|
||||
bool generate_docs;
|
||||
i32 optimization_level;
|
||||
bool show_timings;
|
||||
bool show_unused;
|
||||
bool show_unused_with_location;
|
||||
bool show_more_timings;
|
||||
bool show_system_calls;
|
||||
bool keep_temp_files;
|
||||
@@ -151,6 +185,7 @@ struct BuildContext {
|
||||
bool no_dynamic_literals;
|
||||
bool no_output_files;
|
||||
bool no_crt;
|
||||
bool no_entry_point;
|
||||
bool use_lld;
|
||||
bool vet;
|
||||
bool cross_compiling;
|
||||
@@ -165,6 +200,9 @@ struct BuildContext {
|
||||
bool ignore_microsoft_magic;
|
||||
bool linker_map_file;
|
||||
|
||||
u32 cmd_doc_flags;
|
||||
Array<String> extra_packages;
|
||||
|
||||
QueryDataSetSettings query_data_set_settings;
|
||||
|
||||
gbAffinity affinity;
|
||||
@@ -297,6 +335,19 @@ bool is_excluded_target_filename(String name) {
|
||||
String original_name = name;
|
||||
name = remove_extension_from_path(name);
|
||||
|
||||
if (string_starts_with(name, str_lit("."))) {
|
||||
// Ignore .*.odin files
|
||||
return true;
|
||||
}
|
||||
|
||||
String test_suffix = str_lit("_test");
|
||||
if (build_context.command_kind != Command_test) {
|
||||
if (string_ends_with(name, test_suffix) && name != test_suffix) {
|
||||
// Ignore *_test.odin files
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
String str1 = {};
|
||||
String str2 = {};
|
||||
isize n = 0;
|
||||
|
||||
+5
-8
@@ -113,7 +113,7 @@ Type *check_init_variable(CheckerContext *ctx, Entity *e, Operand *operand, Stri
|
||||
return e->type;
|
||||
}
|
||||
|
||||
void check_init_variables(CheckerContext *ctx, Entity **lhs, isize lhs_count, Array<Ast *> const &inits, String context_name) {
|
||||
void check_init_variables(CheckerContext *ctx, Entity **lhs, isize lhs_count, Slice<Ast *> const &inits, String context_name) {
|
||||
if ((lhs == nullptr || lhs_count == 0) && inits.count == 0) {
|
||||
return;
|
||||
}
|
||||
@@ -121,8 +121,7 @@ void check_init_variables(CheckerContext *ctx, Entity **lhs, isize lhs_count, Ar
|
||||
|
||||
// NOTE(bill): If there is a bad syntax error, rhs > lhs which would mean there would need to be
|
||||
// an extra allocation
|
||||
auto operands = array_make<Operand>(ctx->allocator, 0, 2*lhs_count);
|
||||
defer (array_free(&operands));
|
||||
auto operands = array_make<Operand>(temporary_allocator(), 0, 2*lhs_count);
|
||||
check_unpack_arguments(ctx, lhs, lhs_count, &operands, inits, true, false);
|
||||
|
||||
isize rhs_count = operands.count;
|
||||
@@ -317,7 +316,6 @@ void check_type_decl(CheckerContext *ctx, Entity *e, Ast *init_expr, Type *def)
|
||||
break;
|
||||
default:
|
||||
error(e->token, "Only struct types can have custom atom operations");
|
||||
gb_free(heap_allocator(), ac.atom_op_table);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -638,7 +636,7 @@ String handle_link_name(CheckerContext *ctx, Token token, String link_name, Stri
|
||||
error(token, "'link_name' and 'link_prefix' cannot be used together");
|
||||
} else {
|
||||
isize len = link_prefix.len + token.string.len;
|
||||
u8 *name = gb_alloc_array(ctx->allocator, u8, len+1);
|
||||
u8 *name = gb_alloc_array(permanent_allocator(), u8, len+1);
|
||||
gb_memmove(name, &link_prefix[0], link_prefix.len);
|
||||
gb_memmove(name+link_prefix.len, &token.string[0], token.string.len);
|
||||
name[len] = 0;
|
||||
@@ -975,7 +973,7 @@ void check_proc_group_decl(CheckerContext *ctx, Entity *pg_entity, DeclInfo *d)
|
||||
|
||||
ast_node(pg, ProcGroup, d->init_expr);
|
||||
|
||||
pge->entities = array_make<Entity*>(ctx->allocator, 0, pg->args.count);
|
||||
pge->entities = array_make<Entity*>(permanent_allocator(), 0, pg->args.count);
|
||||
|
||||
// NOTE(bill): This must be set here to prevent cycles in checking if someone
|
||||
// places the entity within itself
|
||||
@@ -1009,11 +1007,10 @@ void check_proc_group_decl(CheckerContext *ctx, Entity *pg_entity, DeclInfo *d)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ptr_set_exists(&entity_set, e)) {
|
||||
if (ptr_set_update(&entity_set, e)) {
|
||||
error(arg, "Previous use of `%.*s` in procedure group", LIT(e->token.string));
|
||||
continue;
|
||||
}
|
||||
ptr_set_add(&entity_set, e);
|
||||
array_add(&pge->entities, e);
|
||||
}
|
||||
|
||||
|
||||
+349
-150
File diff suppressed because it is too large
Load Diff
+14
-21
@@ -15,7 +15,7 @@ bool is_divigering_stmt(Ast *stmt) {
|
||||
return t->kind == Type_Proc && t->Proc.diverging;
|
||||
}
|
||||
|
||||
void check_stmt_list(CheckerContext *ctx, Array<Ast *> const &stmts, u32 flags) {
|
||||
void check_stmt_list(CheckerContext *ctx, Slice<Ast *> const &stmts, u32 flags) {
|
||||
if (stmts.count == 0) {
|
||||
return;
|
||||
}
|
||||
@@ -78,7 +78,7 @@ void check_stmt_list(CheckerContext *ctx, Array<Ast *> const &stmts, u32 flags)
|
||||
}
|
||||
}
|
||||
|
||||
bool check_is_terminating_list(Array<Ast *> const &stmts, String const &label) {
|
||||
bool check_is_terminating_list(Slice<Ast *> const &stmts, String const &label) {
|
||||
// Iterate backwards
|
||||
for (isize n = stmts.count-1; n >= 0; n--) {
|
||||
Ast *stmt = stmts[n];
|
||||
@@ -96,7 +96,7 @@ bool check_is_terminating_list(Array<Ast *> const &stmts, String const &label) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool check_has_break_list(Array<Ast *> const &stmts, String const &label, bool implicit) {
|
||||
bool check_has_break_list(Slice<Ast *> const &stmts, String const &label, bool implicit) {
|
||||
for_array(i, stmts) {
|
||||
Ast *stmt = stmts[i];
|
||||
if (check_has_break(stmt, label, implicit)) {
|
||||
@@ -641,8 +641,7 @@ void add_constant_switch_case(CheckerContext *ctx, Map<TypeAndToken> *seen, Oper
|
||||
TypeAndToken *found = map_get(seen, key);
|
||||
if (found != nullptr) {
|
||||
isize count = multi_map_count(seen, key);
|
||||
TypeAndToken *taps = gb_alloc_array(ctx->allocator, TypeAndToken, count);
|
||||
defer (gb_free(ctx->allocator, taps));
|
||||
TypeAndToken *taps = gb_alloc_array(temporary_allocator(), TypeAndToken, count);
|
||||
|
||||
multi_map_get_all(seen, key, taps);
|
||||
for (isize i = 0; i < count; i++) {
|
||||
@@ -859,8 +858,7 @@ void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
|
||||
token.pos = ast_token(ss->body).pos;
|
||||
token.string = str_lit("true");
|
||||
|
||||
x.expr = gb_alloc_item(ctx->allocator, Ast);
|
||||
x.expr->kind = Ast_Ident;
|
||||
x.expr = alloc_ast_node(nullptr, Ast_Ident);
|
||||
x.expr->Ident.token = token;
|
||||
}
|
||||
|
||||
@@ -1025,8 +1023,7 @@ void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
|
||||
GB_ASSERT(is_type_enum(et));
|
||||
auto fields = et->Enum.fields;
|
||||
|
||||
auto unhandled = array_make<Entity *>(ctx->allocator, 0, fields.count);
|
||||
defer (array_free(&unhandled));
|
||||
auto unhandled = array_make<Entity *>(temporary_allocator(), 0, fields.count);
|
||||
|
||||
for_array(i, fields) {
|
||||
Entity *f = fields[i];
|
||||
@@ -1265,8 +1262,7 @@ void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
|
||||
GB_ASSERT(is_type_union(ut));
|
||||
auto variants = ut->Union.variants;
|
||||
|
||||
auto unhandled = array_make<Type *>(ctx->allocator, 0, variants.count);
|
||||
defer (array_free(&unhandled));
|
||||
auto unhandled = array_make<Type *>(temporary_allocator(), 0, variants.count);
|
||||
|
||||
for_array(i, variants) {
|
||||
Type *t = variants[i];
|
||||
@@ -1433,12 +1429,11 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// NOTE(bill): If there is a bad syntax error, rhs > lhs which would mean there would need to be
|
||||
// an extra allocation
|
||||
auto lhs_operands = array_make<Operand>(ctx->allocator, lhs_count);
|
||||
auto rhs_operands = array_make<Operand>(ctx->allocator, 0, 2*lhs_count);
|
||||
defer (array_free(&lhs_operands));
|
||||
defer (array_free(&rhs_operands));
|
||||
auto lhs_operands = array_make<Operand>(temporary_allocator(), lhs_count);
|
||||
auto rhs_operands = array_make<Operand>(temporary_allocator(), 0, 2*lhs_count);
|
||||
|
||||
for_array(i, as->lhs) {
|
||||
if (is_blank_ident(as->lhs[i])) {
|
||||
@@ -1462,8 +1457,7 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
|
||||
}
|
||||
}
|
||||
|
||||
auto lhs_to_ignore = array_make<bool>(ctx->allocator, lhs_count);
|
||||
defer (array_free(&lhs_to_ignore));
|
||||
auto lhs_to_ignore = array_make<bool>(temporary_allocator(), lhs_count);
|
||||
|
||||
isize max = gb_min(lhs_count, rhs_count);
|
||||
// NOTE(bill, 2020-05-02): This is an utter hack to get these custom atom operations working
|
||||
@@ -1642,8 +1636,7 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
|
||||
} else if (operands.count != result_count) {
|
||||
error(node, "Expected %td return values, got %td", result_count, operands.count);
|
||||
} else {
|
||||
isize max_count = rs->results.count;
|
||||
for (isize i = 0; i < max_count; i++) {
|
||||
for (isize i = 0; i < result_count; i++) {
|
||||
Entity *e = pt->results->Tuple.variables[i];
|
||||
check_assignment(ctx, &operands[i], e->type, str_lit("return statement"));
|
||||
}
|
||||
@@ -1878,7 +1871,7 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
|
||||
DeclInfo *d = decl_info_of_entity(e);
|
||||
GB_ASSERT(d == nullptr);
|
||||
add_entity(ctx->checker, ctx->scope, e->identifier, e);
|
||||
d = make_decl_info(ctx->allocator, ctx->scope, ctx->decl);
|
||||
d = make_decl_info(ctx->scope, ctx->decl);
|
||||
add_entity_and_decl_info(ctx, e->identifier, e, d);
|
||||
}
|
||||
|
||||
@@ -2036,7 +2029,7 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
|
||||
|
||||
case_ast_node(vd, ValueDecl, node);
|
||||
if (vd->is_mutable) {
|
||||
Entity **entities = gb_alloc_array(ctx->allocator, Entity *, vd->names.count);
|
||||
Entity **entities = gb_alloc_array(permanent_allocator(), Entity *, vd->names.count);
|
||||
isize entity_count = 0;
|
||||
|
||||
isize new_name_count = 0;
|
||||
|
||||
+198
-86
@@ -1,3 +1,4 @@
|
||||
ParameterValue handle_parameter_value(CheckerContext *ctx, Type *in_type, Type **out_type_, Ast *expr, bool allow_caller_location);
|
||||
|
||||
void populate_using_array_index(CheckerContext *ctx, Ast *node, AstField *field, Type *t, String name, i32 idx) {
|
||||
t = base_type(t);
|
||||
@@ -116,7 +117,7 @@ bool does_field_type_allow_using(Type *t) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void check_struct_fields(CheckerContext *ctx, Ast *node, Array<Entity *> *fields, Array<String> *tags, Array<Ast *> const ¶ms,
|
||||
void check_struct_fields(CheckerContext *ctx, Ast *node, Array<Entity *> *fields, Array<String> *tags, Slice<Ast *> const ¶ms,
|
||||
isize init_field_capacity, Type *struct_type, String context) {
|
||||
*fields = array_make<Entity *>(heap_allocator(), 0, init_field_capacity);
|
||||
*tags = array_make<String>(heap_allocator(), 0, init_field_capacity);
|
||||
@@ -388,7 +389,7 @@ void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array<
|
||||
|
||||
if (st->polymorphic_params != nullptr) {
|
||||
ast_node(field_list, FieldList, st->polymorphic_params);
|
||||
Array<Ast *> params = field_list->list;
|
||||
Slice<Ast *> params = field_list->list;
|
||||
if (params.count != 0) {
|
||||
isize variable_count = 0;
|
||||
for_array(i, params) {
|
||||
@@ -399,7 +400,7 @@ void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array<
|
||||
}
|
||||
}
|
||||
|
||||
auto entities = array_make<Entity *>(ctx->allocator, 0, variable_count);
|
||||
auto entities = array_make<Entity *>(permanent_allocator(), 0, variable_count);
|
||||
|
||||
for_array(i, params) {
|
||||
Ast *param = params[i];
|
||||
@@ -408,32 +409,50 @@ void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array<
|
||||
}
|
||||
ast_node(p, Field, param);
|
||||
Ast *type_expr = p->type;
|
||||
Ast *default_value = unparen_expr(p->default_value);
|
||||
Type *type = nullptr;
|
||||
bool is_type_param = false;
|
||||
bool is_type_polymorphic_type = false;
|
||||
if (type_expr == nullptr) {
|
||||
if (type_expr == nullptr && default_value == nullptr) {
|
||||
error(param, "Expected a type for this parameter");
|
||||
continue;
|
||||
}
|
||||
if (type_expr->kind == Ast_Ellipsis) {
|
||||
type_expr = type_expr->Ellipsis.expr;
|
||||
error(param, "A polymorphic parameter cannot be variadic");
|
||||
}
|
||||
if (type_expr->kind == Ast_TypeidType) {
|
||||
is_type_param = true;
|
||||
Type *specialization = nullptr;
|
||||
if (type_expr->TypeidType.specialization != nullptr) {
|
||||
Ast *s = type_expr->TypeidType.specialization;
|
||||
specialization = check_type(ctx, s);
|
||||
|
||||
if (type_expr != nullptr) {
|
||||
if (type_expr->kind == Ast_Ellipsis) {
|
||||
type_expr = type_expr->Ellipsis.expr;
|
||||
error(param, "A polymorphic parameter cannot be variadic");
|
||||
}
|
||||
type = alloc_type_generic(ctx->scope, 0, str_lit(""), specialization);
|
||||
} else {
|
||||
type = check_type(ctx, type_expr);
|
||||
if (is_type_polymorphic(type)) {
|
||||
is_type_polymorphic_type = true;
|
||||
if (type_expr->kind == Ast_TypeidType) {
|
||||
is_type_param = true;
|
||||
Type *specialization = nullptr;
|
||||
if (type_expr->TypeidType.specialization != nullptr) {
|
||||
Ast *s = type_expr->TypeidType.specialization;
|
||||
specialization = check_type(ctx, s);
|
||||
}
|
||||
type = alloc_type_generic(ctx->scope, 0, str_lit(""), specialization);
|
||||
} else {
|
||||
type = check_type(ctx, type_expr);
|
||||
if (is_type_polymorphic(type)) {
|
||||
is_type_polymorphic_type = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ParameterValue param_value = {};
|
||||
if (default_value != nullptr) {
|
||||
Type *out_type = nullptr;
|
||||
param_value = handle_parameter_value(ctx, type, &out_type, default_value, false);
|
||||
if (type == nullptr && out_type != nullptr) {
|
||||
type = out_type;
|
||||
}
|
||||
if (param_value.kind != ParameterValue_Constant && param_value.kind != ParameterValue_Nil) {
|
||||
error(default_value, "Invalid parameter value");
|
||||
param_value = {};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (type == nullptr) {
|
||||
error(params[i], "Invalid parameter type");
|
||||
type = t_invalid;
|
||||
@@ -471,7 +490,14 @@ void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array<
|
||||
Token token = name->Ident.token;
|
||||
|
||||
if (poly_operands != nullptr) {
|
||||
Operand operand = (*poly_operands)[entities.count];
|
||||
Operand operand = {};
|
||||
operand.type = t_invalid;
|
||||
if (entities.count < poly_operands->count) {
|
||||
operand = (*poly_operands)[entities.count];
|
||||
} else if (param_value.kind != ParameterValue_Invalid) {
|
||||
operand.mode = Addressing_Constant;
|
||||
operand.value = param_value.value;
|
||||
}
|
||||
if (is_type_param) {
|
||||
if (is_type_polymorphic(base_type(operand.type))) {
|
||||
is_polymorphic = true;
|
||||
@@ -486,6 +512,7 @@ void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array<
|
||||
}
|
||||
if (e == nullptr) {
|
||||
e = alloc_entity_constant(scope, token, operand.type, operand.value);
|
||||
e->Constant.param_value = param_value;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -493,7 +520,8 @@ void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array<
|
||||
e = alloc_entity_type_name(scope, token, type);
|
||||
e->TypeName.is_type_alias = true;
|
||||
} else {
|
||||
e = alloc_entity_constant(scope, token, type, empty_exact_value);
|
||||
e = alloc_entity_constant(scope, token, type, param_value.value);
|
||||
e->Constant.param_value = param_value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -568,7 +596,7 @@ void check_union_type(CheckerContext *ctx, Type *union_type, Ast *node, Array<Op
|
||||
|
||||
Entity *using_index_expr = nullptr;
|
||||
|
||||
auto variants = array_make<Type *>(ctx->allocator, 0, variant_count);
|
||||
auto variants = array_make<Type *>(permanent_allocator(), 0, variant_count);
|
||||
|
||||
union_type->Union.scope = ctx->scope;
|
||||
|
||||
@@ -579,7 +607,7 @@ void check_union_type(CheckerContext *ctx, Type *union_type, Ast *node, Array<Op
|
||||
|
||||
if (ut->polymorphic_params != nullptr) {
|
||||
ast_node(field_list, FieldList, ut->polymorphic_params);
|
||||
Array<Ast *> params = field_list->list;
|
||||
Slice<Ast *> params = field_list->list;
|
||||
if (params.count != 0) {
|
||||
isize variable_count = 0;
|
||||
for_array(i, params) {
|
||||
@@ -590,7 +618,7 @@ void check_union_type(CheckerContext *ctx, Type *union_type, Ast *node, Array<Op
|
||||
}
|
||||
}
|
||||
|
||||
auto entities = array_make<Entity *>(ctx->allocator, 0, variable_count);
|
||||
auto entities = array_make<Entity *>(permanent_allocator(), 0, variable_count);
|
||||
|
||||
for_array(i, params) {
|
||||
Ast *param = params[i];
|
||||
@@ -599,29 +627,45 @@ void check_union_type(CheckerContext *ctx, Type *union_type, Ast *node, Array<Op
|
||||
}
|
||||
ast_node(p, Field, param);
|
||||
Ast *type_expr = p->type;
|
||||
Ast *default_value = unparen_expr(p->default_value);
|
||||
Type *type = nullptr;
|
||||
bool is_type_param = false;
|
||||
bool is_type_polymorphic_type = false;
|
||||
if (type_expr == nullptr) {
|
||||
if (type_expr == nullptr && default_value == nullptr) {
|
||||
error(param, "Expected a type for this parameter");
|
||||
continue;
|
||||
}
|
||||
if (type_expr->kind == Ast_Ellipsis) {
|
||||
type_expr = type_expr->Ellipsis.expr;
|
||||
error(param, "A polymorphic parameter cannot be variadic");
|
||||
}
|
||||
if (type_expr->kind == Ast_TypeidType) {
|
||||
is_type_param = true;
|
||||
Type *specialization = nullptr;
|
||||
if (type_expr->TypeidType.specialization != nullptr) {
|
||||
Ast *s = type_expr->TypeidType.specialization;
|
||||
specialization = check_type(ctx, s);
|
||||
if (type_expr != nullptr) {
|
||||
if (type_expr->kind == Ast_Ellipsis) {
|
||||
type_expr = type_expr->Ellipsis.expr;
|
||||
error(param, "A polymorphic parameter cannot be variadic");
|
||||
}
|
||||
type = alloc_type_generic(ctx->scope, 0, str_lit(""), specialization);
|
||||
} else {
|
||||
type = check_type(ctx, type_expr);
|
||||
if (is_type_polymorphic(type)) {
|
||||
is_type_polymorphic_type = true;
|
||||
if (type_expr->kind == Ast_TypeidType) {
|
||||
is_type_param = true;
|
||||
Type *specialization = nullptr;
|
||||
if (type_expr->TypeidType.specialization != nullptr) {
|
||||
Ast *s = type_expr->TypeidType.specialization;
|
||||
specialization = check_type(ctx, s);
|
||||
}
|
||||
type = alloc_type_generic(ctx->scope, 0, str_lit(""), specialization);
|
||||
} else {
|
||||
type = check_type(ctx, type_expr);
|
||||
if (is_type_polymorphic(type)) {
|
||||
is_type_polymorphic_type = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ParameterValue param_value = {};
|
||||
if (default_value != nullptr) {
|
||||
Type *out_type = nullptr;
|
||||
param_value = handle_parameter_value(ctx, type, &out_type, default_value, false);
|
||||
if (type == nullptr && out_type != nullptr) {
|
||||
type = out_type;
|
||||
}
|
||||
if (param_value.kind != ParameterValue_Constant && param_value.kind != ParameterValue_Nil) {
|
||||
error(default_value, "Invalid parameter value");
|
||||
param_value = {};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -662,7 +706,14 @@ void check_union_type(CheckerContext *ctx, Type *union_type, Ast *node, Array<Op
|
||||
Token token = name->Ident.token;
|
||||
|
||||
if (poly_operands != nullptr) {
|
||||
Operand operand = (*poly_operands)[entities.count];
|
||||
Operand operand = {};
|
||||
operand.type = t_invalid;
|
||||
if (entities.count < poly_operands->count) {
|
||||
operand = (*poly_operands)[entities.count];
|
||||
} else if (param_value.kind != ParameterValue_Invalid) {
|
||||
operand.mode = Addressing_Constant;
|
||||
operand.value = param_value.value;
|
||||
}
|
||||
if (is_type_param) {
|
||||
GB_ASSERT(operand.mode == Addressing_Type ||
|
||||
operand.mode == Addressing_Invalid);
|
||||
@@ -675,6 +726,7 @@ void check_union_type(CheckerContext *ctx, Type *union_type, Ast *node, Array<Op
|
||||
} else {
|
||||
// GB_ASSERT(operand.mode == Addressing_Constant);
|
||||
e = alloc_entity_constant(scope, token, operand.type, operand.value);
|
||||
e->Constant.param_value = param_value;
|
||||
}
|
||||
} else {
|
||||
if (is_type_param) {
|
||||
@@ -682,6 +734,7 @@ void check_union_type(CheckerContext *ctx, Type *union_type, Ast *node, Array<Op
|
||||
e->TypeName.is_type_alias = true;
|
||||
} else {
|
||||
e = alloc_entity_constant(scope, token, type, empty_exact_value);
|
||||
e->Constant.param_value = param_value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -816,7 +869,7 @@ void check_enum_type(CheckerContext *ctx, Type *enum_type, Type *named_type, Ast
|
||||
enum_type->Enum.base_type = base_type;
|
||||
enum_type->Enum.scope = ctx->scope;
|
||||
|
||||
auto fields = array_make<Entity *>(ctx->allocator, 0, et->fields.count);
|
||||
auto fields = array_make<Entity *>(permanent_allocator(), 0, et->fields.count);
|
||||
|
||||
Type *constant_type = enum_type;
|
||||
if (named_type != nullptr) {
|
||||
@@ -933,9 +986,9 @@ void check_bit_field_type(CheckerContext *ctx, Type *bit_field_type, Ast *node)
|
||||
ast_node(bft, BitFieldType, node);
|
||||
GB_ASSERT(is_type_bit_field(bit_field_type));
|
||||
|
||||
auto fields = array_make<Entity*>(ctx->allocator, 0, bft->fields.count);
|
||||
auto sizes = array_make<u32> (ctx->allocator, 0, bft->fields.count);
|
||||
auto offsets = array_make<u32> (ctx->allocator, 0, bft->fields.count);
|
||||
auto fields = array_make<Entity*>(permanent_allocator(), 0, bft->fields.count);
|
||||
auto sizes = array_make<u32> (permanent_allocator(), 0, bft->fields.count);
|
||||
auto offsets = array_make<u32> (permanent_allocator(), 0, bft->fields.count);
|
||||
|
||||
scope_reserve(ctx->scope, bft->fields.count);
|
||||
|
||||
@@ -1337,7 +1390,7 @@ Type *determine_type_from_polymorphic(CheckerContext *ctx, Type *poly_type, Oper
|
||||
|
||||
if (is_polymorphic_type_assignable(ctx, poly_type, operand.type, false, modify_type)) {
|
||||
if (show_error) {
|
||||
set_procedure_abi_types(ctx->allocator, poly_type);
|
||||
set_procedure_abi_types(poly_type);
|
||||
}
|
||||
return poly_type;
|
||||
}
|
||||
@@ -1463,7 +1516,7 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is
|
||||
|
||||
bool success = true;
|
||||
ast_node(field_list, FieldList, _params);
|
||||
Array<Ast *> params = field_list->list;
|
||||
Slice<Ast *> params = field_list->list;
|
||||
|
||||
if (params.count == 0) {
|
||||
if (success_) *success_ = success;
|
||||
@@ -1496,7 +1549,7 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is
|
||||
bool is_variadic = false;
|
||||
isize variadic_index = -1;
|
||||
bool is_c_vararg = false;
|
||||
auto variables = array_make<Entity *>(ctx->allocator, 0, variable_count);
|
||||
auto variables = array_make<Entity *>(permanent_allocator(), 0, variable_count);
|
||||
for_array(i, params) {
|
||||
Ast *param = params[i];
|
||||
if (param->kind != Ast_Field) {
|
||||
@@ -1822,7 +1875,7 @@ Type *check_get_results(CheckerContext *ctx, Scope *scope, Ast *_results) {
|
||||
return nullptr;
|
||||
}
|
||||
ast_node(field_list, FieldList, _results);
|
||||
Array<Ast *> results = field_list->list;
|
||||
Slice<Ast *> results = field_list->list;
|
||||
|
||||
if (results.count == 0) {
|
||||
return nullptr;
|
||||
@@ -1838,7 +1891,7 @@ Type *check_get_results(CheckerContext *ctx, Scope *scope, Ast *_results) {
|
||||
}
|
||||
}
|
||||
|
||||
auto variables = array_make<Entity *>(ctx->allocator, 0, variable_count);
|
||||
auto variables = array_make<Entity *>(permanent_allocator(), 0, variable_count);
|
||||
for_array(i, results) {
|
||||
ast_node(field, Field, results[i]);
|
||||
Ast *default_value = unparen_expr(field->default_value);
|
||||
@@ -2209,6 +2262,11 @@ Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type, ProcCall
|
||||
return new_type;
|
||||
}
|
||||
|
||||
if (is_type_proc(original_type)) {
|
||||
// NOTE(bill): Force a cast to prevent a possible type cycle
|
||||
return t_rawptr;
|
||||
}
|
||||
|
||||
if (cc == ProcCC_None || cc == ProcCC_PureNone || cc == ProcCC_InlineAsm) {
|
||||
return new_type;
|
||||
}
|
||||
@@ -2221,7 +2279,11 @@ Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type, ProcCall
|
||||
return new_type;
|
||||
}
|
||||
if (build_context.ODIN_ARCH == "amd64") {
|
||||
if (is_type_integer_128bit(original_type)) {
|
||||
bool is_128 = is_type_integer_128bit(original_type);
|
||||
if (!is_128 && is_type_bit_set(original_type) && type_size_of(original_type) == 16) {
|
||||
// is_128 = true;
|
||||
}
|
||||
if (is_128) {
|
||||
if (build_context.ODIN_OS == "windows") {
|
||||
return alloc_type_simd_vector(2, t_u64);
|
||||
} else {
|
||||
@@ -2332,6 +2394,11 @@ Type *type_to_abi_compat_result_type(gbAllocator a, Type *original_type, ProcCal
|
||||
return new_type;
|
||||
}
|
||||
|
||||
if (is_type_proc(single_type)) {
|
||||
// NOTE(bill): Force a cast to prevent a possible type cycle
|
||||
return t_rawptr;
|
||||
}
|
||||
|
||||
if (is_type_simd_vector(single_type)) {
|
||||
return new_type;
|
||||
}
|
||||
@@ -2445,16 +2512,21 @@ bool abi_compat_return_by_pointer(gbAllocator a, ProcCallingConvention cc, Type
|
||||
return false;
|
||||
}
|
||||
|
||||
void set_procedure_abi_types(gbAllocator allocator, Type *type) {
|
||||
void set_procedure_abi_types(Type *type) {
|
||||
type = base_type(type);
|
||||
if (type->kind != Type_Proc) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (type->Proc.abi_types_set) {
|
||||
if (type->Proc.abi_types_set || type->flags & TypeFlag_InProcessOfCheckingABI) {
|
||||
return;
|
||||
}
|
||||
|
||||
gbAllocator allocator = permanent_allocator();
|
||||
|
||||
u32 flags = type->flags;
|
||||
type->flags |= TypeFlag_InProcessOfCheckingABI;
|
||||
|
||||
type->Proc.abi_compat_params = array_make<Type *>(allocator, cast(isize)type->Proc.param_count);
|
||||
for (i32 i = 0; i < type->Proc.param_count; i++) {
|
||||
Entity *e = type->Proc.params->Tuple.variables[i];
|
||||
@@ -2466,7 +2538,7 @@ void set_procedure_abi_types(gbAllocator allocator, Type *type) {
|
||||
case ProcCC_Odin:
|
||||
case ProcCC_Contextless:
|
||||
case ProcCC_Pure:
|
||||
if (is_type_pointer(new_type) & !is_type_pointer(e->type)) {
|
||||
if (is_type_pointer(new_type) && !is_type_pointer(e->type) && !is_type_proc(e->type)) {
|
||||
e->flags |= EntityFlag_ImplicitReference;
|
||||
}
|
||||
break;
|
||||
@@ -2474,7 +2546,7 @@ void set_procedure_abi_types(gbAllocator allocator, Type *type) {
|
||||
|
||||
if (build_context.ODIN_OS == "linux" ||
|
||||
build_context.ODIN_OS == "darwin") {
|
||||
if (is_type_pointer(new_type) & !is_type_pointer(e->type)) {
|
||||
if (is_type_pointer(new_type) & !is_type_pointer(e->type) && !is_type_proc(e->type)) {
|
||||
e->flags |= EntityFlag_ByVal;
|
||||
}
|
||||
}
|
||||
@@ -2484,13 +2556,13 @@ void set_procedure_abi_types(gbAllocator allocator, Type *type) {
|
||||
for (i32 i = 0; i < type->Proc.param_count; i++) {
|
||||
Entity *e = type->Proc.params->Tuple.variables[i];
|
||||
if (e->kind == Entity_Variable) {
|
||||
set_procedure_abi_types(allocator, e->type);
|
||||
set_procedure_abi_types(e->type);
|
||||
}
|
||||
}
|
||||
for (i32 i = 0; i < type->Proc.result_count; i++) {
|
||||
Entity *e = type->Proc.results->Tuple.variables[i];
|
||||
if (e->kind == Entity_Variable) {
|
||||
set_procedure_abi_types(allocator, e->type);
|
||||
set_procedure_abi_types(e->type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2499,6 +2571,7 @@ void set_procedure_abi_types(gbAllocator allocator, Type *type) {
|
||||
type->Proc.return_by_pointer = abi_compat_return_by_pointer(allocator, type->Proc.calling_convention, type->Proc.abi_compat_result_type);
|
||||
|
||||
type->Proc.abi_types_set = true;
|
||||
type->flags = flags;
|
||||
}
|
||||
|
||||
// NOTE(bill): 'operands' is for generating non generic procedure type
|
||||
@@ -2711,30 +2784,29 @@ void init_map_entry_type(Type *type) {
|
||||
if (type->Map.entry_type != nullptr) return;
|
||||
|
||||
// NOTE(bill): The preload types may have not been set yet
|
||||
GB_ASSERT(t_map_key != nullptr);
|
||||
gbAllocator a = heap_allocator();
|
||||
GB_ASSERT(t_map_hash != nullptr);
|
||||
Type *entry_type = alloc_type_struct();
|
||||
|
||||
/*
|
||||
struct {
|
||||
hash: __MapKey;
|
||||
next: int;
|
||||
key: Key;
|
||||
value: Value;
|
||||
hash: runtime.Map_Hash,
|
||||
next: int,
|
||||
key: Key,
|
||||
value: Value,
|
||||
}
|
||||
*/
|
||||
Ast *dummy_node = alloc_ast_node(nullptr, Ast_Invalid);
|
||||
Scope *s = create_scope(builtin_pkg->scope, a);
|
||||
Scope *s = create_scope(builtin_pkg->scope);
|
||||
|
||||
auto fields = array_make<Entity *>(a, 0, 3);
|
||||
array_add(&fields, alloc_entity_field(s, make_token_ident(str_lit("key")), t_map_key, false, 0, EntityState_Resolved));
|
||||
array_add(&fields, alloc_entity_field(s, make_token_ident(str_lit("next")), t_int, false, 1, EntityState_Resolved));
|
||||
array_add(&fields, alloc_entity_field(s, make_token_ident(str_lit("value")), type->Map.value, false, 2, EntityState_Resolved));
|
||||
auto fields = array_make<Entity *>(permanent_allocator(), 0, 4);
|
||||
array_add(&fields, alloc_entity_field(s, make_token_ident(str_lit("hash")), t_uintptr, false, cast(i32)fields.count, EntityState_Resolved));
|
||||
array_add(&fields, alloc_entity_field(s, make_token_ident(str_lit("next")), t_int, false, cast(i32)fields.count, EntityState_Resolved));
|
||||
array_add(&fields, alloc_entity_field(s, make_token_ident(str_lit("key")), type->Map.key, false, cast(i32)fields.count, EntityState_Resolved));
|
||||
array_add(&fields, alloc_entity_field(s, make_token_ident(str_lit("value")), type->Map.value, false, cast(i32)fields.count, EntityState_Resolved));
|
||||
|
||||
|
||||
entry_type->Struct.fields = fields;
|
||||
|
||||
// type_set_offsets(a, entry_type);
|
||||
type->Map.entry_type = entry_type;
|
||||
}
|
||||
|
||||
@@ -2757,15 +2829,14 @@ void init_map_internal_types(Type *type) {
|
||||
entries: [dynamic]EntryType;
|
||||
}
|
||||
*/
|
||||
gbAllocator a = heap_allocator();
|
||||
Ast *dummy_node = alloc_ast_node(nullptr, Ast_Invalid);
|
||||
Scope *s = create_scope(builtin_pkg->scope, a);
|
||||
Scope *s = create_scope(builtin_pkg->scope);
|
||||
|
||||
Type *hashes_type = alloc_type_slice(t_int);
|
||||
Type *entries_type = alloc_type_dynamic_array(type->Map.entry_type);
|
||||
|
||||
|
||||
auto fields = array_make<Entity *>(a, 0, 2);
|
||||
auto fields = array_make<Entity *>(permanent_allocator(), 0, 2);
|
||||
array_add(&fields, alloc_entity_field(s, make_token_ident(str_lit("hashes")), hashes_type, false, 0, EntityState_Resolved));
|
||||
array_add(&fields, alloc_entity_field(s, make_token_ident(str_lit("entries")), entries_type, false, 1, EntityState_Resolved));
|
||||
|
||||
@@ -2777,6 +2848,47 @@ void init_map_internal_types(Type *type) {
|
||||
type->Map.lookup_result_type = make_optional_ok_type(value);
|
||||
}
|
||||
|
||||
void add_map_key_type_dependencies(CheckerContext *ctx, Type *key) {
|
||||
key = core_type(key);
|
||||
|
||||
if (is_type_cstring(key)) {
|
||||
add_package_dependency(ctx, "runtime", "default_hasher_cstring");
|
||||
} else if (is_type_string(key)) {
|
||||
add_package_dependency(ctx, "runtime", "default_hasher_string");
|
||||
} else if (!is_type_polymorphic(key)) {
|
||||
if (!is_type_comparable(key)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_type_simple_compare(key)) {
|
||||
i64 sz = type_size_of(key);
|
||||
if (1 <= sz && sz <= 16) {
|
||||
char buf[20] = {};
|
||||
gb_snprintf(buf, 20, "default_hasher%d", cast(i32)sz);
|
||||
add_package_dependency(ctx, "runtime", buf);
|
||||
return;
|
||||
} else {
|
||||
add_package_dependency(ctx, "runtime", "default_hasher_n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (key->kind == Type_Struct) {
|
||||
add_package_dependency(ctx, "runtime", "default_hasher_n");
|
||||
for_array(i, key->Struct.fields) {
|
||||
Entity *field = key->Struct.fields[i];
|
||||
add_map_key_type_dependencies(ctx, field->type);
|
||||
}
|
||||
} else if (key->kind == Type_EnumeratedArray) {
|
||||
add_package_dependency(ctx, "runtime", "default_hasher_n");
|
||||
add_map_key_type_dependencies(ctx, key->EnumeratedArray.elem);
|
||||
} else if (key->kind == Type_Array) {
|
||||
add_package_dependency(ctx, "runtime", "default_hasher_n");
|
||||
add_map_key_type_dependencies(ctx, key->Array.elem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void check_map_type(CheckerContext *ctx, Type *type, Ast *node) {
|
||||
GB_ASSERT(type->kind == Type_Map);
|
||||
ast_node(mt, MapType, node);
|
||||
@@ -2793,16 +2905,16 @@ void check_map_type(CheckerContext *ctx, Type *type, Ast *node) {
|
||||
gb_string_free(str);
|
||||
}
|
||||
}
|
||||
if (type_size_of(key) == 0) {
|
||||
gbString str = type_to_string(key);
|
||||
error(node, "Invalid type of a key for a map of size 0, got '%s'", str);
|
||||
gb_string_free(str);
|
||||
}
|
||||
|
||||
type->Map.key = key;
|
||||
type->Map.value = value;
|
||||
|
||||
if (is_type_string(key)) {
|
||||
add_package_dependency(ctx, "runtime", "default_hash_string");
|
||||
} else {
|
||||
add_package_dependency(ctx, "runtime", "default_hash_ptr");
|
||||
}
|
||||
|
||||
add_map_key_type_dependencies(ctx, key);
|
||||
|
||||
init_core_map_type(ctx->checker);
|
||||
init_map_internal_types(type);
|
||||
@@ -2833,7 +2945,7 @@ Type *make_soa_struct_fixed(CheckerContext *ctx, Ast *array_typ_expr, Ast *elem_
|
||||
soa_struct->Struct.soa_elem = elem;
|
||||
soa_struct->Struct.soa_count = count;
|
||||
|
||||
scope = create_scope(ctx->scope, ctx->allocator);
|
||||
scope = create_scope(ctx->scope);
|
||||
soa_struct->Struct.scope = scope;
|
||||
|
||||
String params_xyzw[4] = {
|
||||
@@ -2866,7 +2978,7 @@ Type *make_soa_struct_fixed(CheckerContext *ctx, Ast *array_typ_expr, Ast *elem_
|
||||
soa_struct->Struct.soa_elem = elem;
|
||||
soa_struct->Struct.soa_count = count;
|
||||
|
||||
scope = create_scope(old_struct->Struct.scope->parent, ctx->allocator);
|
||||
scope = create_scope(old_struct->Struct.scope->parent);
|
||||
soa_struct->Struct.scope = scope;
|
||||
|
||||
for_array(i, old_struct->Struct.fields) {
|
||||
@@ -2927,7 +3039,7 @@ Type *make_soa_struct_slice(CheckerContext *ctx, Ast *array_typ_expr, Ast *elem_
|
||||
soa_struct->Struct.soa_count = 0;
|
||||
soa_struct->Struct.is_polymorphic = true;
|
||||
|
||||
scope = create_scope(ctx->scope, ctx->allocator);
|
||||
scope = create_scope(ctx->scope);
|
||||
soa_struct->Struct.scope = scope;
|
||||
} else if (is_type_array(elem)) {
|
||||
Type *old_array = base_type(elem);
|
||||
@@ -2941,7 +3053,7 @@ Type *make_soa_struct_slice(CheckerContext *ctx, Ast *array_typ_expr, Ast *elem_
|
||||
soa_struct->Struct.soa_elem = elem;
|
||||
soa_struct->Struct.soa_count = 0;
|
||||
|
||||
scope = create_scope(ctx->scope, ctx->allocator);
|
||||
scope = create_scope(ctx->scope);
|
||||
soa_struct->Struct.scope = scope;
|
||||
|
||||
String params_xyzw[4] = {
|
||||
@@ -2977,7 +3089,7 @@ Type *make_soa_struct_slice(CheckerContext *ctx, Ast *array_typ_expr, Ast *elem_
|
||||
soa_struct->Struct.soa_elem = elem;
|
||||
soa_struct->Struct.soa_count = 0;
|
||||
|
||||
scope = create_scope(old_struct->Struct.scope->parent, ctx->allocator);
|
||||
scope = create_scope(old_struct->Struct.scope->parent);
|
||||
soa_struct->Struct.scope = scope;
|
||||
|
||||
for_array(i, old_struct->Struct.fields) {
|
||||
@@ -3044,7 +3156,7 @@ Type *make_soa_struct_dynamic_array(CheckerContext *ctx, Ast *array_typ_expr, As
|
||||
soa_struct->Struct.soa_count = 0;
|
||||
soa_struct->Struct.is_polymorphic = true;
|
||||
|
||||
scope = create_scope(ctx->scope, ctx->allocator);
|
||||
scope = create_scope(ctx->scope);
|
||||
soa_struct->Struct.scope = scope;
|
||||
} else if (is_type_array(elem)) {
|
||||
Type *old_array = base_type(elem);
|
||||
@@ -3058,7 +3170,7 @@ Type *make_soa_struct_dynamic_array(CheckerContext *ctx, Ast *array_typ_expr, As
|
||||
soa_struct->Struct.soa_elem = elem;
|
||||
soa_struct->Struct.soa_count = 0;
|
||||
|
||||
scope = create_scope(ctx->scope, ctx->allocator);
|
||||
scope = create_scope(ctx->scope);
|
||||
soa_struct->Struct.scope = scope;
|
||||
|
||||
String params_xyzw[4] = {
|
||||
@@ -3093,7 +3205,7 @@ Type *make_soa_struct_dynamic_array(CheckerContext *ctx, Ast *array_typ_expr, As
|
||||
soa_struct->Struct.soa_elem = elem;
|
||||
soa_struct->Struct.soa_count = 0;
|
||||
|
||||
scope = create_scope(old_struct->Struct.scope->parent, ctx->allocator);
|
||||
scope = create_scope(old_struct->Struct.scope->parent);
|
||||
soa_struct->Struct.scope = scope;
|
||||
|
||||
for_array(i, old_struct->Struct.fields) {
|
||||
|
||||
+188
-79
@@ -187,8 +187,8 @@ void init_decl_info(DeclInfo *d, Scope *scope, DeclInfo *parent) {
|
||||
array_init (&d->labels, heap_allocator());
|
||||
}
|
||||
|
||||
DeclInfo *make_decl_info(gbAllocator a, Scope *scope, DeclInfo *parent) {
|
||||
DeclInfo *d = gb_alloc_item(a, DeclInfo);
|
||||
DeclInfo *make_decl_info(Scope *scope, DeclInfo *parent) {
|
||||
DeclInfo *d = gb_alloc_item(permanent_allocator(), DeclInfo);
|
||||
init_decl_info(d, scope, parent);
|
||||
return d;
|
||||
}
|
||||
@@ -219,8 +219,8 @@ bool decl_info_has_init(DeclInfo *d) {
|
||||
|
||||
|
||||
|
||||
Scope *create_scope(Scope *parent, gbAllocator allocator, isize init_elements_capacity=DEFAULT_SCOPE_CAPACITY) {
|
||||
Scope *s = gb_alloc_item(allocator, Scope);
|
||||
Scope *create_scope(Scope *parent, isize init_elements_capacity=DEFAULT_SCOPE_CAPACITY) {
|
||||
Scope *s = gb_alloc_item(permanent_allocator(), Scope);
|
||||
s->parent = parent;
|
||||
string_map_init(&s->elements, heap_allocator(), init_elements_capacity);
|
||||
ptr_set_init(&s->imported, heap_allocator(), 0);
|
||||
@@ -244,7 +244,7 @@ Scope *create_scope_from_file(CheckerContext *c, AstFile *f) {
|
||||
GB_ASSERT(f->pkg != nullptr);
|
||||
GB_ASSERT(f->pkg->scope != nullptr);
|
||||
|
||||
Scope *s = create_scope(f->pkg->scope, c->allocator);
|
||||
Scope *s = create_scope(f->pkg->scope);
|
||||
|
||||
array_reserve(&s->delayed_imports, f->imports.count);
|
||||
array_reserve(&s->delayed_directives, f->directive_count);
|
||||
@@ -264,7 +264,7 @@ Scope *create_scope_from_package(CheckerContext *c, AstPackage *pkg) {
|
||||
decl_count += pkg->files[i]->decls.count;
|
||||
}
|
||||
isize init_elements_capacity = 2*decl_count;
|
||||
Scope *s = create_scope(builtin_pkg->scope, c->allocator, init_elements_capacity);
|
||||
Scope *s = create_scope(builtin_pkg->scope, init_elements_capacity);
|
||||
|
||||
s->flags |= ScopeFlag_Pkg;
|
||||
s->pkg = pkg;
|
||||
@@ -324,7 +324,7 @@ void check_open_scope(CheckerContext *c, Ast *node) {
|
||||
GB_ASSERT(node->kind == Ast_Invalid ||
|
||||
is_ast_stmt(node) ||
|
||||
is_ast_type(node));
|
||||
Scope *scope = create_scope(c->scope, c->allocator);
|
||||
Scope *scope = create_scope(c->scope);
|
||||
add_scope(c, node, scope);
|
||||
switch (node->kind) {
|
||||
case Ast_ProcType:
|
||||
@@ -368,9 +368,14 @@ void scope_lookup_parent(Scope *scope, String const &name, Scope **scope_, Entit
|
||||
if (e->kind == Entity_Label) {
|
||||
continue;
|
||||
}
|
||||
if (e->kind == Entity_Variable &&
|
||||
!(e->scope->flags&ScopeFlag_File)) {
|
||||
continue;
|
||||
if (e->kind == Entity_Variable) {
|
||||
if (e->scope->flags&ScopeFlag_File) {
|
||||
// Global variables are file to access
|
||||
} else if (e->flags&EntityFlag_Static) {
|
||||
// Allow static/thread_local variables to be referenced
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -690,31 +695,33 @@ void add_global_type_entity(String name, Type *type) {
|
||||
|
||||
void init_universal(void) {
|
||||
BuildContext *bc = &build_context;
|
||||
|
||||
// NOTE(bill): No need to free these
|
||||
gbAllocator a = heap_allocator();
|
||||
// gbAllocator a = heap_allocator();
|
||||
gbAllocator a = permanent_allocator();
|
||||
|
||||
builtin_pkg = gb_alloc_item(a, AstPackage);
|
||||
builtin_pkg->name = str_lit("builtin");
|
||||
builtin_pkg->kind = Package_Normal;
|
||||
|
||||
builtin_pkg->scope = create_scope(nullptr, a);
|
||||
builtin_pkg->scope->flags |= ScopeFlag_Pkg | ScopeFlag_Global;
|
||||
builtin_pkg->scope = create_scope(nullptr);
|
||||
builtin_pkg->scope->flags |= ScopeFlag_Pkg | ScopeFlag_Global | ScopeFlag_Builtin;
|
||||
builtin_pkg->scope->pkg = builtin_pkg;
|
||||
|
||||
intrinsics_pkg = gb_alloc_item(a, AstPackage);
|
||||
intrinsics_pkg->name = str_lit("intrinsics");
|
||||
intrinsics_pkg->kind = Package_Normal;
|
||||
|
||||
intrinsics_pkg->scope = create_scope(nullptr, a);
|
||||
intrinsics_pkg->scope->flags |= ScopeFlag_Pkg | ScopeFlag_Global;
|
||||
intrinsics_pkg->scope = create_scope(nullptr);
|
||||
intrinsics_pkg->scope->flags |= ScopeFlag_Pkg | ScopeFlag_Global | ScopeFlag_Builtin;
|
||||
intrinsics_pkg->scope->pkg = intrinsics_pkg;
|
||||
|
||||
config_pkg = gb_alloc_item(a, AstPackage);
|
||||
config_pkg->name = str_lit("config");
|
||||
config_pkg->kind = Package_Normal;
|
||||
|
||||
config_pkg->scope = create_scope(nullptr, a);
|
||||
config_pkg->scope->flags |= ScopeFlag_Pkg | ScopeFlag_Global;
|
||||
config_pkg->scope = create_scope(nullptr);
|
||||
config_pkg->scope->flags |= ScopeFlag_Pkg | ScopeFlag_Global | ScopeFlag_Builtin;
|
||||
config_pkg->scope->pkg = config_pkg;
|
||||
|
||||
|
||||
@@ -724,6 +731,18 @@ void init_universal(void) {
|
||||
}
|
||||
add_global_type_entity(str_lit("byte"), &basic_types[Basic_u8]);
|
||||
|
||||
{
|
||||
void set_procedure_abi_types(Type *type);
|
||||
|
||||
Type *equal_args[2] = {t_rawptr, t_rawptr};
|
||||
t_equal_proc = alloc_type_proc_from_types(equal_args, 2, t_bool, false, ProcCC_Contextless);
|
||||
set_procedure_abi_types(t_equal_proc);
|
||||
|
||||
Type *hasher_args[2] = {t_rawptr, t_uintptr};
|
||||
t_hasher_proc = alloc_type_proc_from_types(hasher_args, 2, t_uintptr, false, ProcCC_Contextless);
|
||||
set_procedure_abi_types(t_hasher_proc);
|
||||
}
|
||||
|
||||
// Constants
|
||||
add_global_constant(str_lit("true"), t_untyped_bool, exact_value_bool(true));
|
||||
add_global_constant(str_lit("false"), t_untyped_bool, exact_value_bool(false));
|
||||
@@ -742,6 +761,7 @@ void init_universal(void) {
|
||||
add_global_constant(str_lit("ODIN_DEFAULT_TO_NIL_ALLOCATOR"), t_untyped_bool, exact_value_bool(bc->ODIN_DEFAULT_TO_NIL_ALLOCATOR));
|
||||
add_global_constant(str_lit("ODIN_USE_LLVM_API"), t_untyped_bool, exact_value_bool(bc->use_llvm_api));
|
||||
add_global_constant(str_lit("ODIN_NO_DYNAMIC_LITERALS"), t_untyped_bool, exact_value_bool(bc->no_dynamic_literals));
|
||||
add_global_constant(str_lit("ODIN_TEST"), t_untyped_bool, exact_value_bool(bc->command_kind == Command_test));
|
||||
|
||||
|
||||
// Builtin Procedures
|
||||
@@ -837,6 +857,8 @@ void init_checker_info(CheckerInfo *i) {
|
||||
array_init(&i->variable_init_order, a);
|
||||
array_init(&i->required_foreign_imports_through_force, a);
|
||||
array_init(&i->required_global_variables, a);
|
||||
array_init(&i->testing_procedures, a, 0, 0);
|
||||
|
||||
|
||||
i->allow_identifier_uses = build_context.query_data_set_settings.kind == QueryDataSet_GoToDefinitions;
|
||||
if (i->allow_identifier_uses) {
|
||||
@@ -870,7 +892,6 @@ CheckerContext make_checker_context(Checker *c) {
|
||||
CheckerContext ctx = c->init_ctx;
|
||||
ctx.checker = c;
|
||||
ctx.info = &c->info;
|
||||
ctx.allocator = c->allocator;
|
||||
ctx.scope = builtin_pkg->scope;
|
||||
ctx.pkg = builtin_pkg;
|
||||
|
||||
@@ -895,6 +916,7 @@ bool init_checker(Checker *c, Parser *parser) {
|
||||
gbAllocator a = heap_allocator();
|
||||
|
||||
init_checker_info(&c->info);
|
||||
c->info.checker = c;
|
||||
|
||||
array_init(&c->procs_to_check, a);
|
||||
array_init(&c->procs_with_deferred_to_check, a);
|
||||
@@ -904,8 +926,6 @@ bool init_checker(Checker *c, Parser *parser) {
|
||||
isize total_token_count = c->parser->total_token_count;
|
||||
isize arena_size = 2 * item_size * total_token_count;
|
||||
|
||||
c->allocator = heap_allocator();
|
||||
|
||||
c->init_ctx = make_checker_context(c);
|
||||
return true;
|
||||
}
|
||||
@@ -1502,11 +1522,10 @@ void add_min_dep_type_info(Checker *c, Type *t) {
|
||||
ti_index = type_info_index(&c->info, t, false);
|
||||
}
|
||||
GB_ASSERT(ti_index >= 0);
|
||||
if (ptr_set_exists(set, ti_index)) {
|
||||
if (ptr_set_update(set, ti_index)) {
|
||||
// Type Already exists
|
||||
return;
|
||||
}
|
||||
ptr_set_add(set, ti_index);
|
||||
|
||||
// Add nested types
|
||||
if (t->kind == Type_Named) {
|
||||
@@ -1680,8 +1699,6 @@ void add_dependency_to_set(Checker *c, Entity *entity) {
|
||||
CheckerInfo *info = &c->info;
|
||||
auto *set = &info->minimum_dependency_set;
|
||||
|
||||
String name = entity->token.string;
|
||||
|
||||
if (entity->type != nullptr &&
|
||||
is_type_polymorphic(entity->type)) {
|
||||
|
||||
@@ -1691,12 +1708,10 @@ void add_dependency_to_set(Checker *c, Entity *entity) {
|
||||
}
|
||||
}
|
||||
|
||||
if (ptr_set_exists(set, entity)) {
|
||||
if (ptr_set_update(set, entity)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
ptr_set_add(set, entity);
|
||||
DeclInfo *decl = decl_info_of_entity(entity);
|
||||
if (decl == nullptr) {
|
||||
return;
|
||||
@@ -1715,16 +1730,15 @@ void add_dependency_to_set(Checker *c, Entity *entity) {
|
||||
if (fl != nullptr) {
|
||||
GB_ASSERT_MSG(fl->kind == Entity_LibraryName &&
|
||||
(fl->flags&EntityFlag_Used),
|
||||
"%.*s", LIT(name));
|
||||
"%.*s", LIT(entity->token.string));
|
||||
add_dependency_to_set(c, fl);
|
||||
}
|
||||
}
|
||||
if (e->kind == Entity_Variable && e->Variable.is_foreign) {
|
||||
} else if (e->kind == Entity_Variable && e->Variable.is_foreign) {
|
||||
Entity *fl = e->Variable.foreign_library;
|
||||
if (fl != nullptr) {
|
||||
GB_ASSERT_MSG(fl->kind == Entity_LibraryName &&
|
||||
(fl->flags&EntityFlag_Used),
|
||||
"%.*s", LIT(name));
|
||||
"%.*s", LIT(entity->token.string));
|
||||
add_dependency_to_set(c, fl);
|
||||
}
|
||||
}
|
||||
@@ -1733,7 +1747,10 @@ void add_dependency_to_set(Checker *c, Entity *entity) {
|
||||
|
||||
|
||||
void generate_minimum_dependency_set(Checker *c, Entity *start) {
|
||||
ptr_set_init(&c->info.minimum_dependency_set, heap_allocator());
|
||||
isize entity_count = c->info.entities.count;
|
||||
isize min_dep_set_cap = next_pow2_isize(entity_count*4); // empirically determined factor
|
||||
|
||||
ptr_set_init(&c->info.minimum_dependency_set, heap_allocator(), min_dep_set_cap);
|
||||
ptr_set_init(&c->info.minimum_dependency_type_info_set, heap_allocator());
|
||||
|
||||
String required_runtime_entities[] = {
|
||||
@@ -1769,6 +1786,7 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) {
|
||||
str_lit("memcpy"),
|
||||
str_lit("memmove"),
|
||||
|
||||
str_lit("memory_equal"),
|
||||
str_lit("memory_compare"),
|
||||
str_lit("memory_compare_zero"),
|
||||
|
||||
@@ -1842,7 +1860,68 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) {
|
||||
add_dependency_to_set(c, e);
|
||||
}
|
||||
|
||||
add_dependency_to_set(c, start);
|
||||
for_array(i, c->info.entities) {
|
||||
Entity *e = c->info.entities[i];
|
||||
switch (e->kind) {
|
||||
case Entity_Variable:
|
||||
if (e->Variable.is_export) {
|
||||
add_dependency_to_set(c, e);
|
||||
}
|
||||
break;
|
||||
case Entity_Procedure:
|
||||
if (e->Procedure.is_export) {
|
||||
add_dependency_to_set(c, e);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (build_context.command_kind == Command_test) {
|
||||
AstPackage *pkg = c->info.init_package;
|
||||
Scope *s = pkg->scope;
|
||||
for_array(i, s->elements.entries) {
|
||||
Entity *e = s->elements.entries[i].value;
|
||||
if (e->kind != Entity_Procedure) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (e->file == nullptr || !e->file->is_test) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String name = e->token.string;
|
||||
String prefix = str_lit("test_");
|
||||
|
||||
if (!string_starts_with(name, prefix)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool is_tester = false;
|
||||
if (name != prefix) {
|
||||
is_tester = true;
|
||||
} else {
|
||||
error(e->token, "Invalid testing procedure name: %.*s", LIT(name));
|
||||
}
|
||||
|
||||
Type *t = base_type(e->type);
|
||||
GB_ASSERT(t->kind == Type_Proc);
|
||||
if (t->Proc.param_count == 0 && t->Proc.result_count == 0) {
|
||||
// Good
|
||||
} else {
|
||||
gbString str = type_to_string(t);
|
||||
error(e->token, "Testing procedures must have a signature type of proc(), got %s", str);
|
||||
gb_string_free(str);
|
||||
is_tester = false;
|
||||
}
|
||||
|
||||
if (is_tester) {
|
||||
add_dependency_to_set(c, e);
|
||||
array_add(&c->info.testing_procedures, e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
add_dependency_to_set(c, start);
|
||||
}
|
||||
}
|
||||
|
||||
bool is_entity_a_dependency(Entity *e) {
|
||||
@@ -1881,19 +1960,17 @@ void add_entity_dependency_from_procedure_parameters(Map<EntityGraphNode *> *M,
|
||||
|
||||
}
|
||||
|
||||
Array<EntityGraphNode *> generate_entity_dependency_graph(CheckerInfo *info) {
|
||||
Array<EntityGraphNode *> generate_entity_dependency_graph(CheckerInfo *info, gbAllocator allocator) {
|
||||
#define TIME_SECTION(str) do { if (build_context.show_more_timings) timings_start_section(&global_timings, str_lit(str)); } while (0)
|
||||
|
||||
gbAllocator a = heap_allocator();
|
||||
|
||||
Map<EntityGraphNode *> M = {}; // Key: Entity *
|
||||
map_init(&M, a, info->entities.count);
|
||||
map_init(&M, allocator, info->entities.count);
|
||||
defer (map_destroy(&M));
|
||||
for_array(i, info->entities) {
|
||||
Entity *e = info->entities[i];
|
||||
DeclInfo *d = e->decl_info;
|
||||
if (is_entity_a_dependency(e)) {
|
||||
EntityGraphNode *n = gb_alloc_item(a, EntityGraphNode);
|
||||
EntityGraphNode *n = gb_alloc_item(allocator, EntityGraphNode);
|
||||
n->entity = e;
|
||||
map_set(&M, hash_pointer(e), n);
|
||||
}
|
||||
@@ -1928,7 +2005,7 @@ Array<EntityGraphNode *> generate_entity_dependency_graph(CheckerInfo *info) {
|
||||
// This means that the entity graph node set will have to be thread safe
|
||||
|
||||
TIME_SECTION("generate_entity_dependency_graph: Calculate edges for graph M - Part 2");
|
||||
auto G = array_make<EntityGraphNode *>(a, 0, M.entries.count);
|
||||
auto G = array_make<EntityGraphNode *>(allocator, 0, M.entries.count);
|
||||
|
||||
for_array(i, M.entries) {
|
||||
auto *entry = &M.entries[i];
|
||||
@@ -1949,17 +2026,27 @@ Array<EntityGraphNode *> generate_entity_dependency_graph(CheckerInfo *info) {
|
||||
EntityGraphNode *s = n->succ.entries[k].ptr;
|
||||
// Ignore self-cycles
|
||||
if (s != n) {
|
||||
if (p->entity->kind == Entity_Procedure &&
|
||||
s->entity->kind == Entity_Procedure) {
|
||||
// NOTE(bill, 2020-11-15): Only care about variable initialization ordering
|
||||
// TODO(bill): This is probably wrong!!!!
|
||||
continue;
|
||||
}
|
||||
// IMPORTANT NOTE/TODO(bill, 2020-11-15): These three calls take the majority of the
|
||||
// the time to process
|
||||
|
||||
entity_graph_node_set_add(&p->succ, s);
|
||||
entity_graph_node_set_add(&s->pred, p);
|
||||
// Remove edge to 'n'
|
||||
entity_graph_node_set_remove(&s->pred, n);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove edge to 'n'
|
||||
entity_graph_node_set_remove(&p->succ, n);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
} else if (e->kind == Entity_Variable) {
|
||||
array_add(&G, n);
|
||||
}
|
||||
}
|
||||
@@ -1972,6 +2059,28 @@ Array<EntityGraphNode *> generate_entity_dependency_graph(CheckerInfo *info) {
|
||||
GB_ASSERT(n->dep_count >= 0);
|
||||
}
|
||||
|
||||
// f64 succ_count = 0.0;
|
||||
// f64 pred_count = 0.0;
|
||||
// f64 succ_capacity = 0.0;
|
||||
// f64 pred_capacity = 0.0;
|
||||
// f64 succ_max = 0.0;
|
||||
// f64 pred_max = 0.0;
|
||||
// for_array(i, G) {
|
||||
// EntityGraphNode *n = G[i];
|
||||
// succ_count += n->succ.entries.count;
|
||||
// pred_count += n->pred.entries.count;
|
||||
// succ_capacity += n->succ.entries.capacity;
|
||||
// pred_capacity += n->pred.entries.capacity;
|
||||
|
||||
// succ_max = gb_max(succ_max, n->succ.entries.capacity);
|
||||
// pred_max = gb_max(pred_max, n->pred.entries.capacity);
|
||||
|
||||
// }
|
||||
// f64 count = cast(f64)G.count;
|
||||
// gb_printf_err(">>>count pred: %f succ: %f\n", pred_count/count, succ_count/count);
|
||||
// gb_printf_err(">>>capacity pred: %f succ: %f\n", pred_capacity/count, succ_capacity/count);
|
||||
// gb_printf_err(">>>max pred: %f succ: %f\n", pred_max, succ_max);
|
||||
|
||||
return G;
|
||||
|
||||
#undef TIME_SECTION
|
||||
@@ -2088,9 +2197,9 @@ void init_core_type_info(Checker *c) {
|
||||
t_type_info_enum_value = type_info_enum_value->type;
|
||||
t_type_info_enum_value_ptr = alloc_type_pointer(t_type_info_enum_value);
|
||||
|
||||
GB_ASSERT(tis->fields.count == 4);
|
||||
GB_ASSERT(tis->fields.count == 5);
|
||||
|
||||
Entity *type_info_variant = tis->fields[3];
|
||||
Entity *type_info_variant = tis->fields[4];
|
||||
Type *tiv_type = type_info_variant->type;
|
||||
GB_ASSERT(is_type_union(tiv_type));
|
||||
|
||||
@@ -2186,14 +2295,14 @@ void init_core_source_code_location(Checker *c) {
|
||||
}
|
||||
|
||||
void init_core_map_type(Checker *c) {
|
||||
if (t_map_key == nullptr) {
|
||||
Entity *e = find_core_entity(c, str_lit("Map_Key"));
|
||||
if (t_map_hash == nullptr) {
|
||||
Entity *e = find_core_entity(c, str_lit("Map_Hash"));
|
||||
if (e->state == EntityState_Unresolved) {
|
||||
auto ctx = c->init_ctx;
|
||||
check_entity_decl(&ctx, e, nullptr, nullptr);
|
||||
}
|
||||
t_map_key = e->type;
|
||||
GB_ASSERT(t_map_key != nullptr);
|
||||
t_map_hash = e->type;
|
||||
GB_ASSERT(t_map_hash != nullptr);
|
||||
}
|
||||
|
||||
if (t_map_header == nullptr) {
|
||||
@@ -2579,7 +2688,7 @@ DECL_ATTRIBUTE_PROC(type_decl_attribute) {
|
||||
|
||||
if (valid && build_context.use_llvm_api) {
|
||||
if (ac->atom_op_table == nullptr) {
|
||||
ac->atom_op_table = gb_alloc_item(heap_allocator(), TypeAtomOpTable);
|
||||
ac->atom_op_table = gb_alloc_item(permanent_allocator(), TypeAtomOpTable);
|
||||
}
|
||||
ac->atom_op_table->op[TypeAtomOp_index_get] = e;
|
||||
}
|
||||
@@ -2638,7 +2747,7 @@ DECL_ATTRIBUTE_PROC(type_decl_attribute) {
|
||||
|
||||
if (valid && build_context.use_llvm_api) {
|
||||
if (ac->atom_op_table == nullptr) {
|
||||
ac->atom_op_table = gb_alloc_item(heap_allocator(), TypeAtomOpTable);
|
||||
ac->atom_op_table = gb_alloc_item(permanent_allocator(), TypeAtomOpTable);
|
||||
}
|
||||
ac->atom_op_table->op[TypeAtomOp_index_set] = e;
|
||||
}
|
||||
@@ -2720,7 +2829,7 @@ DECL_ATTRIBUTE_PROC(type_decl_attribute) {
|
||||
|
||||
if (valid && build_context.use_llvm_api) {
|
||||
if (ac->atom_op_table == nullptr) {
|
||||
ac->atom_op_table = gb_alloc_item(heap_allocator(), TypeAtomOpTable);
|
||||
ac->atom_op_table = gb_alloc_item(permanent_allocator(), TypeAtomOpTable);
|
||||
}
|
||||
ac->atom_op_table->op[TypeAtomOp_slice] = e;
|
||||
}
|
||||
@@ -2809,7 +2918,7 @@ void check_decl_attributes(CheckerContext *c, Array<Ast *> const &attributes, De
|
||||
}
|
||||
|
||||
|
||||
isize get_total_value_count(Array<Ast *> const &values) {
|
||||
isize get_total_value_count(Slice<Ast *> const &values) {
|
||||
isize count = 0;
|
||||
for_array(i, values) {
|
||||
Type *t = type_of_expr(values[i]);
|
||||
@@ -2967,8 +3076,8 @@ void check_builtin_attributes(CheckerContext *ctx, Entity *e, Array<Ast *> *attr
|
||||
}
|
||||
|
||||
void check_collect_value_decl(CheckerContext *c, Ast *decl) {
|
||||
if (decl->been_handled) return;
|
||||
decl->been_handled = true;
|
||||
if (decl->state_flags & StateFlag_BeenHandled) return;
|
||||
decl->state_flags |= StateFlag_BeenHandled;
|
||||
|
||||
ast_node(vd, ValueDecl, decl);
|
||||
|
||||
@@ -3023,7 +3132,7 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) {
|
||||
} else {
|
||||
entity_visibility_kind = kind;
|
||||
}
|
||||
array_unordered_remove(elems, j);
|
||||
slice_unordered_remove(elems, j);
|
||||
j -= 1;
|
||||
}
|
||||
}
|
||||
@@ -3072,7 +3181,10 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) {
|
||||
}
|
||||
|
||||
Ast *init_expr = value;
|
||||
DeclInfo *d = make_decl_info(heap_allocator(), c->scope, c->decl);
|
||||
DeclInfo *d = make_decl_info(c->scope, c->decl);
|
||||
d->decl_node = decl;
|
||||
d->comment = vd->comment;
|
||||
d->docs = vd->docs;
|
||||
d->entity = e;
|
||||
d->type_expr = vd->type;
|
||||
d->init_expr = init_expr;
|
||||
@@ -3100,9 +3212,12 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) {
|
||||
Token token = name->Ident.token;
|
||||
|
||||
Ast *fl = c->foreign_context.curr_library;
|
||||
DeclInfo *d = make_decl_info(c->allocator, c->scope, c->decl);
|
||||
Entity *e = nullptr;
|
||||
DeclInfo *d = make_decl_info(c->scope, c->decl);
|
||||
|
||||
d->decl_node = decl;
|
||||
d->comment = vd->comment;
|
||||
d->docs = vd->docs;
|
||||
d->attributes = vd->attributes;
|
||||
d->type_expr = vd->type;
|
||||
d->init_expr = init;
|
||||
@@ -3186,8 +3301,8 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) {
|
||||
}
|
||||
|
||||
void check_add_foreign_block_decl(CheckerContext *ctx, Ast *decl) {
|
||||
if (decl->been_handled) return;
|
||||
decl->been_handled = true;
|
||||
if (decl->state_flags & StateFlag_BeenHandled) return;
|
||||
decl->state_flags |= StateFlag_BeenHandled;
|
||||
|
||||
ast_node(fb, ForeignBlockDecl, decl);
|
||||
Ast *foreign_library = fb->foreign_library;
|
||||
@@ -3207,7 +3322,7 @@ void check_add_foreign_block_decl(CheckerContext *ctx, Ast *decl) {
|
||||
}
|
||||
|
||||
// NOTE(bill): If file_scopes == nullptr, this will act like a local scope
|
||||
void check_collect_entities(CheckerContext *c, Array<Ast *> const &nodes) {
|
||||
void check_collect_entities(CheckerContext *c, Slice<Ast *> const &nodes) {
|
||||
for_array(decl_index, nodes) {
|
||||
Ast *decl = nodes[decl_index];
|
||||
if (!is_ast_decl(decl) && !is_ast_when_stmt(decl)) {
|
||||
@@ -3522,11 +3637,9 @@ struct ImportPathItem {
|
||||
Array<ImportPathItem> find_import_path(Checker *c, AstPackage *start, AstPackage *end, PtrSet<AstPackage *> *visited) {
|
||||
Array<ImportPathItem> empty_path = {};
|
||||
|
||||
if (ptr_set_exists(visited, start)) {
|
||||
if (ptr_set_update(visited, start)) {
|
||||
return empty_path;
|
||||
}
|
||||
ptr_set_add(visited, start);
|
||||
|
||||
|
||||
String path = start->fullpath;
|
||||
AstPackage **found = string_map_get(&c->info.packages, path);
|
||||
@@ -3571,8 +3684,8 @@ Array<ImportPathItem> find_import_path(Checker *c, AstPackage *start, AstPackage
|
||||
}
|
||||
#endif
|
||||
void check_add_import_decl(CheckerContext *ctx, Ast *decl) {
|
||||
if (decl->been_handled) return;
|
||||
decl->been_handled = true;
|
||||
if (decl->state_flags & StateFlag_BeenHandled) return;
|
||||
decl->state_flags |= StateFlag_BeenHandled;
|
||||
|
||||
ast_node(id, ImportDecl, decl);
|
||||
Token token = id->relpath;
|
||||
@@ -3612,10 +3725,8 @@ void check_add_import_decl(CheckerContext *ctx, Ast *decl) {
|
||||
GB_ASSERT(scope->flags&ScopeFlag_Pkg);
|
||||
|
||||
|
||||
if (ptr_set_exists(&parent_scope->imported, scope)) {
|
||||
if (ptr_set_update(&parent_scope->imported, scope)) {
|
||||
// error(token, "Multiple import of the same file within this scope");
|
||||
} else {
|
||||
ptr_set_add(&parent_scope->imported, scope);
|
||||
}
|
||||
|
||||
String import_name = path_to_entity_name(id->import_name.string, id->fullpath, false);
|
||||
@@ -3686,8 +3797,8 @@ DECL_ATTRIBUTE_PROC(foreign_import_decl_attribute) {
|
||||
}
|
||||
|
||||
void check_add_foreign_import_decl(CheckerContext *ctx, Ast *decl) {
|
||||
if (decl->been_handled) return;
|
||||
decl->been_handled = true;
|
||||
if (decl->state_flags & StateFlag_BeenHandled) return;
|
||||
decl->state_flags |= StateFlag_BeenHandled;
|
||||
|
||||
ast_node(fl, ForeignImportDecl, decl);
|
||||
|
||||
@@ -3738,7 +3849,7 @@ void check_add_foreign_import_decl(CheckerContext *ctx, Ast *decl) {
|
||||
}
|
||||
}
|
||||
|
||||
bool collect_checked_packages_from_decl_list(Checker *c, Array<Ast *> const &decls) {
|
||||
bool collect_checked_packages_from_decl_list(Checker *c, Slice<Ast *> const &decls) {
|
||||
bool new_files = false;
|
||||
for_array(i, decls) {
|
||||
Ast *decl = decls[i];
|
||||
@@ -3760,7 +3871,7 @@ bool collect_checked_packages_from_decl_list(Checker *c, Array<Ast *> const &dec
|
||||
}
|
||||
|
||||
// Returns true if a new package is present
|
||||
bool collect_file_decls(CheckerContext *ctx, Array<Ast *> const &decls);
|
||||
bool collect_file_decls(CheckerContext *ctx, Slice<Ast *> const &decls);
|
||||
bool collect_file_decls_from_when_stmt(CheckerContext *ctx, AstWhenStmt *ws);
|
||||
|
||||
bool collect_when_stmt_from_file(CheckerContext *ctx, AstWhenStmt *ws) {
|
||||
@@ -3835,7 +3946,7 @@ bool collect_file_decls_from_when_stmt(CheckerContext *ctx, AstWhenStmt *ws) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool collect_file_decls(CheckerContext *ctx, Array<Ast *> const &decls) {
|
||||
bool collect_file_decls(CheckerContext *ctx, Slice<Ast *> const &decls) {
|
||||
GB_ASSERT(ctx->scope->flags&ScopeFlag_File);
|
||||
|
||||
if (collect_checked_packages_from_decl_list(ctx->checker, decls)) {
|
||||
@@ -3968,10 +4079,9 @@ void check_import_entities(Checker *c) {
|
||||
if (pkg == nullptr) {
|
||||
continue;
|
||||
}
|
||||
if (ptr_set_exists(&emitted, pkg)) {
|
||||
if (ptr_set_update(&emitted, pkg)) {
|
||||
continue;
|
||||
}
|
||||
ptr_set_add(&emitted, pkg);
|
||||
|
||||
array_add(&package_order, n);
|
||||
}
|
||||
@@ -4162,7 +4272,7 @@ void calculate_global_init_order(Checker *c) {
|
||||
CheckerInfo *info = &c->info;
|
||||
|
||||
TIME_SECTION("calculate_global_init_order: generate entity dependency graph");
|
||||
Array<EntityGraphNode *> dep_graph = generate_entity_dependency_graph(info);
|
||||
Array<EntityGraphNode *> dep_graph = generate_entity_dependency_graph(info, heap_allocator());
|
||||
defer ({
|
||||
for_array(i, dep_graph) {
|
||||
entity_graph_node_destroy(dep_graph[i], heap_allocator());
|
||||
@@ -4214,11 +4324,9 @@ void calculate_global_init_order(Checker *c) {
|
||||
// if (!decl_info_has_init(d)) {
|
||||
// continue;
|
||||
// }
|
||||
if (ptr_set_exists(&emitted, d)) {
|
||||
if (ptr_set_update(&emitted, d)) {
|
||||
continue;
|
||||
}
|
||||
ptr_set_add(&emitted, d);
|
||||
|
||||
|
||||
array_add(&info->variable_init_order, d);
|
||||
}
|
||||
@@ -4299,10 +4407,11 @@ void check_parsed_files(Checker *c) {
|
||||
for_array(i, c->parser->packages) {
|
||||
AstPackage *p = c->parser->packages[i];
|
||||
Scope *scope = create_scope_from_package(&c->init_ctx, p);
|
||||
p->decl_info = make_decl_info(c->allocator, scope, c->init_ctx.decl);
|
||||
p->decl_info = make_decl_info(scope, c->init_ctx.decl);
|
||||
string_map_set(&c->info.packages, p->fullpath, p);
|
||||
|
||||
if (scope->flags&ScopeFlag_Init) {
|
||||
c->info.init_package = p;
|
||||
c->info.init_scope = scope;
|
||||
}
|
||||
if (p->kind == Package_Runtime) {
|
||||
@@ -4572,7 +4681,7 @@ void check_parsed_files(Checker *c) {
|
||||
|
||||
|
||||
TIME_SECTION("check entry point");
|
||||
if (build_context.build_mode == BuildMode_Executable) {
|
||||
if (build_context.build_mode == BuildMode_Executable && !build_context.no_entry_point && build_context.command_kind != Command_test) {
|
||||
Scope *s = c->info.init_scope;
|
||||
GB_ASSERT(s != nullptr);
|
||||
GB_ASSERT(s->flags&ScopeFlag_Init);
|
||||
|
||||
+20
-12
@@ -45,7 +45,7 @@ enum StmtFlag {
|
||||
|
||||
Stmt_TypeSwitch = 1<<4,
|
||||
|
||||
Stmt_CheckScopeDecls = 1<<5,
|
||||
Stmt_CheckScopeDecls = 1<<5,
|
||||
};
|
||||
|
||||
enum BuiltinProcPkg {
|
||||
@@ -132,6 +132,7 @@ struct DeclInfo {
|
||||
|
||||
Entity *entity;
|
||||
|
||||
Ast * decl_node;
|
||||
Ast * type_expr;
|
||||
Ast * init_expr;
|
||||
Array<Ast *> attributes;
|
||||
@@ -140,6 +141,9 @@ struct DeclInfo {
|
||||
bool is_using;
|
||||
bool where_clauses_evaluated;
|
||||
|
||||
CommentGroup *comment;
|
||||
CommentGroup *docs;
|
||||
|
||||
PtrSet<Entity *> deps;
|
||||
PtrSet<Type *> type_info_deps;
|
||||
Array<BlockLabel> labels;
|
||||
@@ -160,12 +164,13 @@ struct ProcInfo {
|
||||
|
||||
|
||||
enum ScopeFlag : i32 {
|
||||
ScopeFlag_Pkg = 1<<1,
|
||||
ScopeFlag_Global = 1<<2,
|
||||
ScopeFlag_File = 1<<3,
|
||||
ScopeFlag_Init = 1<<4,
|
||||
ScopeFlag_Proc = 1<<5,
|
||||
ScopeFlag_Type = 1<<6,
|
||||
ScopeFlag_Pkg = 1<<1,
|
||||
ScopeFlag_Builtin = 1<<2,
|
||||
ScopeFlag_Global = 1<<3,
|
||||
ScopeFlag_File = 1<<4,
|
||||
ScopeFlag_Init = 1<<5,
|
||||
ScopeFlag_Proc = 1<<6,
|
||||
ScopeFlag_Type = 1<<7,
|
||||
|
||||
ScopeFlag_HasBeenImported = 1<<10, // This is only applicable to file scopes
|
||||
|
||||
@@ -247,8 +252,12 @@ struct AtomOpMapEntry {
|
||||
};
|
||||
|
||||
|
||||
struct CheckerContext;
|
||||
|
||||
// CheckerInfo stores all the symbol information for a type-checked program
|
||||
struct CheckerInfo {
|
||||
Checker *checker;
|
||||
|
||||
Map<ExprInfo> untyped; // Key: Ast * | Expression -> ExprInfo
|
||||
// NOTE(bill): This needs to be a map and not on the Ast
|
||||
// as it needs to be iterated across
|
||||
@@ -268,6 +277,7 @@ struct CheckerInfo {
|
||||
|
||||
AstPackage * builtin_package;
|
||||
AstPackage * runtime_package;
|
||||
AstPackage * init_package;
|
||||
Scope * init_scope;
|
||||
Entity * entry_point;
|
||||
PtrSet<Entity *> minimum_dependency_set;
|
||||
@@ -278,6 +288,7 @@ struct CheckerInfo {
|
||||
|
||||
Map<AtomOpMapEntry> atom_op_map; // Key: Ast *
|
||||
|
||||
Array<Entity *> testing_procedures;
|
||||
|
||||
bool allow_identifier_uses;
|
||||
Array<Ast *> identifier_uses; // only used by 'odin query'
|
||||
@@ -301,7 +312,6 @@ struct CheckerContext {
|
||||
ProcCallingConvention curr_proc_calling_convention;
|
||||
bool in_proc_sig;
|
||||
ForeignContext foreign_context;
|
||||
gbAllocator allocator;
|
||||
|
||||
CheckerTypePath *type_path;
|
||||
isize type_level; // TODO(bill): Actually handle correctly
|
||||
@@ -317,6 +327,7 @@ struct CheckerContext {
|
||||
bool no_polymorphic_errors;
|
||||
bool hide_polymorphic_errors;
|
||||
bool in_polymorphic_specialization;
|
||||
bool allow_arrow_right_selector_expr;
|
||||
Scope * polymorphic_scope;
|
||||
|
||||
Ast *assignment_lhs_hint;
|
||||
@@ -331,14 +342,11 @@ struct Checker {
|
||||
Array<Entity *> procs_with_deferred_to_check;
|
||||
|
||||
CheckerContext *curr_ctx;
|
||||
gbAllocator allocator;
|
||||
CheckerContext init_ctx;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
gb_global AstPackage *builtin_pkg = nullptr;
|
||||
gb_global AstPackage *intrinsics_pkg = nullptr;
|
||||
gb_global AstPackage *config_pkg = nullptr;
|
||||
@@ -387,7 +395,7 @@ void check_add_foreign_import_decl(CheckerContext *c, Ast *decl);
|
||||
|
||||
|
||||
bool check_arity_match(CheckerContext *c, AstValueDecl *vd, bool is_global = false);
|
||||
void check_collect_entities(CheckerContext *c, Array<Ast *> const &nodes);
|
||||
void check_collect_entities(CheckerContext *c, Slice<Ast *> const &nodes);
|
||||
void check_collect_entities_from_when_stmt(CheckerContext *c, AstWhenStmt *ws);
|
||||
void check_delayed_file_import_entity(CheckerContext *c, Ast *decl);
|
||||
|
||||
|
||||
@@ -183,6 +183,9 @@ BuiltinProc__type_simple_boolean_end,
|
||||
|
||||
BuiltinProc_type_field_index_of,
|
||||
|
||||
BuiltinProc_type_equal_proc,
|
||||
BuiltinProc_type_hasher_proc,
|
||||
|
||||
BuiltinProc__type_end,
|
||||
|
||||
|
||||
@@ -367,5 +370,8 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
|
||||
|
||||
{STR_LIT("type_field_index_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
|
||||
{STR_LIT("type_equal_proc"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_hasher_proc"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
|
||||
{STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
|
||||
};
|
||||
|
||||
+132
-9
@@ -56,6 +56,14 @@ gb_inline isize align_formula_isize(isize size, isize align) {
|
||||
}
|
||||
return size;
|
||||
}
|
||||
gb_inline void *align_formula_ptr(void *ptr, isize align) {
|
||||
if (align > 0) {
|
||||
uintptr result = (cast(uintptr)ptr) + align-1;
|
||||
return (void *)(result - result%align);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
GB_ALLOCATOR_PROC(heap_allocator_proc);
|
||||
|
||||
@@ -373,13 +381,16 @@ typedef struct Arena {
|
||||
gbAllocator backing;
|
||||
isize block_size;
|
||||
gbMutex mutex;
|
||||
|
||||
isize total_used;
|
||||
bool use_mutex;
|
||||
} Arena;
|
||||
|
||||
#define ARENA_MIN_ALIGNMENT 16
|
||||
#define ARENA_DEFAULT_BLOCK_SIZE (8*1024*1024)
|
||||
|
||||
|
||||
gb_global Arena permanent_arena = {};
|
||||
|
||||
void arena_init(Arena *arena, gbAllocator backing, isize block_size=ARENA_DEFAULT_BLOCK_SIZE) {
|
||||
arena->backing = backing;
|
||||
arena->block_size = block_size;
|
||||
@@ -388,8 +399,9 @@ void arena_init(Arena *arena, gbAllocator backing, isize block_size=ARENA_DEFAUL
|
||||
}
|
||||
|
||||
void arena_grow(Arena *arena, isize min_size) {
|
||||
// gb_mutex_lock(&arena->mutex);
|
||||
// defer (gb_mutex_unlock(&arena->mutex));
|
||||
if (arena->use_mutex) {
|
||||
gb_mutex_lock(&arena->mutex);
|
||||
}
|
||||
|
||||
isize size = gb_max(arena->block_size, min_size);
|
||||
size = ALIGN_UP(size, ARENA_MIN_ALIGNMENT);
|
||||
@@ -399,11 +411,16 @@ void arena_grow(Arena *arena, isize min_size) {
|
||||
GB_ASSERT(arena->ptr == ALIGN_DOWN_PTR(arena->ptr, ARENA_MIN_ALIGNMENT));
|
||||
arena->end = arena->ptr + size;
|
||||
array_add(&arena->blocks, arena->ptr);
|
||||
|
||||
if (arena->use_mutex) {
|
||||
gb_mutex_unlock(&arena->mutex);
|
||||
}
|
||||
}
|
||||
|
||||
void *arena_alloc(Arena *arena, isize size, isize alignment) {
|
||||
// gb_mutex_lock(&arena->mutex);
|
||||
// defer (gb_mutex_unlock(&arena->mutex));
|
||||
if (arena->use_mutex) {
|
||||
gb_mutex_lock(&arena->mutex);
|
||||
}
|
||||
|
||||
arena->total_used += size;
|
||||
|
||||
@@ -419,12 +436,17 @@ void *arena_alloc(Arena *arena, isize size, isize alignment) {
|
||||
GB_ASSERT(arena->ptr <= arena->end);
|
||||
GB_ASSERT(ptr == ALIGN_DOWN_PTR(ptr, align));
|
||||
// zero_size(ptr, size);
|
||||
|
||||
if (arena->use_mutex) {
|
||||
gb_mutex_unlock(&arena->mutex);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void arena_free_all(Arena *arena) {
|
||||
// gb_mutex_lock(&arena->mutex);
|
||||
// defer (gb_mutex_unlock(&arena->mutex));
|
||||
if (arena->use_mutex) {
|
||||
gb_mutex_lock(&arena->mutex);
|
||||
}
|
||||
|
||||
for_array(i, arena->blocks) {
|
||||
gb_free(arena->backing, arena->blocks[i]);
|
||||
@@ -432,8 +454,11 @@ void arena_free_all(Arena *arena) {
|
||||
array_clear(&arena->blocks);
|
||||
arena->ptr = nullptr;
|
||||
arena->end = nullptr;
|
||||
}
|
||||
|
||||
if (arena->use_mutex) {
|
||||
gb_mutex_unlock(&arena->mutex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -460,7 +485,14 @@ GB_ALLOCATOR_PROC(arena_allocator_proc) {
|
||||
// GB_PANIC("gbAllocation_Free not supported");
|
||||
break;
|
||||
case gbAllocation_Resize:
|
||||
GB_PANIC("gbAllocation_Resize: not supported");
|
||||
if (size == 0) {
|
||||
ptr = nullptr;
|
||||
} else if (size <= old_size) {
|
||||
ptr = old_memory;
|
||||
} else {
|
||||
ptr = arena_alloc(arena, size, alignment);
|
||||
gb_memmove(ptr, old_memory, old_size);
|
||||
}
|
||||
break;
|
||||
case gbAllocation_FreeAll:
|
||||
arena_free_all(arena);
|
||||
@@ -471,6 +503,97 @@ GB_ALLOCATOR_PROC(arena_allocator_proc) {
|
||||
}
|
||||
|
||||
|
||||
gbAllocator permanent_allocator() {
|
||||
return arena_allocator(&permanent_arena);
|
||||
// return heap_allocator();
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct Temp_Allocator {
|
||||
u8 *data;
|
||||
isize len;
|
||||
isize curr_offset;
|
||||
gbAllocator backup_allocator;
|
||||
Array<void *> leaked_allocations;
|
||||
};
|
||||
|
||||
gb_global Temp_Allocator temporary_allocator_data = {};
|
||||
|
||||
void temp_allocator_init(Temp_Allocator *s, isize size) {
|
||||
s->backup_allocator = heap_allocator();
|
||||
s->data = cast(u8 *)gb_alloc_align(s->backup_allocator, size, 16);
|
||||
s->curr_offset = 0;
|
||||
s->leaked_allocations.allocator = s->backup_allocator;
|
||||
}
|
||||
|
||||
void *temp_allocator_alloc(Temp_Allocator *s, isize size, isize alignment) {
|
||||
size = align_formula_isize(size, alignment);
|
||||
if (s->curr_offset+size <= s->len) {
|
||||
u8 *start = s->data;
|
||||
u8 *ptr = start + s->curr_offset;
|
||||
ptr = cast(u8 *)align_formula_ptr(ptr, alignment);
|
||||
// assume memory is zero
|
||||
|
||||
isize offset = ptr - start;
|
||||
s->curr_offset = offset + size;
|
||||
return ptr;
|
||||
} else if (size <= s->len) {
|
||||
u8 *start = s->data;
|
||||
u8 *ptr = cast(u8 *)align_formula_ptr(start, alignment);
|
||||
// assume memory is zero
|
||||
|
||||
isize offset = ptr - start;
|
||||
s->curr_offset = offset + size;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void *ptr = gb_alloc_align(s->backup_allocator, size, alignment);
|
||||
array_add(&s->leaked_allocations, ptr);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void temp_allocator_free_all(Temp_Allocator *s) {
|
||||
s->curr_offset = 0;
|
||||
for_array(i, s->leaked_allocations) {
|
||||
gb_free(s->backup_allocator, s->leaked_allocations[i]);
|
||||
}
|
||||
array_clear(&s->leaked_allocations);
|
||||
gb_zero_size(s->data, s->len);
|
||||
}
|
||||
|
||||
GB_ALLOCATOR_PROC(temp_allocator_proc) {
|
||||
void *ptr = nullptr;
|
||||
Temp_Allocator *s = cast(Temp_Allocator *)allocator_data;
|
||||
GB_ASSERT_NOT_NULL(s);
|
||||
|
||||
switch (type) {
|
||||
case gbAllocation_Alloc:
|
||||
return temp_allocator_alloc(s, size, alignment);
|
||||
case gbAllocation_Free:
|
||||
break;
|
||||
case gbAllocation_Resize:
|
||||
if (size == 0) {
|
||||
ptr = nullptr;
|
||||
} else if (size <= old_size) {
|
||||
ptr = old_memory;
|
||||
} else {
|
||||
ptr = temp_allocator_alloc(s, size, alignment);
|
||||
gb_memmove(ptr, old_memory, old_size);
|
||||
}
|
||||
break;
|
||||
case gbAllocation_FreeAll:
|
||||
temp_allocator_free_all(s);
|
||||
break;
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
gbAllocator temporary_allocator() {
|
||||
return {temp_allocator_proc, &temporary_allocator_data};
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
+293
-81
@@ -1,22 +1,102 @@
|
||||
// Generates Documentation
|
||||
|
||||
gbString expr_to_string(Ast *expression);
|
||||
gb_global int print_entity_kind_ordering[Entity_Count] = {
|
||||
/*Invalid*/ -1,
|
||||
/*Constant*/ 0,
|
||||
/*Variable*/ 1,
|
||||
/*TypeName*/ 4,
|
||||
/*Procedure*/ 2,
|
||||
/*ProcGroup*/ 3,
|
||||
/*Builtin*/ -1,
|
||||
/*ImportName*/ -1,
|
||||
/*LibraryName*/ -1,
|
||||
/*Nil*/ -1,
|
||||
/*Label*/ -1,
|
||||
};
|
||||
gb_global char const *print_entity_names[Entity_Count] = {
|
||||
/*Invalid*/ "",
|
||||
/*Constant*/ "constants",
|
||||
/*Variable*/ "variables",
|
||||
/*TypeName*/ "types",
|
||||
/*Procedure*/ "procedures",
|
||||
/*ProcGroup*/ "proc_group",
|
||||
/*Builtin*/ "",
|
||||
/*ImportName*/ "import names",
|
||||
/*LibraryName*/ "library names",
|
||||
/*Nil*/ "",
|
||||
/*Label*/ "",
|
||||
};
|
||||
|
||||
String alloc_comment_group_string(gbAllocator a, CommentGroup g) {
|
||||
|
||||
GB_COMPARE_PROC(cmp_entities_for_printing) {
|
||||
GB_ASSERT(a != nullptr);
|
||||
GB_ASSERT(b != nullptr);
|
||||
Entity *x = *cast(Entity **)a;
|
||||
Entity *y = *cast(Entity **)b;
|
||||
int res = 0;
|
||||
res = string_compare(x->pkg->name, y->pkg->name);
|
||||
if (res != 0) {
|
||||
return res;
|
||||
}
|
||||
int ox = print_entity_kind_ordering[x->kind];
|
||||
int oy = print_entity_kind_ordering[y->kind];
|
||||
res = ox - oy;
|
||||
if (res != 0) {
|
||||
return res;
|
||||
}
|
||||
res = string_compare(x->token.string, y->token.string);
|
||||
return res;
|
||||
}
|
||||
|
||||
GB_COMPARE_PROC(cmp_ast_package_by_name) {
|
||||
GB_ASSERT(a != nullptr);
|
||||
GB_ASSERT(b != nullptr);
|
||||
AstPackage *x = *cast(AstPackage **)a;
|
||||
AstPackage *y = *cast(AstPackage **)b;
|
||||
return string_compare(x->name, y->name);
|
||||
}
|
||||
|
||||
void print_doc_line(i32 indent, char const *fmt, ...) {
|
||||
while (indent --> 0) {
|
||||
gb_printf("\t");
|
||||
}
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
gb_printf_va(fmt, va);
|
||||
va_end(va);
|
||||
gb_printf("\n");
|
||||
}
|
||||
void print_doc_line_no_newline(i32 indent, char const *fmt, ...) {
|
||||
while (indent --> 0) {
|
||||
gb_printf("\t");
|
||||
}
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
gb_printf_va(fmt, va);
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
bool print_doc_comment_group_string(i32 indent, CommentGroup *g) {
|
||||
if (g == nullptr) {
|
||||
return false;
|
||||
}
|
||||
isize len = 0;
|
||||
for_array(i, g.list) {
|
||||
String comment = g.list[i].string;
|
||||
for_array(i, g->list) {
|
||||
String comment = g->list[i].string;
|
||||
len += comment.len;
|
||||
len += 1; // for \n
|
||||
}
|
||||
if (len == 0) {
|
||||
return make_string(nullptr, 0);
|
||||
if (len <= g->list.count) {
|
||||
return false;
|
||||
}
|
||||
|
||||
u8 *text = gb_alloc_array(a, u8, len+1);
|
||||
len = 0;
|
||||
for_array(i, g.list) {
|
||||
String comment = g.list[i].string;
|
||||
isize count = 0;
|
||||
for_array(i, g->list) {
|
||||
String comment = g->list[i].string;
|
||||
String original_comment = comment;
|
||||
|
||||
bool slash_slash = comment[1] == '/';
|
||||
bool slash_star = comment[1] == '*';
|
||||
if (comment[1] == '/') {
|
||||
comment.text += 2;
|
||||
comment.len -= 2;
|
||||
@@ -24,84 +104,216 @@ String alloc_comment_group_string(gbAllocator a, CommentGroup g) {
|
||||
comment.text += 2;
|
||||
comment.len -= 4;
|
||||
}
|
||||
comment = string_trim_whitespace(comment);
|
||||
gb_memmove(text+len, comment.text, comment.len);
|
||||
len += comment.len;
|
||||
text[len++] = '\n';
|
||||
}
|
||||
return make_string(text, len);
|
||||
}
|
||||
|
||||
#if 0
|
||||
void print_type_spec(Ast *spec) {
|
||||
ast_node(ts, TypeSpec, spec);
|
||||
GB_ASSERT(ts->name->kind == Ast_Ident);
|
||||
String name = ts->name->Ident.string;
|
||||
if (name.len == 0) {
|
||||
return;
|
||||
}
|
||||
if (name[0] == '_') {
|
||||
return;
|
||||
}
|
||||
gb_printf("type %.*s\n", LIT(name));
|
||||
}
|
||||
// Ignore the first space
|
||||
if (comment.len > 0 && comment[0] == ' ') {
|
||||
comment.text += 1;
|
||||
comment.len -= 1;
|
||||
}
|
||||
|
||||
void print_proc_decl(AstProcDecl *pd) {
|
||||
GB_ASSERT(pd->name->kind == Ast_Ident);
|
||||
String name = pd->name->Ident.string;
|
||||
if (name.len == 0) {
|
||||
return;
|
||||
}
|
||||
if (name[0] == '_') {
|
||||
return;
|
||||
}
|
||||
|
||||
String docs = alloc_comment_group_string(heap_allocator(), pd->docs);
|
||||
defer (gb_free(heap_allocator(), docs.text));
|
||||
|
||||
if (docs.len > 0) {
|
||||
gb_file_write(&gb__std_files[gbFileStandard_Output], docs.text, docs.len);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
ast_node(proc_type, ProcType, pd->type);
|
||||
|
||||
gbString params = expr_to_string(proc_type->params);
|
||||
defer (gb_string_free(params));
|
||||
gb_printf("proc %.*s(%s)", LIT(name), params);
|
||||
if (proc_type->results != nullptr) {
|
||||
ast_node(fl, FieldList, proc_type->results);
|
||||
isize count = fl->list.count;
|
||||
if (count > 0) {
|
||||
gbString results = expr_to_string(proc_type->results);
|
||||
defer (gb_string_free(results));
|
||||
gb_printf(" -> ");
|
||||
if (count != 1) {
|
||||
gb_printf("(");
|
||||
if (slash_slash) {
|
||||
if (string_starts_with(comment, str_lit("+"))) {
|
||||
continue;
|
||||
}
|
||||
gb_printf("%s", results);
|
||||
if (count != 1) {
|
||||
gb_printf(")");
|
||||
if (string_starts_with(comment, str_lit("@("))) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (slash_slash) {
|
||||
print_doc_line(indent, "%.*s", LIT(comment));
|
||||
count += 1;
|
||||
} else {
|
||||
isize pos = 0;
|
||||
for (; pos < comment.len; pos++) {
|
||||
isize end = pos;
|
||||
for (; end < comment.len; end++) {
|
||||
if (comment[end] == '\n') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
String line = substring(comment, pos, end);
|
||||
pos = end+1;
|
||||
String trimmed_line = string_trim_whitespace(line);
|
||||
if (trimmed_line.len == 0) {
|
||||
if (count == 0) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Remove comments with
|
||||
* styles
|
||||
* like this
|
||||
*/
|
||||
if (string_starts_with(line, str_lit("* "))) {
|
||||
line = substring(line, 2, line.len);
|
||||
}
|
||||
|
||||
print_doc_line(indent, "%.*s", LIT(line));
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
gb_printf("\n\n");
|
||||
}
|
||||
#endif
|
||||
void print_declaration(Ast *decl) {
|
||||
|
||||
if (count > 0) {
|
||||
print_doc_line(0, "");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void generate_documentation(Parser *parser) {
|
||||
// for_array(file_index, parser->files) {
|
||||
// AstFile *file = parser->files[file_index];
|
||||
// Tokenizer *tokenizer = &file->tokenizer;
|
||||
// String fullpath = tokenizer->fullpath;
|
||||
// gb_printf("%.*s\n", LIT(fullpath));
|
||||
|
||||
// for_array(decl_index, file->decls) {
|
||||
// Ast *decl = file->decls[decl_index];
|
||||
// print_declaration(decl);
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
void print_doc_expr(Ast *expr) {
|
||||
gbString s = nullptr;
|
||||
if (build_context.cmd_doc_flags & CmdDocFlag_Short) {
|
||||
s = expr_to_string_shorthand(expr);
|
||||
} else {
|
||||
s = expr_to_string(expr);
|
||||
}
|
||||
gb_file_write(gb_file_get_standard(gbFileStandard_Output), s, gb_string_length(s));
|
||||
gb_string_free(s);
|
||||
}
|
||||
|
||||
|
||||
void print_doc_package(CheckerInfo *info, AstPackage *pkg) {
|
||||
if (pkg == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
print_doc_line(0, "package %.*s", LIT(pkg->name));
|
||||
|
||||
|
||||
for_array(i, pkg->files) {
|
||||
AstFile *f = pkg->files[i];
|
||||
if (f->pkg_decl) {
|
||||
GB_ASSERT(f->pkg_decl->kind == Ast_PackageDecl);
|
||||
print_doc_comment_group_string(1, f->pkg_decl->PackageDecl.docs);
|
||||
}
|
||||
}
|
||||
|
||||
if (pkg->scope != nullptr) {
|
||||
auto entities = array_make<Entity *>(heap_allocator(), 0, pkg->scope->elements.entries.count);
|
||||
defer (array_free(&entities));
|
||||
for_array(i, pkg->scope->elements.entries) {
|
||||
Entity *e = pkg->scope->elements.entries[i].value;
|
||||
switch (e->kind) {
|
||||
case Entity_Invalid:
|
||||
case Entity_Builtin:
|
||||
case Entity_Nil:
|
||||
case Entity_Label:
|
||||
continue;
|
||||
case Entity_Constant:
|
||||
case Entity_Variable:
|
||||
case Entity_TypeName:
|
||||
case Entity_Procedure:
|
||||
case Entity_ProcGroup:
|
||||
case Entity_ImportName:
|
||||
case Entity_LibraryName:
|
||||
// Fine
|
||||
break;
|
||||
}
|
||||
array_add(&entities, e);
|
||||
}
|
||||
gb_sort_array(entities.data, entities.count, cmp_entities_for_printing);
|
||||
|
||||
bool show_docs = (build_context.cmd_doc_flags & CmdDocFlag_Short) == 0;
|
||||
|
||||
EntityKind curr_entity_kind = Entity_Invalid;
|
||||
for_array(i, entities) {
|
||||
Entity *e = entities[i];
|
||||
if (e->pkg != pkg) {
|
||||
continue;
|
||||
}
|
||||
if (!is_entity_exported(e)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (curr_entity_kind != e->kind) {
|
||||
if (curr_entity_kind != Entity_Invalid) {
|
||||
print_doc_line(0, "");
|
||||
}
|
||||
curr_entity_kind = e->kind;
|
||||
print_doc_line(1, "%s", print_entity_names[e->kind]);
|
||||
}
|
||||
|
||||
Ast *type_expr = nullptr;
|
||||
Ast *init_expr = nullptr;
|
||||
Ast *decl_node = nullptr;
|
||||
CommentGroup *comment = nullptr;
|
||||
CommentGroup *docs = nullptr;
|
||||
if (e->decl_info != nullptr) {
|
||||
type_expr = e->decl_info->type_expr;
|
||||
init_expr = e->decl_info->init_expr;
|
||||
decl_node = e->decl_info->decl_node;
|
||||
comment = e->decl_info->comment;
|
||||
docs = e->decl_info->docs;
|
||||
}
|
||||
GB_ASSERT(type_expr != nullptr || init_expr != nullptr);
|
||||
|
||||
print_doc_line_no_newline(2, "%.*s", LIT(e->token.string));
|
||||
if (type_expr != nullptr) {
|
||||
gbString t = expr_to_string(type_expr);
|
||||
gb_printf(": %s ", t);
|
||||
gb_string_free(t);
|
||||
} else {
|
||||
gb_printf(" :");
|
||||
}
|
||||
if (e->kind == Entity_Variable) {
|
||||
if (init_expr != nullptr) {
|
||||
gb_printf("= ");
|
||||
print_doc_expr(init_expr);
|
||||
}
|
||||
} else {
|
||||
gb_printf(": ");
|
||||
print_doc_expr(init_expr);
|
||||
}
|
||||
|
||||
gb_printf(";\n");
|
||||
|
||||
if (show_docs) {
|
||||
print_doc_comment_group_string(3, docs);
|
||||
}
|
||||
}
|
||||
print_doc_line(0, "");
|
||||
}
|
||||
|
||||
if (pkg->fullpath.len != 0) {
|
||||
print_doc_line(0, "");
|
||||
print_doc_line(1, "fullpath:");
|
||||
print_doc_line(2, "%.*s", LIT(pkg->fullpath));
|
||||
print_doc_line(1, "files:");
|
||||
for_array(i, pkg->files) {
|
||||
AstFile *f = pkg->files[i];
|
||||
String filename = remove_directory_from_path(f->fullpath);
|
||||
print_doc_line(2, "%.*s", LIT(filename));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void generate_documentation(Checker *c) {
|
||||
CheckerInfo *info = &c->info;
|
||||
|
||||
auto pkgs = array_make<AstPackage *>(permanent_allocator(), 0, info->packages.entries.count);
|
||||
for_array(i, info->packages.entries) {
|
||||
AstPackage *pkg = info->packages.entries[i].value;
|
||||
if (build_context.cmd_doc_flags & CmdDocFlag_AllPackages) {
|
||||
array_add(&pkgs, pkg);
|
||||
} else {
|
||||
if (pkg->kind == Package_Init) {
|
||||
array_add(&pkgs, pkg);
|
||||
} else if (pkg->is_extra) {
|
||||
array_add(&pkgs, pkg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gb_sort_array(pkgs.data, pkgs.count, cmp_ast_package_by_name);
|
||||
|
||||
for_array(i, pkgs) {
|
||||
print_doc_package(info, pkgs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
+4
-3
@@ -120,6 +120,7 @@ struct Entity {
|
||||
union {
|
||||
struct {
|
||||
ExactValue value;
|
||||
ParameterValue param_value;
|
||||
} Constant;
|
||||
struct {
|
||||
Ast *init_expr; // only used for some variables within procedure bodies
|
||||
@@ -164,7 +165,7 @@ struct Entity {
|
||||
Scope *scope;
|
||||
} ImportName;
|
||||
struct {
|
||||
Array<String> paths;
|
||||
Slice<String> paths;
|
||||
String name;
|
||||
} LibraryName;
|
||||
i32 Nil;
|
||||
@@ -219,7 +220,7 @@ bool entity_has_deferred_procedure(Entity *e) {
|
||||
gb_global u64 global_entity_id = 0;
|
||||
|
||||
Entity *alloc_entity(EntityKind kind, Scope *scope, Token token, Type *type) {
|
||||
gbAllocator a = heap_allocator();
|
||||
gbAllocator a = permanent_allocator();
|
||||
Entity *entity = gb_alloc_item(a, Entity);
|
||||
entity->kind = kind;
|
||||
entity->state = EntityState_Unresolved;
|
||||
@@ -332,7 +333,7 @@ Entity *alloc_entity_import_name(Scope *scope, Token token, Type *type,
|
||||
}
|
||||
|
||||
Entity *alloc_entity_library_name(Scope *scope, Token token, Type *type,
|
||||
Array<String> paths, String name) {
|
||||
Slice<String> paths, String name) {
|
||||
Entity *entity = alloc_entity(Entity_LibraryName, scope, token, type);
|
||||
entity->LibraryName.paths = paths;
|
||||
entity->LibraryName.name = name;
|
||||
|
||||
+59
-51
@@ -46,16 +46,16 @@ enum ExactValueKind {
|
||||
struct ExactValue {
|
||||
ExactValueKind kind;
|
||||
union {
|
||||
bool value_bool;
|
||||
String value_string;
|
||||
BigInt value_integer; // NOTE(bill): This must be an integer and not a pointer
|
||||
f64 value_float;
|
||||
i64 value_pointer;
|
||||
Complex128 value_complex;
|
||||
Quaternion256 value_quaternion;
|
||||
Ast * value_compound;
|
||||
Ast * value_procedure;
|
||||
Type * value_typeid;
|
||||
bool value_bool;
|
||||
String value_string;
|
||||
BigInt value_integer; // NOTE(bill): This must be an integer and not a pointer
|
||||
f64 value_float;
|
||||
i64 value_pointer;
|
||||
Complex128 *value_complex;
|
||||
Quaternion256 *value_quaternion;
|
||||
Ast * value_compound;
|
||||
Ast * value_procedure;
|
||||
Type * value_typeid;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -85,9 +85,9 @@ HashKey hash_exact_value(ExactValue v) {
|
||||
case ExactValue_Pointer:
|
||||
return hash_integer(v.value_pointer);
|
||||
case ExactValue_Complex:
|
||||
return hashing_proc(&v.value_complex, gb_size_of(Complex128));
|
||||
return hashing_proc(v.value_complex, gb_size_of(Complex128));
|
||||
case ExactValue_Quaternion:
|
||||
return hashing_proc(&v.value_quaternion, gb_size_of(Quaternion256));
|
||||
return hashing_proc(v.value_quaternion, gb_size_of(Quaternion256));
|
||||
case ExactValue_Compound:
|
||||
return hash_pointer(v.value_compound);
|
||||
case ExactValue_Procedure:
|
||||
@@ -139,17 +139,19 @@ ExactValue exact_value_float(f64 f) {
|
||||
|
||||
ExactValue exact_value_complex(f64 real, f64 imag) {
|
||||
ExactValue result = {ExactValue_Complex};
|
||||
result.value_complex.real = real;
|
||||
result.value_complex.imag = imag;
|
||||
result.value_complex = gb_alloc_item(permanent_allocator(), Complex128);
|
||||
result.value_complex->real = real;
|
||||
result.value_complex->imag = imag;
|
||||
return result;
|
||||
}
|
||||
|
||||
ExactValue exact_value_quaternion(f64 real, f64 imag, f64 jmag, f64 kmag) {
|
||||
ExactValue result = {ExactValue_Quaternion};
|
||||
result.value_quaternion.real = real;
|
||||
result.value_quaternion.imag = imag;
|
||||
result.value_quaternion.jmag = jmag;
|
||||
result.value_quaternion.kmag = kmag;
|
||||
result.value_quaternion = gb_alloc_item(permanent_allocator(), Quaternion256);
|
||||
result.value_quaternion->real = real;
|
||||
result.value_quaternion->imag = imag;
|
||||
result.value_quaternion->jmag = jmag;
|
||||
result.value_quaternion->kmag = kmag;
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -373,6 +375,7 @@ ExactValue exact_value_to_complex(ExactValue v) {
|
||||
// return exact_value_complex(v.value_quaternion.real, v.value_quaternion.imag);
|
||||
}
|
||||
ExactValue r = {ExactValue_Invalid};
|
||||
v.value_complex = gb_alloc_item(permanent_allocator(), Complex128);
|
||||
return r;
|
||||
}
|
||||
ExactValue exact_value_to_quaternion(ExactValue v) {
|
||||
@@ -382,11 +385,12 @@ ExactValue exact_value_to_quaternion(ExactValue v) {
|
||||
case ExactValue_Float:
|
||||
return exact_value_quaternion(v.value_float, 0, 0, 0);
|
||||
case ExactValue_Complex:
|
||||
return exact_value_quaternion(v.value_complex.real, v.value_complex.imag, 0, 0);
|
||||
return exact_value_quaternion(v.value_complex->real, v.value_complex->imag, 0, 0);
|
||||
case ExactValue_Quaternion:
|
||||
return v;
|
||||
}
|
||||
ExactValue r = {ExactValue_Invalid};
|
||||
v.value_quaternion = gb_alloc_item(permanent_allocator(), Quaternion256);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -396,9 +400,9 @@ ExactValue exact_value_real(ExactValue v) {
|
||||
case ExactValue_Float:
|
||||
return v;
|
||||
case ExactValue_Complex:
|
||||
return exact_value_float(v.value_complex.real);
|
||||
return exact_value_float(v.value_complex->real);
|
||||
case ExactValue_Quaternion:
|
||||
return exact_value_float(v.value_quaternion.real);
|
||||
return exact_value_float(v.value_quaternion->real);
|
||||
}
|
||||
ExactValue r = {ExactValue_Invalid};
|
||||
return r;
|
||||
@@ -410,9 +414,9 @@ ExactValue exact_value_imag(ExactValue v) {
|
||||
case ExactValue_Float:
|
||||
return exact_value_i64(0);
|
||||
case ExactValue_Complex:
|
||||
return exact_value_float(v.value_complex.imag);
|
||||
return exact_value_float(v.value_complex->imag);
|
||||
case ExactValue_Quaternion:
|
||||
return exact_value_float(v.value_quaternion.imag);
|
||||
return exact_value_float(v.value_quaternion->imag);
|
||||
}
|
||||
ExactValue r = {ExactValue_Invalid};
|
||||
return r;
|
||||
@@ -425,7 +429,7 @@ ExactValue exact_value_jmag(ExactValue v) {
|
||||
case ExactValue_Complex:
|
||||
return exact_value_i64(0);
|
||||
case ExactValue_Quaternion:
|
||||
return exact_value_float(v.value_quaternion.jmag);
|
||||
return exact_value_float(v.value_quaternion->jmag);
|
||||
}
|
||||
ExactValue r = {ExactValue_Invalid};
|
||||
return r;
|
||||
@@ -438,7 +442,7 @@ ExactValue exact_value_kmag(ExactValue v) {
|
||||
case ExactValue_Complex:
|
||||
return exact_value_i64(0);
|
||||
case ExactValue_Quaternion:
|
||||
return exact_value_float(v.value_quaternion.kmag);
|
||||
return exact_value_float(v.value_quaternion->kmag);
|
||||
}
|
||||
ExactValue r = {ExactValue_Invalid};
|
||||
return r;
|
||||
@@ -532,15 +536,15 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision,
|
||||
return i;
|
||||
}
|
||||
case ExactValue_Complex: {
|
||||
f64 real = v.value_complex.real;
|
||||
f64 imag = v.value_complex.imag;
|
||||
f64 real = v.value_complex->real;
|
||||
f64 imag = v.value_complex->imag;
|
||||
return exact_value_complex(-real, -imag);
|
||||
}
|
||||
case ExactValue_Quaternion: {
|
||||
f64 real = v.value_quaternion.real;
|
||||
f64 imag = v.value_quaternion.imag;
|
||||
f64 jmag = v.value_quaternion.jmag;
|
||||
f64 kmag = v.value_quaternion.kmag;
|
||||
f64 real = v.value_quaternion->real;
|
||||
f64 imag = v.value_quaternion->imag;
|
||||
f64 jmag = v.value_quaternion->jmag;
|
||||
f64 kmag = v.value_quaternion->kmag;
|
||||
return exact_value_quaternion(-real, -imag, -jmag, -kmag);
|
||||
}
|
||||
}
|
||||
@@ -685,6 +689,8 @@ ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y)
|
||||
case Token_CmpOr: return exact_value_bool(x.value_bool || y.value_bool);
|
||||
case Token_And: return exact_value_bool(x.value_bool & y.value_bool);
|
||||
case Token_Or: return exact_value_bool(x.value_bool | y.value_bool);
|
||||
case Token_AndNot: return exact_value_bool(x.value_bool & !y.value_bool);
|
||||
case Token_Xor: return exact_value_bool((x.value_bool && !y.value_bool) || (!x.value_bool && y.value_bool));
|
||||
default: goto error;
|
||||
}
|
||||
break;
|
||||
@@ -730,10 +736,10 @@ ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y)
|
||||
|
||||
case ExactValue_Complex: {
|
||||
y = exact_value_to_complex(y);
|
||||
f64 a = x.value_complex.real;
|
||||
f64 b = x.value_complex.imag;
|
||||
f64 c = y.value_complex.real;
|
||||
f64 d = y.value_complex.imag;
|
||||
f64 a = x.value_complex->real;
|
||||
f64 b = x.value_complex->imag;
|
||||
f64 c = y.value_complex->real;
|
||||
f64 d = y.value_complex->imag;
|
||||
f64 real = 0;
|
||||
f64 imag = 0;
|
||||
switch (op) {
|
||||
@@ -763,14 +769,14 @@ ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y)
|
||||
|
||||
case ExactValue_Quaternion: {
|
||||
y = exact_value_to_quaternion(y);
|
||||
f64 xr = x.value_quaternion.real;
|
||||
f64 xi = x.value_quaternion.imag;
|
||||
f64 xj = x.value_quaternion.jmag;
|
||||
f64 xk = x.value_quaternion.kmag;
|
||||
f64 yr = y.value_quaternion.real;
|
||||
f64 yi = y.value_quaternion.imag;
|
||||
f64 yj = y.value_quaternion.jmag;
|
||||
f64 yk = y.value_quaternion.kmag;
|
||||
f64 xr = x.value_quaternion->real;
|
||||
f64 xi = x.value_quaternion->imag;
|
||||
f64 xj = x.value_quaternion->jmag;
|
||||
f64 xk = x.value_quaternion->kmag;
|
||||
f64 yr = y.value_quaternion->real;
|
||||
f64 yi = y.value_quaternion->imag;
|
||||
f64 yj = y.value_quaternion->jmag;
|
||||
f64 yk = y.value_quaternion->kmag;
|
||||
|
||||
|
||||
f64 real = 0;
|
||||
@@ -897,10 +903,10 @@ bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) {
|
||||
}
|
||||
|
||||
case ExactValue_Complex: {
|
||||
f64 a = x.value_complex.real;
|
||||
f64 b = x.value_complex.imag;
|
||||
f64 c = y.value_complex.real;
|
||||
f64 d = y.value_complex.imag;
|
||||
f64 a = x.value_complex->real;
|
||||
f64 b = x.value_complex->imag;
|
||||
f64 c = y.value_complex->real;
|
||||
f64 d = y.value_complex->imag;
|
||||
switch (op) {
|
||||
case Token_CmpEq: return cmp_f64(a, c) == 0 && cmp_f64(b, d) == 0;
|
||||
case Token_NotEq: return cmp_f64(a, c) != 0 || cmp_f64(b, d) != 0;
|
||||
@@ -945,7 +951,7 @@ bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) {
|
||||
Entity *strip_entity_wrapping(Ast *expr);
|
||||
Entity *strip_entity_wrapping(Entity *e);
|
||||
|
||||
gbString write_expr_to_string(gbString str, Ast *node);
|
||||
gbString write_expr_to_string(gbString str, Ast *node, bool shorthand);
|
||||
|
||||
gbString write_exact_value_to_string(gbString str, ExactValue const &v, isize string_limit=36) {
|
||||
switch (v.kind) {
|
||||
@@ -976,14 +982,16 @@ gbString write_exact_value_to_string(gbString str, ExactValue const &v, isize st
|
||||
case ExactValue_Float:
|
||||
return gb_string_append_fmt(str, "%f", v.value_float);
|
||||
case ExactValue_Complex:
|
||||
return gb_string_append_fmt(str, "%f+%fi", v.value_complex.real, v.value_complex.imag);
|
||||
return gb_string_append_fmt(str, "%f+%fi", v.value_complex->real, v.value_complex->imag);
|
||||
case ExactValue_Quaternion:
|
||||
return gb_string_append_fmt(str, "%f+%fi+%fj+%fk", v.value_quaternion->real, v.value_quaternion->imag, v.value_quaternion->jmag, v.value_quaternion->kmag);
|
||||
|
||||
case ExactValue_Pointer:
|
||||
return str;
|
||||
case ExactValue_Compound:
|
||||
return write_expr_to_string(str, v.value_compound);
|
||||
return write_expr_to_string(str, v.value_compound, false);
|
||||
case ExactValue_Procedure:
|
||||
return write_expr_to_string(str, v.value_procedure);
|
||||
return write_expr_to_string(str, v.value_procedure, false);
|
||||
}
|
||||
return str;
|
||||
};
|
||||
|
||||
+101
-4
@@ -157,7 +157,7 @@ extern "C" {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(_WIN64) || defined(__x86_64__) || defined(_M_X64) || defined(__64BIT__) || defined(__powerpc64__) || defined(__ppc64__)
|
||||
#if defined(_WIN64) || defined(__x86_64__) || defined(_M_X64) || defined(__64BIT__) || defined(__powerpc64__) || defined(__ppc64__) || defined(__aarch64__)
|
||||
#ifndef GB_ARCH_64_BIT
|
||||
#define GB_ARCH_64_BIT 1
|
||||
#endif
|
||||
@@ -230,7 +230,7 @@ extern "C" {
|
||||
#define GB_CACHE_LINE_SIZE 128
|
||||
#endif
|
||||
|
||||
#elif defined(__arm__)
|
||||
#elif defined(__arm__) || defined(__aarch64__) || defined(_M_ARM) || defined(_M_ARM64)
|
||||
#ifndef GB_CPU_ARM
|
||||
#define GB_CPU_ARM 1
|
||||
#endif
|
||||
@@ -3702,6 +3702,12 @@ gb_inline void *gb_memcopy(void *dest, void const *source, isize n) {
|
||||
|
||||
void *dest_copy = dest;
|
||||
__asm__ __volatile__("rep movsb" : "+D"(dest_copy), "+S"(source), "+c"(n) : : "memory");
|
||||
#elif defined(GB_CPU_ARM)
|
||||
u8 *s = cast(u8 *)source;
|
||||
u8 *d = cast(u8 *)dest;
|
||||
for (isize i = 0; i < n; i++) {
|
||||
*d++ = *s++;
|
||||
}
|
||||
#else
|
||||
u8 *d = cast(u8 *)dest;
|
||||
u8 const *s = cast(u8 const *)source;
|
||||
@@ -4438,6 +4444,76 @@ gb_inline i64 gb_atomic64_fetch_or(gbAtomic64 volatile *a, i64 operand) {
|
||||
#endif
|
||||
}
|
||||
|
||||
#elif defined(GB_CPU_ARM)
|
||||
|
||||
gb_inline i32 gb_atomic32_load (gbAtomic32 const volatile *a) {
|
||||
return __atomic_load_n(&a->value, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
gb_inline void gb_atomic32_store(gbAtomic32 volatile *a, i32 value) {
|
||||
__atomic_store_n(&a->value, value, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
|
||||
gb_inline i32 gb_atomic32_compare_exchange(gbAtomic32 volatile *a, i32 expected, i32 desired) {
|
||||
i32 expected_copy = expected;
|
||||
auto result = __atomic_compare_exchange_n(&a->value, &expected_copy, desired, true, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
|
||||
if (result) {
|
||||
return expected;
|
||||
} else {
|
||||
return expected_copy;
|
||||
}
|
||||
}
|
||||
|
||||
gb_inline i32 gb_atomic32_exchanged(gbAtomic32 volatile *a, i32 desired) {
|
||||
return __atomic_exchange_n(&a->value, desired, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
|
||||
gb_inline i32 gb_atomic32_fetch_add(gbAtomic32 volatile *a, i32 operand) {
|
||||
return __atomic_fetch_add(&a->value, operand, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
|
||||
gb_inline i32 gb_atomic32_fetch_and(gbAtomic32 volatile *a, i32 operand) {
|
||||
return __atomic_fetch_and(&a->value, operand, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
|
||||
gb_inline i32 gb_atomic32_fetch_or(gbAtomic32 volatile *a, i32 operand) {
|
||||
return __atomic_fetch_or(&a->value, operand, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
|
||||
gb_inline i64 gb_atomic64_load(gbAtomic64 const volatile *a) {
|
||||
return __atomic_load_n(&a->value, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
|
||||
gb_inline void gb_atomic64_store(gbAtomic64 volatile *a, i64 value) {
|
||||
__atomic_store_n(&a->value, value, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
|
||||
gb_inline i64 gb_atomic64_compare_exchange(gbAtomic64 volatile *a, i64 expected, i64 desired) {
|
||||
i64 expected_copy = expected;
|
||||
auto result = __atomic_compare_exchange_n(&a->value, &expected_copy, desired, true, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
|
||||
if (result) {
|
||||
return expected;
|
||||
} else {
|
||||
return expected_copy;
|
||||
}
|
||||
}
|
||||
|
||||
gb_inline i64 gb_atomic64_exchanged(gbAtomic64 volatile *a, i64 desired) {
|
||||
return __atomic_exchange_n(&a->value, desired, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
|
||||
gb_inline i64 gb_atomic64_fetch_add(gbAtomic64 volatile *a, i64 operand) {
|
||||
return __atomic_fetch_add(&a->value, operand, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
|
||||
gb_inline i64 gb_atomic64_fetch_and(gbAtomic64 volatile *a, i64 operand) {
|
||||
return __atomic_fetch_and(&a->value, operand, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
|
||||
gb_inline i64 gb_atomic64_fetch_or(gbAtomic64 volatile *a, i64 operand) {
|
||||
return __atomic_fetch_or(&a->value, operand, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
#error TODO(bill): Implement Atomics for this CPU
|
||||
#endif
|
||||
@@ -4563,7 +4639,11 @@ gb_inline void gb_yield_thread(void) {
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
_mm_pause();
|
||||
#elif defined(GB_SYSTEM_OSX)
|
||||
#if defined(GB_CPU_X86)
|
||||
__asm__ volatile ("" : : : "memory");
|
||||
#elif defined(GB_CPU_ARM)
|
||||
__asm__ volatile ("yield" : : : "memory");
|
||||
#endif
|
||||
#elif defined(GB_CPU_X86)
|
||||
_mm_pause();
|
||||
#else
|
||||
@@ -4575,7 +4655,11 @@ gb_inline void gb_mfence(void) {
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
_ReadWriteBarrier();
|
||||
#elif defined(GB_SYSTEM_OSX)
|
||||
#if defined(GB_CPU_X86)
|
||||
__sync_synchronize();
|
||||
#elif defined(GB_CPU_ARM)
|
||||
__atomic_thread_fence(__ATOMIC_SEQ_CST);
|
||||
#endif
|
||||
#elif defined(GB_CPU_X86)
|
||||
_mm_mfence();
|
||||
#else
|
||||
@@ -4587,7 +4671,12 @@ gb_inline void gb_sfence(void) {
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
_WriteBarrier();
|
||||
#elif defined(GB_SYSTEM_OSX)
|
||||
#if defined(GB_CPU_X86)
|
||||
__asm__ volatile ("" : : : "memory");
|
||||
#elif defined(GB_CPU_ARM)
|
||||
// TODO(bill): is this correct?
|
||||
__atomic_thread_fence(__ATOMIC_SEQ_CST);
|
||||
#endif
|
||||
#elif defined(GB_CPU_X86)
|
||||
_mm_sfence();
|
||||
#else
|
||||
@@ -5156,7 +5245,7 @@ b32 gb_affinity_set(gbAffinity *a, isize core, isize thread_index) {
|
||||
|
||||
index = core * a->threads_per_core + thread_index;
|
||||
thread = pthread_self();
|
||||
|
||||
|
||||
|
||||
cpuset_t mn;
|
||||
CPU_ZERO(&mn);
|
||||
@@ -5202,7 +5291,7 @@ void gb_affinity_init(gbAffinity *a) {
|
||||
for (;;) {
|
||||
// The 'temporary char'. Everything goes into this char,
|
||||
// so that we can check against EOF at the end of this loop.
|
||||
char c;
|
||||
int c;
|
||||
|
||||
#define AF__CHECK(letter) ((c = getc(cpu_info)) == letter)
|
||||
if (AF__CHECK('c') && AF__CHECK('p') && AF__CHECK('u') && AF__CHECK(' ') &&
|
||||
@@ -8808,6 +8897,14 @@ gb_inline gbDllProc gb_dll_proc_address(gbDllHandle dll, char const *proc_name)
|
||||
|
||||
return result;
|
||||
}
|
||||
#elif defined(__aarch64__)
|
||||
gb_inline u64 gb_rdtsc(void) {
|
||||
int64_t virtual_timer_value;
|
||||
asm volatile("mrs %0, cntvct_el0" : "=r"(virtual_timer_value));
|
||||
return virtual_timer_value;
|
||||
}
|
||||
#else
|
||||
#error "gb_rdtsc not supported"
|
||||
#endif
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
|
||||
+415
-109
@@ -25,6 +25,9 @@ struct irModule {
|
||||
Map<irDebugInfo *> debug_info; // Key: Unique pointer
|
||||
Map<irValue *> anonymous_proc_lits; // Key: Ast *
|
||||
|
||||
Map<irValue *> equal_procs; // Key: Type *
|
||||
Map<irValue *> hasher_procs; // Key: Type *
|
||||
|
||||
irDebugInfo * debug_compile_unit;
|
||||
Array<irDebugInfo *> debug_location_stack;
|
||||
|
||||
@@ -161,6 +164,7 @@ struct irProcedure {
|
||||
Ast * return_ptr_hint_ast;
|
||||
bool return_ptr_hint_used;
|
||||
|
||||
bool ignore_dead_instr;
|
||||
|
||||
Array<irBranchBlocks> branch_blocks;
|
||||
|
||||
@@ -454,7 +458,6 @@ struct irValueSourceCodeLocation {
|
||||
irValue *line;
|
||||
irValue *column;
|
||||
irValue *procedure;
|
||||
u64 hash;
|
||||
};
|
||||
|
||||
|
||||
@@ -525,6 +528,11 @@ struct irAddr {
|
||||
|
||||
Type *ir_type(irValue *value);
|
||||
irValue *ir_gen_anonymous_proc_lit(irModule *m, String prefix_name, Ast *expr, irProcedure *proc = nullptr);
|
||||
void ir_begin_procedure_body(irProcedure *proc);
|
||||
void ir_end_procedure_body(irProcedure *proc);
|
||||
irValue *ir_get_equal_proc_for_type(irModule *m, Type *type);
|
||||
irValue *ir_get_hasher_proc_for_type(irModule *m, Type *type);
|
||||
|
||||
|
||||
irAddr ir_addr(irValue *addr) {
|
||||
irAddr v = {irAddr_Default, addr};
|
||||
@@ -1159,7 +1167,7 @@ irValue *ir_instr_atomic_cxchg(irProcedure *p, Type *type, irValue *address, irV
|
||||
GB_ASSERT(type->Tuple.variables.count == 2);
|
||||
Type *elem = type->Tuple.variables[0]->type;
|
||||
// LEAK TODO(bill): LLVM returns {T, i1} whilst Odin does {T, bool}, fix this mapping hack
|
||||
gbAllocator a = heap_allocator();
|
||||
gbAllocator a = permanent_allocator();
|
||||
Type *llvm_type = alloc_type_tuple();
|
||||
array_init(&llvm_type->Tuple.variables, a, 0, 2);
|
||||
array_add (&llvm_type->Tuple.variables, alloc_entity_field(nullptr, blank_token, elem, false, 0));
|
||||
@@ -1799,7 +1807,7 @@ irValue *ir_add_local(irProcedure *proc, Entity *e, Ast *expr, bool zero_initial
|
||||
if (zero_initialized) {
|
||||
ir_emit_zero_init(proc, instr, expr);
|
||||
}
|
||||
set_procedure_abi_types(heap_allocator(), e->type);
|
||||
set_procedure_abi_types(e->type);
|
||||
|
||||
// if (proc->module->generate_debug_info && expr != nullptr && proc->entity != nullptr) {
|
||||
// if (proc->module->generate_debug_info && proc->entity != nullptr) {
|
||||
@@ -2132,7 +2140,7 @@ irDebugInfo *ir_add_debug_info_field(irModule *module, irDebugInfo *scope, Entit
|
||||
if (e->token.string.len == 0) {
|
||||
// If no name available for field, use its field index as its name.
|
||||
isize max_len = 8;
|
||||
u8 *str = cast(u8 *)gb_alloc_array(heap_allocator(), u8, max_len);
|
||||
u8 *str = cast(u8 *)gb_alloc_array(permanent_allocator(), u8, max_len);
|
||||
isize len = gb_snprintf(cast(char *)str, 8, "%d", index);
|
||||
di->DerivedType.name = make_string(str, len-1);
|
||||
}
|
||||
@@ -3282,7 +3290,7 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, Array<irValue *> const &ar
|
||||
context_ptr = ir_find_or_generate_context_ptr(p);
|
||||
}
|
||||
|
||||
set_procedure_abi_types(heap_allocator(), pt);
|
||||
set_procedure_abi_types(pt);
|
||||
|
||||
bool is_c_vararg = pt->Proc.c_vararg;
|
||||
isize param_count = pt->Proc.param_count;
|
||||
@@ -3293,7 +3301,7 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, Array<irValue *> const &ar
|
||||
GB_ASSERT_MSG(param_count == args.count, "%.*s %td == %td", LIT(p->entity->token.string), param_count, args.count);
|
||||
}
|
||||
|
||||
auto processed_args = array_make<irValue *>(heap_allocator(), 0, args.count);
|
||||
auto processed_args = array_make<irValue *>(permanent_allocator(), 0, args.count);
|
||||
|
||||
for (isize i = 0; i < param_count; i++) {
|
||||
Entity *e = pt->Proc.params->Tuple.variables[i];
|
||||
@@ -3416,7 +3424,7 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, Array<irValue *> const &ar
|
||||
case DeferredProcedure_in_out:
|
||||
{
|
||||
auto out_args = ir_value_to_array(p, result);
|
||||
array_init(&result_as_args, heap_allocator(), in_args.count + out_args.count);
|
||||
array_init(&result_as_args, permanent_allocator(), in_args.count + out_args.count);
|
||||
array_copy(&result_as_args, in_args, 0);
|
||||
array_copy(&result_as_args, out_args, in_args.count);
|
||||
}
|
||||
@@ -3587,65 +3595,69 @@ irValue *ir_gen_map_header(irProcedure *proc, irValue *map_val_ptr, Type *map_ty
|
||||
irValue *m = ir_emit_conv(proc, map_val_ptr, type_deref(ir_type(gep0)));
|
||||
ir_emit_store(proc, gep0, m);
|
||||
|
||||
ir_emit_store(proc, ir_emit_struct_ep(proc, h, 1), ir_const_bool(is_type_string(key_type)));
|
||||
|
||||
i64 entry_size = type_size_of (map_type->Map.entry_type);
|
||||
i64 entry_align = type_align_of (map_type->Map.entry_type);
|
||||
i64 value_offset = type_offset_of(map_type->Map.entry_type, 2);
|
||||
i64 key_offset = type_offset_of(map_type->Map.entry_type, 2);
|
||||
i64 key_size = type_size_of (map_type->Map.key);
|
||||
i64 value_offset = type_offset_of(map_type->Map.entry_type, 3);
|
||||
i64 value_size = type_size_of (map_type->Map.value);
|
||||
|
||||
ir_emit_store(proc, ir_emit_struct_ep(proc, h, 1), ir_get_equal_proc_for_type(proc->module, key_type));
|
||||
ir_emit_store(proc, ir_emit_struct_ep(proc, h, 2), ir_const_int(entry_size));
|
||||
ir_emit_store(proc, ir_emit_struct_ep(proc, h, 3), ir_const_int(entry_align));
|
||||
ir_emit_store(proc, ir_emit_struct_ep(proc, h, 4), ir_const_uintptr(value_offset));
|
||||
ir_emit_store(proc, ir_emit_struct_ep(proc, h, 5), ir_const_int(value_size));
|
||||
ir_emit_store(proc, ir_emit_struct_ep(proc, h, 4), ir_const_uintptr(key_offset));
|
||||
ir_emit_store(proc, ir_emit_struct_ep(proc, h, 5), ir_const_int(key_size));
|
||||
ir_emit_store(proc, ir_emit_struct_ep(proc, h, 6), ir_const_uintptr(value_offset));
|
||||
ir_emit_store(proc, ir_emit_struct_ep(proc, h, 7), ir_const_int(value_size));
|
||||
|
||||
return ir_emit_load(proc, h);
|
||||
}
|
||||
|
||||
irValue *ir_gen_map_key(irProcedure *proc, irValue *key, Type *key_type) {
|
||||
irValue *ir_const_hash(irModule *m, irValue *key, Type *key_type) {
|
||||
irValue *hashed_key = nullptr;
|
||||
|
||||
if (key->kind == irValue_Constant) {
|
||||
u64 hash = 0xcbf29ce484222325;
|
||||
if (is_type_string(key_type)) {
|
||||
GB_ASSERT(key->Constant.value.kind == ExactValue_String);
|
||||
String s = key->Constant.value.value_string;
|
||||
hash = fnv64a(s.text, s.len);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
// TODO(bill): other const hash types
|
||||
|
||||
if (build_context.word_size == 4) {
|
||||
hash &= 0xffffffffull;
|
||||
}
|
||||
hashed_key = ir_const_uintptr(hash);
|
||||
}
|
||||
|
||||
return hashed_key;
|
||||
}
|
||||
|
||||
irValue *ir_gen_map_hash(irProcedure *proc, irValue *key, Type *key_type) {
|
||||
Type *hash_type = t_u64;
|
||||
irValue *v = ir_add_local_generated(proc, t_map_key, true);
|
||||
irValue *v = ir_add_local_generated(proc, t_map_hash, true);
|
||||
Type *t = base_type(ir_type(key));
|
||||
key = ir_emit_conv(proc, key, key_type);
|
||||
|
||||
if (is_type_string(t)) {
|
||||
irValue *str = ir_emit_conv(proc, key, t_string);
|
||||
irValue *hashed_str = nullptr;
|
||||
irValue *key_ptr = ir_address_from_load_or_generate_local(proc, key);
|
||||
key_ptr = ir_emit_conv(proc, key_ptr, t_rawptr);
|
||||
|
||||
if (str->kind == irValue_Constant) {
|
||||
ExactValue ev = str->Constant.value;
|
||||
GB_ASSERT(ev.kind == ExactValue_String);
|
||||
u64 hs = fnv64a(ev.value_string.text, ev.value_string.len);
|
||||
hashed_str = ir_value_constant(t_u64, exact_value_u64(hs));
|
||||
} else {
|
||||
auto args = array_make<irValue *>(ir_allocator(), 1);
|
||||
args[0] = str;
|
||||
hashed_str = ir_emit_runtime_call(proc, "default_hash_string", args);
|
||||
}
|
||||
ir_emit_store(proc, ir_emit_struct_ep(proc, v, 0), hashed_str);
|
||||
|
||||
irValue *key_data = ir_emit_struct_ep(proc, v, 1);
|
||||
key_data = ir_emit_conv(proc, key_data, alloc_type_pointer(key_type));
|
||||
ir_emit_store(proc, key_data, str);
|
||||
} else {
|
||||
i64 sz = type_size_of(t);
|
||||
GB_ASSERT(sz <= 8);
|
||||
if (sz != 0) {
|
||||
auto args = array_make<irValue *>(ir_allocator(), 2);
|
||||
args[0] = ir_address_from_load_or_generate_local(proc, key);
|
||||
args[1] = ir_const_int(sz);
|
||||
irValue *hash = ir_emit_runtime_call(proc, "default_hash_ptr", args);
|
||||
|
||||
|
||||
irValue *hash_ptr = ir_emit_struct_ep(proc, v, 0);
|
||||
irValue *key_data = ir_emit_struct_ep(proc, v, 1);
|
||||
key_data = ir_emit_conv(proc, key_data, alloc_type_pointer(key_type));
|
||||
|
||||
ir_emit_store(proc, hash_ptr, hash);
|
||||
ir_emit_store(proc, key_data, key);
|
||||
}
|
||||
irValue *hashed_key = ir_const_hash(proc->module, key, key_type);
|
||||
if (hashed_key == nullptr) {
|
||||
irValue *hasher = ir_get_hasher_proc_for_type(proc->module, key_type);
|
||||
auto args = array_make<irValue *>(permanent_allocator(), 2);
|
||||
args[0] = key_ptr;
|
||||
args[1] = ir_value_constant(t_uintptr, exact_value_i64(0));
|
||||
hashed_key = ir_emit_call(proc, hasher, args);
|
||||
}
|
||||
|
||||
ir_emit_store(proc, ir_emit_struct_ep(proc, v, 0), hashed_key);
|
||||
ir_emit_store(proc, ir_emit_struct_ep(proc, v, 1), key_ptr);
|
||||
|
||||
return ir_emit_load(proc, v);
|
||||
}
|
||||
|
||||
@@ -3701,7 +3713,7 @@ irValue *ir_insert_dynamic_map_key_and_value(irProcedure *proc, irValue *addr, T
|
||||
map_type = base_type(map_type);
|
||||
|
||||
irValue *h = ir_gen_map_header(proc, addr, map_type);
|
||||
irValue *key = ir_gen_map_key(proc, map_key, map_type->Map.key);
|
||||
irValue *key = ir_gen_map_hash(proc, map_key, map_type->Map.key);
|
||||
irValue *v = ir_emit_conv(proc, map_value, map_type->Map.value);
|
||||
|
||||
irValue *ptr = ir_add_local_generated(proc, ir_type(v), false);
|
||||
@@ -4058,7 +4070,7 @@ irValue *ir_addr_load(irProcedure *proc, irAddr const &addr) {
|
||||
Type *map_type = base_type(addr.map_type);
|
||||
irValue *v = ir_add_local_generated(proc, map_type->Map.lookup_result_type, true);
|
||||
irValue *h = ir_gen_map_header(proc, addr.addr, map_type);
|
||||
irValue *key = ir_gen_map_key(proc, addr.map_key, map_type->Map.key);
|
||||
irValue *key = ir_gen_map_hash(proc, addr.map_key, map_type->Map.key);
|
||||
|
||||
auto args = array_make<irValue *>(ir_allocator(), 2);
|
||||
args[0] = h;
|
||||
@@ -4226,7 +4238,7 @@ irValue *ir_addr_get_ptr(irProcedure *proc, irAddr const &addr, bool allow_refer
|
||||
if (allow_reference) {
|
||||
Type *map_type = base_type(addr.map_type);
|
||||
irValue *h = ir_gen_map_header(proc, addr.addr, map_type);
|
||||
irValue *key = ir_gen_map_key(proc, addr.map_key, map_type->Map.key);
|
||||
irValue *key = ir_gen_map_hash(proc, addr.map_key, map_type->Map.key);
|
||||
|
||||
auto args = array_make<irValue *>(ir_allocator(), 2);
|
||||
args[0] = h;
|
||||
@@ -4537,7 +4549,7 @@ irValue *ir_emit_arith(irProcedure *proc, TokenKind op, irValue *left, irValue *
|
||||
Type *ft = base_complex_elem_type(t_left);
|
||||
|
||||
if (op == Token_Quo) {
|
||||
auto args = array_make<irValue *>(heap_allocator(), 2);
|
||||
auto args = array_make<irValue *>(permanent_allocator(), 2);
|
||||
args[0] = left;
|
||||
args[1] = right;
|
||||
|
||||
@@ -4615,7 +4627,7 @@ irValue *ir_emit_arith(irProcedure *proc, TokenKind op, irValue *left, irValue *
|
||||
|
||||
return ir_emit_load(proc, res);
|
||||
} else if (op == Token_Mul) {
|
||||
auto args = array_make<irValue *>(heap_allocator(), 2);
|
||||
auto args = array_make<irValue *>(permanent_allocator(), 2);
|
||||
args[0] = left;
|
||||
args[1] = right;
|
||||
|
||||
@@ -4625,7 +4637,7 @@ irValue *ir_emit_arith(irProcedure *proc, TokenKind op, irValue *left, irValue *
|
||||
default: GB_PANIC("Unknown float type"); break;
|
||||
}
|
||||
} else if (op == Token_Quo) {
|
||||
auto args = array_make<irValue *>(heap_allocator(), 2);
|
||||
auto args = array_make<irValue *>(permanent_allocator(), 2);
|
||||
args[0] = left;
|
||||
args[1] = right;
|
||||
|
||||
@@ -4828,7 +4840,7 @@ irValue *ir_emit_comp_against_nil(irProcedure *proc, TokenKind op_kind, irValue
|
||||
irValue *invalid_typeid = ir_value_constant(t_typeid, exact_value_i64(0));
|
||||
return ir_emit_comp(proc, op_kind, x, invalid_typeid);
|
||||
} else if (is_type_bit_field(t)) {
|
||||
auto args = array_make<irValue *>(heap_allocator(), 2);
|
||||
auto args = array_make<irValue *>(permanent_allocator(), 2);
|
||||
irValue *lhs = ir_address_from_load_or_generate_local(proc, x);
|
||||
args[0] = ir_emit_conv(proc, lhs, t_rawptr);
|
||||
args[1] = ir_const_int(type_size_of(t));
|
||||
@@ -4848,7 +4860,7 @@ irValue *ir_emit_comp_against_nil(irProcedure *proc, TokenKind op_kind, irValue
|
||||
return ir_emit_comp(proc, op_kind, cap, v_zero);
|
||||
}
|
||||
} else if (is_type_struct(t) && type_has_nil(t)) {
|
||||
auto args = array_make<irValue *>(heap_allocator(), 2);
|
||||
auto args = array_make<irValue *>(permanent_allocator(), 2);
|
||||
irValue *lhs = ir_address_from_load_or_generate_local(proc, x);
|
||||
args[0] = ir_emit_conv(proc, lhs, t_rawptr);
|
||||
args[1] = ir_const_int(type_size_of(t));
|
||||
@@ -4859,6 +4871,244 @@ irValue *ir_emit_comp_against_nil(irProcedure *proc, TokenKind op_kind, irValue
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
irValue *ir_get_equal_proc_for_type(irModule *m, Type *type) {
|
||||
Type *original_type = type;
|
||||
type = base_type(type);
|
||||
Type *pt = alloc_type_pointer(type);
|
||||
|
||||
auto key = hash_type(type);
|
||||
irValue **found = map_get(&m->equal_procs, key);
|
||||
if (found) {
|
||||
return *found;
|
||||
}
|
||||
|
||||
static u32 proc_index = 0;
|
||||
|
||||
char buf[16] = {};
|
||||
isize n = gb_snprintf(buf, 16, "__$equal%u", ++proc_index);
|
||||
char *str = gb_alloc_str_len(permanent_allocator(), buf, n-1);
|
||||
String proc_name = make_string_c(str);
|
||||
|
||||
|
||||
Ast *body = alloc_ast_node(nullptr, Ast_Invalid);
|
||||
Entity *e = alloc_entity_procedure(nullptr, make_token_ident(proc_name), t_equal_proc, 0);
|
||||
e->Procedure.link_name = proc_name;
|
||||
irValue *p = ir_value_procedure(m, e, t_equal_proc, nullptr, body, proc_name);
|
||||
map_set(&m->values, hash_entity(e), p);
|
||||
string_map_set(&m->members, proc_name, p);
|
||||
map_set(&m->equal_procs, key, p);
|
||||
|
||||
irProcedure *proc = &p->Proc;
|
||||
proc->is_startup = true;
|
||||
proc->ignore_dead_instr = true;
|
||||
ir_begin_procedure_body(proc);
|
||||
// ir_start_block(proc, proc->decl_block);
|
||||
GB_ASSERT(proc->curr_block != nullptr);
|
||||
|
||||
irValue *x = proc->params[0];
|
||||
irValue *y = proc->params[1];
|
||||
irValue *lhs = ir_emit_conv(proc, x, pt);
|
||||
irValue *rhs = ir_emit_conv(proc, y, pt);
|
||||
|
||||
irBlock *block_same_ptr = ir_new_block(proc, nullptr, "same_ptr");
|
||||
irBlock *block_diff_ptr = ir_new_block(proc, nullptr, "diff_ptr");
|
||||
|
||||
irValue *same_ptr = ir_emit_comp(proc, Token_CmpEq, lhs, rhs);
|
||||
ir_emit_if(proc, same_ptr, block_same_ptr, block_diff_ptr);
|
||||
ir_start_block(proc, block_same_ptr);
|
||||
ir_emit(proc, ir_instr_return(proc, ir_const_bool(true)));
|
||||
|
||||
ir_start_block(proc, block_diff_ptr);
|
||||
|
||||
if (type->kind == Type_Struct) {
|
||||
type_set_offsets(type);
|
||||
|
||||
irBlock *done = ir_new_block(proc, nullptr, "done"); // NOTE(bill): Append later
|
||||
|
||||
irBlock *block_false = ir_new_block(proc, nullptr, "bfalse");
|
||||
|
||||
for_array(i, type->Struct.fields) {
|
||||
irBlock *next_block = ir_new_block(proc, nullptr, "btrue");
|
||||
|
||||
irValue *pleft = ir_emit_struct_ep(proc, lhs, cast(i32)i);
|
||||
irValue *pright = ir_emit_struct_ep(proc, rhs, cast(i32)i);
|
||||
irValue *left = ir_emit_load(proc, pleft);
|
||||
irValue *right = ir_emit_load(proc, pright);
|
||||
irValue *ok = ir_emit_comp(proc, Token_CmpEq, left, right);
|
||||
|
||||
ir_emit_if(proc, ok, next_block, block_false);
|
||||
|
||||
ir_emit_jump(proc, next_block);
|
||||
ir_start_block(proc, next_block);
|
||||
}
|
||||
|
||||
ir_emit_jump(proc, done);
|
||||
ir_start_block(proc, block_false);
|
||||
|
||||
ir_emit(proc, ir_instr_return(proc, ir_const_bool(false)));
|
||||
|
||||
ir_emit_jump(proc, done);
|
||||
ir_start_block(proc, done);
|
||||
ir_emit(proc, ir_instr_return(proc, ir_const_bool(true)));
|
||||
} else {
|
||||
irValue *left = ir_emit_load(proc, lhs);
|
||||
irValue *right = ir_emit_load(proc, rhs);
|
||||
irValue *ok = ir_emit_comp(proc, Token_CmpEq, left, right);
|
||||
ok = ir_emit_conv(proc, ok, t_bool);
|
||||
ir_emit(proc, ir_instr_return(proc, ok));
|
||||
}
|
||||
|
||||
ir_end_procedure_body(proc);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
irValue *ir_simple_compare_hash(irProcedure *p, Type *type, irValue *data, irValue *seed) {
|
||||
GB_ASSERT_MSG(is_type_simple_compare(type), "%s", type_to_string(type));
|
||||
|
||||
i64 sz = type_size_of(type);
|
||||
if (1 <= sz && sz <= 16) {
|
||||
char name[20] = {};
|
||||
gb_snprintf(name, 20, "default_hasher%d", cast(i32)sz);
|
||||
|
||||
auto args = array_make<irValue *>(permanent_allocator(), 2);
|
||||
args[0] = data;
|
||||
args[1] = seed;
|
||||
return ir_emit_runtime_call(p, name, args);
|
||||
}
|
||||
|
||||
auto args = array_make<irValue *>(permanent_allocator(), 3);
|
||||
args[0] = data;
|
||||
args[1] = seed;
|
||||
args[2] = ir_const_int(type_size_of(type));
|
||||
return ir_emit_runtime_call(p, "default_hasher_n", args);
|
||||
}
|
||||
|
||||
irValue *ir_get_hasher_proc_for_type(irModule *m, Type *type) {
|
||||
Type *original_type = type;
|
||||
type = core_type(type);
|
||||
Type *pt = alloc_type_pointer(type);
|
||||
|
||||
GB_ASSERT(is_type_valid_for_keys(type));
|
||||
|
||||
auto key = hash_type(type);
|
||||
irValue **found = map_get(&m->hasher_procs, key);
|
||||
if (found) {
|
||||
return *found;
|
||||
}
|
||||
|
||||
static u32 proc_index = 0;
|
||||
|
||||
char buf[16] = {};
|
||||
isize n = gb_snprintf(buf, 16, "__$hasher%u", ++proc_index);
|
||||
char *str = gb_alloc_str_len(permanent_allocator(), buf, n-1);
|
||||
String proc_name = make_string_c(str);
|
||||
|
||||
|
||||
Ast *body = alloc_ast_node(nullptr, Ast_Invalid);
|
||||
Entity *e = alloc_entity_procedure(nullptr, make_token_ident(proc_name), t_hasher_proc, 0);
|
||||
e->Procedure.link_name = proc_name;
|
||||
irValue *p = ir_value_procedure(m, e, t_hasher_proc, nullptr, body, proc_name);
|
||||
map_set(&m->values, hash_entity(e), p);
|
||||
string_map_set(&m->members, proc_name, p);
|
||||
map_set(&m->hasher_procs, key, p);
|
||||
|
||||
irProcedure *proc = &p->Proc;
|
||||
proc->is_startup = true;
|
||||
proc->ignore_dead_instr = true;
|
||||
ir_begin_procedure_body(proc);
|
||||
defer (ir_end_procedure_body(proc));
|
||||
|
||||
// ir_start_block(proc, proc->decl_block);
|
||||
GB_ASSERT(proc->curr_block != nullptr);
|
||||
|
||||
irValue *data = proc->params[0];
|
||||
irValue *seed = proc->params[1];
|
||||
|
||||
if (is_type_simple_compare(type)) {
|
||||
irValue *res = ir_simple_compare_hash(proc, type, data, seed);
|
||||
ir_emit(proc, ir_instr_return(proc, res));
|
||||
return p;
|
||||
}
|
||||
|
||||
if (is_type_cstring(type)) {
|
||||
auto args = array_make<irValue *>(permanent_allocator(), 2);
|
||||
args[0] = data;
|
||||
args[1] = seed;
|
||||
irValue *res = ir_emit_runtime_call(proc, "default_hasher_cstring", args);
|
||||
ir_emit(proc, ir_instr_return(proc, res));
|
||||
} else if (is_type_string(type)) {
|
||||
auto args = array_make<irValue *>(permanent_allocator(), 2);
|
||||
args[0] = data;
|
||||
args[1] = seed;
|
||||
irValue *res = ir_emit_runtime_call(proc, "default_hasher_string", args);
|
||||
ir_emit(proc, ir_instr_return(proc, res));
|
||||
} else if (type->kind == Type_Struct) {
|
||||
type_set_offsets(type);
|
||||
data = ir_emit_conv(proc, data, t_u8_ptr);
|
||||
|
||||
auto args = array_make<irValue *>(permanent_allocator(), 2);
|
||||
for_array(i, type->Struct.fields) {
|
||||
i64 offset = type->Struct.offsets[i];
|
||||
Entity *field = type->Struct.fields[i];
|
||||
irValue *field_hasher = ir_get_hasher_proc_for_type(m, field->type);
|
||||
irValue *ptr = ir_emit_ptr_offset(proc, data, ir_const_uintptr(offset));
|
||||
|
||||
args[0] = ptr;
|
||||
args[1] = seed;
|
||||
seed = ir_emit_call(proc, field_hasher, args);
|
||||
}
|
||||
ir_emit(proc, ir_instr_return(proc, seed));
|
||||
} else if (type->kind == Type_Array) {
|
||||
irValue *pres = ir_add_local_generated(proc, t_uintptr, false);
|
||||
ir_emit_store(proc, pres, seed);
|
||||
|
||||
auto args = array_make<irValue *>(permanent_allocator(), 2);
|
||||
irValue *elem_hasher = ir_get_hasher_proc_for_type(m, type->Array.elem);
|
||||
|
||||
auto loop_data = ir_loop_start(proc, type->Array.count, t_i32);
|
||||
|
||||
data = ir_emit_conv(proc, data, pt);
|
||||
|
||||
irValue *ptr = ir_emit_array_ep(proc, data, loop_data.idx);
|
||||
args[0] = ptr;
|
||||
args[1] = ir_emit_load(proc, pres);
|
||||
irValue *new_seed = ir_emit_call(proc, elem_hasher, args);
|
||||
ir_emit_store(proc, pres, new_seed);
|
||||
|
||||
ir_loop_end(proc, loop_data);
|
||||
|
||||
irValue *res = ir_emit_load(proc, pres);
|
||||
ir_emit(proc, ir_instr_return(proc, res));
|
||||
} else if (type->kind == Type_EnumeratedArray) {
|
||||
irValue *pres = ir_add_local_generated(proc, t_uintptr, false);
|
||||
ir_emit_store(proc, pres, seed);
|
||||
|
||||
auto args = array_make<irValue *>(permanent_allocator(), 2);
|
||||
irValue *elem_hasher = ir_get_hasher_proc_for_type(m, type->Array.elem);
|
||||
|
||||
auto loop_data = ir_loop_start(proc, type->Array.count, t_i32);
|
||||
|
||||
data = ir_emit_conv(proc, data, pt);
|
||||
|
||||
irValue *ptr = ir_emit_array_ep(proc, data, loop_data.idx);
|
||||
args[0] = ptr;
|
||||
args[1] = ir_emit_load(proc, pres);
|
||||
irValue *new_seed = ir_emit_call(proc, elem_hasher, args);
|
||||
ir_emit_store(proc, pres, new_seed);
|
||||
|
||||
ir_loop_end(proc, loop_data);
|
||||
|
||||
irValue *res = ir_emit_load(proc, pres);
|
||||
ir_emit(proc, ir_instr_return(proc, res));
|
||||
} else {
|
||||
GB_PANIC("Unhandled type for hasher: %s", type_to_string(type));
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
irValue *ir_emit_comp(irProcedure *proc, TokenKind op_kind, irValue *left, irValue *right) {
|
||||
Type *a = base_type(ir_type(left));
|
||||
Type *b = base_type(ir_type(right));
|
||||
@@ -4966,7 +5216,7 @@ irValue *ir_emit_comp(irProcedure *proc, TokenKind op_kind, irValue *left, irVal
|
||||
} else {
|
||||
if (is_type_simple_compare(tl) && (op_kind == Token_CmpEq || op_kind == Token_NotEq)) {
|
||||
// TODO(bill): Test to see if this is actually faster!!!!
|
||||
auto args = array_make<irValue *>(heap_allocator(), 3);
|
||||
auto args = array_make<irValue *>(permanent_allocator(), 3);
|
||||
args[0] = ir_emit_conv(proc, lhs, t_rawptr);
|
||||
args[1] = ir_emit_conv(proc, rhs, t_rawptr);
|
||||
args[2] = ir_const_int(type_size_of(tl));
|
||||
@@ -4992,6 +5242,30 @@ irValue *ir_emit_comp(irProcedure *proc, TokenKind op_kind, irValue *left, irVal
|
||||
}
|
||||
}
|
||||
|
||||
if (is_type_struct(a) && is_type_comparable(a)) {
|
||||
irValue *left_ptr = ir_address_from_load_or_generate_local(proc, left);
|
||||
irValue *right_ptr = ir_address_from_load_or_generate_local(proc, right);
|
||||
irValue *res = {};
|
||||
if (is_type_simple_compare(a)) {
|
||||
// TODO(bill): Test to see if this is actually faster!!!!
|
||||
auto args = array_make<irValue *>(permanent_allocator(), 3);
|
||||
args[0] = ir_emit_conv(proc, left_ptr, t_rawptr);
|
||||
args[1] = ir_emit_conv(proc, right_ptr, t_rawptr);
|
||||
args[2] = ir_const_int(type_size_of(a));
|
||||
res = ir_emit_runtime_call(proc, "memory_equal", args);
|
||||
} else {
|
||||
irValue *value = ir_get_equal_proc_for_type(proc->module, a);
|
||||
auto args = array_make<irValue *>(permanent_allocator(), 2);
|
||||
args[0] = ir_emit_conv(proc, left_ptr, t_rawptr);
|
||||
args[1] = ir_emit_conv(proc, right_ptr, t_rawptr);
|
||||
res = ir_emit_call(proc, value, args);
|
||||
}
|
||||
if (op_kind == Token_NotEq) {
|
||||
res = ir_emit_unary_arith(proc, Token_Not, res, ir_type(res));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
if (is_type_string(a)) {
|
||||
if (is_type_cstring(a)) {
|
||||
left = ir_emit_conv(proc, left, t_string);
|
||||
@@ -6636,7 +6910,7 @@ void ir_mangle_add_sub_type_name(irModule *m, Entity *field, String parent) {
|
||||
return;
|
||||
}
|
||||
if (is_type_proc(field->type)) {
|
||||
set_procedure_abi_types(heap_allocator(), field->type);
|
||||
set_procedure_abi_types(field->type);
|
||||
}
|
||||
|
||||
String cn = field->token.string;
|
||||
@@ -6733,7 +7007,7 @@ irValue *ir_gen_anonymous_proc_lit(irModule *m, String prefix_name, Ast *expr, i
|
||||
String name = make_string(name_text, name_len-1);
|
||||
|
||||
Type *type = type_of_expr(expr);
|
||||
set_procedure_abi_types(heap_allocator(), type);
|
||||
set_procedure_abi_types(type);
|
||||
irValue *value = ir_value_procedure(m, nullptr, type, pl->type, pl->body, name);
|
||||
|
||||
value->Proc.tags = pl->tags;
|
||||
@@ -6789,6 +7063,9 @@ void ir_gen_global_type_name(irModule *m, Entity *e, String name) {
|
||||
if (!ir_min_dep_entity(m, e)) {
|
||||
return;
|
||||
}
|
||||
if (is_type_proc(e->type)) {
|
||||
return;
|
||||
}
|
||||
irValue *t = ir_value_type_name(name, e->type);
|
||||
ir_module_add_value(m, e, t);
|
||||
string_map_set(&m->members, name, t);
|
||||
@@ -6884,7 +7161,7 @@ irValue *ir_find_global_variable(irProcedure *proc, String name) {
|
||||
return *value;
|
||||
}
|
||||
|
||||
void ir_build_stmt_list(irProcedure *proc, Array<Ast *> stmts);
|
||||
void ir_build_stmt_list(irProcedure *proc, Slice<Ast *> stmts);
|
||||
void ir_build_assign_op(irProcedure *proc, irAddr const &lhs, irValue *value, TokenKind op);
|
||||
|
||||
bool is_double_pointer(Type *t) {
|
||||
@@ -6898,17 +7175,6 @@ bool is_double_pointer(Type *t) {
|
||||
return is_type_pointer(td);
|
||||
}
|
||||
|
||||
|
||||
u64 ir_generate_source_code_location_hash(TokenPos pos) {
|
||||
u64 h = 0xcbf29ce484222325;
|
||||
for (isize i = 0; i < pos.file.len; i++) {
|
||||
h = (h ^ u64(pos.file[i])) * 0x100000001b3;
|
||||
}
|
||||
h = h ^ (u64(pos.line) * 0x100000001b3);
|
||||
h = h ^ (u64(pos.column) * 0x100000001b3);
|
||||
return h;
|
||||
}
|
||||
|
||||
irValue *ir_emit_source_code_location(irProcedure *proc, String procedure, TokenPos pos) {
|
||||
gbAllocator a = ir_allocator();
|
||||
irValue *v = ir_alloc_value(irValue_SourceCodeLocation);
|
||||
@@ -6916,7 +7182,6 @@ irValue *ir_emit_source_code_location(irProcedure *proc, String procedure, Token
|
||||
v->SourceCodeLocation.line = ir_const_int(pos.line);
|
||||
v->SourceCodeLocation.column = ir_const_int(pos.column);
|
||||
v->SourceCodeLocation.procedure = ir_find_or_add_entity_string(proc->module, procedure);
|
||||
v->SourceCodeLocation.hash = ir_generate_source_code_location_hash(pos);
|
||||
return v;
|
||||
}
|
||||
|
||||
@@ -7355,7 +7620,7 @@ irValue *ir_build_builtin_proc(irProcedure *proc, Ast *expr, TypeAndValue tv, Bu
|
||||
// "Intrinsics"
|
||||
case BuiltinProc_alloca:
|
||||
{
|
||||
auto args = array_make<irValue *>(heap_allocator(), 2);
|
||||
auto args = array_make<irValue *>(permanent_allocator(), 2);
|
||||
args[0] = ir_emit_conv(proc, ir_build_expr(proc, ce->args[0]), t_i32);
|
||||
args[1] = ir_build_expr(proc, ce->args[1]);
|
||||
return ir_emit(proc, ir_instr_inline_code(proc, id, args, t_u8_ptr));
|
||||
@@ -7459,7 +7724,11 @@ irValue *ir_build_builtin_proc(irProcedure *proc, Ast *expr, TypeAndValue tv, Bu
|
||||
return ir_emit(proc, ir_instr_atomic_cxchg(proc, type, address, old_value, new_value, id));
|
||||
}
|
||||
|
||||
case BuiltinProc_type_equal_proc:
|
||||
return ir_get_equal_proc_for_type(proc->module, ce->args[0]->tav.type);
|
||||
|
||||
case BuiltinProc_type_hasher_proc:
|
||||
return ir_get_hasher_proc_for_type(proc->module, ce->args[0]->tav.type);
|
||||
}
|
||||
|
||||
GB_PANIC("Unhandled built-in procedure");
|
||||
@@ -7584,7 +7853,7 @@ irValue *ir_build_call_expr(irProcedure *proc, Ast *expr) {
|
||||
Type *proc_type_ = base_type(ir_type(value));
|
||||
GB_ASSERT(proc_type_->kind == Type_Proc);
|
||||
TypeProc *pt = &proc_type_->Proc;
|
||||
set_procedure_abi_types(heap_allocator(), proc_type_);
|
||||
set_procedure_abi_types(proc_type_);
|
||||
|
||||
if (is_call_expr_field_value(ce)) {
|
||||
auto args = array_make<irValue *>(ir_allocator(), pt->param_count);
|
||||
@@ -7801,7 +8070,11 @@ irValue *ir_build_expr_internal(irProcedure *proc, Ast *expr) {
|
||||
|
||||
if (tv.value.kind != ExactValue_Invalid) {
|
||||
// NOTE(bill): Edge case
|
||||
if (tv.value.kind != ExactValue_Compound &&
|
||||
if (is_type_u8_array(tv.type) && tv.value.kind == ExactValue_String) {
|
||||
return ir_add_module_constant(proc->module, tv.type, tv.value);
|
||||
} else if (is_type_rune_array(tv.type) && tv.value.kind == ExactValue_String) {
|
||||
return ir_add_module_constant(proc->module, tv.type, tv.value);
|
||||
} else if (tv.value.kind != ExactValue_Compound &&
|
||||
is_type_array(tv.type)) {
|
||||
Type *elem = core_array_type(tv.type);
|
||||
ExactValue value = convert_exact_value_for_type(tv.value, elem);
|
||||
@@ -8207,7 +8480,7 @@ irValue *ir_build_expr_internal(irProcedure *proc, Ast *expr) {
|
||||
|
||||
irValue *addr = ir_address_from_load_or_generate_local(proc, right);
|
||||
irValue *h = ir_gen_map_header(proc, addr, rt);
|
||||
irValue *key = ir_gen_map_key(proc, left, rt->Map.key);
|
||||
irValue *key = ir_gen_map_hash(proc, left, rt->Map.key);
|
||||
|
||||
auto args = array_make<irValue *>(ir_allocator(), 2);
|
||||
args[0] = h;
|
||||
@@ -9024,8 +9297,7 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
|
||||
if (cl->elems.count > 0) {
|
||||
ir_emit_store(proc, v, ir_add_module_constant(proc->module, type, exact_value_compound(expr)));
|
||||
|
||||
auto temp_data = array_make<irCompoundLitElemTempData>(heap_allocator(), 0, cl->elems.count);
|
||||
defer (array_free(&temp_data));
|
||||
auto temp_data = array_make<irCompoundLitElemTempData>(temporary_allocator(), 0, cl->elems.count);
|
||||
|
||||
// NOTE(bill): Separate value, gep, store into their own chunks
|
||||
for_array(i, cl->elems) {
|
||||
@@ -9123,8 +9395,7 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
|
||||
if (cl->elems.count > 0) {
|
||||
ir_emit_store(proc, v, ir_add_module_constant(proc->module, type, exact_value_compound(expr)));
|
||||
|
||||
auto temp_data = array_make<irCompoundLitElemTempData>(heap_allocator(), 0, cl->elems.count);
|
||||
defer (array_free(&temp_data));
|
||||
auto temp_data = array_make<irCompoundLitElemTempData>(temporary_allocator(), 0, cl->elems.count);
|
||||
|
||||
// NOTE(bill): Separate value, gep, store into their own chunks
|
||||
for_array(i, cl->elems) {
|
||||
@@ -9232,8 +9503,7 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
|
||||
|
||||
irValue *data = ir_emit_array_ep(proc, slice->ConstantSlice.backing_array, v_zero32);
|
||||
|
||||
auto temp_data = array_make<irCompoundLitElemTempData>(heap_allocator(), 0, cl->elems.count);
|
||||
defer (array_free(&temp_data));
|
||||
auto temp_data = array_make<irCompoundLitElemTempData>(temporary_allocator(), 0, cl->elems.count);
|
||||
|
||||
for_array(i, cl->elems) {
|
||||
Ast *elem = cl->elems[i];
|
||||
@@ -9574,7 +9844,7 @@ void ir_build_nested_proc(irProcedure *proc, AstProcLit *pd, Entity *e) {
|
||||
name_len = gb_snprintf(cast(char *)name_text, name_len, "%.*s.%.*s-%d", LIT(proc->name), LIT(pd_name), guid);
|
||||
String name = make_string(name_text, name_len-1);
|
||||
|
||||
set_procedure_abi_types(heap_allocator(), e->type);
|
||||
set_procedure_abi_types(e->type);
|
||||
irValue *value = ir_value_procedure(proc->module, e, e->type, pd->type, pd->body, name);
|
||||
|
||||
value->Proc.tags = pd->tags;
|
||||
@@ -9673,7 +9943,7 @@ void ir_build_constant_value_decl(irProcedure *proc, AstValueDecl *vd) {
|
||||
return;
|
||||
}
|
||||
|
||||
set_procedure_abi_types(heap_allocator(), e->type);
|
||||
set_procedure_abi_types(e->type);
|
||||
irValue *value = ir_value_procedure(proc->module, e, e->type, pl->type, pl->body, name);
|
||||
|
||||
value->Proc.tags = pl->tags;
|
||||
@@ -9692,7 +9962,7 @@ void ir_build_constant_value_decl(irProcedure *proc, AstValueDecl *vd) {
|
||||
}
|
||||
}
|
||||
|
||||
void ir_build_stmt_list(irProcedure *proc, Array<Ast *> stmts) {
|
||||
void ir_build_stmt_list(irProcedure *proc, Slice<Ast *> stmts) {
|
||||
// NOTE(bill): Precollect constant entities
|
||||
for_array(i, stmts) {
|
||||
Ast *stmt = stmts[i];
|
||||
@@ -9844,13 +10114,8 @@ void ir_build_range_indexed(irProcedure *proc, irValue *expr, Type *val_type, ir
|
||||
elem = ir_emit_load(proc, elem);
|
||||
|
||||
irValue *entry = ir_emit_ptr_offset(proc, elem, idx);
|
||||
val = ir_emit_load(proc, ir_emit_struct_ep(proc, entry, 2));
|
||||
|
||||
irValue *key_raw = ir_emit_struct_ep(proc, entry, 0);
|
||||
key_raw = ir_emit_struct_ep(proc, key_raw, 1);
|
||||
irValue *key = ir_emit_conv(proc, key_raw, alloc_type_pointer(expr_type->Map.key));
|
||||
|
||||
idx = ir_emit_load(proc, key);
|
||||
idx = ir_emit_load(proc, ir_emit_struct_ep(proc, entry, 2));
|
||||
val = ir_emit_load(proc, ir_emit_struct_ep(proc, entry, 3));
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -9995,7 +10260,7 @@ void ir_build_range_enum(irProcedure *proc, Type *enum_type, Type *val_type, irV
|
||||
irValue *max_count = ir_const_int(enum_count);
|
||||
|
||||
irValue *ti = ir_type_info(proc, t);
|
||||
irValue *variant = ir_emit_struct_ep(proc, ti, 3);
|
||||
irValue *variant = ir_emit_struct_ep(proc, ti, 4);
|
||||
irValue *eti_ptr = ir_emit_conv(proc, variant, t_type_info_enum_ptr);
|
||||
irValue *values = ir_emit_load(proc, ir_emit_struct_ep(proc, eti_ptr, 2));
|
||||
irValue *values_data = ir_slice_elem(proc, values);
|
||||
@@ -10179,7 +10444,7 @@ void ir_build_stmt_internal(irProcedure *proc, Ast *node) {
|
||||
|
||||
String mangled_name = {};
|
||||
{
|
||||
gbString str = gb_string_make_length(heap_allocator(), proc->name.text, proc->name.len);
|
||||
gbString str = gb_string_make_length(permanent_allocator(), proc->name.text, proc->name.len);
|
||||
str = gb_string_appendc(str, "-");
|
||||
str = gb_string_append_fmt(str, ".%.*s-%llu", LIT(name), cast(long long)e->id);
|
||||
mangled_name.text = cast(u8 *)str;
|
||||
@@ -10902,7 +11167,7 @@ void ir_build_stmt_internal(irProcedure *proc, Ast *node) {
|
||||
|
||||
ast_node(body, BlockStmt, ss->body);
|
||||
|
||||
Array<Ast *> default_stmts = {};
|
||||
Slice<Ast *> default_stmts = {};
|
||||
irBlock *default_fall = nullptr;
|
||||
irBlock *default_block = nullptr;
|
||||
|
||||
@@ -11349,6 +11614,9 @@ void ir_begin_procedure_body(irProcedure *proc) {
|
||||
|
||||
|
||||
bool ir_remove_dead_instr(irProcedure *proc) {
|
||||
if (proc->ignore_dead_instr) {
|
||||
return false;
|
||||
}
|
||||
isize elimination_count = 0;
|
||||
retry:
|
||||
#if 1
|
||||
@@ -11471,11 +11739,11 @@ void ir_insert_code_before_proc(irProcedure* proc, irProcedure *parent) {
|
||||
void ir_build_proc(irValue *value, irProcedure *parent) {
|
||||
irProcedure *proc = &value->Proc;
|
||||
|
||||
set_procedure_abi_types(heap_allocator(), proc->type);
|
||||
set_procedure_abi_types(proc->type);
|
||||
|
||||
proc->parent = parent;
|
||||
|
||||
if (proc->body != nullptr) {
|
||||
if (proc->body != nullptr && proc->body->kind != Ast_Invalid) {
|
||||
u64 prev_state_flags = proc->module->state_flags;
|
||||
|
||||
if (proc->tags != 0) {
|
||||
@@ -11577,6 +11845,8 @@ void ir_init_module(irModule *m, Checker *c) {
|
||||
map_init(&m->debug_info, heap_allocator());
|
||||
map_init(&m->entity_names, heap_allocator());
|
||||
map_init(&m->anonymous_proc_lits, heap_allocator());
|
||||
map_init(&m->equal_procs, heap_allocator());
|
||||
map_init(&m->hasher_procs, heap_allocator());
|
||||
array_init(&m->procs, heap_allocator());
|
||||
array_init(&m->procs_to_generate, heap_allocator());
|
||||
array_init(&m->foreign_library_paths, heap_allocator());
|
||||
@@ -11860,6 +12130,8 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info
|
||||
// Useful types
|
||||
Type *t_i64_slice_ptr = alloc_type_pointer(alloc_type_slice(t_i64));
|
||||
Type *t_string_slice_ptr = alloc_type_pointer(alloc_type_slice(t_string));
|
||||
Entity *type_info_flags_entity = find_core_entity(info->checker, str_lit("Type_Info_Flags"));
|
||||
Type *t_type_info_flags = type_info_flags_entity->type;
|
||||
|
||||
i32 type_info_member_types_index = 0;
|
||||
i32 type_info_member_names_index = 0;
|
||||
@@ -11879,11 +12151,14 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info
|
||||
|
||||
irValue *tag = nullptr;
|
||||
irValue *ti_ptr = ir_emit_array_epi(proc, ir_global_type_info_data, cast(i32)entry_index);
|
||||
irValue *variant_ptr = ir_emit_struct_ep(proc, ti_ptr, 3);
|
||||
irValue *variant_ptr = ir_emit_struct_ep(proc, ti_ptr, 4);
|
||||
|
||||
irValue *type_info_flags = ir_value_constant(t_type_info_flags, exact_value_i64(type_info_flags_of_type(t)));
|
||||
|
||||
ir_emit_store(proc, ir_emit_struct_ep(proc, ti_ptr, 0), ir_const_int(type_size_of(t)));
|
||||
ir_emit_store(proc, ir_emit_struct_ep(proc, ti_ptr, 1), ir_const_int(type_align_of(t)));
|
||||
ir_emit_store(proc, ir_emit_struct_ep(proc, ti_ptr, 2), ir_typeid(proc->module, t));
|
||||
ir_emit_store(proc, ir_emit_struct_ep(proc, ti_ptr, 2), type_info_flags);
|
||||
ir_emit_store(proc, ir_emit_struct_ep(proc, ti_ptr, 3), ir_typeid(proc->module, t));
|
||||
|
||||
|
||||
switch (t->kind) {
|
||||
@@ -11897,6 +12172,21 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info
|
||||
|
||||
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 0), name);
|
||||
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 1), gtip);
|
||||
|
||||
if (t->Named.type_name->pkg) {
|
||||
irValue *name = ir_const_string(proc->module, t->Named.type_name->pkg->name);
|
||||
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 2), name);
|
||||
}
|
||||
|
||||
String proc_name = {};
|
||||
if (t->Named.type_name->parent_proc_decl) {
|
||||
DeclInfo *decl = t->Named.type_name->parent_proc_decl;
|
||||
if (decl->entity && decl->entity->kind == Entity_Procedure) {
|
||||
proc_name = decl->entity->token.string;
|
||||
}
|
||||
}
|
||||
irValue *loc = ir_emit_source_code_location(proc, proc_name, t->Named.type_name->token.pos);
|
||||
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 3), loc);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -12234,8 +12524,13 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info
|
||||
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 6), is_raw_union);
|
||||
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 7), is_custom_align);
|
||||
|
||||
if (is_type_comparable(t) && !is_type_simple_compare(t)) {
|
||||
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 8), ir_get_equal_proc_for_type(proc->module, t));
|
||||
}
|
||||
|
||||
|
||||
if (t->Struct.soa_kind != StructSoa_None) {
|
||||
irValue *kind = ir_emit_struct_ep(proc, tag, 8);
|
||||
irValue *kind = ir_emit_struct_ep(proc, tag, 9);
|
||||
Type *kind_type = type_deref(ir_type(kind));
|
||||
|
||||
irValue *soa_kind = ir_value_constant(kind_type, exact_value_i64(t->Struct.soa_kind));
|
||||
@@ -12244,8 +12539,8 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info
|
||||
|
||||
|
||||
ir_emit_store(proc, kind, soa_kind);
|
||||
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 9), soa_type);
|
||||
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 10), soa_len);
|
||||
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 10), soa_type);
|
||||
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 11), soa_len);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12308,10 +12603,14 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info
|
||||
irValue *key = ir_emit_struct_ep(proc, tag, 0);
|
||||
irValue *value = ir_emit_struct_ep(proc, tag, 1);
|
||||
irValue *generated_struct = ir_emit_struct_ep(proc, tag, 2);
|
||||
irValue *key_equal = ir_emit_struct_ep(proc, tag, 3);
|
||||
irValue *key_hasher = ir_emit_struct_ep(proc, tag, 4);
|
||||
|
||||
ir_emit_store(proc, key, ir_get_type_info_ptr(proc, t->Map.key));
|
||||
ir_emit_store(proc, value, ir_get_type_info_ptr(proc, t->Map.value));
|
||||
ir_emit_store(proc, generated_struct, ir_get_type_info_ptr(proc, t->Map.generated_struct_type));
|
||||
ir_emit_store(proc, key_equal, ir_get_equal_proc_for_type(proc->module, t->Map.key));
|
||||
ir_emit_store(proc, key_hasher, ir_get_hasher_proc_for_type(proc->module, t->Map.key));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -12612,7 +12911,7 @@ void ir_gen_tree(irGen *s) {
|
||||
|
||||
Ast *type_expr = pl->type;
|
||||
|
||||
set_procedure_abi_types(heap_allocator(), e->type);
|
||||
set_procedure_abi_types(e->type);
|
||||
irValue *p = ir_value_procedure(m, e, e->type, type_expr, body, name);
|
||||
p->Proc.tags = pl->tags;
|
||||
p->Proc.inlining = pl->inlining;
|
||||
@@ -12646,7 +12945,7 @@ void ir_gen_tree(irGen *s) {
|
||||
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
if (build_context.build_mode == BuildMode_DynamicLibrary && !has_dll_main) {
|
||||
if (build_context.build_mode == BuildMode_DynamicLibrary && !has_dll_main && !build_context.no_entry_point) {
|
||||
// DllMain :: proc(inst: rawptr, reason: u32, reserved: rawptr) -> i32
|
||||
String name = str_lit("DllMain");
|
||||
Type *proc_params = alloc_type_tuple();
|
||||
@@ -12717,7 +13016,7 @@ void ir_gen_tree(irGen *s) {
|
||||
ir_emit_return(proc, v_one32);
|
||||
}
|
||||
#endif
|
||||
if (!(build_context.build_mode == BuildMode_DynamicLibrary && !has_dll_main)) {
|
||||
if (!(build_context.build_mode == BuildMode_DynamicLibrary && !has_dll_main) && !build_context.no_entry_point) {
|
||||
// main :: proc(argc: i32, argv: ^^u8) -> i32
|
||||
String name = str_lit("main");
|
||||
|
||||
@@ -12784,11 +13083,18 @@ void ir_gen_tree(irGen *s) {
|
||||
ir_fill_slice(proc, global_args, argv, ir_emit_conv(proc, argc, t_int));
|
||||
|
||||
ir_emit(proc, ir_alloc_instr(proc, irInstr_StartupRuntime));
|
||||
{
|
||||
Array<irValue *> empty_args = {};
|
||||
if (build_context.command_kind == Command_test) {
|
||||
for_array(i, m->info->testing_procedures) {
|
||||
Entity *e = m->info->testing_procedures[i];
|
||||
irValue **found = map_get(&proc->module->values, hash_entity(e));
|
||||
GB_ASSERT(found != nullptr);
|
||||
ir_emit_call(proc, *found, empty_args);
|
||||
}
|
||||
} else {
|
||||
irValue **found = map_get(&proc->module->values, hash_entity(entry_point));
|
||||
if (found != nullptr) {
|
||||
Array<irValue *> args = {};
|
||||
ir_emit_call(proc, *found, args);
|
||||
ir_emit_call(proc, *found, empty_args);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12796,7 +13102,7 @@ void ir_gen_tree(irGen *s) {
|
||||
}
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
if (build_context.build_mode != BuildMode_DynamicLibrary && build_context.no_crt) {
|
||||
if (build_context.build_mode != BuildMode_DynamicLibrary && build_context.no_crt && !build_context.no_entry_point) {
|
||||
s->print_chkstk = true;
|
||||
|
||||
{
|
||||
|
||||
+45
-20
@@ -76,7 +76,6 @@ void ir_write_u64(irFileBuffer *f, u64 i) {
|
||||
}
|
||||
void ir_write_big_int(irFileBuffer *f, BigInt const &x, Type *type, bool swap_endian) {
|
||||
if (x.len == 2) {
|
||||
gbAllocator a = heap_allocator(); // TODO(bill): Change this allocator
|
||||
u64 words[2] = {};
|
||||
BigInt y = x;
|
||||
if (swap_endian) {
|
||||
@@ -88,9 +87,8 @@ void ir_write_big_int(irFileBuffer *f, BigInt const &x, Type *type, bool swap_en
|
||||
y.d.words = words;
|
||||
}
|
||||
|
||||
String s = big_int_to_string(a, &y, 10);
|
||||
String s = big_int_to_string(temporary_allocator(), &y, 10);
|
||||
ir_write_string(f, s);
|
||||
gb_free(a, s.text);
|
||||
} else {
|
||||
i64 i = 0;
|
||||
if (x.neg) {
|
||||
@@ -296,7 +294,7 @@ void ir_print_alignment_prefix_hack(irFileBuffer *f, i64 alignment) {
|
||||
|
||||
|
||||
void ir_print_proc_results(irFileBuffer *f, irModule *m, Type *t) {
|
||||
set_procedure_abi_types(heap_allocator(), t);
|
||||
set_procedure_abi_types(t);
|
||||
|
||||
GB_ASSERT(is_type_proc(t));
|
||||
t = base_type(t);
|
||||
@@ -325,7 +323,7 @@ void ir_print_proc_results(irFileBuffer *f, irModule *m, Type *t) {
|
||||
|
||||
|
||||
void ir_print_proc_type_without_pointer(irFileBuffer *f, irModule *m, Type *t) {
|
||||
set_procedure_abi_types(heap_allocator(), t);
|
||||
set_procedure_abi_types(t);
|
||||
|
||||
i64 word_bits = 8*build_context.word_size;
|
||||
t = base_type(t);
|
||||
@@ -736,6 +734,28 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
|
||||
if (is_type_array(type) && value.kind == ExactValue_String && !is_type_u8(core_array_type(type))) {
|
||||
i64 count = type->Array.count;
|
||||
Type *elem = type->Array.elem;
|
||||
|
||||
if (is_type_rune_array(type)) {
|
||||
Rune rune;
|
||||
isize offset = 0;
|
||||
isize width = 1;
|
||||
String s = value.value_string;
|
||||
ir_write_byte(f, '[');
|
||||
for (i64 i = 0; i < count && offset < s.len; i++) {
|
||||
width = gb_utf8_decode(s.text+offset, s.len-offset, &rune);
|
||||
if (i > 0) ir_write_str_lit(f, ", ");
|
||||
ir_print_type(f, m, elem);
|
||||
ir_write_byte(f, ' ');
|
||||
ir_print_exact_value(f, m, exact_value_i64(rune), elem);
|
||||
offset += width;
|
||||
}
|
||||
GB_ASSERT(offset == s.len);
|
||||
|
||||
ir_write_byte(f, ']');
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
ir_write_byte(f, '[');
|
||||
|
||||
for (i64 i = 0; i < count; i++) {
|
||||
@@ -747,7 +767,7 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
|
||||
|
||||
ir_write_byte(f, ']');
|
||||
return;
|
||||
} else if (is_type_array(type) &&
|
||||
} else if (is_type_array(type) &&
|
||||
value.kind != ExactValue_Invalid &&
|
||||
value.kind != ExactValue_String &&
|
||||
value.kind != ExactValue_Compound) {
|
||||
@@ -798,7 +818,11 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
|
||||
GB_ASSERT(is_type_array(type));
|
||||
ir_write_str_lit(f, "c\"");
|
||||
ir_print_escape_string(f, str, false, false);
|
||||
ir_write_str_lit(f, "\\00\"");
|
||||
if (type->Array.count == str.len) {
|
||||
ir_write_str_lit(f, "\"");
|
||||
} else {
|
||||
ir_write_str_lit(f, "\\00\"");
|
||||
}
|
||||
} else if (is_type_cstring(t)) {
|
||||
// HACK NOTE(bill): This is a hack but it works because strings are created at the very end
|
||||
// of the .ll file
|
||||
@@ -812,7 +836,7 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
|
||||
ir_write_str_lit(f, ", ");
|
||||
ir_print_type(f, m, t_i32);
|
||||
ir_write_str_lit(f, " 0, i32 0)");
|
||||
}else {
|
||||
} else {
|
||||
// HACK NOTE(bill): This is a hack but it works because strings are created at the very end
|
||||
// of the .ll file
|
||||
irValue *str_array = ir_add_global_string_array(m, str);
|
||||
@@ -929,9 +953,9 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
|
||||
ir_write_byte(f, ' ');
|
||||
ir_write_byte(f, '{');
|
||||
ir_print_type(f, m, ft); ir_write_byte(f, ' ');
|
||||
ir_print_exact_value(f, m, exact_value_float(value.value_complex.real), ft);
|
||||
ir_print_exact_value(f, m, exact_value_float(value.value_complex->real), ft);
|
||||
ir_write_str_lit(f, ", "); ir_print_type(f, m, ft); ir_write_byte(f, ' ');
|
||||
ir_print_exact_value(f, m, exact_value_float(value.value_complex.imag), ft);
|
||||
ir_print_exact_value(f, m, exact_value_float(value.value_complex->imag), ft);
|
||||
ir_write_byte(f, '}');
|
||||
break;
|
||||
}
|
||||
@@ -944,13 +968,13 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
|
||||
ir_write_byte(f, ' ');
|
||||
ir_write_byte(f, '{');
|
||||
ir_print_type(f, m, ft); ir_write_byte(f, ' ');
|
||||
ir_print_exact_value(f, m, exact_value_float(value.value_quaternion.imag), ft);
|
||||
ir_print_exact_value(f, m, exact_value_float(value.value_quaternion->imag), ft);
|
||||
ir_write_str_lit(f, ", "); ir_print_type(f, m, ft); ir_write_byte(f, ' ');
|
||||
ir_print_exact_value(f, m, exact_value_float(value.value_quaternion.jmag), ft);
|
||||
ir_print_exact_value(f, m, exact_value_float(value.value_quaternion->jmag), ft);
|
||||
ir_write_str_lit(f, ", "); ir_print_type(f, m, ft); ir_write_byte(f, ' ');
|
||||
ir_print_exact_value(f, m, exact_value_float(value.value_quaternion.kmag), ft);
|
||||
ir_print_exact_value(f, m, exact_value_float(value.value_quaternion->kmag), ft);
|
||||
ir_write_str_lit(f, ", "); ir_print_type(f, m, ft); ir_write_byte(f, ' ');
|
||||
ir_print_exact_value(f, m, exact_value_float(value.value_quaternion.real), ft);
|
||||
ir_print_exact_value(f, m, exact_value_float(value.value_quaternion->real), ft);
|
||||
ir_write_byte(f, '}');
|
||||
break;
|
||||
}
|
||||
@@ -1406,7 +1430,6 @@ void ir_print_value(irFileBuffer *f, irModule *m, irValue *value, Type *type_hin
|
||||
irValue *line = value->SourceCodeLocation.line;
|
||||
irValue *column = value->SourceCodeLocation.column;
|
||||
irValue *procedure = value->SourceCodeLocation.procedure;
|
||||
u64 hash = value->SourceCodeLocation.hash;
|
||||
|
||||
ir_write_byte(f, '{');
|
||||
ir_print_type(f, m, t_string); ir_write_byte(f, ' '); ir_print_value(f, m, file, t_string);
|
||||
@@ -1416,8 +1439,6 @@ void ir_print_value(irFileBuffer *f, irModule *m, irValue *value, Type *type_hin
|
||||
ir_print_type(f, m, t_int); ir_write_byte(f, ' '); ir_print_value(f, m, column, t_int);
|
||||
ir_write_string(f, str_lit(", "));
|
||||
ir_print_type(f, m, t_string); ir_write_byte(f, ' '); ir_print_value(f, m, procedure, t_string);
|
||||
ir_write_string(f, str_lit(", "));
|
||||
ir_print_type(f, m, t_u64); ir_write_byte(f, ' '); ir_write_u64(f, hash);
|
||||
ir_write_byte(f, '}');
|
||||
break;
|
||||
}
|
||||
@@ -1551,7 +1572,11 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
||||
break;
|
||||
|
||||
case BuiltinProc_cpu_relax:
|
||||
ir_write_str_lit(f, "call void asm sideeffect \"pause\", \"\"()");
|
||||
if (build_context.metrics.arch == TargetArch_amd64) {
|
||||
ir_write_str_lit(f, "call void asm sideeffect \"pause\", \"\"()");
|
||||
} else {
|
||||
// ir_write_str_lit(f, "call void asm sideeffect \"yield\", \"\"()");
|
||||
}
|
||||
break;
|
||||
default: GB_PANIC("Unknown inline code %d", instr->InlineCode.id); break;
|
||||
}
|
||||
@@ -2189,7 +2214,7 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
||||
irInstrCall *call = &instr->Call;
|
||||
Type *proc_type = base_type(ir_type(call->value));
|
||||
GB_ASSERT(is_type_proc(proc_type));
|
||||
set_procedure_abi_types(heap_allocator(), proc_type);
|
||||
set_procedure_abi_types(proc_type);
|
||||
|
||||
bool is_c_vararg = proc_type->Proc.c_vararg;
|
||||
Type *result_type = call->type;
|
||||
@@ -2396,7 +2421,7 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
||||
|
||||
|
||||
void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) {
|
||||
set_procedure_abi_types(heap_allocator(), proc->type);
|
||||
set_procedure_abi_types(proc->type);
|
||||
|
||||
if (proc->body == nullptr) {
|
||||
ir_write_str_lit(f, "declare ");
|
||||
|
||||
@@ -0,0 +1,959 @@
|
||||
enum lbArgKind {
|
||||
lbArg_Direct,
|
||||
lbArg_Indirect,
|
||||
lbArg_Ignore,
|
||||
};
|
||||
|
||||
struct lbArgType {
|
||||
lbArgKind kind;
|
||||
LLVMTypeRef type;
|
||||
LLVMTypeRef cast_type; // Optional
|
||||
LLVMTypeRef pad_type; // Optional
|
||||
LLVMAttributeRef attribute; // Optional
|
||||
};
|
||||
|
||||
lbArgType lb_arg_type_direct(LLVMTypeRef type, LLVMTypeRef cast_type, LLVMTypeRef pad_type, LLVMAttributeRef attr) {
|
||||
return lbArgType{lbArg_Direct, type, cast_type, pad_type, attr};
|
||||
}
|
||||
lbArgType lb_arg_type_direct(LLVMTypeRef type) {
|
||||
return lb_arg_type_direct(type, nullptr, nullptr, nullptr);
|
||||
}
|
||||
|
||||
lbArgType lb_arg_type_indirect(LLVMTypeRef type, LLVMAttributeRef attr) {
|
||||
return lbArgType{lbArg_Indirect, type, nullptr, nullptr, attr};
|
||||
}
|
||||
|
||||
lbArgType lb_arg_type_ignore(LLVMTypeRef type) {
|
||||
return lbArgType{lbArg_Ignore, type, nullptr, nullptr, nullptr};
|
||||
}
|
||||
|
||||
struct lbFunctionType {
|
||||
LLVMContextRef ctx;
|
||||
ProcCallingConvention calling_convention;
|
||||
Array<lbArgType> args;
|
||||
lbArgType ret;
|
||||
};
|
||||
|
||||
i64 llvm_align_formula(i64 off, i64 a) {
|
||||
return (off + a - 1) / a * a;
|
||||
}
|
||||
|
||||
|
||||
bool lb_is_type_kind(LLVMTypeRef type, LLVMTypeKind kind) {
|
||||
if (type == nullptr) {
|
||||
return false;
|
||||
}
|
||||
return LLVMGetTypeKind(type) == kind;
|
||||
}
|
||||
|
||||
LLVMTypeRef lb_function_type_to_llvm_ptr(lbFunctionType *ft, bool is_var_arg) {
|
||||
unsigned arg_count = cast(unsigned)ft->args.count;
|
||||
unsigned offset = 0;
|
||||
|
||||
LLVMTypeRef ret = nullptr;
|
||||
if (ft->ret.kind == lbArg_Direct) {
|
||||
if (ft->ret.cast_type != nullptr) {
|
||||
ret = ft->ret.cast_type;
|
||||
} else {
|
||||
ret = ft->ret.type;
|
||||
}
|
||||
} else if (ft->ret.kind == lbArg_Indirect) {
|
||||
offset += 1;
|
||||
ret = LLVMVoidTypeInContext(ft->ctx);
|
||||
} else if (ft->ret.kind == lbArg_Ignore) {
|
||||
ret = LLVMVoidTypeInContext(ft->ctx);
|
||||
}
|
||||
GB_ASSERT_MSG(ret != nullptr, "%d", ft->ret.kind);
|
||||
|
||||
unsigned maximum_arg_count = offset+arg_count;
|
||||
LLVMTypeRef *args = gb_alloc_array(heap_allocator(), LLVMTypeRef, maximum_arg_count);
|
||||
if (offset == 1) {
|
||||
GB_ASSERT(ft->ret.kind == lbArg_Indirect);
|
||||
args[0] = LLVMPointerType(ft->ret.type, 0);
|
||||
}
|
||||
|
||||
unsigned arg_index = offset;
|
||||
for (unsigned i = 0; i < arg_count; i++) {
|
||||
lbArgType *arg = &ft->args[i];
|
||||
if (arg->kind == lbArg_Direct) {
|
||||
LLVMTypeRef arg_type = nullptr;
|
||||
if (ft->args[i].cast_type != nullptr) {
|
||||
arg_type = arg->cast_type;
|
||||
} else {
|
||||
arg_type = arg->type;
|
||||
}
|
||||
args[arg_index++] = arg_type;
|
||||
} else if (arg->kind == lbArg_Indirect) {
|
||||
GB_ASSERT(!lb_is_type_kind(arg->type, LLVMPointerTypeKind));
|
||||
args[arg_index++] = LLVMPointerType(arg->type, 0);
|
||||
} else if (arg->kind == lbArg_Ignore) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
unsigned total_arg_count = arg_index;
|
||||
LLVMTypeRef func_type = LLVMFunctionType(ret, args, total_arg_count, is_var_arg);
|
||||
return LLVMPointerType(func_type, 0);
|
||||
}
|
||||
|
||||
|
||||
void lb_add_function_type_attributes(LLVMValueRef fn, lbFunctionType *ft, ProcCallingConvention calling_convention) {
|
||||
if (ft == nullptr) {
|
||||
return;
|
||||
}
|
||||
unsigned arg_count = cast(unsigned)ft->args.count;
|
||||
unsigned offset = 0;
|
||||
if (ft->ret.kind == lbArg_Indirect) {
|
||||
offset += 1;
|
||||
}
|
||||
|
||||
LLVMContextRef c = ft->ctx;
|
||||
LLVMAttributeRef noalias_attr = lb_create_enum_attribute(c, "noalias", true);
|
||||
LLVMAttributeRef nonnull_attr = lb_create_enum_attribute(c, "nonnull", true);
|
||||
LLVMAttributeRef nocapture_attr = lb_create_enum_attribute(c, "nocapture", true);
|
||||
|
||||
unsigned arg_index = offset;
|
||||
for (unsigned i = 0; i < arg_count; i++) {
|
||||
lbArgType *arg = &ft->args[i];
|
||||
if (arg->kind == lbArg_Ignore) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (arg->attribute) {
|
||||
LLVMAddAttributeAtIndex(fn, arg_index+1, arg->attribute);
|
||||
}
|
||||
|
||||
arg_index++;
|
||||
}
|
||||
|
||||
if (offset != 0 && ft->ret.kind == lbArg_Indirect && ft->ret.attribute != nullptr) {
|
||||
LLVMAddAttributeAtIndex(fn, offset, ft->ret.attribute);
|
||||
LLVMAddAttributeAtIndex(fn, offset, noalias_attr);
|
||||
}
|
||||
|
||||
lbCallingConventionKind cc_kind = lbCallingConvention_C;
|
||||
// TODO(bill): Clean up this logic
|
||||
if (build_context.metrics.os != TargetOs_js) {
|
||||
cc_kind = lb_calling_convention_map[calling_convention];
|
||||
}
|
||||
LLVMSetFunctionCallConv(fn, cc_kind);
|
||||
if (calling_convention == ProcCC_Odin) {
|
||||
unsigned context_index = offset+arg_count;
|
||||
LLVMAddAttributeAtIndex(fn, context_index, noalias_attr);
|
||||
LLVMAddAttributeAtIndex(fn, context_index, nonnull_attr);
|
||||
LLVMAddAttributeAtIndex(fn, context_index, nocapture_attr);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
i64 lb_sizeof(LLVMTypeRef type);
|
||||
i64 lb_alignof(LLVMTypeRef type);
|
||||
|
||||
i64 lb_sizeof(LLVMTypeRef type) {
|
||||
LLVMTypeKind kind = LLVMGetTypeKind(type);
|
||||
switch (kind) {
|
||||
case LLVMVoidTypeKind:
|
||||
return 0;
|
||||
case LLVMIntegerTypeKind:
|
||||
{
|
||||
unsigned w = LLVMGetIntTypeWidth(type);
|
||||
return (w + 7)/8;
|
||||
}
|
||||
case LLVMFloatTypeKind:
|
||||
return 4;
|
||||
case LLVMDoubleTypeKind:
|
||||
return 8;
|
||||
case LLVMPointerTypeKind:
|
||||
return build_context.word_size;
|
||||
case LLVMStructTypeKind:
|
||||
{
|
||||
unsigned field_count = LLVMCountStructElementTypes(type);
|
||||
i64 offset = 0;
|
||||
if (LLVMIsPackedStruct(type)) {
|
||||
for (unsigned i = 0; i < field_count; i++) {
|
||||
LLVMTypeRef field = LLVMStructGetTypeAtIndex(type, i);
|
||||
offset += lb_sizeof(field);
|
||||
}
|
||||
} else {
|
||||
for (unsigned i = 0; i < field_count; i++) {
|
||||
LLVMTypeRef field = LLVMStructGetTypeAtIndex(type, i);
|
||||
i64 align = lb_alignof(field);
|
||||
offset = llvm_align_formula(offset, align);
|
||||
offset += lb_sizeof(field);
|
||||
}
|
||||
offset = llvm_align_formula(offset, lb_alignof(type));
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
break;
|
||||
case LLVMArrayTypeKind:
|
||||
{
|
||||
LLVMTypeRef elem = LLVMGetElementType(type);
|
||||
i64 elem_size = lb_sizeof(elem);
|
||||
i64 count = LLVMGetArrayLength(type);
|
||||
i64 size = count * elem_size;
|
||||
return size;
|
||||
}
|
||||
break;
|
||||
|
||||
case LLVMX86_MMXTypeKind:
|
||||
return 8;
|
||||
case LLVMVectorTypeKind:
|
||||
{
|
||||
LLVMTypeRef elem = LLVMGetElementType(type);
|
||||
i64 elem_size = lb_sizeof(elem);
|
||||
i64 count = LLVMGetVectorSize(type);
|
||||
i64 size = count * elem_size;
|
||||
return gb_clamp(next_pow2(size), 1, build_context.max_align);
|
||||
}
|
||||
|
||||
}
|
||||
GB_PANIC("Unhandled type for lb_sizeof -> %s", LLVMPrintTypeToString(type));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
i64 lb_alignof(LLVMTypeRef type) {
|
||||
LLVMTypeKind kind = LLVMGetTypeKind(type);
|
||||
switch (kind) {
|
||||
case LLVMVoidTypeKind:
|
||||
return 1;
|
||||
case LLVMIntegerTypeKind:
|
||||
{
|
||||
unsigned w = LLVMGetIntTypeWidth(type);
|
||||
return gb_clamp((w + 7)/8, 1, build_context.max_align);
|
||||
}
|
||||
case LLVMFloatTypeKind:
|
||||
return 4;
|
||||
case LLVMDoubleTypeKind:
|
||||
return 8;
|
||||
case LLVMPointerTypeKind:
|
||||
return build_context.word_size;
|
||||
case LLVMStructTypeKind:
|
||||
{
|
||||
if (LLVMIsPackedStruct(type)) {
|
||||
return 1;
|
||||
} else {
|
||||
unsigned field_count = LLVMCountStructElementTypes(type);
|
||||
i64 max_align = 1;
|
||||
for (unsigned i = 0; i < field_count; i++) {
|
||||
LLVMTypeRef field = LLVMStructGetTypeAtIndex(type, i);
|
||||
i64 field_align = lb_alignof(field);
|
||||
max_align = gb_max(max_align, field_align);
|
||||
}
|
||||
return max_align;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case LLVMArrayTypeKind:
|
||||
return lb_alignof(LLVMGetElementType(type));
|
||||
|
||||
case LLVMX86_MMXTypeKind:
|
||||
return 8;
|
||||
case LLVMVectorTypeKind:
|
||||
{
|
||||
LLVMTypeRef elem = LLVMGetElementType(type);
|
||||
i64 elem_size = lb_sizeof(elem);
|
||||
i64 count = LLVMGetVectorSize(type);
|
||||
i64 size = count * elem_size;
|
||||
return gb_clamp(next_pow2(size), 1, build_context.max_align);
|
||||
}
|
||||
|
||||
}
|
||||
GB_PANIC("Unhandled type for lb_sizeof -> %s", LLVMPrintTypeToString(type));
|
||||
|
||||
// LLVMValueRef v = LLVMAlignOf(type);
|
||||
// GB_ASSERT(LLVMIsConstant(v));
|
||||
// return LLVMConstIntGetSExtValue(v);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if 0
|
||||
Type *lb_abi_to_odin_type(lbModule *m, LLVMTypeRef type, bool is_return, u32 level = 0) {
|
||||
Type **found = map_get(&m->llvm_types, hash_pointer(type));
|
||||
if (found) {
|
||||
return *found;
|
||||
}
|
||||
GB_ASSERT_MSG(level < 64, "%s %d", LLVMPrintTypeToString(type), is_return);
|
||||
|
||||
LLVMTypeKind kind = LLVMGetTypeKind(type);
|
||||
switch (kind) {
|
||||
case LLVMVoidTypeKind:
|
||||
return nullptr;
|
||||
case LLVMIntegerTypeKind:
|
||||
{
|
||||
unsigned w = LLVMGetIntTypeWidth(type);
|
||||
if (w == 1) {
|
||||
return t_llvm_bool;
|
||||
}
|
||||
unsigned bytes = (w + 7)/8;
|
||||
switch (bytes) {
|
||||
case 1: return t_u8;
|
||||
case 2: return t_u16;
|
||||
case 4: return t_u32;
|
||||
case 8: return t_u64;
|
||||
case 16: return t_u128;
|
||||
}
|
||||
GB_PANIC("Unhandled integer type");
|
||||
}
|
||||
case LLVMFloatTypeKind:
|
||||
return t_f32;
|
||||
case LLVMDoubleTypeKind:
|
||||
return t_f64;
|
||||
case LLVMPointerTypeKind:
|
||||
{
|
||||
LLVMTypeRef elem = LLVMGetElementType(type);
|
||||
if (lb_is_type_kind(elem, LLVMFunctionTypeKind)) {
|
||||
unsigned param_count = LLVMCountParamTypes(elem);
|
||||
LLVMTypeRef *params = gb_alloc_array(heap_allocator(), LLVMTypeRef, param_count);
|
||||
defer (gb_free(heap_allocator(), params));
|
||||
LLVMGetParamTypes(elem, params);
|
||||
|
||||
Type **param_types = gb_alloc_array(heap_allocator(), Type *, param_count);
|
||||
defer (gb_free(heap_allocator(), param_types));
|
||||
|
||||
for (unsigned i = 0; i < param_count; i++) {
|
||||
param_types[i] = lb_abi_to_odin_type(m, params[i], false, level+1);
|
||||
}
|
||||
|
||||
LLVMTypeRef ret = LLVMGetReturnType(elem);
|
||||
Type *ret_type = lb_abi_to_odin_type(m, ret, true, level+1);
|
||||
|
||||
bool is_c_vararg = !!LLVMIsFunctionVarArg(elem);
|
||||
return alloc_type_proc_from_types(param_types, param_count, ret_type, is_c_vararg);
|
||||
}
|
||||
return alloc_type_pointer(lb_abi_to_odin_type(m, elem, false, level+1));
|
||||
}
|
||||
case LLVMFunctionTypeKind:
|
||||
GB_PANIC("LLVMFunctionTypeKind should not be seen on its own");
|
||||
break;
|
||||
|
||||
case LLVMStructTypeKind:
|
||||
{
|
||||
unsigned field_count = LLVMCountStructElementTypes(type);
|
||||
Type **fields = gb_alloc_array(heap_allocator(), Type *, field_count);
|
||||
for (unsigned i = 0; i < field_count; i++) {
|
||||
LLVMTypeRef field_type = LLVMStructGetTypeAtIndex(type, i);
|
||||
if (lb_is_type_kind(field_type, LLVMPointerTypeKind) && level > 0) {
|
||||
fields[i] = t_rawptr;
|
||||
} else {
|
||||
fields[i] = lb_abi_to_odin_type(m, field_type, false, level+1);
|
||||
}
|
||||
}
|
||||
if (is_return) {
|
||||
return alloc_type_tuple_from_field_types(fields, field_count, !!LLVMIsPackedStruct(type), false);
|
||||
} else {
|
||||
return alloc_type_struct_from_field_types(fields, field_count, !!LLVMIsPackedStruct(type));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case LLVMArrayTypeKind:
|
||||
{
|
||||
|
||||
i64 count = LLVMGetArrayLength(type);
|
||||
Type *elem = lb_abi_to_odin_type(m, LLVMGetElementType(type), false, level+1);
|
||||
return alloc_type_array(elem, count);
|
||||
}
|
||||
break;
|
||||
|
||||
case LLVMX86_MMXTypeKind:
|
||||
return t_vector_x86_mmx;
|
||||
case LLVMVectorTypeKind:
|
||||
{
|
||||
i64 count = LLVMGetVectorSize(type);
|
||||
Type *elem = lb_abi_to_odin_type(m, LLVMGetElementType(type), false, level+1);
|
||||
return alloc_type_simd_vector(count, elem);
|
||||
}
|
||||
|
||||
}
|
||||
GB_PANIC("Unhandled type for lb_abi_to_odin_type -> %s", LLVMPrintTypeToString(type));
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#define LB_ABI_INFO(name) lbFunctionType *name(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count, LLVMTypeRef return_type, bool return_is_defined, ProcCallingConvention calling_convention)
|
||||
typedef LB_ABI_INFO(lbAbiInfoType);
|
||||
|
||||
|
||||
// NOTE(bill): I hate `namespace` in C++ but this is just because I don't want to prefix everything
|
||||
namespace lbAbi386 {
|
||||
Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count);
|
||||
lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined);
|
||||
|
||||
LB_ABI_INFO(abi_info) {
|
||||
lbFunctionType *ft = gb_alloc_item(heap_allocator(), lbFunctionType);
|
||||
ft->ctx = c;
|
||||
ft->args = compute_arg_types(c, arg_types, arg_count);
|
||||
ft->ret = compute_return_type(c, return_type, return_is_defined);
|
||||
ft->calling_convention = calling_convention;
|
||||
return ft;
|
||||
}
|
||||
|
||||
lbArgType non_struct(LLVMContextRef c, LLVMTypeRef type, bool is_return) {
|
||||
if (!is_return && lb_sizeof(type) > 8) {
|
||||
return lb_arg_type_indirect(type, nullptr);
|
||||
}
|
||||
|
||||
if (build_context.metrics.os == TargetOs_windows &&
|
||||
build_context.word_size == 8 &&
|
||||
lb_is_type_kind(type, LLVMIntegerTypeKind) &&
|
||||
type == LLVMIntTypeInContext(c, 128)) {
|
||||
// NOTE(bill): Because Windows AMD64 is weird
|
||||
LLVMTypeRef cast_type = LLVMVectorType(LLVMInt64TypeInContext(c), 2);
|
||||
return lb_arg_type_direct(type, cast_type, nullptr, nullptr);
|
||||
}
|
||||
|
||||
LLVMAttributeRef attr = nullptr;
|
||||
LLVMTypeRef i1 = LLVMInt1TypeInContext(c);
|
||||
if (type == i1) {
|
||||
attr = lb_create_enum_attribute(c, "zeroext", true);
|
||||
}
|
||||
return lb_arg_type_direct(type, nullptr, nullptr, attr);
|
||||
}
|
||||
|
||||
Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count) {
|
||||
auto args = array_make<lbArgType>(heap_allocator(), arg_count);
|
||||
|
||||
for (unsigned i = 0; i < arg_count; i++) {
|
||||
LLVMTypeRef t = arg_types[i];
|
||||
LLVMTypeKind kind = LLVMGetTypeKind(t);
|
||||
i64 sz = lb_sizeof(t);
|
||||
if (kind == LLVMStructTypeKind) {
|
||||
if (sz == 0) {
|
||||
args[i] = lb_arg_type_ignore(t);
|
||||
} else {
|
||||
args[i] = lb_arg_type_indirect(t, lb_create_enum_attribute(c, "byval", true));
|
||||
}
|
||||
} else {
|
||||
args[i] = non_struct(c, t, false);
|
||||
}
|
||||
}
|
||||
return args;
|
||||
}
|
||||
|
||||
lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined) {
|
||||
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)) {
|
||||
i64 sz = lb_sizeof(return_type);
|
||||
switch (sz) {
|
||||
case 1: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 8), nullptr, nullptr);
|
||||
case 2: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 16), nullptr, nullptr);
|
||||
case 4: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 32), nullptr, nullptr);
|
||||
case 8: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 64), nullptr, nullptr);
|
||||
}
|
||||
return lb_arg_type_indirect(return_type, lb_create_enum_attribute(c, "sret", true));
|
||||
}
|
||||
return non_struct(c, return_type, true);
|
||||
}
|
||||
};
|
||||
|
||||
namespace lbAbiAmd64Win64 {
|
||||
Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count);
|
||||
|
||||
|
||||
LB_ABI_INFO(abi_info) {
|
||||
lbFunctionType *ft = gb_alloc_item(heap_allocator(), lbFunctionType);
|
||||
ft->ctx = c;
|
||||
ft->args = compute_arg_types(c, arg_types, arg_count);
|
||||
ft->ret = lbAbi386::compute_return_type(c, return_type, return_is_defined);
|
||||
ft->calling_convention = calling_convention;
|
||||
return ft;
|
||||
}
|
||||
|
||||
Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count) {
|
||||
auto args = array_make<lbArgType>(heap_allocator(), arg_count);
|
||||
|
||||
for (unsigned i = 0; i < arg_count; i++) {
|
||||
LLVMTypeRef t = arg_types[i];
|
||||
LLVMTypeKind kind = LLVMGetTypeKind(t);
|
||||
if (kind == LLVMStructTypeKind) {
|
||||
i64 sz = lb_sizeof(t);
|
||||
switch (sz) {
|
||||
case 1:
|
||||
case 2:
|
||||
case 4:
|
||||
case 8:
|
||||
args[i] = lb_arg_type_direct(t, LLVMIntTypeInContext(c, 8*cast(unsigned)sz), nullptr, nullptr);
|
||||
break;
|
||||
default:
|
||||
args[i] = lb_arg_type_indirect(t, nullptr);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
args[i] = lbAbi386::non_struct(c, t, false);
|
||||
}
|
||||
}
|
||||
return args;
|
||||
}
|
||||
};
|
||||
|
||||
// NOTE(bill): I hate `namespace` in C++ but this is just because I don't want to prefix everything
|
||||
namespace lbAbiAmd64SysV {
|
||||
enum RegClass {
|
||||
RegClass_NoClass,
|
||||
RegClass_Int,
|
||||
RegClass_SSEFs,
|
||||
RegClass_SSEFv,
|
||||
RegClass_SSEDs,
|
||||
RegClass_SSEDv,
|
||||
RegClass_SSEInt8,
|
||||
RegClass_SSEInt16,
|
||||
RegClass_SSEInt32,
|
||||
RegClass_SSEInt64,
|
||||
RegClass_SSEUp,
|
||||
RegClass_X87,
|
||||
RegClass_X87Up,
|
||||
RegClass_ComplexX87,
|
||||
RegClass_Memory,
|
||||
};
|
||||
|
||||
bool is_sse(RegClass reg_class) {
|
||||
switch (reg_class) {
|
||||
case RegClass_SSEFs:
|
||||
case RegClass_SSEFv:
|
||||
case RegClass_SSEDv:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void all_mem(Array<RegClass> *cs) {
|
||||
for_array(i, *cs) {
|
||||
(*cs)[i] = RegClass_Memory;
|
||||
}
|
||||
}
|
||||
|
||||
enum Amd64TypeAttributeKind {
|
||||
Amd64TypeAttribute_None,
|
||||
Amd64TypeAttribute_ByVal,
|
||||
Amd64TypeAttribute_StructRect,
|
||||
};
|
||||
|
||||
Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count);
|
||||
lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined);
|
||||
void classify_with(LLVMTypeRef t, Array<RegClass> *cls, i64 ix, i64 off);
|
||||
void fixup(LLVMTypeRef t, Array<RegClass> *cls);
|
||||
lbArgType amd64_type(LLVMContextRef c, LLVMTypeRef type, Amd64TypeAttributeKind attribute_kind);
|
||||
Array<RegClass> classify(LLVMTypeRef t);
|
||||
LLVMTypeRef llreg(LLVMContextRef c, Array<RegClass> const ®_classes);
|
||||
|
||||
LB_ABI_INFO(abi_info) {
|
||||
lbFunctionType *ft = gb_alloc_item(heap_allocator(), lbFunctionType);
|
||||
ft->ctx = c;
|
||||
ft->calling_convention = calling_convention;
|
||||
|
||||
ft->args = array_make<lbArgType>(heap_allocator(), arg_count);
|
||||
for (unsigned i = 0; i < arg_count; i++) {
|
||||
ft->args[i] = amd64_type(c, arg_types[i], Amd64TypeAttribute_ByVal);
|
||||
}
|
||||
|
||||
if (return_is_defined) {
|
||||
ft->ret = amd64_type(c, return_type, Amd64TypeAttribute_StructRect);
|
||||
} else {
|
||||
ft->ret = lb_arg_type_direct(LLVMVoidTypeInContext(c));
|
||||
}
|
||||
|
||||
return ft;
|
||||
}
|
||||
|
||||
bool is_mem_cls(Array<RegClass> const &cls, Amd64TypeAttributeKind attribute_kind) {
|
||||
if (attribute_kind == Amd64TypeAttribute_ByVal) {
|
||||
if (cls.count == 0) {
|
||||
return false;
|
||||
}
|
||||
auto first = cls[0];
|
||||
return first == RegClass_Memory || first == RegClass_X87 || first == RegClass_ComplexX87;
|
||||
} else if (attribute_kind == Amd64TypeAttribute_StructRect) {
|
||||
if (cls.count == 0) {
|
||||
return false;
|
||||
}
|
||||
return cls[0] == RegClass_Memory;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool is_register(LLVMTypeRef type) {
|
||||
LLVMTypeKind kind = LLVMGetTypeKind(type);
|
||||
switch (kind) {
|
||||
case LLVMIntegerTypeKind:
|
||||
case LLVMFloatTypeKind:
|
||||
case LLVMDoubleTypeKind:
|
||||
case LLVMPointerTypeKind:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
lbArgType amd64_type(LLVMContextRef c, LLVMTypeRef type, Amd64TypeAttributeKind attribute_kind) {
|
||||
if (is_register(type)) {
|
||||
LLVMAttributeRef attribute = nullptr;
|
||||
if (type == LLVMInt1TypeInContext(c)) {
|
||||
attribute = lb_create_enum_attribute(c, "zeroext", true);
|
||||
}
|
||||
return lb_arg_type_direct(type, nullptr, nullptr, attribute);
|
||||
}
|
||||
|
||||
auto cls = classify(type);
|
||||
if (is_mem_cls(cls, attribute_kind)) {
|
||||
LLVMAttributeRef attribute = nullptr;
|
||||
if (attribute_kind == Amd64TypeAttribute_ByVal) {
|
||||
attribute = lb_create_enum_attribute(c, "byval", true);
|
||||
} else if (attribute_kind == Amd64TypeAttribute_StructRect) {
|
||||
attribute = lb_create_enum_attribute(c, "sret", true);
|
||||
}
|
||||
return lb_arg_type_indirect(type, attribute);
|
||||
} else {
|
||||
return lb_arg_type_direct(type, llreg(c, cls), nullptr, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
lbArgType non_struct(LLVMContextRef c, LLVMTypeRef type) {
|
||||
LLVMAttributeRef attr = nullptr;
|
||||
LLVMTypeRef i1 = LLVMInt1TypeInContext(c);
|
||||
if (type == i1) {
|
||||
attr = lb_create_enum_attribute(c, "zeroext", true);
|
||||
}
|
||||
return lb_arg_type_direct(type, nullptr, nullptr, attr);
|
||||
}
|
||||
|
||||
Array<RegClass> classify(LLVMTypeRef t) {
|
||||
i64 sz = lb_sizeof(t);
|
||||
i64 words = (sz + 7)/8;
|
||||
auto reg_classes = array_make<RegClass>(heap_allocator(), cast(isize)words);
|
||||
if (words > 4) {
|
||||
all_mem(®_classes);
|
||||
} else {
|
||||
classify_with(t, ®_classes, 0, 0);
|
||||
fixup(t, ®_classes);
|
||||
}
|
||||
return reg_classes;
|
||||
}
|
||||
|
||||
void unify(Array<RegClass> *cls, i64 i, RegClass newv) {
|
||||
RegClass &oldv = (*cls)[i];
|
||||
if (oldv == newv) {
|
||||
return;
|
||||
} else if (oldv == RegClass_NoClass) {
|
||||
oldv = newv;
|
||||
} else if (newv == RegClass_NoClass) {
|
||||
return;
|
||||
} else if (oldv == RegClass_Memory || newv == RegClass_Memory) {
|
||||
return;
|
||||
} else if (oldv == RegClass_Int || newv == RegClass_Int) {
|
||||
return;
|
||||
} else if (oldv == RegClass_X87 || oldv == RegClass_X87Up || oldv == RegClass_ComplexX87 ||
|
||||
newv == RegClass_X87 || newv == RegClass_X87Up || newv == RegClass_ComplexX87) {
|
||||
oldv = RegClass_Memory;
|
||||
} else {
|
||||
oldv = newv;
|
||||
}
|
||||
}
|
||||
|
||||
void fixup(LLVMTypeRef t, Array<RegClass> *cls) {
|
||||
i64 i = 0;
|
||||
i64 e = cls->count;
|
||||
if (e > 2 && (lb_is_type_kind(t, LLVMStructTypeKind) || lb_is_type_kind(t, LLVMArrayTypeKind))) {
|
||||
RegClass &oldv = (*cls)[i];
|
||||
if (is_sse(oldv)) {
|
||||
for (i++; i < e; i++) {
|
||||
if (oldv != RegClass_SSEUp) {
|
||||
all_mem(cls);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
all_mem(cls);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
while (i < e) {
|
||||
RegClass &oldv = (*cls)[i];
|
||||
if (oldv == RegClass_Memory) {
|
||||
all_mem(cls);
|
||||
return;
|
||||
} else if (oldv == RegClass_X87Up) {
|
||||
// NOTE(bill): Darwin
|
||||
all_mem(cls);
|
||||
return;
|
||||
} else if (oldv == RegClass_SSEUp) {
|
||||
oldv = RegClass_SSEDv;
|
||||
} else if (is_sse(oldv)) {
|
||||
i++;
|
||||
while (i != e && oldv == RegClass_SSEUp) {
|
||||
i++;
|
||||
}
|
||||
} else if (oldv == RegClass_X87) {
|
||||
i++;
|
||||
while (i != e && oldv == RegClass_X87Up) {
|
||||
i++;
|
||||
}
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned llvec_len(Array<RegClass> const ®_classes, isize offset) {
|
||||
unsigned len = 1;
|
||||
for (isize i = offset+1; i < reg_classes.count; i++) {
|
||||
if (reg_classes[offset] != RegClass_SSEFv && reg_classes[i] != RegClass_SSEUp) {
|
||||
break;
|
||||
}
|
||||
len++;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
LLVMTypeRef llreg(LLVMContextRef c, Array<RegClass> const ®_classes) {
|
||||
auto types = array_make<LLVMTypeRef>(heap_allocator(), 0, reg_classes.count);
|
||||
for_array(i, reg_classes) {
|
||||
RegClass reg_class = reg_classes[i];
|
||||
switch (reg_class) {
|
||||
case RegClass_Int:
|
||||
array_add(&types, LLVMIntTypeInContext(c, 64));
|
||||
break;
|
||||
case RegClass_SSEFv:
|
||||
case RegClass_SSEDv:
|
||||
case RegClass_SSEInt8:
|
||||
case RegClass_SSEInt16:
|
||||
case RegClass_SSEInt32:
|
||||
case RegClass_SSEInt64:
|
||||
{
|
||||
unsigned elems_per_word = 0;
|
||||
LLVMTypeRef elem_type = nullptr;
|
||||
switch (reg_class) {
|
||||
case RegClass_SSEFv:
|
||||
elems_per_word = 2;
|
||||
elem_type = LLVMFloatTypeInContext(c);
|
||||
break;
|
||||
case RegClass_SSEDv:
|
||||
elems_per_word = 1;
|
||||
elem_type = LLVMDoubleTypeInContext(c);
|
||||
break;
|
||||
case RegClass_SSEInt8:
|
||||
elems_per_word = 64/8;
|
||||
elem_type = LLVMIntTypeInContext(c, 8);
|
||||
break;
|
||||
case RegClass_SSEInt16:
|
||||
elems_per_word = 64/16;
|
||||
elem_type = LLVMIntTypeInContext(c, 16);
|
||||
break;
|
||||
case RegClass_SSEInt32:
|
||||
elems_per_word = 64/32;
|
||||
elem_type = LLVMIntTypeInContext(c, 32);
|
||||
break;
|
||||
case RegClass_SSEInt64:
|
||||
elems_per_word = 64/64;
|
||||
elem_type = LLVMIntTypeInContext(c, 64);
|
||||
break;
|
||||
}
|
||||
|
||||
unsigned vec_len = llvec_len(reg_classes, i);
|
||||
LLVMTypeRef vec_type = LLVMVectorType(elem_type, vec_len * elems_per_word);
|
||||
array_add(&types, vec_type);
|
||||
i += vec_len;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case RegClass_SSEFs:
|
||||
array_add(&types, LLVMFloatTypeInContext(c));
|
||||
break;
|
||||
case RegClass_SSEDs:
|
||||
array_add(&types, LLVMDoubleTypeInContext(c));
|
||||
break;
|
||||
default:
|
||||
GB_PANIC("Unhandled RegClass");
|
||||
}
|
||||
}
|
||||
|
||||
GB_ASSERT(types.count != 0);
|
||||
if (types.count == 1) {
|
||||
return types[0];
|
||||
}
|
||||
return LLVMStructTypeInContext(c, types.data, cast(unsigned)types.count, false);
|
||||
}
|
||||
|
||||
void classify_with(LLVMTypeRef t, Array<RegClass> *cls, i64 ix, i64 off) {
|
||||
i64 t_align = lb_alignof(t);
|
||||
i64 t_size = lb_sizeof(t);
|
||||
|
||||
i64 misalign = off % t_align;
|
||||
if (misalign != 0) {
|
||||
i64 e = (off + t_size + 7) / 8;
|
||||
for (i64 i = off / 8; i < e; i++) {
|
||||
unify(cls, ix+i, RegClass_Memory);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
switch (LLVMGetTypeKind(t)) {
|
||||
case LLVMIntegerTypeKind:
|
||||
case LLVMPointerTypeKind:
|
||||
unify(cls, ix + off/8, RegClass_Int);
|
||||
break;
|
||||
case LLVMFloatTypeKind:
|
||||
unify(cls, ix + off/8, (off%8 == 4) ? RegClass_SSEFv : RegClass_SSEFs);
|
||||
break;
|
||||
case LLVMDoubleTypeKind:
|
||||
unify(cls, ix + off/8, RegClass_SSEDs);
|
||||
break;
|
||||
case LLVMStructTypeKind:
|
||||
{
|
||||
LLVMBool packed = LLVMIsPackedStruct(t);
|
||||
unsigned field_count = LLVMCountStructElementTypes(t);
|
||||
|
||||
i64 field_off = off;
|
||||
for (unsigned field_index = 0; field_index < field_count; field_index++) {
|
||||
LLVMTypeRef field_type = LLVMStructGetTypeAtIndex(t, field_index);
|
||||
if (!packed) {
|
||||
field_off = llvm_align_formula(field_off, lb_alignof(field_type));
|
||||
}
|
||||
classify_with(field_type, cls, ix, field_off);
|
||||
field_off += lb_sizeof(field_type);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case LLVMArrayTypeKind:
|
||||
{
|
||||
i64 len = LLVMGetArrayLength(t);
|
||||
LLVMTypeRef elem = LLVMGetElementType(t);
|
||||
i64 elem_sz = lb_sizeof(elem);
|
||||
for (i64 i = 0; i < len; i++) {
|
||||
classify_with(elem, cls, ix, off + i*elem_sz);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case LLVMVectorTypeKind:
|
||||
{
|
||||
i64 len = LLVMGetVectorSize(t);
|
||||
LLVMTypeRef elem = LLVMGetElementType(t);
|
||||
i64 elem_sz = lb_sizeof(elem);
|
||||
LLVMTypeKind elem_kind = LLVMGetTypeKind(elem);
|
||||
RegClass reg = RegClass_NoClass;
|
||||
switch (elem_kind) {
|
||||
case LLVMIntegerTypeKind:
|
||||
switch (LLVMGetIntTypeWidth(elem)) {
|
||||
case 8: reg = RegClass_SSEInt8;
|
||||
case 16: reg = RegClass_SSEInt16;
|
||||
case 32: reg = RegClass_SSEInt32;
|
||||
case 64: reg = RegClass_SSEInt64;
|
||||
default:
|
||||
GB_PANIC("Unhandled integer width for vector type");
|
||||
}
|
||||
break;
|
||||
case LLVMFloatTypeKind:
|
||||
reg = RegClass_SSEFv;
|
||||
break;
|
||||
case LLVMDoubleTypeKind:
|
||||
reg = RegClass_SSEDv;
|
||||
break;
|
||||
default:
|
||||
GB_PANIC("Unhandled vector element type");
|
||||
}
|
||||
|
||||
for (i64 i = 0; i < len; i++) {
|
||||
unify(cls, ix + (off + i*elem_sz)/8, reg);
|
||||
// NOTE(bill): Everything after the first one is the upper
|
||||
// half of a register
|
||||
reg = RegClass_SSEUp;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
GB_PANIC("Unhandled type");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count) {
|
||||
auto args = array_make<lbArgType>(heap_allocator(), arg_count);
|
||||
|
||||
for (unsigned i = 0; i < arg_count; i++) {
|
||||
LLVMTypeRef t = arg_types[i];
|
||||
LLVMTypeKind kind = LLVMGetTypeKind(t);
|
||||
if (kind == LLVMStructTypeKind) {
|
||||
i64 sz = lb_sizeof(t);
|
||||
if (sz == 0) {
|
||||
args[i] = lb_arg_type_ignore(t);
|
||||
} else {
|
||||
args[i] = lb_arg_type_indirect(t, lb_create_enum_attribute(c, "byval", true));
|
||||
}
|
||||
} else {
|
||||
args[i] = non_struct(c, t);
|
||||
}
|
||||
}
|
||||
return args;
|
||||
}
|
||||
|
||||
lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined) {
|
||||
if (!return_is_defined) {
|
||||
return lb_arg_type_direct(LLVMVoidTypeInContext(c));
|
||||
} else if (lb_is_type_kind(return_type, LLVMStructTypeKind)) {
|
||||
i64 sz = lb_sizeof(return_type);
|
||||
switch (sz) {
|
||||
case 1: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 8), nullptr, nullptr);
|
||||
case 2: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 16), nullptr, nullptr);
|
||||
case 4: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 32), nullptr, nullptr);
|
||||
case 8: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 64), nullptr, nullptr);
|
||||
}
|
||||
return lb_arg_type_indirect(return_type, lb_create_enum_attribute(c, "sret", true));
|
||||
} else if (build_context.metrics.os == TargetOs_windows && lb_is_type_kind(return_type, LLVMIntegerTypeKind) && lb_sizeof(return_type) == 16) {
|
||||
return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 128), nullptr, nullptr);
|
||||
}
|
||||
return non_struct(c, return_type);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
namespace lbAbiAarch64 {
|
||||
LB_ABI_INFO(abi_info) {
|
||||
lbFunctionType *ft = gb_alloc_item(heap_allocator(), lbFunctionType);
|
||||
ft->ctx = c;
|
||||
// ft->args = compute_arg_types(c, arg_types, arg_count);
|
||||
// ft->ret = lbAbi386::compute_return_type(c, return_type, return_is_defined);
|
||||
// ft->calling_convention = calling_convention;
|
||||
return ft;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
LB_ABI_INFO(lb_get_abi_info) {
|
||||
switch (calling_convention) {
|
||||
case ProcCC_None:
|
||||
case ProcCC_PureNone:
|
||||
case ProcCC_InlineAsm:
|
||||
{
|
||||
lbFunctionType *ft = gb_alloc_item(heap_allocator(), lbFunctionType);
|
||||
ft->ctx = c;
|
||||
ft->args = array_make<lbArgType>(heap_allocator(), arg_count);
|
||||
for (unsigned i = 0; i < arg_count; i++) {
|
||||
ft->args[i] = lb_arg_type_direct(arg_types[i]);
|
||||
}
|
||||
if (return_is_defined) {
|
||||
ft->ret = lb_arg_type_direct(return_type);
|
||||
} else {
|
||||
ft->ret = lb_arg_type_direct(LLVMVoidTypeInContext(c));
|
||||
}
|
||||
ft->calling_convention = calling_convention;
|
||||
return ft;
|
||||
}
|
||||
}
|
||||
|
||||
if (build_context.metrics.arch == TargetArch_amd64) {
|
||||
if (build_context.metrics.os == TargetOs_windows) {
|
||||
return lbAbiAmd64Win64::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention);
|
||||
} else {
|
||||
return lbAbiAmd64SysV::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention);
|
||||
}
|
||||
} else if (build_context.metrics.arch == TargetArch_386) {
|
||||
return lbAbi386::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention);
|
||||
} else if (build_context.metrics.arch == TargetArch_wasm32) {
|
||||
return lbAbi386::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention);
|
||||
}
|
||||
GB_PANIC("Unsupported ABI");
|
||||
return {};
|
||||
}
|
||||
+1453
-622
File diff suppressed because it is too large
Load Diff
+31
-2
@@ -1,3 +1,5 @@
|
||||
#if defined(LLVM_BACKEND_SUPPORT)
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
#include "llvm-c/Core.h"
|
||||
#include "llvm-c/ExecutionEngine.h"
|
||||
#include "llvm-c/Target.h"
|
||||
@@ -12,6 +14,23 @@
|
||||
#include "llvm-c/Transforms/Scalar.h"
|
||||
#include "llvm-c/Transforms/Utils.h"
|
||||
#include "llvm-c/Transforms/Vectorize.h"
|
||||
#else
|
||||
#include <llvm-c/Core.h>
|
||||
#include <llvm-c/ExecutionEngine.h>
|
||||
#include <llvm-c/Target.h>
|
||||
#include <llvm-c/Analysis.h>
|
||||
#include <llvm-c/Object.h>
|
||||
#include <llvm-c/BitWriter.h>
|
||||
#include <llvm-c/DebugInfo.h>
|
||||
#include <llvm-c/Transforms/AggressiveInstCombine.h>
|
||||
#include <llvm-c/Transforms/InstCombine.h>
|
||||
#include <llvm-c/Transforms/IPO.h>
|
||||
#include <llvm-c/Transforms/PassManagerBuilder.h>
|
||||
#include <llvm-c/Transforms/Scalar.h>
|
||||
#include <llvm-c/Transforms/Utils.h>
|
||||
#include <llvm-c/Transforms/Vectorize.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
struct lbProcedure;
|
||||
|
||||
@@ -74,6 +93,8 @@ struct lbModule {
|
||||
gbMutex mutex;
|
||||
|
||||
Map<LLVMTypeRef> types; // Key: Type *
|
||||
Map<Type *> llvm_types; // Key: LLVMTypeRef
|
||||
i32 internal_type_level;
|
||||
|
||||
Map<lbValue> values; // Key: Entity *
|
||||
StringMap<lbValue> members;
|
||||
@@ -83,6 +104,10 @@ struct lbModule {
|
||||
StringMap<LLVMValueRef> const_strings;
|
||||
|
||||
Map<lbProcedure *> anonymous_proc_lits; // Key: Ast *
|
||||
Map<struct lbFunctionType *> function_type_map; // Key: Type *
|
||||
|
||||
Map<lbProcedure *> equal_procs; // Key: Type *
|
||||
Map<lbProcedure *> hasher_procs; // Key: Type *
|
||||
|
||||
u32 global_array_index;
|
||||
u32 global_generated_index;
|
||||
@@ -199,6 +224,7 @@ struct lbProcedure {
|
||||
bool is_entry_point;
|
||||
bool is_startup;
|
||||
|
||||
lbFunctionType *abi_function_type;
|
||||
|
||||
LLVMValueRef value;
|
||||
LLVMBuilderRef builder;
|
||||
@@ -301,7 +327,7 @@ lbAddr lb_add_local(lbProcedure *p, Type *type, Entity *e=nullptr, bool zero_ini
|
||||
|
||||
void lb_add_foreign_library_path(lbModule *m, Entity *e);
|
||||
|
||||
lbValue lb_typeid(lbModule *m, Type *type, Type *typeid_type=t_typeid);
|
||||
lbValue lb_typeid(lbModule *m, Type *type);
|
||||
|
||||
lbValue lb_address_from_load_or_generate_local(lbProcedure *p, lbValue value);
|
||||
lbValue lb_address_from_load(lbProcedure *p, lbValue value);
|
||||
@@ -344,7 +370,7 @@ String lb_get_const_string(lbModule *m, lbValue value);
|
||||
lbValue lb_generate_local_array(lbProcedure *p, Type *elem_type, i64 count, bool zero_init=true);
|
||||
lbValue lb_generate_global_array(lbModule *m, Type *elem_type, i64 count, String prefix, i64 id);
|
||||
lbValue lb_gen_map_header(lbProcedure *p, lbValue map_val_ptr, Type *map_type);
|
||||
lbValue lb_gen_map_key(lbProcedure *p, lbValue key, Type *key_type);
|
||||
lbValue lb_gen_map_hash(lbProcedure *p, lbValue key, Type *key_type);
|
||||
void lb_insert_dynamic_map_key_and_value(lbProcedure *p, lbAddr addr, Type *map_type, lbValue map_key, lbValue map_value, Ast *node);
|
||||
|
||||
|
||||
@@ -354,6 +380,9 @@ lbValue lb_emit_source_code_location(lbProcedure *p, String const &procedure, To
|
||||
|
||||
lbValue lb_handle_param_value(lbProcedure *p, Type *parameter_type, ParameterValue const ¶m_value, TokenPos const &pos);
|
||||
|
||||
lbValue lb_get_equal_proc_for_type(lbModule *m, Type *type);
|
||||
lbValue lb_get_hasher_proc_for_type(lbModule *m, Type *type);
|
||||
lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t);
|
||||
|
||||
#define LB_STARTUP_RUNTIME_PROC_NAME "__$startup_runtime"
|
||||
#define LB_STARTUP_TYPE_INFO_PROC_NAME "__$startup_type_info"
|
||||
|
||||
+376
-181
File diff suppressed because it is too large
Load Diff
+184
-100
@@ -108,8 +108,25 @@ Token ast_token(Ast *node) {
|
||||
return empty_token;
|
||||
}
|
||||
|
||||
|
||||
isize ast_node_size(AstKind kind) {
|
||||
return align_formula_isize(gb_size_of(AstCommonStuff) + ast_variant_sizes[kind], gb_align_of(void *));
|
||||
|
||||
}
|
||||
// NOTE(bill): And this below is why is I/we need a new language! Discriminated unions are a pain in C/C++
|
||||
Ast *alloc_ast_node(AstFile *f, AstKind kind) {
|
||||
gbAllocator a = ast_allocator(f);
|
||||
|
||||
isize size = ast_node_size(kind);
|
||||
|
||||
Ast *node = cast(Ast *)gb_alloc(a, size);
|
||||
node->kind = kind;
|
||||
node->file = f;
|
||||
return node;
|
||||
}
|
||||
|
||||
Ast *clone_ast(Ast *node);
|
||||
Array<Ast *> clone_ast_array(Array<Ast *> array) {
|
||||
Array<Ast *> clone_ast_array(Array<Ast *> const &array) {
|
||||
Array<Ast *> result = {};
|
||||
if (array.count > 0) {
|
||||
result = array_make<Ast *>(ast_allocator(nullptr), array.count);
|
||||
@@ -119,13 +136,23 @@ Array<Ast *> clone_ast_array(Array<Ast *> array) {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
Slice<Ast *> clone_ast_array(Slice<Ast *> const &array) {
|
||||
Slice<Ast *> result = {};
|
||||
if (array.count > 0) {
|
||||
result = slice_clone(permanent_allocator(), array);
|
||||
for_array(i, array) {
|
||||
result[i] = clone_ast(array[i]);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Ast *clone_ast(Ast *node) {
|
||||
if (node == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
Ast *n = alloc_ast_node(node->file, node->kind);
|
||||
gb_memmove(n, node, gb_size_of(Ast));
|
||||
gb_memmove(n, node, ast_node_size(node->kind));
|
||||
|
||||
switch (n->kind) {
|
||||
default: GB_PANIC("Unhandled Ast %.*s", LIT(ast_strings[n->kind])); break;
|
||||
@@ -463,23 +490,6 @@ bool ast_node_expect(Ast *node, AstKind kind) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
gb_global gbAtomic64 total_allocated_node_memory = {0};
|
||||
gb_global gbAtomic64 total_subtype_node_memory_test = {0};
|
||||
|
||||
// NOTE(bill): And this below is why is I/we need a new language! Discriminated unions are a pain in C/C++
|
||||
Ast *alloc_ast_node(AstFile *f, AstKind kind) {
|
||||
gbAllocator a = ast_allocator(f);
|
||||
|
||||
gb_atomic64_fetch_add(&total_allocated_node_memory, cast(i64)(gb_size_of(Ast)));
|
||||
gb_atomic64_fetch_add(&total_subtype_node_memory_test, cast(i64)(gb_size_of(AstCommonStuff) + ast_variant_sizes[kind]));
|
||||
|
||||
Ast *node = gb_alloc_item(a, Ast);
|
||||
node->kind = kind;
|
||||
node->file = f;
|
||||
return node;
|
||||
}
|
||||
|
||||
Ast *ast_bad_expr(AstFile *f, Token begin, Token end) {
|
||||
Ast *result = alloc_ast_node(f, Ast_BadExpr);
|
||||
result->BadExpr.begin = begin;
|
||||
@@ -537,10 +547,10 @@ Ast *ast_paren_expr(AstFile *f, Ast *expr, Token open, Token close) {
|
||||
return result;
|
||||
}
|
||||
|
||||
Ast *ast_call_expr(AstFile *f, Ast *proc, Array<Ast *> args, Token open, Token close, Token ellipsis) {
|
||||
Ast *ast_call_expr(AstFile *f, Ast *proc, Array<Ast *> const &args, Token open, Token close, Token ellipsis) {
|
||||
Ast *result = alloc_ast_node(f, Ast_CallExpr);
|
||||
result->CallExpr.proc = proc;
|
||||
result->CallExpr.args = args;
|
||||
result->CallExpr.args = slice_from_array(args);
|
||||
result->CallExpr.open = open;
|
||||
result->CallExpr.close = close;
|
||||
result->CallExpr.ellipsis = ellipsis;
|
||||
@@ -624,7 +634,8 @@ Ast *ast_undef(AstFile *f, Token token) {
|
||||
Ast *ast_basic_lit(AstFile *f, Token basic_lit) {
|
||||
Ast *result = alloc_ast_node(f, Ast_BasicLit);
|
||||
result->BasicLit.token = basic_lit;
|
||||
result->BasicLit.value = exact_value_from_basic_literal(basic_lit);
|
||||
result->tav.mode = Addressing_Constant;
|
||||
result->tav.value = exact_value_from_basic_literal(basic_lit);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -643,12 +654,12 @@ Ast *ast_ellipsis(AstFile *f, Token token, Ast *expr) {
|
||||
}
|
||||
|
||||
|
||||
Ast *ast_proc_group(AstFile *f, Token token, Token open, Token close, Array<Ast *> args) {
|
||||
Ast *ast_proc_group(AstFile *f, Token token, Token open, Token close, Array<Ast *> const &args) {
|
||||
Ast *result = alloc_ast_node(f, Ast_ProcGroup);
|
||||
result->ProcGroup.token = token;
|
||||
result->ProcGroup.open = open;
|
||||
result->ProcGroup.close = close;
|
||||
result->ProcGroup.args = args;
|
||||
result->ProcGroup.args = slice_from_array(args);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -658,7 +669,7 @@ Ast *ast_proc_lit(AstFile *f, Ast *type, Ast *body, u64 tags, Token where_token,
|
||||
result->ProcLit.body = body;
|
||||
result->ProcLit.tags = tags;
|
||||
result->ProcLit.where_token = where_token;
|
||||
result->ProcLit.where_clauses = where_clauses;
|
||||
result->ProcLit.where_clauses = slice_from_array(where_clauses);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -670,10 +681,10 @@ Ast *ast_field_value(AstFile *f, Ast *field, Ast *value, Token eq) {
|
||||
return result;
|
||||
}
|
||||
|
||||
Ast *ast_compound_lit(AstFile *f, Ast *type, Array<Ast *> elems, Token open, Token close) {
|
||||
Ast *ast_compound_lit(AstFile *f, Ast *type, Array<Ast *> const &elems, Token open, Token close) {
|
||||
Ast *result = alloc_ast_node(f, Ast_CompoundLit);
|
||||
result->CompoundLit.type = type;
|
||||
result->CompoundLit.elems = elems;
|
||||
result->CompoundLit.elems = slice_from_array(elems);
|
||||
result->CompoundLit.open = open;
|
||||
result->CompoundLit.close = close;
|
||||
return result;
|
||||
@@ -736,7 +747,7 @@ Ast *ast_inline_asm_expr(AstFile *f, Token token, Token open, Token close,
|
||||
result->InlineAsmExpr.token = token;
|
||||
result->InlineAsmExpr.open = open;
|
||||
result->InlineAsmExpr.close = close;
|
||||
result->InlineAsmExpr.param_types = param_types;
|
||||
result->InlineAsmExpr.param_types = slice_from_array(param_types);
|
||||
result->InlineAsmExpr.return_type = return_type;
|
||||
result->InlineAsmExpr.asm_string = asm_string;
|
||||
result->InlineAsmExpr.constraints_string = constraints_string;
|
||||
@@ -768,18 +779,18 @@ Ast *ast_expr_stmt(AstFile *f, Ast *expr) {
|
||||
return result;
|
||||
}
|
||||
|
||||
Ast *ast_assign_stmt(AstFile *f, Token op, Array<Ast *> lhs, Array<Ast *> rhs) {
|
||||
Ast *ast_assign_stmt(AstFile *f, Token op, Array<Ast *> const &lhs, Array<Ast *> const &rhs) {
|
||||
Ast *result = alloc_ast_node(f, Ast_AssignStmt);
|
||||
result->AssignStmt.op = op;
|
||||
result->AssignStmt.lhs = lhs;
|
||||
result->AssignStmt.rhs = rhs;
|
||||
result->AssignStmt.lhs = slice_from_array(lhs);
|
||||
result->AssignStmt.rhs = slice_from_array(rhs);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
Ast *ast_block_stmt(AstFile *f, Array<Ast *> stmts, Token open, Token close) {
|
||||
Ast *ast_block_stmt(AstFile *f, Array<Ast *> const &stmts, Token open, Token close) {
|
||||
Ast *result = alloc_ast_node(f, Ast_BlockStmt);
|
||||
result->BlockStmt.stmts = stmts;
|
||||
result->BlockStmt.stmts = slice_from_array(stmts);
|
||||
result->BlockStmt.open = open;
|
||||
result->BlockStmt.close = close;
|
||||
return result;
|
||||
@@ -805,10 +816,10 @@ Ast *ast_when_stmt(AstFile *f, Token token, Ast *cond, Ast *body, Ast *else_stmt
|
||||
}
|
||||
|
||||
|
||||
Ast *ast_return_stmt(AstFile *f, Token token, Array<Ast *> results) {
|
||||
Ast *ast_return_stmt(AstFile *f, Token token, Array<Ast *> const &results) {
|
||||
Ast *result = alloc_ast_node(f, Ast_ReturnStmt);
|
||||
result->ReturnStmt.token = token;
|
||||
result->ReturnStmt.results = results;
|
||||
result->ReturnStmt.results = slice_from_array(results);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -866,11 +877,11 @@ Ast *ast_type_switch_stmt(AstFile *f, Token token, Ast *tag, Ast *body) {
|
||||
return result;
|
||||
}
|
||||
|
||||
Ast *ast_case_clause(AstFile *f, Token token, Array<Ast *> list, Array<Ast *> stmts) {
|
||||
Ast *ast_case_clause(AstFile *f, Token token, Array<Ast *> const &list, Array<Ast *> const &stmts) {
|
||||
Ast *result = alloc_ast_node(f, Ast_CaseClause);
|
||||
result->CaseClause.token = token;
|
||||
result->CaseClause.list = list;
|
||||
result->CaseClause.stmts = stmts;
|
||||
result->CaseClause.list = slice_from_array(list);
|
||||
result->CaseClause.stmts = slice_from_array(stmts);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -889,10 +900,10 @@ Ast *ast_branch_stmt(AstFile *f, Token token, Ast *label) {
|
||||
return result;
|
||||
}
|
||||
|
||||
Ast *ast_using_stmt(AstFile *f, Token token, Array<Ast *> list) {
|
||||
Ast *ast_using_stmt(AstFile *f, Token token, Array<Ast *> const &list) {
|
||||
Ast *result = alloc_ast_node(f, Ast_UsingStmt);
|
||||
result->UsingStmt.token = token;
|
||||
result->UsingStmt.list = list;
|
||||
result->UsingStmt.list = slice_from_array(list);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -905,10 +916,10 @@ Ast *ast_bad_decl(AstFile *f, Token begin, Token end) {
|
||||
return result;
|
||||
}
|
||||
|
||||
Ast *ast_field(AstFile *f, Array<Ast *> names, Ast *type, Ast *default_value, u32 flags, Token tag,
|
||||
Ast *ast_field(AstFile *f, Array<Ast *> const &names, Ast *type, Ast *default_value, u32 flags, Token tag,
|
||||
CommentGroup *docs, CommentGroup *comment) {
|
||||
Ast *result = alloc_ast_node(f, Ast_Field);
|
||||
result->Field.names = names;
|
||||
result->Field.names = slice_from_array(names);
|
||||
result->Field.type = type;
|
||||
result->Field.default_value = default_value;
|
||||
result->Field.flags = flags;
|
||||
@@ -918,10 +929,10 @@ Ast *ast_field(AstFile *f, Array<Ast *> names, Ast *type, Ast *default_value, u3
|
||||
return result;
|
||||
}
|
||||
|
||||
Ast *ast_field_list(AstFile *f, Token token, Array<Ast *> list) {
|
||||
Ast *ast_field_list(AstFile *f, Token token, Array<Ast *> const &list) {
|
||||
Ast *result = alloc_ast_node(f, Ast_FieldList);
|
||||
result->FieldList.token = token;
|
||||
result->FieldList.list = list;
|
||||
result->FieldList.list = slice_from_array(list);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1002,7 +1013,7 @@ Ast *ast_dynamic_array_type(AstFile *f, Token token, Ast *elem) {
|
||||
return result;
|
||||
}
|
||||
|
||||
Ast *ast_struct_type(AstFile *f, Token token, Array<Ast *> fields, isize field_count,
|
||||
Ast *ast_struct_type(AstFile *f, Token token, Slice<Ast *> fields, isize field_count,
|
||||
Ast *polymorphic_params, bool is_packed, bool is_raw_union,
|
||||
Ast *align,
|
||||
Token where_token, Array<Ast *> const &where_clauses) {
|
||||
@@ -1015,38 +1026,38 @@ Ast *ast_struct_type(AstFile *f, Token token, Array<Ast *> fields, isize field_c
|
||||
result->StructType.is_raw_union = is_raw_union;
|
||||
result->StructType.align = align;
|
||||
result->StructType.where_token = where_token;
|
||||
result->StructType.where_clauses = where_clauses;
|
||||
result->StructType.where_clauses = slice_from_array(where_clauses);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
Ast *ast_union_type(AstFile *f, Token token, Array<Ast *> variants, Ast *polymorphic_params, Ast *align, bool no_nil, bool maybe,
|
||||
Ast *ast_union_type(AstFile *f, Token token, Array<Ast *> const &variants, Ast *polymorphic_params, Ast *align, bool no_nil, bool maybe,
|
||||
Token where_token, Array<Ast *> const &where_clauses) {
|
||||
Ast *result = alloc_ast_node(f, Ast_UnionType);
|
||||
result->UnionType.token = token;
|
||||
result->UnionType.variants = variants;
|
||||
result->UnionType.variants = slice_from_array(variants);
|
||||
result->UnionType.polymorphic_params = polymorphic_params;
|
||||
result->UnionType.align = align;
|
||||
result->UnionType.no_nil = no_nil;
|
||||
result->UnionType.maybe = maybe;
|
||||
result->UnionType.maybe = maybe;
|
||||
result->UnionType.where_token = where_token;
|
||||
result->UnionType.where_clauses = where_clauses;
|
||||
result->UnionType.where_clauses = slice_from_array(where_clauses);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
Ast *ast_enum_type(AstFile *f, Token token, Ast *base_type, Array<Ast *> fields) {
|
||||
Ast *ast_enum_type(AstFile *f, Token token, Ast *base_type, Array<Ast *> const &fields) {
|
||||
Ast *result = alloc_ast_node(f, Ast_EnumType);
|
||||
result->EnumType.token = token;
|
||||
result->EnumType.base_type = base_type;
|
||||
result->EnumType.fields = fields;
|
||||
result->EnumType.fields = slice_from_array(fields);
|
||||
return result;
|
||||
}
|
||||
|
||||
Ast *ast_bit_field_type(AstFile *f, Token token, Array<Ast *> fields, Ast *align) {
|
||||
Ast *ast_bit_field_type(AstFile *f, Token token, Array<Ast *> const &fields, Ast *align) {
|
||||
Ast *result = alloc_ast_node(f, Ast_BitFieldType);
|
||||
result->BitFieldType.token = token;
|
||||
result->BitFieldType.fields = fields;
|
||||
result->BitFieldType.fields = slice_from_array(fields);
|
||||
result->BitFieldType.align = align;
|
||||
return result;
|
||||
}
|
||||
@@ -1069,7 +1080,7 @@ Ast *ast_map_type(AstFile *f, Token token, Ast *key, Ast *value) {
|
||||
|
||||
|
||||
Ast *ast_foreign_block_decl(AstFile *f, Token token, Ast *foreign_library, Ast *body,
|
||||
CommentGroup *docs) {
|
||||
CommentGroup *docs) {
|
||||
Ast *result = alloc_ast_node(f, Ast_ForeignBlockDecl);
|
||||
result->ForeignBlockDecl.token = token;
|
||||
result->ForeignBlockDecl.foreign_library = foreign_library;
|
||||
@@ -1087,12 +1098,12 @@ Ast *ast_label_decl(AstFile *f, Token token, Ast *name) {
|
||||
return result;
|
||||
}
|
||||
|
||||
Ast *ast_value_decl(AstFile *f, Array<Ast *> names, Ast *type, Array<Ast *> values, bool is_mutable,
|
||||
CommentGroup *docs, CommentGroup *comment) {
|
||||
Ast *ast_value_decl(AstFile *f, Array<Ast *> const &names, Ast *type, Array<Ast *> const &values, bool is_mutable,
|
||||
CommentGroup *docs, CommentGroup *comment) {
|
||||
Ast *result = alloc_ast_node(f, Ast_ValueDecl);
|
||||
result->ValueDecl.names = names;
|
||||
result->ValueDecl.names = slice_from_array(names);
|
||||
result->ValueDecl.type = type;
|
||||
result->ValueDecl.values = values;
|
||||
result->ValueDecl.values = slice_from_array(values);
|
||||
result->ValueDecl.is_mutable = is_mutable;
|
||||
result->ValueDecl.docs = docs;
|
||||
result->ValueDecl.comment = comment;
|
||||
@@ -1111,7 +1122,7 @@ Ast *ast_package_decl(AstFile *f, Token token, Token name, CommentGroup *docs, C
|
||||
}
|
||||
|
||||
Ast *ast_import_decl(AstFile *f, Token token, bool is_using, Token relpath, Token import_name,
|
||||
CommentGroup *docs, CommentGroup *comment) {
|
||||
CommentGroup *docs, CommentGroup *comment) {
|
||||
Ast *result = alloc_ast_node(f, Ast_ImportDecl);
|
||||
result->ImportDecl.token = token;
|
||||
result->ImportDecl.is_using = is_using;
|
||||
@@ -1123,10 +1134,10 @@ Ast *ast_import_decl(AstFile *f, Token token, bool is_using, Token relpath, Toke
|
||||
}
|
||||
|
||||
Ast *ast_foreign_import_decl(AstFile *f, Token token, Array<Token> filepaths, Token library_name,
|
||||
CommentGroup *docs, CommentGroup *comment) {
|
||||
CommentGroup *docs, CommentGroup *comment) {
|
||||
Ast *result = alloc_ast_node(f, Ast_ForeignImportDecl);
|
||||
result->ForeignImportDecl.token = token;
|
||||
result->ForeignImportDecl.filepaths = filepaths;
|
||||
result->ForeignImportDecl.filepaths = slice_from_array(filepaths);
|
||||
result->ForeignImportDecl.library_name = library_name;
|
||||
result->ForeignImportDecl.docs = docs;
|
||||
result->ForeignImportDecl.comment = comment;
|
||||
@@ -1136,11 +1147,11 @@ Ast *ast_foreign_import_decl(AstFile *f, Token token, Array<Token> filepaths, To
|
||||
}
|
||||
|
||||
|
||||
Ast *ast_attribute(AstFile *f, Token token, Token open, Token close, Array<Ast *> elems) {
|
||||
Ast *ast_attribute(AstFile *f, Token token, Token open, Token close, Array<Ast *> const &elems) {
|
||||
Ast *result = alloc_ast_node(f, Ast_Attribute);
|
||||
result->Attribute.token = token;
|
||||
result->Attribute.open = open;
|
||||
result->Attribute.elems = elems;
|
||||
result->Attribute.elems = slice_from_array(elems);
|
||||
result->Attribute.close = close;
|
||||
return result;
|
||||
}
|
||||
@@ -1182,6 +1193,12 @@ CommentGroup *consume_comment_group(AstFile *f, isize n, isize *end_line_) {
|
||||
Array<Token> list = {};
|
||||
list.allocator = heap_allocator();
|
||||
isize end_line = f->curr_token.pos.line;
|
||||
if (f->curr_token_index == 1 &&
|
||||
f->prev_token.kind == Token_Comment &&
|
||||
f->prev_token.pos.line+1 == f->curr_token.pos.line) {
|
||||
// NOTE(bill): Special logic for the first comment in the file
|
||||
array_add(&list, f->prev_token);
|
||||
}
|
||||
while (f->curr_token.kind == Token_Comment &&
|
||||
f->curr_token.pos.line <= end_line+n) {
|
||||
array_add(&list, consume_comment(f, &end_line));
|
||||
@@ -1192,7 +1209,7 @@ CommentGroup *consume_comment_group(AstFile *f, isize n, isize *end_line_) {
|
||||
CommentGroup *comments = nullptr;
|
||||
if (list.count > 0) {
|
||||
comments = gb_alloc_item(heap_allocator(), CommentGroup);
|
||||
comments->list = list;
|
||||
comments->list = slice_from_array(list);
|
||||
array_add(&f->comments, comments);
|
||||
}
|
||||
return comments;
|
||||
@@ -1894,12 +1911,18 @@ Ast *parse_operand(AstFile *f, bool lhs) {
|
||||
|
||||
case Token_opaque: {
|
||||
Token token = expect_token(f, Token_opaque);
|
||||
warning(token, "opaque is deprecated, please use #opaque");
|
||||
Ast *type = parse_type(f);
|
||||
return ast_opaque_type(f, token, type);
|
||||
}
|
||||
|
||||
case Token_Hash: {
|
||||
Token token = expect_token(f, Token_Hash);
|
||||
if (allow_token(f, Token_opaque)) {
|
||||
Ast *type = parse_type(f);
|
||||
return ast_opaque_type(f, token, type);
|
||||
}
|
||||
|
||||
Token name = expect_token(f, Token_Ident);
|
||||
if (name.string == "type") {
|
||||
return ast_helper_type(f, token, parse_type(f));
|
||||
@@ -2201,7 +2224,7 @@ Ast *parse_operand(AstFile *f, bool lhs) {
|
||||
|
||||
if (allow_token(f, Token_OpenParen)) {
|
||||
isize param_count = 0;
|
||||
polymorphic_params = parse_field_list(f, ¶m_count, 0, Token_CloseParen, false, true);
|
||||
polymorphic_params = parse_field_list(f, ¶m_count, 0, Token_CloseParen, true, true);
|
||||
if (param_count == 0) {
|
||||
syntax_error(polymorphic_params, "Expected at least 1 polymorphic parameter");
|
||||
polymorphic_params = nullptr;
|
||||
@@ -2262,7 +2285,7 @@ Ast *parse_operand(AstFile *f, bool lhs) {
|
||||
Ast *fields = parse_struct_field_list(f, &name_count);
|
||||
Token close = expect_token(f, Token_CloseBrace);
|
||||
|
||||
Array<Ast *> decls = {};
|
||||
Slice<Ast *> decls = {};
|
||||
if (fields != nullptr) {
|
||||
GB_ASSERT(fields->kind == Ast_FieldList);
|
||||
decls = fields->FieldList.list;
|
||||
@@ -2284,7 +2307,7 @@ Ast *parse_operand(AstFile *f, bool lhs) {
|
||||
|
||||
if (allow_token(f, Token_OpenParen)) {
|
||||
isize param_count = 0;
|
||||
polymorphic_params = parse_field_list(f, ¶m_count, 0, Token_CloseParen, false, true);
|
||||
polymorphic_params = parse_field_list(f, ¶m_count, 0, Token_CloseParen, true, true);
|
||||
if (param_count == 0) {
|
||||
syntax_error(polymorphic_params, "Expected at least 1 polymorphic parametric");
|
||||
polymorphic_params = nullptr;
|
||||
@@ -2586,7 +2609,15 @@ Ast *parse_call_expr(AstFile *f, Ast *operand) {
|
||||
f->expr_level--;
|
||||
close_paren = expect_closing(f, Token_CloseParen, str_lit("argument list"));
|
||||
|
||||
return ast_call_expr(f, operand, args, open_paren, close_paren, ellipsis);
|
||||
|
||||
Ast *call = ast_call_expr(f, operand, args, open_paren, close_paren, ellipsis);
|
||||
|
||||
Ast *o = unparen_expr(operand);
|
||||
if (o->kind == Ast_SelectorExpr && o->SelectorExpr.token.kind == Token_ArrowRight) {
|
||||
return ast_selector_call_expr(f, o->SelectorExpr.token, o, call);
|
||||
}
|
||||
|
||||
return call;
|
||||
}
|
||||
|
||||
Ast *parse_atom_expr(AstFile *f, Ast *operand, bool lhs) {
|
||||
@@ -2638,11 +2669,10 @@ Ast *parse_atom_expr(AstFile *f, Ast *operand, bool lhs) {
|
||||
|
||||
case Token_ArrowRight: {
|
||||
Token token = advance_token(f);
|
||||
// syntax_error(token, "Selector expressions use '.' rather than '->'");
|
||||
|
||||
Ast *sel = ast_selector_expr(f, token, operand, parse_ident(f));
|
||||
Ast *call = parse_call_expr(f, sel);
|
||||
operand = ast_selector_call_expr(f, token, sel, call);
|
||||
operand = ast_selector_expr(f, token, operand, parse_ident(f));
|
||||
// Ast *call = parse_call_expr(f, sel);
|
||||
// operand = ast_selector_call_expr(f, token, sel, call);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -3317,11 +3347,10 @@ FieldPrefixKind is_token_field_prefix(AstFile *f) {
|
||||
return FieldPrefix_no_alias;
|
||||
} else if (f->curr_token.string == "c_vararg") {
|
||||
return FieldPrefix_c_var_arg;
|
||||
} else if (f->curr_token.string == "const") {
|
||||
return FieldPrefix_const;
|
||||
}
|
||||
break;
|
||||
|
||||
case Token_const:
|
||||
return FieldPrefix_const;
|
||||
}
|
||||
return FieldPrefix_Unknown;
|
||||
}
|
||||
@@ -4723,18 +4752,14 @@ void parser_add_foreign_file_to_process(Parser *p, AstPackage *pkg, AstForeignFi
|
||||
|
||||
|
||||
// NOTE(bill): Returns true if it's added
|
||||
bool try_add_import_path(Parser *p, String const &path, String const &rel_path, TokenPos pos, PackageKind kind = Package_Normal) {
|
||||
if (build_context.generate_docs) {
|
||||
return false;
|
||||
}
|
||||
|
||||
AstPackage *try_add_import_path(Parser *p, String const &path, String const &rel_path, TokenPos pos, PackageKind kind = Package_Normal) {
|
||||
String const FILE_EXT = str_lit(".odin");
|
||||
|
||||
gb_mutex_lock(&p->file_add_mutex);
|
||||
defer (gb_mutex_unlock(&p->file_add_mutex));
|
||||
|
||||
if (string_set_exists(&p->imported_files, path)) {
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
string_set_add(&p->imported_files, path);
|
||||
|
||||
@@ -4757,7 +4782,7 @@ bool try_add_import_path(Parser *p, String const &path, String const &rel_path,
|
||||
pkg->is_single_file = true;
|
||||
parser_add_file_to_process(p, pkg, fi, pos);
|
||||
parser_add_package(p, pkg);
|
||||
return true;
|
||||
return pkg;
|
||||
}
|
||||
|
||||
|
||||
@@ -4773,22 +4798,22 @@ bool try_add_import_path(Parser *p, String const &path, String const &rel_path,
|
||||
switch (rd_err) {
|
||||
case ReadDirectory_InvalidPath:
|
||||
syntax_error(pos, "Invalid path: %.*s", LIT(rel_path));
|
||||
return false;
|
||||
return nullptr;
|
||||
case ReadDirectory_NotExists:
|
||||
syntax_error(pos, "Path does not exist: %.*s", LIT(rel_path));
|
||||
return false;
|
||||
return nullptr;
|
||||
case ReadDirectory_Permission:
|
||||
syntax_error(pos, "Unknown error whilst reading path %.*s", LIT(rel_path));
|
||||
return false;
|
||||
return nullptr;
|
||||
case ReadDirectory_NotDir:
|
||||
syntax_error(pos, "Expected a directory for a package, got a file: %.*s", LIT(rel_path));
|
||||
return false;
|
||||
return nullptr;
|
||||
case ReadDirectory_Empty:
|
||||
syntax_error(pos, "Empty directory: %.*s", LIT(rel_path));
|
||||
return false;
|
||||
return nullptr;
|
||||
case ReadDirectory_Unknown:
|
||||
syntax_error(pos, "Unknown error whilst reading path %.*s", LIT(rel_path));
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
for_array(list_index, list) {
|
||||
@@ -4810,7 +4835,7 @@ bool try_add_import_path(Parser *p, String const &path, String const &rel_path,
|
||||
|
||||
parser_add_package(p, pkg);
|
||||
|
||||
return true;
|
||||
return pkg;
|
||||
}
|
||||
|
||||
gb_global Rune illegal_import_runes[] = {
|
||||
@@ -4829,7 +4854,7 @@ bool is_import_path_valid(String path) {
|
||||
u8 *curr = start;
|
||||
while (curr < end) {
|
||||
isize width = 1;
|
||||
Rune r = curr[0];
|
||||
Rune r = *curr;
|
||||
if (r >= 0x80) {
|
||||
width = gb_utf8_decode(curr, end-curr, &r);
|
||||
if (r == GB_RUNE_INVALID && width == 1) {
|
||||
@@ -4854,6 +4879,45 @@ bool is_import_path_valid(String path) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool is_build_flag_path_valid(String path) {
|
||||
if (path.len > 0) {
|
||||
u8 *start = path.text;
|
||||
u8 *end = path.text + path.len;
|
||||
u8 *curr = start;
|
||||
isize index = 0;
|
||||
while (curr < end) {
|
||||
isize width = 1;
|
||||
Rune r = *curr;
|
||||
if (r >= 0x80) {
|
||||
width = gb_utf8_decode(curr, end-curr, &r);
|
||||
if (r == GB_RUNE_INVALID && width == 1) {
|
||||
return false;
|
||||
}
|
||||
else if (r == GB_RUNE_BOM && curr-start > 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (isize i = 0; i < gb_count_of(illegal_import_runes); i++) {
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
if (r == '\\') {
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
if (r == illegal_import_runes[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
curr += width;
|
||||
index += 1;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool is_package_name_reserved(String const &name) {
|
||||
if (name == "builtin") {
|
||||
@@ -4974,7 +5038,7 @@ bool determine_path_from_string(gbMutex *file_mutex, Ast *node, String base_dir,
|
||||
|
||||
|
||||
|
||||
void parse_setup_file_decls(Parser *p, AstFile *f, String base_dir, Array<Ast *> &decls);
|
||||
void parse_setup_file_decls(Parser *p, AstFile *f, String base_dir, Slice<Ast *> &decls);
|
||||
|
||||
void parse_setup_file_when_stmt(Parser *p, AstFile *f, String base_dir, AstWhenStmt *ws) {
|
||||
if (ws->body != nullptr) {
|
||||
@@ -4995,7 +5059,7 @@ void parse_setup_file_when_stmt(Parser *p, AstFile *f, String base_dir, AstWhenS
|
||||
}
|
||||
}
|
||||
|
||||
void parse_setup_file_decls(Parser *p, AstFile *f, String base_dir, Array<Ast *> &decls) {
|
||||
void parse_setup_file_decls(Parser *p, AstFile *f, String base_dir, Slice<Ast *> &decls) {
|
||||
for_array(i, decls) {
|
||||
Ast *node = decls[i];
|
||||
if (!is_ast_decl(node) &&
|
||||
@@ -5034,8 +5098,7 @@ void parse_setup_file_decls(Parser *p, AstFile *f, String base_dir, Array<Ast *>
|
||||
} else if (node->kind == Ast_ForeignImportDecl) {
|
||||
ast_node(fl, ForeignImportDecl, node);
|
||||
|
||||
fl->fullpaths.allocator = heap_allocator();
|
||||
array_reserve(&fl->fullpaths, fl->filepaths.count);
|
||||
auto fullpaths = array_make<String>(permanent_allocator(), 0, fl->filepaths.count);
|
||||
|
||||
for_array(fp_idx, fl->filepaths) {
|
||||
String file_str = fl->filepaths[fp_idx].string;
|
||||
@@ -5049,14 +5112,17 @@ void parse_setup_file_decls(Parser *p, AstFile *f, String base_dir, Array<Ast *>
|
||||
}
|
||||
fullpath = foreign_path;
|
||||
}
|
||||
array_add(&fl->fullpaths, fullpath);
|
||||
array_add(&fullpaths, fullpath);
|
||||
}
|
||||
if (fl->fullpaths.count == 0) {
|
||||
if (fullpaths.count == 0) {
|
||||
syntax_error(decls[i], "No foreign paths found");
|
||||
decls[i] = ast_bad_decl(f, fl->filepaths[0], fl->filepaths[fl->filepaths.count-1]);
|
||||
goto end;
|
||||
}
|
||||
|
||||
fl->fullpaths = slice_from_array(fullpaths);
|
||||
|
||||
|
||||
} else if (node->kind == Ast_WhenStmt) {
|
||||
ast_node(ws, WhenStmt, node);
|
||||
parse_setup_file_when_stmt(p, f, base_dir, ws);
|
||||
@@ -5218,12 +5284,12 @@ bool parse_file(Parser *p, AstFile *f) {
|
||||
f->pkg_decl = pd;
|
||||
|
||||
if (f->error_count == 0) {
|
||||
f->decls = array_make<Ast *>(heap_allocator());
|
||||
auto decls = array_make<Ast *>(heap_allocator());
|
||||
|
||||
while (f->curr_token.kind != Token_EOF) {
|
||||
Ast *stmt = parse_stmt(f);
|
||||
if (stmt && stmt->kind != Ast_EmptyStmt) {
|
||||
array_add(&f->decls, stmt);
|
||||
array_add(&decls, stmt);
|
||||
if (stmt->kind == Ast_ExprStmt &&
|
||||
stmt->ExprStmt.expr != nullptr &&
|
||||
stmt->ExprStmt.expr->kind == Ast_ProcLit) {
|
||||
@@ -5232,6 +5298,8 @@ bool parse_file(Parser *p, AstFile *f) {
|
||||
}
|
||||
}
|
||||
|
||||
f->decls = slice_from_array(decls);
|
||||
|
||||
parse_setup_file_decls(p, f, base_dir, f->decls);
|
||||
}
|
||||
|
||||
@@ -5325,7 +5393,7 @@ ParseFileError parse_packages(Parser *p, String init_filename) {
|
||||
}
|
||||
|
||||
TokenPos init_pos = {};
|
||||
if (!build_context.generate_docs) {
|
||||
{
|
||||
String s = get_fullpath_core(heap_allocator(), str_lit("runtime"));
|
||||
try_add_import_path(p, s, s, init_pos, Package_Runtime);
|
||||
}
|
||||
@@ -5333,6 +5401,22 @@ ParseFileError parse_packages(Parser *p, String init_filename) {
|
||||
try_add_import_path(p, init_fullpath, init_fullpath, init_pos, Package_Init);
|
||||
p->init_fullpath = init_fullpath;
|
||||
|
||||
for_array(i, build_context.extra_packages) {
|
||||
String path = build_context.extra_packages[i];
|
||||
String fullpath = path_to_full_path(heap_allocator(), path); // LEAK?
|
||||
if (!path_is_directory(fullpath)) {
|
||||
String const ext = str_lit(".odin");
|
||||
if (!string_ends_with(fullpath, ext)) {
|
||||
error_line("Expected either a directory or a .odin file, got '%.*s'\n", LIT(fullpath));
|
||||
return ParseFile_WrongExtension;
|
||||
}
|
||||
}
|
||||
AstPackage *pkg = try_add_import_path(p, fullpath, fullpath, init_pos, Package_Normal);
|
||||
if (pkg) {
|
||||
pkg->is_extra = true;
|
||||
}
|
||||
}
|
||||
|
||||
thread_pool_start(&parser_thread_pool);
|
||||
thread_pool_wait_to_process(&parser_thread_pool);
|
||||
|
||||
|
||||
+42
-39
@@ -46,7 +46,7 @@ enum ParseFileError {
|
||||
};
|
||||
|
||||
struct CommentGroup {
|
||||
Array<Token> list; // Token_Comment
|
||||
Slice<Token> list; // Token_Comment
|
||||
};
|
||||
|
||||
|
||||
@@ -98,8 +98,8 @@ struct AstFile {
|
||||
bool in_foreign_block;
|
||||
bool allow_type;
|
||||
|
||||
Array<Ast *> decls;
|
||||
Array<Ast *> imports; // 'import' 'using import'
|
||||
Slice<Ast *> decls;
|
||||
Array<Ast *> imports; // 'import'
|
||||
isize directive_count;
|
||||
|
||||
Ast * curr_proc;
|
||||
@@ -107,6 +107,8 @@ struct AstFile {
|
||||
f64 time_to_tokenize; // seconds
|
||||
f64 time_to_parse; // seconds
|
||||
|
||||
bool is_test;
|
||||
|
||||
CommentGroup *lead_comment; // Comment (block) before the decl
|
||||
CommentGroup *line_comment; // Comment after the semicolon
|
||||
CommentGroup *docs; // current docs
|
||||
@@ -148,6 +150,7 @@ struct AstPackage {
|
||||
Scope * scope;
|
||||
DeclInfo *decl_info;
|
||||
bool used;
|
||||
bool is_extra;
|
||||
};
|
||||
|
||||
|
||||
@@ -217,14 +220,16 @@ enum ProcCallingConvention {
|
||||
ProcCC_ForeignBlockDefault = -1,
|
||||
};
|
||||
|
||||
enum StateFlag {
|
||||
enum StateFlag : u16 {
|
||||
StateFlag_bounds_check = 1<<0,
|
||||
StateFlag_no_bounds_check = 1<<1,
|
||||
|
||||
StateFlag_no_deferred = 1<<5,
|
||||
|
||||
StateFlag_BeenHandled = 1<<15,
|
||||
};
|
||||
|
||||
enum ViralStateFlag {
|
||||
enum ViralStateFlag : u16 {
|
||||
ViralStateFlag_ContainsDeferredProcedure = 1<<0,
|
||||
};
|
||||
|
||||
@@ -275,7 +280,6 @@ char const *inline_asm_dialect_strings[InlineAsmDialect_COUNT] = {
|
||||
AST_KIND(Undef, "undef", Token) \
|
||||
AST_KIND(BasicLit, "basic literal", struct { \
|
||||
Token token; \
|
||||
ExactValue value; \
|
||||
}) \
|
||||
AST_KIND(BasicDirective, "basic directive", struct { \
|
||||
Token token; \
|
||||
@@ -289,7 +293,7 @@ char const *inline_asm_dialect_strings[InlineAsmDialect_COUNT] = {
|
||||
Token token; \
|
||||
Token open; \
|
||||
Token close; \
|
||||
Array<Ast *> args; \
|
||||
Slice<Ast *> args; \
|
||||
}) \
|
||||
AST_KIND(ProcLit, "procedure literal", struct { \
|
||||
Ast *type; \
|
||||
@@ -297,12 +301,12 @@ char const *inline_asm_dialect_strings[InlineAsmDialect_COUNT] = {
|
||||
u64 tags; \
|
||||
ProcInlining inlining; \
|
||||
Token where_token; \
|
||||
Array<Ast *> where_clauses; \
|
||||
Slice<Ast *> where_clauses; \
|
||||
DeclInfo *decl; \
|
||||
}) \
|
||||
AST_KIND(CompoundLit, "compound literal", struct { \
|
||||
Ast *type; \
|
||||
Array<Ast *> elems; \
|
||||
Slice<Ast *> elems; \
|
||||
Token open, close; \
|
||||
i64 max_count; \
|
||||
}) \
|
||||
@@ -325,7 +329,7 @@ AST_KIND(_ExprBegin, "", bool) \
|
||||
}) \
|
||||
AST_KIND(CallExpr, "call expression", struct { \
|
||||
Ast * proc; \
|
||||
Array<Ast *> args; \
|
||||
Slice<Ast *> args; \
|
||||
Token open; \
|
||||
Token close; \
|
||||
Token ellipsis; \
|
||||
@@ -342,7 +346,7 @@ AST_KIND(_ExprBegin, "", bool) \
|
||||
AST_KIND(InlineAsmExpr, "inline asm expression", struct { \
|
||||
Token token; \
|
||||
Token open, close; \
|
||||
Array<Ast *> param_types; \
|
||||
Slice<Ast *> param_types; \
|
||||
Ast *return_type; \
|
||||
Ast *asm_string; \
|
||||
Ast *constraints_string; \
|
||||
@@ -362,11 +366,11 @@ AST_KIND(_StmtBegin, "", bool) \
|
||||
}) \
|
||||
AST_KIND(AssignStmt, "assign statement", struct { \
|
||||
Token op; \
|
||||
Array<Ast *> lhs, rhs; \
|
||||
Slice<Ast *> lhs, rhs; \
|
||||
}) \
|
||||
AST_KIND(_ComplexStmtBegin, "", bool) \
|
||||
AST_KIND(BlockStmt, "block statement", struct { \
|
||||
Array<Ast *> stmts; \
|
||||
Slice<Ast *> stmts; \
|
||||
Ast *label; \
|
||||
Token open, close; \
|
||||
}) \
|
||||
@@ -388,7 +392,7 @@ AST_KIND(_ComplexStmtBegin, "", bool) \
|
||||
}) \
|
||||
AST_KIND(ReturnStmt, "return statement", struct { \
|
||||
Token token; \
|
||||
Array<Ast *> results; \
|
||||
Slice<Ast *> results; \
|
||||
}) \
|
||||
AST_KIND(ForStmt, "for statement", struct { \
|
||||
Token token; \
|
||||
@@ -418,8 +422,8 @@ AST_KIND(_ComplexStmtBegin, "", bool) \
|
||||
}) \
|
||||
AST_KIND(CaseClause, "case clause", struct { \
|
||||
Token token; \
|
||||
Array<Ast *> list; \
|
||||
Array<Ast *> stmts; \
|
||||
Slice<Ast *> list; \
|
||||
Slice<Ast *> stmts; \
|
||||
Entity *implicit_entity; \
|
||||
}) \
|
||||
AST_KIND(SwitchStmt, "switch statement", struct { \
|
||||
@@ -436,12 +440,12 @@ AST_KIND(_ComplexStmtBegin, "", bool) \
|
||||
Ast *tag; \
|
||||
Ast *body; \
|
||||
bool partial; \
|
||||
}) \
|
||||
}) \
|
||||
AST_KIND(DeferStmt, "defer statement", struct { Token token; Ast *stmt; }) \
|
||||
AST_KIND(BranchStmt, "branch statement", struct { Token token; Ast *label; }) \
|
||||
AST_KIND(UsingStmt, "using statement", struct { \
|
||||
Token token; \
|
||||
Array<Ast *> list; \
|
||||
Slice<Ast *> list; \
|
||||
}) \
|
||||
AST_KIND(_ComplexStmtEnd, "", bool) \
|
||||
AST_KIND(_StmtEnd, "", bool) \
|
||||
@@ -459,9 +463,9 @@ AST_KIND(_DeclBegin, "", bool) \
|
||||
Ast *name; \
|
||||
}) \
|
||||
AST_KIND(ValueDecl, "value declaration", struct { \
|
||||
Array<Ast *> names; \
|
||||
Slice<Ast *> names; \
|
||||
Ast * type; \
|
||||
Array<Ast *> values; \
|
||||
Slice<Ast *> values; \
|
||||
Array<Ast *> attributes; \
|
||||
CommentGroup *docs; \
|
||||
CommentGroup *comment; \
|
||||
@@ -486,10 +490,10 @@ AST_KIND(_DeclBegin, "", bool) \
|
||||
}) \
|
||||
AST_KIND(ForeignImportDecl, "foreign import declaration", struct { \
|
||||
Token token; \
|
||||
Array<Token> filepaths; \
|
||||
Slice<Token> filepaths; \
|
||||
Token library_name; \
|
||||
String collection_name; \
|
||||
Array<String> fullpaths; \
|
||||
Slice<String> fullpaths; \
|
||||
Array<Ast *> attributes; \
|
||||
CommentGroup *docs; \
|
||||
CommentGroup *comment; \
|
||||
@@ -497,11 +501,11 @@ AST_KIND(_DeclBegin, "", bool) \
|
||||
AST_KIND(_DeclEnd, "", bool) \
|
||||
AST_KIND(Attribute, "attribute", struct { \
|
||||
Token token; \
|
||||
Array<Ast *> elems; \
|
||||
Slice<Ast *> elems; \
|
||||
Token open, close; \
|
||||
}) \
|
||||
AST_KIND(Field, "field", struct { \
|
||||
Array<Ast *> names; \
|
||||
Slice<Ast *> names; \
|
||||
Ast * type; \
|
||||
Ast * default_value; \
|
||||
Token tag; \
|
||||
@@ -511,7 +515,7 @@ AST_KIND(_DeclEnd, "", bool) \
|
||||
}) \
|
||||
AST_KIND(FieldList, "field list", struct { \
|
||||
Token token; \
|
||||
Array<Ast *> list; \
|
||||
Slice<Ast *> list; \
|
||||
}) \
|
||||
AST_KIND(_TypeBegin, "", bool) \
|
||||
AST_KIND(TypeidType, "typeid", struct { \
|
||||
@@ -565,34 +569,34 @@ AST_KIND(_TypeBegin, "", bool) \
|
||||
}) \
|
||||
AST_KIND(StructType, "struct type", struct { \
|
||||
Token token; \
|
||||
Array<Ast *> fields; \
|
||||
Slice<Ast *> fields; \
|
||||
isize field_count; \
|
||||
Ast *polymorphic_params; \
|
||||
Ast *align; \
|
||||
Token where_token; \
|
||||
Array<Ast *> where_clauses; \
|
||||
Slice<Ast *> where_clauses; \
|
||||
bool is_packed; \
|
||||
bool is_raw_union; \
|
||||
}) \
|
||||
AST_KIND(UnionType, "union type", struct { \
|
||||
Token token; \
|
||||
Array<Ast *> variants; \
|
||||
Slice<Ast *> variants; \
|
||||
Ast *polymorphic_params; \
|
||||
Ast * align; \
|
||||
bool maybe; \
|
||||
bool no_nil; \
|
||||
Token where_token; \
|
||||
Array<Ast *> where_clauses; \
|
||||
Slice<Ast *> where_clauses; \
|
||||
}) \
|
||||
AST_KIND(EnumType, "enum type", struct { \
|
||||
Token token; \
|
||||
Ast * base_type; \
|
||||
Array<Ast *> fields; /* FieldValue */ \
|
||||
Slice<Ast *> fields; /* FieldValue */ \
|
||||
bool is_using; \
|
||||
}) \
|
||||
AST_KIND(BitFieldType, "bit field type", struct { \
|
||||
Token token; \
|
||||
Array<Ast *> fields; /* FieldValue with : */ \
|
||||
Slice<Ast *> fields; /* FieldValue with : */ \
|
||||
Ast * align; \
|
||||
}) \
|
||||
AST_KIND(BitSetType, "bit set type", struct { \
|
||||
@@ -638,23 +642,22 @@ isize const ast_variant_sizes[] = {
|
||||
|
||||
struct AstCommonStuff {
|
||||
AstKind kind;
|
||||
u32 state_flags;
|
||||
u32 viral_state_flags;
|
||||
bool been_handled;
|
||||
u16 state_flags;
|
||||
u16 viral_state_flags;
|
||||
AstFile * file;
|
||||
Scope * scope;
|
||||
TypeAndValue tav;
|
||||
TypeAndValue tav; // TODO(bill): Make this a pointer to minimize pointer size
|
||||
};
|
||||
|
||||
struct Ast {
|
||||
AstKind kind;
|
||||
u32 state_flags;
|
||||
u32 viral_state_flags;
|
||||
bool been_handled;
|
||||
u16 state_flags;
|
||||
u16 viral_state_flags;
|
||||
AstFile * file;
|
||||
Scope * scope;
|
||||
TypeAndValue tav;
|
||||
TypeAndValue tav; // TODO(bill): Make this a pointer to minimize pointer size
|
||||
|
||||
// IMPORTANT NOTE(bill): This must be at the end since the AST is allocated to be size of the variant
|
||||
union {
|
||||
#define AST_KIND(_kind_name_, name, ...) GB_JOIN2(Ast, _kind_name_) _kind_name_;
|
||||
AST_KINDS
|
||||
|
||||
+91
-46
@@ -1,25 +1,30 @@
|
||||
typedef u32 PtrSetIndex;
|
||||
|
||||
struct PtrSetFindResult {
|
||||
isize hash_index;
|
||||
isize entry_prev;
|
||||
isize entry_index;
|
||||
PtrSetIndex hash_index;
|
||||
PtrSetIndex entry_prev;
|
||||
PtrSetIndex entry_index;
|
||||
};
|
||||
|
||||
enum : PtrSetIndex { PTR_SET_SENTINEL = ~(PtrSetIndex)0 };
|
||||
|
||||
|
||||
template <typename T>
|
||||
struct PtrSetEntry {
|
||||
T ptr;
|
||||
isize next;
|
||||
T ptr;
|
||||
PtrSetIndex next;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct PtrSet {
|
||||
Array<isize> hashes;
|
||||
Array<PtrSetIndex> hashes;
|
||||
Array<PtrSetEntry<T>> entries;
|
||||
};
|
||||
|
||||
template <typename T> void ptr_set_init (PtrSet<T> *s, gbAllocator a, isize capacity = 16);
|
||||
template <typename T> void ptr_set_destroy(PtrSet<T> *s);
|
||||
template <typename T> T ptr_set_add (PtrSet<T> *s, T ptr);
|
||||
template <typename T> bool ptr_set_update (PtrSet<T> *s, T ptr); // returns true if it previously existsed
|
||||
template <typename T> bool ptr_set_exists (PtrSet<T> *s, T ptr);
|
||||
template <typename T> void ptr_set_remove (PtrSet<T> *s, T ptr);
|
||||
template <typename T> void ptr_set_clear (PtrSet<T> *s);
|
||||
@@ -27,12 +32,31 @@ template <typename T> void ptr_set_grow (PtrSet<T> *s);
|
||||
template <typename T> void ptr_set_rehash (PtrSet<T> *s, isize new_count);
|
||||
|
||||
|
||||
isize next_pow2_isize(isize n) {
|
||||
if (n <= 0) {
|
||||
return 0;
|
||||
}
|
||||
n--;
|
||||
n |= n >> 1;
|
||||
n |= n >> 2;
|
||||
n |= n >> 4;
|
||||
n |= n >> 8;
|
||||
n |= n >> 16;
|
||||
if (gb_size_of(isize) == 8) {
|
||||
n |= n >> 32;
|
||||
}
|
||||
n++;
|
||||
return n;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void ptr_set_init(PtrSet<T> *s, gbAllocator a, isize capacity) {
|
||||
capacity = next_pow2_isize(gb_max(16, capacity));
|
||||
|
||||
array_init(&s->hashes, a, capacity);
|
||||
array_init(&s->entries, a, 0, capacity);
|
||||
for (isize i = 0; i < capacity; i++) {
|
||||
s->hashes.data[i] = -1;
|
||||
s->hashes.data[i] = PTR_SET_SENTINEL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,72 +67,69 @@ void ptr_set_destroy(PtrSet<T> *s) {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
gb_internal isize ptr_set__add_entry(PtrSet<T> *s, T ptr) {
|
||||
gb_internal PtrSetIndex ptr_set__add_entry(PtrSet<T> *s, T ptr) {
|
||||
PtrSetEntry<T> e = {};
|
||||
e.ptr = ptr;
|
||||
e.next = -1;
|
||||
e.next = PTR_SET_SENTINEL;
|
||||
array_add(&s->entries, e);
|
||||
return s->entries.count-1;
|
||||
return cast(PtrSetIndex)(s->entries.count-1);
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
gb_internal PtrSetFindResult ptr_set__find(PtrSet<T> *s, T ptr) {
|
||||
PtrSetFindResult fr = {-1, -1, -1};
|
||||
if (s->hashes.count > 0) {
|
||||
PtrSetFindResult fr = {PTR_SET_SENTINEL, PTR_SET_SENTINEL, PTR_SET_SENTINEL};
|
||||
if (s->hashes.count != 0) {
|
||||
u64 hash = 0xcbf29ce484222325ull ^ cast(u64)cast(uintptr)ptr;
|
||||
u64 n = cast(u64)s->hashes.count;
|
||||
fr.hash_index = cast(isize)(hash % n);
|
||||
fr.entry_index = s->hashes[fr.hash_index];
|
||||
while (fr.entry_index >= 0) {
|
||||
if (s->entries[fr.entry_index].ptr == ptr) {
|
||||
fr.hash_index = cast(PtrSetIndex)(hash & (n-1));
|
||||
fr.entry_index = s->hashes.data[fr.hash_index];
|
||||
while (fr.entry_index != PTR_SET_SENTINEL) {
|
||||
if (s->entries.data[fr.entry_index].ptr == ptr) {
|
||||
return fr;
|
||||
}
|
||||
fr.entry_prev = fr.entry_index;
|
||||
fr.entry_index = s->entries[fr.entry_index].next;
|
||||
fr.entry_index = s->entries.data[fr.entry_index].next;
|
||||
}
|
||||
}
|
||||
return fr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
gb_internal b32 ptr_set__full(PtrSet<T> *s) {
|
||||
gb_internal bool ptr_set__full(PtrSet<T> *s) {
|
||||
return 0.75f * s->hashes.count <= s->entries.count;
|
||||
}
|
||||
|
||||
#define PTR_ARRAY_GROW_FORMULA(x) (4*(x) + 7)
|
||||
GB_STATIC_ASSERT(PTR_ARRAY_GROW_FORMULA(0) > 0);
|
||||
|
||||
template <typename T>
|
||||
gb_inline void ptr_set_grow(PtrSet<T> *s) {
|
||||
isize new_count = PTR_ARRAY_GROW_FORMULA(s->entries.count);
|
||||
isize new_count = s->hashes.count*2;
|
||||
ptr_set_rehash(s, new_count);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void ptr_set_rehash(PtrSet<T> *s, isize new_count) {
|
||||
isize i, j;
|
||||
PtrSetIndex i, j;
|
||||
PtrSet<T> ns = {};
|
||||
ptr_set_init(&ns, s->hashes.allocator);
|
||||
array_resize(&ns.hashes, new_count);
|
||||
array_reserve(&ns.entries, s->entries.count);
|
||||
for (i = 0; i < new_count; i++) {
|
||||
ns.hashes[i] = -1;
|
||||
ns.hashes.data[i] = PTR_SET_SENTINEL;
|
||||
}
|
||||
for (i = 0; i < s->entries.count; i++) {
|
||||
PtrSetEntry<T> *e = &s->entries[i];
|
||||
PtrSetEntry<T> *e = &s->entries.data[i];
|
||||
PtrSetFindResult fr;
|
||||
if (ns.hashes.count == 0) {
|
||||
ptr_set_grow(&ns);
|
||||
}
|
||||
fr = ptr_set__find(&ns, e->ptr);
|
||||
j = ptr_set__add_entry(&ns, e->ptr);
|
||||
if (fr.entry_prev < 0) {
|
||||
ns.hashes[fr.hash_index] = j;
|
||||
if (fr.entry_prev == PTR_SET_SENTINEL) {
|
||||
ns.hashes.data[fr.hash_index] = j;
|
||||
} else {
|
||||
ns.entries[fr.entry_prev].next = j;
|
||||
ns.entries.data[fr.entry_prev].next = j;
|
||||
}
|
||||
ns.entries[j].next = fr.entry_index;
|
||||
ns.entries.data[j].next = fr.entry_index;
|
||||
if (ptr_set__full(&ns)) {
|
||||
ptr_set_grow(&ns);
|
||||
}
|
||||
@@ -120,26 +141,24 @@ void ptr_set_rehash(PtrSet<T> *s, isize new_count) {
|
||||
template <typename T>
|
||||
gb_inline bool ptr_set_exists(PtrSet<T> *s, T ptr) {
|
||||
isize index = ptr_set__find(s, ptr).entry_index;
|
||||
return index >= 0;
|
||||
return index != PTR_SET_SENTINEL;
|
||||
}
|
||||
|
||||
// Returns true if it already exists
|
||||
template <typename T>
|
||||
T ptr_set_add(PtrSet<T> *s, T ptr) {
|
||||
isize index;
|
||||
PtrSetIndex index;
|
||||
PtrSetFindResult fr;
|
||||
if (s->hashes.count == 0) {
|
||||
ptr_set_grow(s);
|
||||
}
|
||||
fr = ptr_set__find(s, ptr);
|
||||
if (fr.entry_index >= 0) {
|
||||
index = fr.entry_index;
|
||||
} else {
|
||||
if (fr.entry_index == PTR_SET_SENTINEL) {
|
||||
index = ptr_set__add_entry(s, ptr);
|
||||
if (fr.entry_prev >= 0) {
|
||||
s->entries[fr.entry_prev].next = index;
|
||||
if (fr.entry_prev != PTR_SET_SENTINEL) {
|
||||
s->entries.data[fr.entry_prev].next = index;
|
||||
} else {
|
||||
s->hashes[fr.hash_index] = index;
|
||||
s->hashes.data[fr.hash_index] = index;
|
||||
}
|
||||
}
|
||||
if (ptr_set__full(s)) {
|
||||
@@ -148,32 +167,58 @@ T ptr_set_add(PtrSet<T> *s, T ptr) {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool ptr_set_update(PtrSet<T> *s, T ptr) { // returns true if it previously existsed
|
||||
bool exists = false;
|
||||
PtrSetIndex index;
|
||||
PtrSetFindResult fr;
|
||||
if (s->hashes.count == 0) {
|
||||
ptr_set_grow(s);
|
||||
}
|
||||
fr = ptr_set__find(s, ptr);
|
||||
if (fr.entry_index != PTR_SET_SENTINEL) {
|
||||
exists = true;
|
||||
} else {
|
||||
index = ptr_set__add_entry(s, ptr);
|
||||
if (fr.entry_prev != PTR_SET_SENTINEL) {
|
||||
s->entries.data[fr.entry_prev].next = index;
|
||||
} else {
|
||||
s->hashes.data[fr.hash_index] = index;
|
||||
}
|
||||
}
|
||||
if (ptr_set__full(s)) {
|
||||
ptr_set_grow(s);
|
||||
}
|
||||
return exists;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <typename T>
|
||||
void ptr_set__erase(PtrSet<T> *s, PtrSetFindResult fr) {
|
||||
PtrSetFindResult last;
|
||||
if (fr.entry_prev < 0) {
|
||||
s->hashes[fr.hash_index] = s->entries[fr.entry_index].next;
|
||||
if (fr.entry_prev == PTR_SET_SENTINEL) {
|
||||
s->hashes.data[fr.hash_index] = s->entries.data[fr.entry_index].next;
|
||||
} else {
|
||||
s->entries[fr.entry_prev].next = s->entries[fr.entry_index].next;
|
||||
s->entries.data[fr.entry_prev].next = s->entries.data[fr.entry_index].next;
|
||||
}
|
||||
if (fr.entry_index == s->entries.count-1) {
|
||||
array_pop(&s->entries);
|
||||
return;
|
||||
}
|
||||
s->entries[fr.entry_index] = s->entries[s->entries.count-1];
|
||||
last = ptr_set__find(s, s->entries[fr.entry_index].ptr);
|
||||
if (last.entry_prev >= 0) {
|
||||
s->entries[last.entry_prev].next = fr.entry_index;
|
||||
s->entries.data[fr.entry_index] = s->entries.data[s->entries.count-1];
|
||||
last = ptr_set__find(s, s->entries.data[fr.entry_index].ptr);
|
||||
if (last.entry_prev != PTR_SET_SENTINEL) {
|
||||
s->entries.data[last.entry_prev].next = fr.entry_index;
|
||||
} else {
|
||||
s->hashes[last.hash_index] = fr.entry_index;
|
||||
s->hashes.data[last.hash_index] = fr.entry_index;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void ptr_set_remove(PtrSet<T> *s, T ptr) {
|
||||
PtrSetFindResult fr = ptr_set__find(s, ptr);
|
||||
if (fr.entry_index >= 0) {
|
||||
if (fr.entry_index != PTR_SET_SENTINEL) {
|
||||
ptr_set__erase(s, fr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,6 +164,7 @@ int string_compare(String const &x, String const &y) {
|
||||
return cast(int)x[offset] - cast(int)y[offset];
|
||||
}
|
||||
}
|
||||
return cast(int)(x.len - y.len);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -118,8 +118,6 @@ TOKEN_KIND(Token__KeywordBegin, ""), \
|
||||
TOKEN_KIND(Token_no_inline, "no_inline"), \
|
||||
TOKEN_KIND(Token_context, "context"), \
|
||||
TOKEN_KIND(Token_asm, "asm"), \
|
||||
TOKEN_KIND(Token_macro, "macro"), \
|
||||
TOKEN_KIND(Token_const, "const"), \
|
||||
TOKEN_KIND(Token__KeywordEnd, ""), \
|
||||
TOKEN_KIND(Token_Count, "")
|
||||
|
||||
|
||||
+224
-68
@@ -323,6 +323,8 @@ String const type_strings[] = {
|
||||
enum TypeFlag : u32 {
|
||||
TypeFlag_Polymorphic = 1<<1,
|
||||
TypeFlag_PolySpecialized = 1<<2,
|
||||
TypeFlag_InProcessOfCheckingPolymorphic = 1<<3,
|
||||
TypeFlag_InProcessOfCheckingABI = 1<<4,
|
||||
};
|
||||
|
||||
struct Type {
|
||||
@@ -371,7 +373,28 @@ enum Typeid_Kind : u8 {
|
||||
Typeid_Relative_Slice,
|
||||
};
|
||||
|
||||
// IMPORTANT NOTE(bill): This must match the same as the in core.odin
|
||||
enum TypeInfoFlag : u32 {
|
||||
TypeInfoFlag_Comparable = 1<<0,
|
||||
TypeInfoFlag_Simple_Compare = 1<<1,
|
||||
};
|
||||
|
||||
bool is_type_comparable(Type *t);
|
||||
bool is_type_simple_compare(Type *t);
|
||||
|
||||
u32 type_info_flags_of_type(Type *type) {
|
||||
if (type == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
u32 flags = 0;
|
||||
if (is_type_comparable(type)) {
|
||||
flags |= TypeInfoFlag_Comparable;
|
||||
}
|
||||
if (is_type_simple_compare(type)) {
|
||||
flags |= TypeInfoFlag_Comparable;
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
||||
|
||||
// TODO(bill): Should I add extra information here specifying the kind of selection?
|
||||
@@ -661,12 +684,15 @@ gb_global Type *t_context_ptr = nullptr;
|
||||
gb_global Type *t_source_code_location = nullptr;
|
||||
gb_global Type *t_source_code_location_ptr = nullptr;
|
||||
|
||||
gb_global Type *t_map_key = nullptr;
|
||||
gb_global Type *t_map_hash = nullptr;
|
||||
gb_global Type *t_map_header = nullptr;
|
||||
|
||||
gb_global Type *t_vector_x86_mmx = nullptr;
|
||||
|
||||
|
||||
gb_global Type *t_equal_proc = nullptr;
|
||||
gb_global Type *t_hasher_proc = nullptr;
|
||||
|
||||
|
||||
i64 type_size_of (Type *t);
|
||||
i64 type_align_of (Type *t);
|
||||
@@ -769,7 +795,8 @@ void set_base_type(Type *t, Type *base) {
|
||||
|
||||
|
||||
Type *alloc_type(TypeKind kind) {
|
||||
gbAllocator a = heap_allocator();
|
||||
// gbAllocator a = heap_allocator();
|
||||
gbAllocator a = permanent_allocator();
|
||||
Type *t = gb_alloc_item(a, Type);
|
||||
zero_item(t);
|
||||
t->kind = kind;
|
||||
@@ -884,6 +911,25 @@ Type *alloc_type_named(String name, Type *base, Entity *type_name) {
|
||||
return t;
|
||||
}
|
||||
|
||||
bool is_calling_convention_none(ProcCallingConvention calling_convention) {
|
||||
switch (calling_convention) {
|
||||
case ProcCC_None:
|
||||
case ProcCC_PureNone:
|
||||
case ProcCC_InlineAsm:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool is_calling_convention_odin(ProcCallingConvention calling_convention) {
|
||||
switch (calling_convention) {
|
||||
case ProcCC_Odin:
|
||||
case ProcCC_Contextless:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Type *alloc_type_tuple() {
|
||||
Type *t = alloc_type(Type_Tuple);
|
||||
return t;
|
||||
@@ -918,7 +964,6 @@ bool is_type_valid_for_keys(Type *t);
|
||||
|
||||
Type *alloc_type_map(i64 count, Type *key, Type *value) {
|
||||
if (key != nullptr) {
|
||||
GB_ASSERT(is_type_valid_for_keys(key));
|
||||
GB_ASSERT(value != nullptr);
|
||||
}
|
||||
Type *t = alloc_type(Type_Map);
|
||||
@@ -1192,20 +1237,6 @@ bool is_type_slice(Type *t) {
|
||||
t = base_type(t);
|
||||
return t->kind == Type_Slice;
|
||||
}
|
||||
bool is_type_u8_slice(Type *t) {
|
||||
t = base_type(t);
|
||||
if (t->kind == Type_Slice) {
|
||||
return is_type_u8(t->Slice.elem);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool is_type_u8_ptr(Type *t) {
|
||||
t = base_type(t);
|
||||
if (t->kind == Type_Pointer) {
|
||||
return is_type_u8(t->Slice.elem);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool is_type_proc(Type *t) {
|
||||
t = base_type(t);
|
||||
return t->kind == Type_Proc;
|
||||
@@ -1249,6 +1280,37 @@ bool is_type_relative_slice(Type *t) {
|
||||
return t->kind == Type_RelativeSlice;
|
||||
}
|
||||
|
||||
bool is_type_u8_slice(Type *t) {
|
||||
t = base_type(t);
|
||||
if (t->kind == Type_Slice) {
|
||||
return is_type_u8(t->Slice.elem);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool is_type_u8_array(Type *t) {
|
||||
t = base_type(t);
|
||||
if (t->kind == Type_Array) {
|
||||
return is_type_u8(t->Array.elem);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool is_type_u8_ptr(Type *t) {
|
||||
t = base_type(t);
|
||||
if (t->kind == Type_Pointer) {
|
||||
return is_type_u8(t->Slice.elem);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool is_type_rune_array(Type *t) {
|
||||
t = base_type(t);
|
||||
if (t->kind == Type_Array) {
|
||||
return is_type_rune(t->Array.elem);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Type *core_array_type(Type *t) {
|
||||
for (;;) {
|
||||
@@ -1261,53 +1323,7 @@ Type *core_array_type(Type *t) {
|
||||
return t;
|
||||
}
|
||||
|
||||
// NOTE(bill): type can be easily compared using memcmp
|
||||
bool is_type_simple_compare(Type *t) {
|
||||
t = core_type(t);
|
||||
switch (t->kind) {
|
||||
case Type_Array:
|
||||
return is_type_simple_compare(t->Array.elem);
|
||||
|
||||
case Type_EnumeratedArray:
|
||||
return is_type_simple_compare(t->EnumeratedArray.elem);
|
||||
|
||||
case Type_Basic:
|
||||
if (t->Basic.flags & BasicFlag_SimpleCompare) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
case Type_Pointer:
|
||||
case Type_Proc:
|
||||
case Type_BitSet:
|
||||
case Type_BitField:
|
||||
return true;
|
||||
|
||||
case Type_Struct:
|
||||
for_array(i, t->Struct.fields) {
|
||||
Entity *f = t->Struct.fields[i];
|
||||
if (!is_type_simple_compare(f->type)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
case Type_Union:
|
||||
for_array(i, t->Union.variants) {
|
||||
Type *v = t->Union.variants[i];
|
||||
if (!is_type_simple_compare(v)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
case Type_SimdVector:
|
||||
return is_type_simple_compare(t->SimdVector.elem);
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Type *base_complex_elem_type(Type *t) {
|
||||
t = core_type(t);
|
||||
@@ -1526,6 +1542,8 @@ bool is_type_valid_for_keys(Type *t) {
|
||||
if (is_type_untyped(t)) {
|
||||
return false;
|
||||
}
|
||||
return is_type_comparable(t);
|
||||
#if 0
|
||||
if (is_type_integer(t)) {
|
||||
return true;
|
||||
}
|
||||
@@ -1541,8 +1559,15 @@ bool is_type_valid_for_keys(Type *t) {
|
||||
if (is_type_typeid(t)) {
|
||||
return true;
|
||||
}
|
||||
if (is_type_simple_compare(t)) {
|
||||
return true;
|
||||
}
|
||||
if (is_type_comparable(t)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool is_type_valid_bit_set_elem(Type *t) {
|
||||
@@ -1695,12 +1720,23 @@ TypeTuple *get_record_polymorphic_params(Type *t) {
|
||||
|
||||
|
||||
bool is_type_polymorphic(Type *t, bool or_specialized=false) {
|
||||
if (t->flags & TypeFlag_InProcessOfCheckingPolymorphic) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (t->kind) {
|
||||
case Type_Generic:
|
||||
return true;
|
||||
|
||||
case Type_Named:
|
||||
return is_type_polymorphic(t->Named.base, or_specialized);
|
||||
{
|
||||
u32 flags = t->flags;
|
||||
t->flags |= TypeFlag_InProcessOfCheckingPolymorphic;
|
||||
bool ok = is_type_polymorphic(t->Named.base, or_specialized);
|
||||
t->flags = flags;
|
||||
return ok;
|
||||
}
|
||||
|
||||
case Type_Opaque:
|
||||
return is_type_polymorphic(t->Opaque.elem, or_specialized);
|
||||
case Type_Pointer:
|
||||
@@ -1892,10 +1928,77 @@ bool is_type_comparable(Type *t) {
|
||||
|
||||
case Type_Opaque:
|
||||
return is_type_comparable(t->Opaque.elem);
|
||||
|
||||
case Type_Struct:
|
||||
if (type_size_of(t) == 0) {
|
||||
return false;
|
||||
}
|
||||
if (t->Struct.is_raw_union) {
|
||||
return is_type_simple_compare(t);
|
||||
}
|
||||
for_array(i, t->Struct.fields) {
|
||||
Entity *f = t->Struct.fields[i];
|
||||
if (!is_type_comparable(f->type)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// NOTE(bill): type can be easily compared using memcmp
|
||||
bool is_type_simple_compare(Type *t) {
|
||||
t = core_type(t);
|
||||
switch (t->kind) {
|
||||
case Type_Array:
|
||||
return is_type_simple_compare(t->Array.elem);
|
||||
|
||||
case Type_EnumeratedArray:
|
||||
return is_type_simple_compare(t->EnumeratedArray.elem);
|
||||
|
||||
case Type_Basic:
|
||||
if (t->Basic.flags & BasicFlag_SimpleCompare) {
|
||||
return true;
|
||||
}
|
||||
if (t->Basic.kind == Basic_typeid) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
case Type_Pointer:
|
||||
case Type_Proc:
|
||||
case Type_BitSet:
|
||||
case Type_BitField:
|
||||
return true;
|
||||
|
||||
case Type_Struct:
|
||||
for_array(i, t->Struct.fields) {
|
||||
Entity *f = t->Struct.fields[i];
|
||||
if (!is_type_simple_compare(f->type)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
case Type_Union:
|
||||
for_array(i, t->Union.variants) {
|
||||
Type *v = t->Union.variants[i];
|
||||
if (!is_type_simple_compare(v)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
case Type_SimdVector:
|
||||
return is_type_simple_compare(t->SimdVector.elem);
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Type *strip_type_aliasing(Type *x) {
|
||||
if (x == nullptr) {
|
||||
return x;
|
||||
@@ -2317,7 +2420,7 @@ Selection lookup_field_from_index(Type *type, i64 index) {
|
||||
GB_ASSERT(is_type_struct(type) || is_type_union(type) || is_type_tuple(type));
|
||||
type = base_type(type);
|
||||
|
||||
gbAllocator a = heap_allocator();
|
||||
gbAllocator a = permanent_allocator();
|
||||
isize max_count = 0;
|
||||
switch (type->kind) {
|
||||
case Type_Struct: max_count = type->Struct.fields.count; break;
|
||||
@@ -2365,7 +2468,6 @@ Selection lookup_field_from_index(Type *type, i64 index) {
|
||||
return empty_selection;
|
||||
}
|
||||
|
||||
|
||||
Entity *scope_lookup_current(Scope *s, String const &name);
|
||||
|
||||
Selection lookup_field_with_selection(Type *type_, String field_name, bool is_type, Selection sel, bool allow_blank_ident) {
|
||||
@@ -2375,7 +2477,6 @@ Selection lookup_field_with_selection(Type *type_, String field_name, bool is_ty
|
||||
return empty_selection;
|
||||
}
|
||||
|
||||
gbAllocator a = heap_allocator();
|
||||
Type *type = type_deref(type_);
|
||||
bool is_ptr = type != type_;
|
||||
sel.indirect = sel.indirect || is_ptr;
|
||||
@@ -2964,7 +3065,7 @@ i64 type_align_of_internal(Type *t, TypePath *path) {
|
||||
}
|
||||
|
||||
Array<i64> type_set_offsets_of(Array<Entity *> const &fields, bool is_packed, bool is_raw_union) {
|
||||
gbAllocator a = heap_allocator();
|
||||
gbAllocator a = permanent_allocator();
|
||||
auto offsets = array_make<i64>(a, fields.count);
|
||||
i64 curr_offset = 0;
|
||||
if (is_raw_union) {
|
||||
@@ -3353,6 +3454,58 @@ Type *reduce_tuple_to_single_type(Type *original_type) {
|
||||
}
|
||||
|
||||
|
||||
Type *alloc_type_struct_from_field_types(Type **field_types, isize field_count, bool is_packed) {
|
||||
Type *t = alloc_type_struct();
|
||||
t->Struct.fields = array_make<Entity *>(heap_allocator(), field_count);
|
||||
|
||||
Scope *scope = nullptr;
|
||||
for_array(i, t->Struct.fields) {
|
||||
t->Struct.fields[i] = alloc_entity_field(scope, blank_token, field_types[i], false, cast(i32)i, EntityState_Resolved);
|
||||
}
|
||||
t->Struct.is_packed = is_packed;
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
Type *alloc_type_tuple_from_field_types(Type **field_types, isize field_count, bool is_packed, bool must_be_tuple) {
|
||||
if (field_count == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!must_be_tuple && field_count == 1) {
|
||||
return field_types[0];
|
||||
}
|
||||
|
||||
Type *t = alloc_type_tuple();
|
||||
t->Tuple.variables = array_make<Entity *>(heap_allocator(), field_count);
|
||||
|
||||
Scope *scope = nullptr;
|
||||
for_array(i, t->Tuple.variables) {
|
||||
t->Tuple.variables[i] = alloc_entity_param(scope, blank_token, field_types[i], false, false);
|
||||
}
|
||||
t->Tuple.is_packed = is_packed;
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
Type *alloc_type_proc_from_types(Type **param_types, unsigned param_count, Type *results, bool is_c_vararg, ProcCallingConvention calling_convention) {
|
||||
|
||||
Type *params = alloc_type_tuple_from_field_types(param_types, param_count, false, true);
|
||||
isize results_count = 0;
|
||||
if (results != nullptr) {
|
||||
if (results->kind != Type_Tuple) {
|
||||
results = alloc_type_tuple_from_field_types(&results, 1, false, true);
|
||||
}
|
||||
results_count = results->Tuple.variables.count;
|
||||
}
|
||||
|
||||
Scope *scope = nullptr;
|
||||
Type *t = alloc_type_proc(scope, params, param_count, results, results_count, false, calling_convention);
|
||||
t->Proc.c_vararg = is_c_vararg;
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
|
||||
gbString write_type_to_string(gbString str, Type *type) {
|
||||
if (type == nullptr) {
|
||||
return gb_string_appendc(str, "<no type>");
|
||||
@@ -3671,3 +3824,6 @@ gbString type_to_string(Type *type) {
|
||||
return write_type_to_string(gb_string_make(heap_allocator(), ""), type);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user