mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-31 11:50:07 +00:00
Merge remote-tracking branch 'offical/master'
This commit is contained in:
@@ -1857,6 +1857,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
case BuiltinProc_objc_register_class:
|
||||
case BuiltinProc_atomic_type_is_lock_free:
|
||||
case BuiltinProc_has_target_feature:
|
||||
case BuiltinProc_procedure_of:
|
||||
// NOTE(bill): The first arg may be a Type, this will be checked case by case
|
||||
break;
|
||||
|
||||
@@ -6171,6 +6172,51 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
break;
|
||||
}
|
||||
|
||||
case BuiltinProc_procedure_of:
|
||||
{
|
||||
Ast *call_expr = unparen_expr(ce->args[0]);
|
||||
Operand op = {};
|
||||
check_expr_base(c, &op, ce->args[0], nullptr);
|
||||
if (op.mode != Addressing_Value && !(call_expr && call_expr->kind == Ast_CallExpr)) {
|
||||
error(ce->args[0], "Expected a call expression for '%.*s'", LIT(builtin_name));
|
||||
return false;
|
||||
}
|
||||
|
||||
Ast *proc = call_expr->CallExpr.proc;
|
||||
Entity *e = entity_of_node(proc);
|
||||
|
||||
if (e == nullptr) {
|
||||
error(ce->args[0], "Invalid procedure value, expected a regular/specialized procedure");
|
||||
return false;
|
||||
}
|
||||
|
||||
TypeAndValue tav = proc->tav;
|
||||
|
||||
|
||||
operand->type = e->type;
|
||||
operand->mode = Addressing_Value;
|
||||
operand->value = tav.value;
|
||||
operand->builtin_id = BuiltinProc_Invalid;
|
||||
operand->proc_group = nullptr;
|
||||
|
||||
if (tav.mode == Addressing_Builtin) {
|
||||
operand->mode = tav.mode;
|
||||
operand->builtin_id = cast(BuiltinProcId)e->Builtin.id;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!is_type_proc(e->type)) {
|
||||
gbString s = type_to_string(e->type);
|
||||
error(ce->args[0], "Expected a procedure value, got '%s'", s);
|
||||
gb_string_free(s);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
ce->entity_procedure_of = e;
|
||||
break;
|
||||
}
|
||||
|
||||
case BuiltinProc_constant_utf16_cstring:
|
||||
{
|
||||
String value = {};
|
||||
|
||||
+23
-6
@@ -88,11 +88,17 @@ gb_internal Type *check_init_variable(CheckerContext *ctx, Entity *e, Operand *o
|
||||
e->type = t_invalid;
|
||||
return nullptr;
|
||||
} else if (is_type_polymorphic(t)) {
|
||||
gbString str = type_to_string(t);
|
||||
defer (gb_string_free(str));
|
||||
error(e->token, "Invalid use of a polymorphic type '%s' in %.*s", str, LIT(context_name));
|
||||
e->type = t_invalid;
|
||||
return nullptr;
|
||||
Entity *e = entity_of_node(operand->expr);
|
||||
if (e == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
if (e->state.load() != EntityState_Resolved) {
|
||||
gbString str = type_to_string(t);
|
||||
defer (gb_string_free(str));
|
||||
error(e->token, "Invalid use of a polymorphic type '%s' in %.*s", str, LIT(context_name));
|
||||
e->type = t_invalid;
|
||||
return nullptr;
|
||||
}
|
||||
} else if (is_type_empty_union(t)) {
|
||||
gbString str = type_to_string(t);
|
||||
defer (gb_string_free(str));
|
||||
@@ -479,6 +485,9 @@ gb_internal void check_const_decl(CheckerContext *ctx, Entity *e, Ast *type_expr
|
||||
entity = check_selector(ctx, &operand, init, e->type);
|
||||
} else {
|
||||
check_expr_or_type(ctx, &operand, init, e->type);
|
||||
if (init->kind == Ast_CallExpr) {
|
||||
entity = init->CallExpr.entity_procedure_of;
|
||||
}
|
||||
}
|
||||
|
||||
switch (operand.mode) {
|
||||
@@ -526,6 +535,7 @@ gb_internal void check_const_decl(CheckerContext *ctx, Entity *e, Ast *type_expr
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (entity != nullptr) {
|
||||
if (e->type != nullptr) {
|
||||
Operand x = {};
|
||||
@@ -1135,7 +1145,14 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
|
||||
}
|
||||
|
||||
if (ac.link_name.len > 0) {
|
||||
e->Procedure.link_name = ac.link_name;
|
||||
String ln = ac.link_name;
|
||||
e->Procedure.link_name = ln;
|
||||
if (ln == "memcpy" ||
|
||||
ln == "memmove" ||
|
||||
ln == "mem_copy" ||
|
||||
ln == "mem_copy_non_overlapping") {
|
||||
e->Procedure.is_memcpy_like = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (ac.deferred_procedure.entity != nullptr) {
|
||||
|
||||
+2
-1
@@ -578,6 +578,7 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E
|
||||
d->defer_use_checked = false;
|
||||
|
||||
Entity *entity = alloc_entity_procedure(nullptr, token, final_proc_type, tags);
|
||||
entity->state.store(EntityState_Resolved);
|
||||
entity->identifier = ident;
|
||||
|
||||
add_entity_and_decl_info(&nctx, ident, entity, d);
|
||||
@@ -7674,7 +7675,7 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c
|
||||
if (decl->proc_lit) {
|
||||
ast_node(pl, ProcLit, decl->proc_lit);
|
||||
if (pl->inlining == ProcInlining_no_inline) {
|
||||
error(call, "'#force_inline' cannot be applied to a procedure that has be marked as '#force_no_inline'");
|
||||
error(call, "'#force_inline' cannot be applied to a procedure that has been marked as '#force_no_inline'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+9
-1
@@ -2224,8 +2224,16 @@ gb_internal void check_expr_stmt(CheckerContext *ctx, Ast *node) {
|
||||
}
|
||||
if (do_require) {
|
||||
gbString expr_str = expr_to_string(ce->proc);
|
||||
defer (gb_string_free(expr_str));
|
||||
if (builtin_id) {
|
||||
String real_name = builtin_procs[builtin_id].name;
|
||||
if (real_name != make_string(cast(u8 const *)expr_str, gb_string_length(expr_str))) {
|
||||
error(node, "'%s' ('%.*s.%.*s') requires that its results must be handled", expr_str,
|
||||
LIT(builtin_proc_pkg_name[builtin_procs[builtin_id].pkg]), LIT(real_name));
|
||||
return;
|
||||
}
|
||||
}
|
||||
error(node, "'%s' requires that its results must be handled", expr_str);
|
||||
gb_string_free(expr_str);
|
||||
}
|
||||
return;
|
||||
} else if (expr && expr->kind == Ast_SelectorCallExpr) {
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
#include "entity.cpp"
|
||||
#include "types.cpp"
|
||||
|
||||
String get_final_microarchitecture();
|
||||
|
||||
gb_internal void check_expr(CheckerContext *c, Operand *operand, Ast *expression);
|
||||
gb_internal void check_expr_or_type(CheckerContext *c, Operand *operand, Ast *expression, Type *type_hint=nullptr);
|
||||
gb_internal void add_comparison_procedures_for_fields(CheckerContext *c, Type *t);
|
||||
@@ -1040,6 +1042,8 @@ gb_internal void init_universal(void) {
|
||||
add_global_enum_constant(fields, "ODIN_ARCH", bc->metrics.arch);
|
||||
add_global_string_constant("ODIN_ARCH_STRING", target_arch_names[bc->metrics.arch]);
|
||||
}
|
||||
|
||||
add_global_string_constant("ODIN_MICROARCH_STRING", get_final_microarchitecture());
|
||||
|
||||
{
|
||||
GlobalEnumValue values[BuildMode_COUNT] = {
|
||||
@@ -1130,6 +1134,17 @@ gb_internal void init_universal(void) {
|
||||
|
||||
add_global_constant("ODIN_COMPILE_TIMESTAMP", t_untyped_integer, exact_value_i64(odin_compile_timestamp()));
|
||||
|
||||
{
|
||||
String version = {};
|
||||
|
||||
#ifdef GIT_SHA
|
||||
version.text = cast(u8 *)GIT_SHA;
|
||||
version.len = gb_strlen(GIT_SHA);
|
||||
#endif
|
||||
|
||||
add_global_string_constant("ODIN_VERSION_HASH", version);
|
||||
}
|
||||
|
||||
{
|
||||
bool f16_supported = lb_use_new_pass_system();
|
||||
if (is_arch_wasm()) {
|
||||
@@ -1167,6 +1182,18 @@ gb_internal void init_universal(void) {
|
||||
add_global_constant("ODIN_SANITIZER_FLAGS", named_type, exact_value_u64(bc->sanitizer_flags));
|
||||
}
|
||||
|
||||
{
|
||||
GlobalEnumValue values[5] = {
|
||||
{"None", -1},
|
||||
{"Minimal", 0},
|
||||
{"Size", 1},
|
||||
{"Speed", 2},
|
||||
{"Aggressive", 3},
|
||||
};
|
||||
|
||||
auto fields = add_global_enum_type(str_lit("Odin_Optimization_Mode"), values, gb_count_of(values));
|
||||
add_global_enum_constant(fields, "ODIN_OPTIMIZATION_MODE", bc->optimization_level);
|
||||
}
|
||||
|
||||
|
||||
// Builtin Procedures
|
||||
@@ -1452,6 +1479,10 @@ gb_internal Entity *entity_of_node(Ast *expr) {
|
||||
case_ast_node(cc, CaseClause, expr);
|
||||
return cc->implicit_entity;
|
||||
case_end;
|
||||
|
||||
case_ast_node(ce, CallExpr, expr);
|
||||
return ce->entity_procedure_of;
|
||||
case_end;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -51,6 +51,12 @@ enum StmtFlag {
|
||||
enum BuiltinProcPkg {
|
||||
BuiltinProcPkg_builtin,
|
||||
BuiltinProcPkg_intrinsics,
|
||||
BuiltinProcPkg_COUNT
|
||||
};
|
||||
|
||||
String builtin_proc_pkg_name[BuiltinProcPkg_COUNT] = {
|
||||
str_lit("builtin"),
|
||||
str_lit("intrinsics"),
|
||||
};
|
||||
|
||||
struct BuiltinProc {
|
||||
|
||||
@@ -299,6 +299,8 @@ BuiltinProc__type_simple_boolean_end,
|
||||
|
||||
BuiltinProc__type_end,
|
||||
|
||||
BuiltinProc_procedure_of,
|
||||
|
||||
BuiltinProc___entry_point,
|
||||
|
||||
BuiltinProc_objc_send,
|
||||
@@ -614,6 +616,8 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
|
||||
|
||||
{STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
|
||||
|
||||
{STR_LIT("procedure_of"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
|
||||
{STR_LIT("__entry_point"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
|
||||
|
||||
{STR_LIT("objc_send"), 3, true, Expr_Expr, BuiltinProcPkg_intrinsics, false, true},
|
||||
|
||||
@@ -256,6 +256,7 @@ struct Entity {
|
||||
bool generated_from_polymorphic : 1;
|
||||
bool entry_point_only : 1;
|
||||
bool has_instrumentation : 1;
|
||||
bool is_memcpy_like : 1;
|
||||
} Procedure;
|
||||
struct {
|
||||
Array<Entity *> entities;
|
||||
|
||||
+2
-2
@@ -516,7 +516,7 @@ gb_internal void syntax_error_with_verbose_va(TokenPos const &pos, TokenPos end,
|
||||
|
||||
if (pos.line == 0) {
|
||||
error_out_empty();
|
||||
error_out_coloured("Syntax_Error: ", TerminalStyle_Normal, TerminalColour_Red);
|
||||
error_out_coloured("Syntax Error: ", TerminalStyle_Normal, TerminalColour_Red);
|
||||
error_out_va(fmt, va);
|
||||
error_out("\n");
|
||||
} else {
|
||||
@@ -527,7 +527,7 @@ gb_internal void syntax_error_with_verbose_va(TokenPos const &pos, TokenPos end,
|
||||
error_out_pos(pos);
|
||||
}
|
||||
if (has_ansi_terminal_colours()) {
|
||||
error_out_coloured("Syntax_Error: ", TerminalStyle_Normal, TerminalColour_Red);
|
||||
error_out_coloured("Syntax Error: ", TerminalStyle_Normal, TerminalColour_Red);
|
||||
}
|
||||
error_out_va(fmt, va);
|
||||
error_out("\n");
|
||||
|
||||
+136
-108
@@ -9,6 +9,11 @@
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef LLVM_IGNORE_VERIFICATION
|
||||
#define LLVM_IGNORE_VERIFICATION 0
|
||||
#endif
|
||||
|
||||
|
||||
#include "llvm_backend.hpp"
|
||||
#include "llvm_abi.cpp"
|
||||
#include "llvm_backend_opt.cpp"
|
||||
@@ -1125,6 +1130,53 @@ gb_internal void lb_finalize_objc_names(lbProcedure *p) {
|
||||
lb_end_procedure_body(p);
|
||||
}
|
||||
|
||||
gb_internal void lb_verify_function(lbModule *m, lbProcedure *p, bool dump_ll=false) {
|
||||
if (LLVM_IGNORE_VERIFICATION) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m->debug_builder && LLVMVerifyFunction(p->value, LLVMReturnStatusAction)) {
|
||||
char *llvm_error = nullptr;
|
||||
|
||||
gb_printf_err("LLVM CODE GEN FAILED FOR PROCEDURE: %.*s\n", LIT(p->name));
|
||||
LLVMDumpValue(p->value);
|
||||
gb_printf_err("\n");
|
||||
if (dump_ll) {
|
||||
gb_printf_err("\n\n\n");
|
||||
String filepath_ll = lb_filepath_ll_for_module(m);
|
||||
if (LLVMPrintModuleToFile(m->mod, cast(char const *)filepath_ll.text, &llvm_error)) {
|
||||
gb_printf_err("LLVM Error: %s\n", llvm_error);
|
||||
}
|
||||
}
|
||||
LLVMVerifyFunction(p->value, LLVMPrintMessageAction);
|
||||
exit_with_errors();
|
||||
}
|
||||
}
|
||||
|
||||
gb_internal WORKER_TASK_PROC(lb_llvm_module_verification_worker_proc) {
|
||||
char *llvm_error = nullptr;
|
||||
defer (LLVMDisposeMessage(llvm_error));
|
||||
lbModule *m = cast(lbModule *)data;
|
||||
|
||||
if (LLVMVerifyModule(m->mod, LLVMReturnStatusAction, &llvm_error)) {
|
||||
gb_printf_err("LLVM Error:\n%s\n", llvm_error);
|
||||
if (build_context.keep_temp_files) {
|
||||
TIME_SECTION("LLVM Print Module to File");
|
||||
String filepath_ll = lb_filepath_ll_for_module(m);
|
||||
if (LLVMPrintModuleToFile(m->mod, cast(char const *)filepath_ll.text, &llvm_error)) {
|
||||
gb_printf_err("LLVM Error: %s\n", llvm_error);
|
||||
exit_with_errors();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
exit_with_errors();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
gb_internal lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProcedure *objc_names, Array<lbGlobalVariable> &global_variables) { // Startup Runtime
|
||||
Type *proc_type = alloc_type_proc(nullptr, nullptr, 0, nullptr, 0, false, ProcCC_Odin);
|
||||
|
||||
@@ -1227,13 +1279,7 @@ gb_internal lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProc
|
||||
|
||||
lb_end_procedure_body(p);
|
||||
|
||||
if (!main_module->debug_builder && LLVMVerifyFunction(p->value, LLVMReturnStatusAction)) {
|
||||
gb_printf_err("LLVM CODE GEN FAILED FOR PROCEDURE: %s\n", "main");
|
||||
LLVMDumpValue(p->value);
|
||||
gb_printf_err("\n\n\n\n");
|
||||
LLVMVerifyFunction(p->value, LLVMAbortProcessAction);
|
||||
}
|
||||
|
||||
lb_verify_function(main_module, p);
|
||||
return p;
|
||||
}
|
||||
|
||||
@@ -1256,31 +1302,21 @@ gb_internal lbProcedure *lb_create_cleanup_runtime(lbModule *main_module) { // C
|
||||
|
||||
lb_end_procedure_body(p);
|
||||
|
||||
if (!main_module->debug_builder && LLVMVerifyFunction(p->value, LLVMReturnStatusAction)) {
|
||||
gb_printf_err("LLVM CODE GEN FAILED FOR PROCEDURE: %s\n", "main");
|
||||
LLVMDumpValue(p->value);
|
||||
gb_printf_err("\n\n\n\n");
|
||||
LLVMVerifyFunction(p->value, LLVMAbortProcessAction);
|
||||
}
|
||||
|
||||
lb_verify_function(main_module, p);
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
gb_internal WORKER_TASK_PROC(lb_generate_procedures_and_types_per_module) {
|
||||
lbModule *m = cast(lbModule *)data;
|
||||
for (Entity *e : m->global_procedures_and_types_to_create) {
|
||||
if (e->kind == Entity_TypeName) {
|
||||
(void)lb_get_entity_name(m, e);
|
||||
lb_type(m, e->type);
|
||||
}
|
||||
for (Entity *e : m->global_types_to_create) {
|
||||
(void)lb_get_entity_name(m, e);
|
||||
(void)lb_type(m, e->type);
|
||||
}
|
||||
|
||||
for (Entity *e : m->global_procedures_and_types_to_create) {
|
||||
if (e->kind == Entity_Procedure) {
|
||||
(void)lb_get_entity_name(m, e);
|
||||
array_add(&m->procedures_to_generate, lb_create_procedure(m, e));
|
||||
}
|
||||
for (Entity *e : m->global_procedures_to_create) {
|
||||
(void)lb_get_entity_name(m, e);
|
||||
array_add(&m->procedures_to_generate, lb_create_procedure(m, e));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1334,16 +1370,24 @@ gb_internal void lb_create_global_procedures_and_types(lbGenerator *gen, Checker
|
||||
m = lb_module_of_entity(gen, e);
|
||||
}
|
||||
|
||||
array_add(&m->global_procedures_and_types_to_create, e);
|
||||
if (e->kind == Entity_Procedure) {
|
||||
array_add(&m->global_procedures_to_create, e);
|
||||
} else if (e->kind == Entity_TypeName) {
|
||||
array_add(&m->global_types_to_create, e);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto const &entry : gen->modules) {
|
||||
lbModule *m = entry.value;
|
||||
if (do_threading) {
|
||||
if (do_threading) {
|
||||
for (auto const &entry : gen->modules) {
|
||||
lbModule *m = entry.value;
|
||||
thread_pool_add_task(lb_generate_procedures_and_types_per_module, m);
|
||||
} else {
|
||||
}
|
||||
} else {
|
||||
for (auto const &entry : gen->modules) {
|
||||
lbModule *m = entry.value;
|
||||
lb_generate_procedures_and_types_per_module(m);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
thread_pool_wait();
|
||||
@@ -2374,16 +2418,19 @@ gb_internal WORKER_TASK_PROC(lb_generate_procedures_worker_proc) {
|
||||
}
|
||||
|
||||
gb_internal void lb_generate_procedures(lbGenerator *gen, bool do_threading) {
|
||||
for (auto const &entry : gen->modules) {
|
||||
lbModule *m = entry.value;
|
||||
if (do_threading) {
|
||||
if (do_threading) {
|
||||
for (auto const &entry : gen->modules) {
|
||||
lbModule *m = entry.value;
|
||||
thread_pool_add_task(lb_generate_procedures_worker_proc, m);
|
||||
} else {
|
||||
}
|
||||
|
||||
thread_pool_wait();
|
||||
} else {
|
||||
for (auto const &entry : gen->modules) {
|
||||
lbModule *m = entry.value;
|
||||
lb_generate_procedures_worker_proc(m);
|
||||
}
|
||||
}
|
||||
|
||||
thread_pool_wait();
|
||||
}
|
||||
|
||||
gb_internal WORKER_TASK_PROC(lb_generate_missing_procedures_to_check_worker_proc) {
|
||||
@@ -2397,17 +2444,20 @@ gb_internal WORKER_TASK_PROC(lb_generate_missing_procedures_to_check_worker_proc
|
||||
}
|
||||
|
||||
gb_internal void lb_generate_missing_procedures(lbGenerator *gen, bool do_threading) {
|
||||
for (auto const &entry : gen->modules) {
|
||||
lbModule *m = entry.value;
|
||||
// NOTE(bill): procedures may be added during generation
|
||||
if (do_threading) {
|
||||
if (do_threading) {
|
||||
for (auto const &entry : gen->modules) {
|
||||
lbModule *m = entry.value;
|
||||
// NOTE(bill): procedures may be added during generation
|
||||
thread_pool_add_task(lb_generate_missing_procedures_to_check_worker_proc, m);
|
||||
} else {
|
||||
}
|
||||
thread_pool_wait();
|
||||
} else {
|
||||
for (auto const &entry : gen->modules) {
|
||||
lbModule *m = entry.value;
|
||||
// NOTE(bill): procedures may be added during generation
|
||||
lb_generate_missing_procedures_to_check_worker_proc(m);
|
||||
}
|
||||
}
|
||||
|
||||
thread_pool_wait();
|
||||
}
|
||||
|
||||
gb_internal void lb_debug_info_complete_types_and_finalize(lbGenerator *gen) {
|
||||
@@ -2420,32 +2470,45 @@ gb_internal void lb_debug_info_complete_types_and_finalize(lbGenerator *gen) {
|
||||
}
|
||||
|
||||
gb_internal void lb_llvm_function_passes(lbGenerator *gen, bool do_threading) {
|
||||
for (auto const &entry : gen->modules) {
|
||||
lbModule *m = entry.value;
|
||||
if (do_threading) {
|
||||
if (do_threading) {
|
||||
for (auto const &entry : gen->modules) {
|
||||
lbModule *m = entry.value;
|
||||
thread_pool_add_task(lb_llvm_function_pass_per_module, m);
|
||||
} else {
|
||||
}
|
||||
thread_pool_wait();
|
||||
} else {
|
||||
for (auto const &entry : gen->modules) {
|
||||
lbModule *m = entry.value;
|
||||
lb_llvm_function_pass_per_module(m);
|
||||
}
|
||||
}
|
||||
thread_pool_wait();
|
||||
}
|
||||
|
||||
|
||||
gb_internal void lb_llvm_module_passes(lbGenerator *gen, bool do_threading) {
|
||||
for (auto const &entry : gen->modules) {
|
||||
lbModule *m = entry.value;
|
||||
auto wd = gb_alloc_item(permanent_allocator(), lbLLVMModulePassWorkerData);
|
||||
wd->m = m;
|
||||
wd->target_machine = m->target_machine;
|
||||
if (do_threading) {
|
||||
for (auto const &entry : gen->modules) {
|
||||
lbModule *m = entry.value;
|
||||
auto wd = gb_alloc_item(permanent_allocator(), lbLLVMModulePassWorkerData);
|
||||
wd->m = m;
|
||||
wd->target_machine = m->target_machine;
|
||||
|
||||
if (do_threading) {
|
||||
thread_pool_add_task(lb_llvm_module_pass_worker_proc, wd);
|
||||
} else {
|
||||
if (do_threading) {
|
||||
thread_pool_add_task(lb_llvm_module_pass_worker_proc, wd);
|
||||
} else {
|
||||
lb_llvm_module_pass_worker_proc(wd);
|
||||
}
|
||||
}
|
||||
thread_pool_wait();
|
||||
} else {
|
||||
for (auto const &entry : gen->modules) {
|
||||
lbModule *m = entry.value;
|
||||
auto wd = gb_alloc_item(permanent_allocator(), lbLLVMModulePassWorkerData);
|
||||
wd->m = m;
|
||||
wd->target_machine = m->target_machine;
|
||||
lb_llvm_module_pass_worker_proc(wd);
|
||||
}
|
||||
}
|
||||
thread_pool_wait();
|
||||
}
|
||||
|
||||
gb_internal String lb_filepath_ll_for_module(lbModule *m) {
|
||||
@@ -2523,40 +2586,27 @@ gb_internal String lb_filepath_obj_for_module(lbModule *m) {
|
||||
return concatenate_strings(permanent_allocator(), path, ext);
|
||||
}
|
||||
|
||||
gb_internal WORKER_TASK_PROC(lb_llvm_module_verification_worker_proc) {
|
||||
char *llvm_error = nullptr;
|
||||
defer (LLVMDisposeMessage(llvm_error));
|
||||
lbModule *m = cast(lbModule *)data;
|
||||
if (LLVMVerifyModule(m->mod, LLVMReturnStatusAction, &llvm_error)) {
|
||||
gb_printf_err("LLVM Error:\n%s\n", llvm_error);
|
||||
if (build_context.keep_temp_files) {
|
||||
TIME_SECTION("LLVM Print Module to File");
|
||||
String filepath_ll = lb_filepath_ll_for_module(m);
|
||||
if (LLVMPrintModuleToFile(m->mod, cast(char const *)filepath_ll.text, &llvm_error)) {
|
||||
gb_printf_err("LLVM Error: %s\n", llvm_error);
|
||||
exit_with_errors();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
exit_with_errors();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
gb_internal bool lb_llvm_module_verification(lbGenerator *gen, bool do_threading) {
|
||||
for (auto const &entry : gen->modules) {
|
||||
lbModule *m = entry.value;
|
||||
if (do_threading) {
|
||||
if (LLVM_IGNORE_VERIFICATION) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (do_threading) {
|
||||
for (auto const &entry : gen->modules) {
|
||||
lbModule *m = entry.value;
|
||||
thread_pool_add_task(lb_llvm_module_verification_worker_proc, m);
|
||||
} else {
|
||||
}
|
||||
thread_pool_wait();
|
||||
|
||||
} else {
|
||||
for (auto const &entry : gen->modules) {
|
||||
lbModule *m = entry.value;
|
||||
if (lb_llvm_module_verification_worker_proc(m)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
thread_pool_wait();
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -2777,12 +2827,7 @@ gb_internal lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *star
|
||||
}
|
||||
|
||||
|
||||
if (!m->debug_builder && LLVMVerifyFunction(p->value, LLVMReturnStatusAction)) {
|
||||
gb_printf_err("LLVM CODE GEN FAILED FOR PROCEDURE: %s\n", "main");
|
||||
LLVMDumpValue(p->value);
|
||||
gb_printf_err("\n\n\n\n");
|
||||
LLVMVerifyFunction(p->value, LLVMAbortProcessAction);
|
||||
}
|
||||
lb_verify_function(m, p);
|
||||
|
||||
lb_run_function_pass_manager(default_function_pass_manager, p, lbFunctionPassManager_default);
|
||||
return p;
|
||||
@@ -2803,28 +2848,11 @@ gb_internal void lb_generate_procedure(lbModule *m, lbProcedure *p) {
|
||||
lb_end_procedure(p);
|
||||
|
||||
// Add Flags
|
||||
if (p->body != nullptr) {
|
||||
if (p->name == "memcpy" || p->name == "memmove" ||
|
||||
p->name == "runtime.mem_copy" || p->name == "mem_copy_non_overlapping" ||
|
||||
string_starts_with(p->name, str_lit("llvm.memcpy")) ||
|
||||
string_starts_with(p->name, str_lit("llvm.memmove"))) {
|
||||
p->flags |= lbProcedureFlag_WithoutMemcpyPass;
|
||||
}
|
||||
if (p->entity && p->entity->kind == Entity_Procedure && p->entity->Procedure.is_memcpy_like) {
|
||||
p->flags |= lbProcedureFlag_WithoutMemcpyPass;
|
||||
}
|
||||
|
||||
if (!m->debug_builder && LLVMVerifyFunction(p->value, LLVMReturnStatusAction)) {
|
||||
char *llvm_error = nullptr;
|
||||
|
||||
gb_printf_err("LLVM CODE GEN FAILED FOR PROCEDURE: %.*s\n", LIT(p->name));
|
||||
LLVMDumpValue(p->value);
|
||||
gb_printf_err("\n\n\n\n");
|
||||
String filepath_ll = lb_filepath_ll_for_module(m);
|
||||
if (LLVMPrintModuleToFile(m->mod, cast(char const *)filepath_ll.text, &llvm_error)) {
|
||||
gb_printf_err("LLVM Error: %s\n", llvm_error);
|
||||
}
|
||||
LLVMVerifyFunction(p->value, LLVMPrintMessageAction);
|
||||
exit_with_errors();
|
||||
}
|
||||
lb_verify_function(m, p, true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -181,7 +181,8 @@ struct lbModule {
|
||||
std::atomic<u32> nested_type_name_guid;
|
||||
|
||||
Array<lbProcedure *> procedures_to_generate;
|
||||
Array<Entity *> global_procedures_and_types_to_create;
|
||||
Array<Entity *> global_procedures_to_create;
|
||||
Array<Entity *> global_types_to_create;
|
||||
|
||||
lbProcedure *curr_procedure;
|
||||
|
||||
|
||||
+18
-18
@@ -626,50 +626,50 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) {
|
||||
case Basic_complex32:
|
||||
{
|
||||
LLVMMetadataRef elements[2] = {};
|
||||
elements[0] = lb_debug_struct_field(m, str_lit("real"), t_f16, 0);
|
||||
elements[1] = lb_debug_struct_field(m, str_lit("imag"), t_f16, 4);
|
||||
elements[0] = lb_debug_struct_field(m, str_lit("real"), t_f16, 0*16);
|
||||
elements[1] = lb_debug_struct_field(m, str_lit("imag"), t_f16, 1*16);
|
||||
return lb_debug_basic_struct(m, str_lit("complex32"), 64, 32, elements, gb_count_of(elements));
|
||||
}
|
||||
case Basic_complex64:
|
||||
{
|
||||
LLVMMetadataRef elements[2] = {};
|
||||
elements[0] = lb_debug_struct_field(m, str_lit("real"), t_f32, 0);
|
||||
elements[1] = lb_debug_struct_field(m, str_lit("imag"), t_f32, 4);
|
||||
elements[0] = lb_debug_struct_field(m, str_lit("real"), t_f32, 0*32);
|
||||
elements[1] = lb_debug_struct_field(m, str_lit("imag"), t_f32, 2*32);
|
||||
return lb_debug_basic_struct(m, str_lit("complex64"), 64, 32, elements, gb_count_of(elements));
|
||||
}
|
||||
case Basic_complex128:
|
||||
{
|
||||
LLVMMetadataRef elements[2] = {};
|
||||
elements[0] = lb_debug_struct_field(m, str_lit("real"), t_f64, 0);
|
||||
elements[1] = lb_debug_struct_field(m, str_lit("imag"), t_f64, 8);
|
||||
elements[0] = lb_debug_struct_field(m, str_lit("real"), t_f64, 0*64);
|
||||
elements[1] = lb_debug_struct_field(m, str_lit("imag"), t_f64, 1*64);
|
||||
return lb_debug_basic_struct(m, str_lit("complex128"), 128, 64, elements, gb_count_of(elements));
|
||||
}
|
||||
|
||||
case Basic_quaternion64:
|
||||
{
|
||||
LLVMMetadataRef elements[4] = {};
|
||||
elements[0] = lb_debug_struct_field(m, str_lit("imag"), t_f16, 0);
|
||||
elements[1] = lb_debug_struct_field(m, str_lit("jmag"), t_f16, 4);
|
||||
elements[2] = lb_debug_struct_field(m, str_lit("kmag"), t_f16, 8);
|
||||
elements[3] = lb_debug_struct_field(m, str_lit("real"), t_f16, 12);
|
||||
elements[0] = lb_debug_struct_field(m, str_lit("imag"), t_f16, 0*16);
|
||||
elements[1] = lb_debug_struct_field(m, str_lit("jmag"), t_f16, 1*16);
|
||||
elements[2] = lb_debug_struct_field(m, str_lit("kmag"), t_f16, 2*16);
|
||||
elements[3] = lb_debug_struct_field(m, str_lit("real"), t_f16, 3*16);
|
||||
return lb_debug_basic_struct(m, str_lit("quaternion64"), 128, 32, elements, gb_count_of(elements));
|
||||
}
|
||||
case Basic_quaternion128:
|
||||
{
|
||||
LLVMMetadataRef elements[4] = {};
|
||||
elements[0] = lb_debug_struct_field(m, str_lit("imag"), t_f32, 0);
|
||||
elements[1] = lb_debug_struct_field(m, str_lit("jmag"), t_f32, 4);
|
||||
elements[2] = lb_debug_struct_field(m, str_lit("kmag"), t_f32, 8);
|
||||
elements[3] = lb_debug_struct_field(m, str_lit("real"), t_f32, 12);
|
||||
elements[0] = lb_debug_struct_field(m, str_lit("imag"), t_f32, 0*32);
|
||||
elements[1] = lb_debug_struct_field(m, str_lit("jmag"), t_f32, 1*32);
|
||||
elements[2] = lb_debug_struct_field(m, str_lit("kmag"), t_f32, 2*32);
|
||||
elements[3] = lb_debug_struct_field(m, str_lit("real"), t_f32, 3*32);
|
||||
return lb_debug_basic_struct(m, str_lit("quaternion128"), 128, 32, elements, gb_count_of(elements));
|
||||
}
|
||||
case Basic_quaternion256:
|
||||
{
|
||||
LLVMMetadataRef elements[4] = {};
|
||||
elements[0] = lb_debug_struct_field(m, str_lit("imag"), t_f64, 0);
|
||||
elements[1] = lb_debug_struct_field(m, str_lit("jmag"), t_f64, 8);
|
||||
elements[2] = lb_debug_struct_field(m, str_lit("kmag"), t_f64, 16);
|
||||
elements[3] = lb_debug_struct_field(m, str_lit("real"), t_f64, 24);
|
||||
elements[0] = lb_debug_struct_field(m, str_lit("imag"), t_f64, 0*64);
|
||||
elements[1] = lb_debug_struct_field(m, str_lit("jmag"), t_f64, 1*64);
|
||||
elements[2] = lb_debug_struct_field(m, str_lit("kmag"), t_f64, 2*64);
|
||||
elements[3] = lb_debug_struct_field(m, str_lit("real"), t_f64, 3*64);
|
||||
return lb_debug_basic_struct(m, str_lit("quaternion256"), 256, 32, elements, gb_count_of(elements));
|
||||
}
|
||||
|
||||
|
||||
@@ -78,7 +78,8 @@ gb_internal void lb_init_module(lbModule *m, Checker *c) {
|
||||
array_init(&m->procedures_to_generate, a, 0, c->info.all_procedures.count);
|
||||
map_init(&m->procedure_values, c->info.all_procedures.count*2);
|
||||
}
|
||||
array_init(&m->global_procedures_and_types_to_create, a, 0, 1024);
|
||||
array_init(&m->global_procedures_to_create, a, 0, 1024);
|
||||
array_init(&m->global_types_to_create, a, 0, 1024);
|
||||
array_init(&m->missing_procedures_to_check, a, 0, 16);
|
||||
map_init(&m->debug_values);
|
||||
|
||||
|
||||
+11
-6
@@ -555,7 +555,7 @@ gb_internal Ast *ast_unary_expr(AstFile *f, Token op, Ast *expr) {
|
||||
syntax_error_with_verbose(expr, "'or_return' within an unary expression not wrapped in parentheses (...)");
|
||||
break;
|
||||
case Ast_OrBranchExpr:
|
||||
syntax_error_with_verbose(expr, "'or_%.*s' within an unary expression not wrapped in parentheses (...)", LIT(expr->OrBranchExpr.token.string));
|
||||
syntax_error_with_verbose(expr, "'%.*s' within an unary expression not wrapped in parentheses (...)", LIT(expr->OrBranchExpr.token.string));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -583,7 +583,7 @@ gb_internal Ast *ast_binary_expr(AstFile *f, Token op, Ast *left, Ast *right) {
|
||||
syntax_error_with_verbose(left, "'or_return' within a binary expression not wrapped in parentheses (...)");
|
||||
break;
|
||||
case Ast_OrBranchExpr:
|
||||
syntax_error_with_verbose(left, "'or_%.*s' within a binary expression not wrapped in parentheses (...)", LIT(left->OrBranchExpr.token.string));
|
||||
syntax_error_with_verbose(left, "'%.*s' within a binary expression not wrapped in parentheses (...)", LIT(left->OrBranchExpr.token.string));
|
||||
break;
|
||||
}
|
||||
if (right) switch (right->kind) {
|
||||
@@ -591,7 +591,7 @@ gb_internal Ast *ast_binary_expr(AstFile *f, Token op, Ast *left, Ast *right) {
|
||||
syntax_error_with_verbose(right, "'or_return' within a binary expression not wrapped in parentheses (...)");
|
||||
break;
|
||||
case Ast_OrBranchExpr:
|
||||
syntax_error_with_verbose(right, "'or_%.*s' within a binary expression not wrapped in parentheses (...)", LIT(right->OrBranchExpr.token.string));
|
||||
syntax_error_with_verbose(right, "'%.*s' within a binary expression not wrapped in parentheses (...)", LIT(right->OrBranchExpr.token.string));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2091,6 +2091,9 @@ gb_internal bool ast_on_same_line(Token const &x, Ast *yp) {
|
||||
gb_internal Ast *parse_force_inlining_operand(AstFile *f, Token token) {
|
||||
Ast *expr = parse_unary_expr(f, false);
|
||||
Ast *e = strip_or_return_expr(expr);
|
||||
if (e == nullptr) {
|
||||
return expr;
|
||||
}
|
||||
if (e->kind != Ast_ProcLit && e->kind != Ast_CallExpr) {
|
||||
syntax_error(expr, "%.*s must be followed by a procedure literal or call, got %.*s", LIT(token.string), LIT(ast_strings[expr->kind]));
|
||||
return ast_bad_expr(f, token, f->curr_token);
|
||||
@@ -3102,7 +3105,7 @@ gb_internal void parse_check_or_return(Ast *operand, char const *msg) {
|
||||
syntax_error_with_verbose(operand, "'or_return' use within %s is not wrapped in parentheses (...)", msg);
|
||||
break;
|
||||
case Ast_OrBranchExpr:
|
||||
syntax_error_with_verbose(operand, "'or_%.*s' use within %s is not wrapped in parentheses (...)", msg, LIT(operand->OrBranchExpr.token.string));
|
||||
syntax_error_with_verbose(operand, "'%.*s' use within %s is not wrapped in parentheses (...)", msg, LIT(operand->OrBranchExpr.token.string));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -3747,8 +3750,10 @@ gb_internal Ast *parse_simple_stmt(AstFile *f, u32 flags) {
|
||||
case Ast_TypeSwitchStmt:
|
||||
stmt->TypeSwitchStmt.partial = true;
|
||||
break;
|
||||
default:
|
||||
syntax_error(partial_token, "Incorrect use of directive, use '%.*s: #partial switch'", LIT(ast_token(name).string));
|
||||
break;
|
||||
}
|
||||
syntax_error(partial_token, "Incorrect use of directive, use '#partial %.*s: switch'", LIT(ast_token(name).string));
|
||||
} else if (is_reverse) {
|
||||
switch (stmt->kind) {
|
||||
case Ast_RangeStmt:
|
||||
@@ -5176,7 +5181,7 @@ gb_internal Ast *parse_stmt(AstFile *f) {
|
||||
} else if (tag == "unroll") {
|
||||
return parse_unrolled_for_loop(f, name);
|
||||
} else if (tag == "reverse") {
|
||||
Ast *for_stmt = parse_for_stmt(f);
|
||||
Ast *for_stmt = parse_stmt(f);
|
||||
if (for_stmt->kind == Ast_RangeStmt) {
|
||||
if (for_stmt->RangeStmt.reverse) {
|
||||
syntax_error(token, "#reverse already applied to a 'for in' statement");
|
||||
|
||||
@@ -458,6 +458,7 @@ AST_KIND(_ExprBegin, "", bool) \
|
||||
bool optional_ok_one; \
|
||||
bool was_selector; \
|
||||
AstSplitArgs *split_args; \
|
||||
Entity *entity_procedure_of; \
|
||||
}) \
|
||||
AST_KIND(FieldValue, "field value", struct { Token eq; Ast *field, *value; }) \
|
||||
AST_KIND(EnumFieldValue, "enum field value", struct { \
|
||||
|
||||
Reference in New Issue
Block a user