aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorflysand7 <yyakut.ac@gmail.com>2023-12-06 00:23:41 +1100
committerflysand7 <yyakut.ac@gmail.com>2023-12-06 00:23:41 +1100
commit92d3a681cd6cc2aceb0865d4bffdf8a112f6f0d6 (patch)
tree6feb95445ee9f39f3c4e1dadc1ecb9d0410ec0c1 /src
parentcb66ed52cefde3274b9b055a1fecbf938e4b5155 (diff)
parent65afe6f70d6baa2d4070791325701e38d6f2df61 (diff)
Merge branch 'master' into sys-linux-additions
Diffstat (limited to 'src')
-rw-r--r--src/build_settings.cpp20
-rw-r--r--src/check_builtin.cpp198
-rw-r--r--src/check_expr.cpp44
-rw-r--r--src/checker.cpp15
-rw-r--r--src/checker_builtin_procs.hpp14
-rw-r--r--src/linker.cpp42
-rw-r--r--src/llvm_backend.cpp52
-rw-r--r--src/llvm_backend.hpp3
-rw-r--r--src/llvm_backend_expr.cpp30
-rw-r--r--src/llvm_backend_general.cpp12
-rw-r--r--src/llvm_backend_stmt.cpp22
-rw-r--r--src/llvm_backend_type.cpp7
-rw-r--r--src/llvm_backend_utility.cpp4
-rw-r--r--src/main.cpp314
-rw-r--r--src/string.cpp26
-rw-r--r--src/threading.cpp2
16 files changed, 615 insertions, 190 deletions
diff --git a/src/build_settings.cpp b/src/build_settings.cpp
index ffb276d1e..94807a852 100644
--- a/src/build_settings.cpp
+++ b/src/build_settings.cpp
@@ -82,6 +82,23 @@ gb_global String target_arch_names[TargetArch_COUNT] = {
str_lit("wasm64p32"),
};
+gb_global String target_microarch_list[TargetArch_COUNT] = {
+ // TargetArch_Invalid,
+ str_lit("Invalid!"),
+ // TargetArch_amd64,
+ str_lit("alderlake,amdfam10,athlon-fx,athlon64,athlon64-sse3,atom_sse4_2,atom_sse4_2_movbe,barcelona,bdver1,bdver2,bdver3,bdver4,broadwell,btver1,btver2,cannonlake,cascadelake,cooperlake,core-avx-i,core-avx2,core2,core_2_duo_sse4_1,core_2_duo_ssse3,core_2nd_gen_avx,core_3rd_gen_avx,core_4th_gen_avx,core_4th_gen_avx_tsx,core_5th_gen_avx,core_5th_gen_avx_tsx,core_aes_pclmulqdq,core_i7_sse4_2,corei7,corei7-avx,generic,goldmont,goldmont-plus,goldmont_plus,grandridge,graniterapids,graniterapids-d,graniterapids_d,haswell,icelake-client,icelake-server,icelake_client,icelake_server,ivybridge,k8,k8-sse3,knl,knm,meteorlake,mic_avx512,native,nehalem,nocona,opteron,opteron-sse3,penryn,raptorlake,rocketlake,sandybridge,sapphirerapids,sierraforest,silvermont,skx,skylake,skylake-avx512,skylake_avx512,slm,tigerlake,tremont,westmere,x86-64,x86-64-v2,x86-64-v3,x86-64-v4,znver1,znver2,znver3,znver4"),
+ // TargetArch_i386,
+ str_lit("athlon,athlon-4,athlon-mp,athlon-tbird,athlon-xp,atom,bonnell,c3,c3-2,generic,geode,i386,i486,i586,i686,k6,k6-2,k6-3,lakemont,native,pentium,pentium-m,pentium-mmx,pentium2,pentium3,pentium3m,pentium4,pentium4m,pentium_4,pentium_4_sse3,pentium_ii,pentium_iii,pentium_iii_no_xmm_regs,pentium_m,pentium_mmx,pentium_pro,pentiumpro,prescott,winchip-c6,winchip2,yonah"),
+ // TargetArch_arm32,
+ str_lit("arm1020e,arm1020t,arm1022e,arm10e,arm10tdmi,arm1136j-s,arm1136jf-s,arm1156t2-s,arm1156t2f-s,arm1176jz-s,arm1176jzf-s,arm710t,arm720t,arm7tdmi,arm7tdmi-s,arm8,arm810,arm9,arm920,arm920t,arm922t,arm926ej-s,arm940t,arm946e-s,arm966e-s,arm968e-s,arm9e,arm9tdmi,cortex-a12,cortex-a15,cortex-a17,cortex-a32,cortex-a35,cortex-a5,cortex-a53,cortex-a55,cortex-a57,cortex-a7,cortex-a710,cortex-a72,cortex-a73,cortex-a75,cortex-a76,cortex-a76ae,cortex-a77,cortex-a78,cortex-a78c,cortex-a8,cortex-a9,cortex-m0,cortex-m0plus,cortex-m1,cortex-m23,cortex-m3,cortex-m33,cortex-m35p,cortex-m4,cortex-m55,cortex-m7,cortex-m85,cortex-r4,cortex-r4f,cortex-r5,cortex-r52,cortex-r7,cortex-r8,cortex-x1,cortex-x1c,cyclone,ep9312,exynos-m3,exynos-m4,exynos-m5,generic,iwmmxt,krait,kryo,mpcore,mpcorenovfp,native,neoverse-n1,neoverse-n2,neoverse-v1,sc000,sc300,strongarm,strongarm110,strongarm1100,strongarm1110,swift,xscale"),
+ // TargetArch_arm64,
+ str_lit("a64fx,ampere1,ampere1a,apple-a10,apple-a11,apple-a12,apple-a13,apple-a14,apple-a15,apple-a16,apple-a7,apple-a8,apple-a9,apple-latest,apple-m1,apple-m2,apple-s4,apple-s5,carmel,cortex-a34,cortex-a35,cortex-a510,cortex-a53,cortex-a55,cortex-a57,cortex-a65,cortex-a65ae,cortex-a710,cortex-a715,cortex-a72,cortex-a73,cortex-a75,cortex-a76,cortex-a76ae,cortex-a77,cortex-a78,cortex-a78c,cortex-r82,cortex-x1,cortex-x1c,cortex-x2,cortex-x3,cyclone,exynos-m3,exynos-m4,exynos-m5,falkor,generic,kryo,native,neoverse-512tvb,neoverse-e1,neoverse-n1,neoverse-n2,neoverse-v1,neoverse-v2,saphira,thunderx,thunderx2t99,thunderx3t110,thunderxt81,thunderxt83,thunderxt88,tsv110"),
+ // TargetArch_wasm32,
+ str_lit("generic"),
+ // TargetArch_wasm64p32,
+ str_lit("generic"),
+};
+
gb_global String target_endian_names[TargetEndian_COUNT] = {
str_lit("little"),
str_lit("big"),
@@ -109,8 +126,6 @@ gb_global TargetEndianKind target_endians[TargetArch_COUNT] = {
gb_global String const ODIN_VERSION = str_lit(ODIN_VERSION_RAW);
-
-
struct TargetMetrics {
TargetOsKind os;
TargetArchKind arch;
@@ -623,7 +638,6 @@ gb_internal TargetArchKind get_target_arch_from_string(String str) {
return TargetArch_Invalid;
}
-
gb_internal bool is_excluded_target_filename(String name) {
String original_name = name;
name = remove_extension_from_path(name);
diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp
index 77ba6b435..c0061a397 100644
--- a/src/check_builtin.cpp
+++ b/src/check_builtin.cpp
@@ -2088,6 +2088,8 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
t = default_type(t);
add_type_info_type(c, t);
+ GB_ASSERT(t_type_info_ptr != nullptr);
+ add_type_info_type(c, t_type_info_ptr);
if (is_operand_value(o) && is_type_typeid(t)) {
add_package_dependency(c, "runtime", "__type_info_of");
@@ -5117,6 +5119,202 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
}
break;
+ case BuiltinProc_type_union_tag_type:
+ {
+ if (operand->mode != Addressing_Type) {
+ error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name));
+ operand->mode = Addressing_Invalid;
+ operand->type = t_invalid;
+ return false;
+ }
+
+ Type *u = operand->type;
+
+ if (!is_type_union(u)) {
+ error(operand->expr, "Expected a union type for '%.*s'", LIT(builtin_name));
+ operand->mode = Addressing_Invalid;
+ operand->type = t_invalid;
+ return false;
+ }
+
+ u = base_type(u);
+ GB_ASSERT(u->kind == Type_Union);
+
+ operand->mode = Addressing_Type;
+ operand->type = union_tag_type(u);
+ }
+ break;
+
+ case BuiltinProc_type_union_tag_offset:
+ {
+ if (operand->mode != Addressing_Type) {
+ error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name));
+ operand->mode = Addressing_Invalid;
+ operand->type = t_invalid;
+ return false;
+ }
+
+ Type *u = operand->type;
+
+ if (!is_type_union(u)) {
+ error(operand->expr, "Expected a union type for '%.*s'", LIT(builtin_name));
+ operand->mode = Addressing_Invalid;
+ operand->type = t_invalid;
+ return false;
+ }
+
+ u = base_type(u);
+ GB_ASSERT(u->kind == Type_Union);
+
+ // NOTE(jakubtomsu): forces calculation of variant_block_size
+ type_size_of(u);
+ i64 tag_offset = u->Union.variant_block_size;
+ GB_ASSERT(tag_offset > 0);
+
+ operand->mode = Addressing_Constant;
+ operand->type = t_untyped_integer;
+ operand->value = exact_value_i64(tag_offset);
+ }
+ break;
+
+ case BuiltinProc_type_union_base_tag_value:
+ {
+ if (operand->mode != Addressing_Type) {
+ error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name));
+ operand->mode = Addressing_Invalid;
+ operand->type = t_invalid;
+ return false;
+ }
+
+ Type *u = operand->type;
+
+ if (!is_type_union(u)) {
+ error(operand->expr, "Expected a union type for '%.*s'", LIT(builtin_name));
+ operand->mode = Addressing_Invalid;
+ operand->type = t_invalid;
+ return false;
+ }
+
+ u = base_type(u);
+ GB_ASSERT(u->kind == Type_Union);
+
+ operand->mode = Addressing_Constant;
+ operand->type = t_untyped_integer;
+ operand->value = exact_value_i64(u->Union.kind == UnionType_no_nil ? 0 : 1);
+ } break;
+
+ case BuiltinProc_type_union_variant_count:
+ {
+ if (operand->mode != Addressing_Type) {
+ error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name));
+ operand->mode = Addressing_Invalid;
+ operand->type = t_invalid;
+ return false;
+ }
+
+ Type *u = operand->type;
+
+ if (!is_type_union(u)) {
+ error(operand->expr, "Expected a union type for '%.*s'", LIT(builtin_name));
+ operand->mode = Addressing_Invalid;
+ operand->type = t_invalid;
+ return false;
+ }
+
+ u = base_type(u);
+ GB_ASSERT(u->kind == Type_Union);
+
+ operand->mode = Addressing_Constant;
+ operand->type = t_untyped_integer;
+ operand->value = exact_value_i64(u->Union.variants.count);
+ } break;
+
+ case BuiltinProc_type_variant_type_of:
+ {
+ if (operand->mode != Addressing_Type) {
+ error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name));
+ operand->mode = Addressing_Invalid;
+ operand->type = t_invalid;
+ return false;
+ }
+
+ Type *u = operand->type;
+
+ if (!is_type_union(u)) {
+ error(operand->expr, "Expected a union type for '%.*s'", LIT(builtin_name));
+ operand->mode = Addressing_Invalid;
+ operand->type = t_invalid;
+ return false;
+ }
+
+ u = base_type(u);
+ GB_ASSERT(u->kind == Type_Union);
+ Operand x = {};
+ check_expr_or_type(c, &x, ce->args[1]);
+ if (!is_type_integer(x.type) || x.mode != Addressing_Constant) {
+ error(call, "Expected a constant integer for '%.*s", LIT(builtin_name));
+ operand->mode = Addressing_Type;
+ operand->type = t_invalid;
+ return false;
+ }
+
+ i64 index = big_int_to_i64(&x.value.value_integer);
+ if (index < 0 || index >= u->Union.variants.count) {
+ error(call, "Variant tag out of bounds index for '%.*s", LIT(builtin_name));
+ operand->mode = Addressing_Type;
+ operand->type = t_invalid;
+ return false;
+ }
+
+ operand->mode = Addressing_Type;
+ operand->type = u->Union.variants[index];
+ }
+ break;
+
+ case BuiltinProc_type_variant_index_of:
+ {
+ if (operand->mode != Addressing_Type) {
+ error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name));
+ operand->mode = Addressing_Invalid;
+ operand->type = t_invalid;
+ return false;
+ }
+
+ Type *u = operand->type;
+
+ if (!is_type_union(u)) {
+ error(operand->expr, "Expected a union type for '%.*s'", LIT(builtin_name));
+ operand->mode = Addressing_Invalid;
+ operand->type = t_invalid;
+ return false;
+ }
+
+ Type *v = check_type(c, ce->args[1]);
+ u = base_type(u);
+ GB_ASSERT(u->kind == Type_Union);
+
+ i64 index = -1;
+ for_array(i, u->Union.variants) {
+ Type *vt = u->Union.variants[i];
+ if (union_variant_index_types_equal(v, vt)) {
+ index = i64(i);
+ break;
+ }
+ }
+
+ if (index < 0) {
+ error(operand->expr, "Expected a variant type for '%.*s'", LIT(builtin_name));
+ operand->mode = Addressing_Invalid;
+ operand->type = t_invalid;
+ return false;
+ }
+
+ operand->mode = Addressing_Constant;
+ operand->type = t_untyped_integer;
+ operand->value = exact_value_i64(index);
+ }
+ break;
+
case BuiltinProc_type_struct_field_count:
operand->value = exact_value_i64(0);
if (operand->mode != Addressing_Type) {
diff --git a/src/check_expr.cpp b/src/check_expr.cpp
index 2ee761b9c..71accfb81 100644
--- a/src/check_expr.cpp
+++ b/src/check_expr.cpp
@@ -2339,7 +2339,7 @@ gb_internal void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast *
ast_node(ue, UnaryExpr, node);
if (ast_node_expect(ue->expr, Ast_IndexExpr)) {
ast_node(ie, IndexExpr, ue->expr);
- Type *soa_type = type_of_expr(ie->expr);
+ Type *soa_type = type_deref(type_of_expr(ie->expr));
GB_ASSERT(is_type_soa_struct(soa_type));
o->type = alloc_type_soa_pointer(soa_type);
} else {
@@ -2768,6 +2768,11 @@ gb_internal void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *nod
gb_string_free(to_type);
x->mode = Addressing_Invalid;
}
+ } else if (!is_type_integer(x->type)) {
+ gbString x_str = expr_to_string(x->expr);
+ error(node, "Non-integer shifted operand '%s' is not allowed", x_str);
+ gb_string_free(x_str);
+ x->mode = Addressing_Invalid;
}
// x->value = x_val;
return;
@@ -3558,6 +3563,30 @@ gb_internal void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Typ
return;
}
+ switch (op.kind) {
+ case Token_Quo:
+ case Token_Mod:
+ case Token_ModMod:
+ case Token_QuoEq:
+ case Token_ModEq:
+ case Token_ModModEq:
+ if (is_type_integer(y->type) && !is_type_untyped(y->type) &&
+ is_type_float(x->type) && is_type_untyped(x->type)) {
+ char const *suggestion = "\tSuggestion: Try explicitly casting the constant value for clarity";
+
+ gbString t = type_to_string(y->type);
+ if (x->value.kind != ExactValue_Invalid) {
+ gbString s = exact_value_to_string(x->value);
+ warning(node, "Dividing an untyped float '%s' by '%s' will perform integer division\n%s", s, t, suggestion);
+ gb_string_free(s);
+ } else {
+ warning(node, "Dividing an untyped float by '%s' will perform integer division\n%s", t, suggestion);
+ }
+ gb_string_free(t);
+ }
+ break;
+ }
+
convert_to_typed(c, x, y->type);
if (x->mode == Addressing_Invalid) {
return;
@@ -5577,9 +5606,6 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A
for (isize i = 0; i < pt->param_count; i++) {
if (!visited[i]) {
Entity *e = pt->params->Tuple.variables[i];
- if (is_blank_ident(e->token)) {
- continue;
- }
if (e->kind == Entity_Variable) {
if (e->Variable.param_value.kind != ParameterValue_Invalid) {
ordered_operands[i].mode = Addressing_Value;
@@ -5623,6 +5649,14 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A
} else {
if (show_error) {
check_assignment(c, o, param_type, str_lit("procedure argument"));
+
+ Type *src = base_type(o->type);
+ Type *dst = base_type(param_type);
+ if (is_type_slice(src) && are_types_identical(src->Slice.elem, dst)) {
+ gbString a = expr_to_string(o->expr);
+ error_line("\tSuggestion: Did you mean to pass the slice into the variadic parameter with ..%s?\n\n", a);
+ gb_string_free(a);
+ }
}
err = CallArgumentError_WrongTypes;
}
@@ -7391,7 +7425,7 @@ gb_internal bool check_set_index_data(Operand *o, Type *t, bool indirection, i64
*max_count = t->Struct.soa_count;
}
o->type = t->Struct.soa_elem;
- if (o->mode == Addressing_SoaVariable || o->mode == Addressing_Variable) {
+ if (o->mode == Addressing_SoaVariable || o->mode == Addressing_Variable || indirection) {
o->mode = Addressing_SoaVariable;
} else {
o->mode = Addressing_Value;
diff --git a/src/checker.cpp b/src/checker.cpp
index 29f22bd9c..60b2bbb90 100644
--- a/src/checker.cpp
+++ b/src/checker.cpp
@@ -2211,9 +2211,14 @@ gb_internal void add_min_dep_type_info(Checker *c, Type *t) {
Entity *e = entry.value;
switch (bt->Struct.soa_kind) {
case StructSoa_Dynamic:
+ add_min_dep_type_info(c, t_type_info_ptr); // append_soa
+
add_min_dep_type_info(c, t_allocator);
/*fallthrough*/
case StructSoa_Slice:
+ add_min_dep_type_info(c, t_int);
+ add_min_dep_type_info(c, t_uint);
+ /*fallthrough*/
case StructSoa_Fixed:
add_min_dep_type_info(c, alloc_type_pointer(e->type));
break;
@@ -4733,7 +4738,7 @@ gb_internal void check_add_foreign_import_decl(CheckerContext *ctx, Ast *decl) {
}
if (has_asm_extension(fullpath)) {
- if (build_context.metrics.arch != TargetArch_amd64) {
+ if (build_context.metrics.arch != TargetArch_amd64 && build_context.metrics.os != TargetOs_darwin) {
error(decl, "Assembly files are not yet supported on this platform: %.*s_%.*s",
LIT(target_os_names[build_context.metrics.os]), LIT(target_arch_names[build_context.metrics.arch]));
}
@@ -6091,9 +6096,6 @@ gb_internal void check_parsed_files(Checker *c) {
TIME_SECTION("calculate global init order");
calculate_global_init_order(c);
- TIME_SECTION("check test procedures");
- check_test_procedures(c);
-
TIME_SECTION("add type info for type definitions");
add_type_info_for_type_definitions(c);
check_merge_queues_into_arrays(c);
@@ -6104,6 +6106,11 @@ gb_internal void check_parsed_files(Checker *c) {
TIME_SECTION("generate minimum dependency set");
generate_minimum_dependency_set(c, c->info.entry_point);
+ // NOTE(laytan): has to be ran after generate_minimum_dependency_set,
+ // because that collects the test procedures.
+ TIME_SECTION("check test procedures");
+ check_test_procedures(c);
+
TIME_SECTION("check bodies have all been checked");
check_unchecked_bodies(c);
diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp
index c89ab2429..3bab16293 100644
--- a/src/checker_builtin_procs.hpp
+++ b/src/checker_builtin_procs.hpp
@@ -260,6 +260,12 @@ BuiltinProc__type_simple_boolean_end,
BuiltinProc_type_is_specialization_of,
BuiltinProc_type_is_variant_of,
+ BuiltinProc_type_union_tag_type,
+ BuiltinProc_type_union_tag_offset,
+ BuiltinProc_type_union_base_tag_value,
+ BuiltinProc_type_union_variant_count,
+ BuiltinProc_type_variant_type_of,
+ BuiltinProc_type_variant_index_of,
BuiltinProc_type_struct_field_count,
@@ -557,7 +563,13 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
{STR_LIT("type_is_specialization_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
- {STR_LIT("type_is_variant_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
+ {STR_LIT("type_is_variant_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
+ {STR_LIT("type_union_tag_type"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
+ {STR_LIT("type_union_tag_offset"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
+ {STR_LIT("type_union_base_tag_value"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
+ {STR_LIT("type_union_variant_count"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
+ {STR_LIT("type_variant_type_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
+ {STR_LIT("type_variant_index_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_struct_field_count"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
diff --git a/src/linker.cpp b/src/linker.cpp
index eb3687ae2..c3ede0f55 100644
--- a/src/linker.cpp
+++ b/src/linker.cpp
@@ -337,20 +337,34 @@ gb_internal i32 linker_stage(LinkerData *gen) {
obj_format = str_lit("elf32");
}
#endif // GB_ARCH_*_BIT
- // Note(bumbread): I'm assuming nasm is installed on the host machine.
- // Shipping binaries on unix-likes gets into the weird territorry of
- // "which version of glibc" is it linked with.
- result = system_exec_command_line_app("nasm",
- "nasm \"%.*s\" "
- "-f \"%.*s\" "
- "-o \"%.*s\" "
- "%.*s "
- "",
- LIT(asm_file),
- LIT(obj_format),
- LIT(obj_file),
- LIT(build_context.extra_assembler_flags)
- );
+
+ if (is_osx) {
+ // `as` comes with MacOS.
+ result = system_exec_command_line_app("as",
+ "as \"%.*s\" "
+ "-o \"%.*s\" "
+ "%.*s "
+ "",
+ LIT(asm_file),
+ LIT(obj_file),
+ LIT(build_context.extra_assembler_flags)
+ );
+ } else {
+ // Note(bumbread): I'm assuming nasm is installed on the host machine.
+ // Shipping binaries on unix-likes gets into the weird territorry of
+ // "which version of glibc" is it linked with.
+ result = system_exec_command_line_app("nasm",
+ "nasm \"%.*s\" "
+ "-f \"%.*s\" "
+ "-o \"%.*s\" "
+ "%.*s "
+ "",
+ LIT(asm_file),
+ LIT(obj_format),
+ LIT(obj_file),
+ LIT(build_context.extra_assembler_flags)
+ );
+ }
array_add(&gen->output_object_paths, obj_file);
} else {
if (string_set_update(&libs, lib)) {
diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp
index 513b40a4d..f61c297bd 100644
--- a/src/llvm_backend.cpp
+++ b/src/llvm_backend.cpp
@@ -21,6 +21,25 @@
#include "llvm_backend_stmt.cpp"
#include "llvm_backend_proc.cpp"
+String get_default_microarchitecture() {
+ String default_march = str_lit("generic");
+ if (build_context.metrics.arch == TargetArch_amd64) {
+ // NOTE(bill): x86-64-v2 is more than enough for everyone
+ //
+ // x86-64: CMOV, CMPXCHG8B, FPU, FXSR, MMX, FXSR, SCE, SSE, SSE2
+ // x86-64-v2: (close to Nehalem) CMPXCHG16B, LAHF-SAHF, POPCNT, SSE3, SSE4.1, SSE4.2, SSSE3
+ // x86-64-v3: (close to Haswell) AVX, AVX2, BMI1, BMI2, F16C, FMA, LZCNT, MOVBE, XSAVE
+ // x86-64-v4: AVX512F, AVX512BW, AVX512CD, AVX512DQ, AVX512VL
+ if (ODIN_LLVM_MINIMUM_VERSION_12) {
+ if (build_context.metrics.os == TargetOs_freestanding) {
+ default_march = str_lit("x86-64");
+ } else {
+ default_march = str_lit("x86-64-v2");
+ }
+ }
+ }
+ return default_march;
+}
gb_internal void lb_add_foreign_library_path(lbModule *m, Entity *e) {
if (e == nullptr) {
@@ -1827,7 +1846,7 @@ cgscc(
function-attrs,
function(
require<should-not-run-function-passes>
- ),
+ )
)
),
deadargelim,
@@ -2490,34 +2509,27 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
code_mode = LLVMCodeModelKernel;
}
- char const *host_cpu_name = LLVMGetHostCPUName();
- char const *llvm_cpu = "generic";
+ String host_cpu_name = copy_string(permanent_allocator(), make_string_c(LLVMGetHostCPUName()));
+ String llvm_cpu = get_default_microarchitecture();
char const *llvm_features = "";
if (build_context.microarch.len != 0) {
if (build_context.microarch == "native") {
llvm_cpu = host_cpu_name;
} else {
- llvm_cpu = alloc_cstring(permanent_allocator(), build_context.microarch);
+ llvm_cpu = copy_string(permanent_allocator(), build_context.microarch);
}
- if (gb_strcmp(llvm_cpu, host_cpu_name) == 0) {
+ if (llvm_cpu == host_cpu_name) {
llvm_features = LLVMGetHostCPUFeatures();
}
- } else if (build_context.metrics.arch == TargetArch_amd64) {
- // NOTE(bill): x86-64-v2 is more than enough for everyone
- //
- // x86-64: CMOV, CMPXCHG8B, FPU, FXSR, MMX, FXSR, SCE, SSE, SSE2
- // x86-64-v2: (close to Nehalem) CMPXCHG16B, LAHF-SAHF, POPCNT, SSE3, SSE4.1, SSE4.2, SSSE3
- // x86-64-v3: (close to Haswell) AVX, AVX2, BMI1, BMI2, F16C, FMA, LZCNT, MOVBE, XSAVE
- // x86-64-v4: AVX512F, AVX512BW, AVX512CD, AVX512DQ, AVX512VL
- if (ODIN_LLVM_MINIMUM_VERSION_12) {
- if (build_context.metrics.os == TargetOs_freestanding) {
- llvm_cpu = "x86-64";
- } else {
- llvm_cpu = "x86-64-v2";
- }
- }
}
+ // NOTE(Jeroen): Uncomment to get the list of supported microarchitectures.
+ /*
+ if (build_context.microarch == "?") {
+ string_set_add(&build_context.target_features_set, str_lit("+cpuhelp"));
+ }
+ */
+
if (build_context.target_features_set.entries.count != 0) {
llvm_features = target_features_set_to_cstring(permanent_allocator(), false);
}
@@ -2566,7 +2578,7 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
for (auto const &entry : gen->modules) {
LLVMTargetMachineRef target_machine = LLVMCreateTargetMachine(
- target, target_triple, llvm_cpu,
+ target, target_triple, (const char *)llvm_cpu.text,
llvm_features,
code_gen_level,
reloc_mode,
diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp
index 5894dd38a..4e193bcea 100644
--- a/src/llvm_backend.hpp
+++ b/src/llvm_backend.hpp
@@ -339,6 +339,8 @@ struct lbProcedure {
bool in_multi_assignment;
Array<LLVMValueRef> raw_input_parameters;
+ LLVMValueRef temp_callee_return_struct_memory;
+
Ast *curr_stmt;
Array<Scope *> scope_stack;
@@ -550,6 +552,7 @@ gb_internal LLVMValueRef lb_call_intrinsic(lbProcedure *p, const char *name, LLV
gb_internal void lb_mem_copy_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbValue len, bool is_volatile=false);
gb_internal void lb_mem_copy_non_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbValue len, bool is_volatile=false);
gb_internal LLVMValueRef lb_mem_zero_ptr_internal(lbProcedure *p, LLVMValueRef ptr, LLVMValueRef len, unsigned alignment, bool is_volatile);
+gb_internal LLVMValueRef lb_mem_zero_ptr_internal(lbProcedure *p, LLVMValueRef ptr, usize len, unsigned alignment, bool is_volatile);
gb_internal gb_inline i64 lb_max_zero_init_size(void) {
return cast(i64)(4*build_context.int_size);
diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp
index bde975d96..d1176f896 100644
--- a/src/llvm_backend_expr.cpp
+++ b/src/llvm_backend_expr.cpp
@@ -684,7 +684,8 @@ gb_internal lbValue lb_emit_matrix_flatten(lbProcedure *p, lbValue m, Type *type
Type *mt = base_type(m.type);
GB_ASSERT(mt->kind == Type_Matrix);
- if (lb_is_matrix_simdable(mt)) {
+ // TODO(bill): Determine why this fails on Windows sometimes
+ if (false && lb_is_matrix_simdable(mt)) {
LLVMValueRef vector = lb_matrix_to_trimmed_vector(p, m);
return lb_matrix_cast_vector_to_type(p, vector, type);
}
@@ -693,13 +694,29 @@ gb_internal lbValue lb_emit_matrix_flatten(lbProcedure *p, lbValue m, Type *type
i64 row_count = mt->Matrix.row_count;
i64 column_count = mt->Matrix.column_count;
+ TEMPORARY_ALLOCATOR_GUARD();
+
+ auto srcs = array_make<lbValue>(temporary_allocator(), 0, row_count*column_count);
+ auto dsts = array_make<lbValue>(temporary_allocator(), 0, row_count*column_count);
+
for (i64 j = 0; j < column_count; j++) {
for (i64 i = 0; i < row_count; i++) {
lbValue src = lb_emit_matrix_ev(p, m, i, j);
+ array_add(&srcs, src);
+ }
+ }
+
+ for (i64 j = 0; j < column_count; j++) {
+ for (i64 i = 0; i < row_count; i++) {
lbValue dst = lb_emit_array_epi(p, res.addr, i + j*row_count);
- lb_emit_store(p, dst, src);
+ array_add(&dsts, dst);
}
}
+
+ GB_ASSERT(srcs.count == dsts.count);
+ for_array(i, srcs) {
+ lb_emit_store(p, dsts[i], srcs[i]);
+ }
return lb_addr_load(p, res);
}
@@ -1069,6 +1086,7 @@ gb_internal lbValue lb_emit_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbV
args[1] = rhs;
switch (type_size_of(ft)) {
+ case 2: return lb_emit_runtime_call(p, "quo_complex32", args);
case 4: return lb_emit_runtime_call(p, "quo_complex64", args);
case 8: return lb_emit_runtime_call(p, "quo_complex128", args);
default: GB_PANIC("Unknown float type"); break;
@@ -1145,6 +1163,7 @@ gb_internal lbValue lb_emit_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbV
args[1] = rhs;
switch (8*type_size_of(ft)) {
+ case 16: return lb_emit_runtime_call(p, "mul_quaternion64", args);
case 32: return lb_emit_runtime_call(p, "mul_quaternion128", args);
case 64: return lb_emit_runtime_call(p, "mul_quaternion256", args);
default: GB_PANIC("Unknown float type"); break;
@@ -1157,6 +1176,7 @@ gb_internal lbValue lb_emit_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbV
args[1] = rhs;
switch (8*type_size_of(ft)) {
+ case 16: return lb_emit_runtime_call(p, "quo_quaternion64", args);
case 32: return lb_emit_runtime_call(p, "quo_quaternion128", args);
case 64: return lb_emit_runtime_call(p, "quo_quaternion256", args);
default: GB_PANIC("Unknown float type"); break;
@@ -2919,6 +2939,12 @@ gb_internal lbValue lb_build_unary_and(lbProcedure *p, Ast *expr) {
} else if (is_type_soa_pointer(tv.type)) {
ast_node(ie, IndexExpr, ue_expr);
lbValue addr = lb_build_addr_ptr(p, ie->expr);
+
+ if (is_type_pointer(type_deref(addr.type))) {
+ addr = lb_emit_load(p, addr);
+ }
+ GB_ASSERT(is_type_pointer(addr.type));
+
lbValue index = lb_build_expr(p, ie->index);
if (!build_context.no_bounds_check) {
diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp
index fdcf94f29..c149ec853 100644
--- a/src/llvm_backend_general.cpp
+++ b/src/llvm_backend_general.cpp
@@ -1332,6 +1332,8 @@ gb_internal void lb_emit_store_union_variant(lbProcedure *p, lbValue parent, lbV
Type *pt = base_type(type_deref(parent.type));
GB_ASSERT(pt->kind == Type_Union);
if (pt->Union.kind == UnionType_shared_nil) {
+ GB_ASSERT(type_size_of(variant_type));
+
lbBlock *if_nil = lb_create_block(p, "shared_nil.if_nil");
lbBlock *if_not_nil = lb_create_block(p, "shared_nil.if_not_nil");
lbBlock *done = lb_create_block(p, "shared_nil.done");
@@ -1353,9 +1355,13 @@ gb_internal void lb_emit_store_union_variant(lbProcedure *p, lbValue parent, lbV
} else {
- lbValue underlying = lb_emit_conv(p, parent, alloc_type_pointer(variant_type));
-
- lb_emit_store(p, underlying, variant);
+ if (type_size_of(variant_type) == 0) {
+ unsigned alignment = 1;
+ lb_mem_zero_ptr_internal(p, parent.value, pt->Union.variant_block_size, alignment, false);
+ } else {
+ lbValue underlying = lb_emit_conv(p, parent, alloc_type_pointer(variant_type));
+ lb_emit_store(p, underlying, variant);
+ }
lb_emit_store_union_variant_tag(p, parent, variant_type);
}
}
diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp
index 9d688be6a..002fef881 100644
--- a/src/llvm_backend_stmt.cpp
+++ b/src/llvm_backend_stmt.cpp
@@ -1846,9 +1846,25 @@ gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res) {
LLVMBuildRetVoid(p->builder);
} else {
LLVMValueRef ret_val = res.value;
- ret_val = OdinLLVMBuildTransmute(p, ret_val, p->abi_function_type->ret.type);
- if (p->abi_function_type->ret.cast_type != nullptr) {
- ret_val = OdinLLVMBuildTransmute(p, ret_val, p->abi_function_type->ret.cast_type);
+ LLVMTypeRef ret_type = p->abi_function_type->ret.type;
+ if (LLVMTypeRef cast_type = p->abi_function_type->ret.cast_type) {
+ ret_type = cast_type;
+ }
+
+ if (LLVMGetTypeKind(ret_type) == LLVMStructTypeKind) {
+ LLVMTypeRef src_type = LLVMTypeOf(ret_val);
+
+ if (p->temp_callee_return_struct_memory == nullptr) {
+ i64 max_align = gb_max(lb_alignof(ret_type), lb_alignof(src_type));
+ p->temp_callee_return_struct_memory = llvm_alloca(p, ret_type, max_align);
+ }
+ // reuse the temp return value memory where possible
+ LLVMValueRef ptr = p->temp_callee_return_struct_memory;
+ LLVMValueRef nptr = LLVMBuildPointerCast(p->builder, ptr, LLVMPointerType(src_type, 0), "");
+ LLVMBuildStore(p->builder, ret_val, nptr);
+ ret_val = LLVMBuildLoad2(p->builder, ret_type, ptr, "");
+ } else {
+ ret_val = OdinLLVMBuildTransmute(p, ret_val, ret_type);
}
lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr);
diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp
index 02dad2a3a..e291e40a5 100644
--- a/src/llvm_backend_type.cpp
+++ b/src/llvm_backend_type.cpp
@@ -9,7 +9,12 @@ gb_internal isize lb_type_info_index(CheckerInfo *info, Type *type, bool err_on_
}
}
if (err_on_not_found) {
- GB_PANIC("NOT FOUND lb_type_info_index %s @ index %td", type_to_string(type), index);
+ gb_printf_err("NOT FOUND lb_type_info_index:\n\t%s\n\t@ index %td\n\tmax count: %u\nFound:\n", type_to_string(type), index, set->count);
+ for (auto const &entry : *set) {
+ isize type_info_index = entry.key;
+ gb_printf_err("\t%s\n", type_to_string(info->type_info_types[type_info_index]));
+ }
+ GB_PANIC("NOT FOUND");
}
return -1;
}
diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp
index d8dbfd736..be3ae9c8a 100644
--- a/src/llvm_backend_utility.cpp
+++ b/src/llvm_backend_utility.cpp
@@ -57,6 +57,10 @@ gb_internal lbValue lb_correct_endianness(lbProcedure *p, lbValue value) {
return value;
}
+gb_internal LLVMValueRef lb_mem_zero_ptr_internal(lbProcedure *p, LLVMValueRef ptr, usize len, unsigned alignment, bool is_volatile) {
+ return lb_mem_zero_ptr_internal(p, ptr, LLVMConstInt(lb_type(p->module, t_uint), len, false), alignment, is_volatile);
+}
+
gb_internal LLVMValueRef lb_mem_zero_ptr_internal(lbProcedure *p, LLVMValueRef ptr, LLVMValueRef len, unsigned alignment, bool is_volatile) {
bool is_inlinable = false;
diff --git a/src/main.cpp b/src/main.cpp
index 79c2b3561..14f7e84ec 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -199,19 +199,19 @@ gb_internal void print_usage_line(i32 indent, char const *fmt, ...) {
}
gb_internal void usage(String argv0) {
- print_usage_line(0, "%.*s is a tool for managing Odin source code", LIT(argv0));
+ print_usage_line(0, "%.*s is a tool for managing Odin source code.", LIT(argv0));
print_usage_line(0, "Usage:");
print_usage_line(1, "%.*s command [arguments]", LIT(argv0));
print_usage_line(0, "Commands:");
- print_usage_line(1, "build compile directory of .odin files, as an executable.");
- print_usage_line(1, " one must contain the program's entry point, all must be in the same package.");
- print_usage_line(1, "run same as 'build', but also then runs the newly compiled executable.");
- print_usage_line(1, "check parse, and type check a directory of .odin files");
- print_usage_line(1, "strip-semicolon parse, type check, and remove unneeded semicolons from the entire program");
- print_usage_line(1, "test build and runs procedures with the attribute @(test) in the initial package");
- print_usage_line(1, "doc generate documentation on a directory of .odin files");
- print_usage_line(1, "version print version");
- print_usage_line(1, "report print information useful to reporting a bug");
+ print_usage_line(1, "build Compiles directory of .odin files, as an executable.");
+ print_usage_line(1, " One must contain the program's entry point, all must be in the same package.");
+ print_usage_line(1, "run Same as 'build', but also then runs the newly compiled executable.");
+ print_usage_line(1, "check Parses, and type checks a directory of .odin files.");
+ print_usage_line(1, "strip-semicolon Parses, type checks, and removes unneeded semicolons from the entire program.");
+ print_usage_line(1, "test Builds and runs procedures with the attribute @(test) in the initial package.");
+ print_usage_line(1, "doc Generates documentation on a directory of .odin files.");
+ print_usage_line(1, "version Prints version.");
+ print_usage_line(1, "report Prints information useful to reporting a bug.");
print_usage_line(0, "");
print_usage_line(0, "For further details on a command, invoke command help:");
print_usage_line(1, "e.g. `odin build -help` or `odin help build`");
@@ -1580,45 +1580,45 @@ gb_internal void remove_temp_files(lbGenerator *gen) {
gb_internal void print_show_help(String const arg0, String const &command) {
- print_usage_line(0, "%.*s is a tool for managing Odin source code", LIT(arg0));
+ print_usage_line(0, "%.*s is a tool for managing Odin source code.", LIT(arg0));
print_usage_line(0, "Usage:");
print_usage_line(1, "%.*s %.*s [arguments]", LIT(arg0), LIT(command));
print_usage_line(0, "");
if (command == "build") {
- print_usage_line(1, "build Compile directory of .odin files as an executable.");
+ print_usage_line(1, "build Compiles directory of .odin files as an executable.");
print_usage_line(2, "One must contain the program's entry point, all must be in the same package.");
print_usage_line(2, "Use `-file` to build a single file instead.");
print_usage_line(2, "Examples:");
- print_usage_line(3, "odin build . # Build package in current directory");
- print_usage_line(3, "odin build <dir> # Build package in <dir>");
- print_usage_line(3, "odin build filename.odin -file # Build single-file package, must contain entry point.");
+ print_usage_line(3, "odin build . Builds package in current directory.");
+ print_usage_line(3, "odin build <dir> Builds package in <dir>.");
+ print_usage_line(3, "odin build filename.odin -file Builds single-file package, must contain entry point.");
} else if (command == "run") {
print_usage_line(1, "run Same as 'build', but also then runs the newly compiled executable.");
print_usage_line(2, "Append an empty flag and then the args, '-- <args>', to specify args for the output.");
print_usage_line(2, "Examples:");
- print_usage_line(3, "odin run . # Build and run package in current directory");
- print_usage_line(3, "odin run <dir> # Build and run package in <dir>");
- print_usage_line(3, "odin run filename.odin -file # Build and run single-file package, must contain entry point.");
+ print_usage_line(3, "odin run . Builds and runs package in current directory.");
+ print_usage_line(3, "odin run <dir> Builds and runs package in <dir>.");
+ print_usage_line(3, "odin run filename.odin -file Builds and runs single-file package, must contain entry point.");
} else if (command == "check") {
- print_usage_line(1, "check Parse and type check directory of .odin files");
+ print_usage_line(1, "check Parses and type checks directory of .odin files.");
print_usage_line(2, "Examples:");
- print_usage_line(3, "odin check . # Type check package in current directory");
- print_usage_line(3, "odin check <dir> # Type check package in <dir>");
- print_usage_line(3, "odin check filename.odin -file # Type check single-file package, must contain entry point.");
+ print_usage_line(3, "odin check . Type checks package in current directory.");
+ print_usage_line(3, "odin check <dir> Type checks package in <dir>.");
+ print_usage_line(3, "odin check filename.odin -file Type checks single-file package, must contain entry point.");
} else if (command == "test") {
- print_usage_line(1, "test Build and runs procedures with the attribute @(test) in the initial package");
+ print_usage_line(1, "test Builds and runs procedures with the attribute @(test) in the initial package.");
} else if (command == "doc") {
- print_usage_line(1, "doc generate documentation from a directory of .odin files");
+ print_usage_line(1, "doc Generates documentation from a directory of .odin files.");
print_usage_line(2, "Examples:");
- print_usage_line(3, "odin doc . # Generate documentation on package in current directory");
- print_usage_line(3, "odin doc <dir> # Generate documentation on package in <dir>");
- print_usage_line(3, "odin doc filename.odin -file # Generate documentation on single-file package.");
+ print_usage_line(3, "odin doc . Generates documentation on package in current directory.");
+ print_usage_line(3, "odin doc <dir> Generates documentation on package in <dir>.");
+ print_usage_line(3, "odin doc filename.odin -file Generates documentation on single-file package.");
} else if (command == "version") {
- print_usage_line(1, "version print version");
+ print_usage_line(1, "version Prints version.");
} else if (command == "strip-semicolon") {
print_usage_line(1, "strip-semicolon");
- print_usage_line(2, "Parse and type check .odin file(s) and then remove unneeded semicolons from the entire project");
+ print_usage_line(2, "Parses and type checks .odin file(s) and then removes unneeded semicolons from the entire project.");
}
bool doc = command == "doc";
@@ -1642,311 +1642,318 @@ gb_internal void print_show_help(String const arg0, String const &command) {
if (doc) {
print_usage_line(1, "-short");
- print_usage_line(2, "Show shortened documentation for the packages");
+ print_usage_line(2, "Shows shortened documentation for the packages.");
print_usage_line(0, "");
print_usage_line(1, "-all-packages");
- print_usage_line(2, "Generates documentation for all packages used in the current project");
+ print_usage_line(2, "Generates documentation for all packages used in the current project.");
print_usage_line(0, "");
print_usage_line(1, "-doc-format");
- print_usage_line(2, "Generates documentation as the .odin-doc format (useful for external tooling)");
+ print_usage_line(2, "Generates documentation as the .odin-doc format (useful for external tooling).");
print_usage_line(0, "");
}
if (run_or_build) {
print_usage_line(1, "-out:<filepath>");
- print_usage_line(2, "Set the file name of the outputted executable");
+ print_usage_line(2, "Sets the file name of the outputted executable.");
print_usage_line(2, "Example: -out:foo.exe");
print_usage_line(0, "");
print_usage_line(1, "-o:<string>");
- print_usage_line(2, "Set the optimization mode for compilation");
+ print_usage_line(2, "Sets the optimization mode for compilation.");
+ print_usage_line(2, "Available options:");
+ print_usage_line(3, "-o:none");
+ print_usage_line(3, "-o:minimal");
+ print_usage_line(3, "-o:size");
+ print_usage_line(3, "-o:speed");
if (LB_USE_NEW_PASS_SYSTEM) {
- print_usage_line(2, "Accepted values: none, minimal, size, speed, aggressive");
- } else {
- print_usage_line(2, "Accepted values: none, minimal, size, speed");
+ print_usage_line(3, "-o:aggressive");
}
- print_usage_line(2, "Example: -o:speed");
- print_usage_line(2, "The default is -o:minimal");
+ print_usage_line(2, "The default is -o:minimal.");
print_usage_line(0, "");
}
if (check) {
print_usage_line(1, "-show-timings");
- print_usage_line(2, "Shows basic overview of the timings of different stages within the compiler in milliseconds");
+ print_usage_line(2, "Shows basic overview of the timings of different stages within the compiler in milliseconds.");
print_usage_line(0, "");
print_usage_line(1, "-show-more-timings");
- print_usage_line(2, "Shows an advanced overview of the timings of different stages within the compiler in milliseconds");
+ print_usage_line(2, "Shows an advanced overview of the timings of different stages within the compiler in milliseconds.");
print_usage_line(0, "");
print_usage_line(1, "-show-system-calls");
- print_usage_line(2, "Prints the whole command and arguments for calls to external tools like linker and assembler");
+ print_usage_line(2, "Prints the whole command and arguments for calls to external tools like linker and assembler.");
print_usage_line(0, "");
print_usage_line(1, "-export-timings:<format>");
- print_usage_line(2, "Export timings to one of a few formats. Requires `-show-timings` or `-show-more-timings`");
+ print_usage_line(2, "Exports timings to one of a few formats. Requires `-show-timings` or `-show-more-timings`.");
print_usage_line(2, "Available options:");
- print_usage_line(3, "-export-timings:json Export compile time stats to JSON");
- print_usage_line(3, "-export-timings:csv Export compile time stats to CSV");
+ print_usage_line(3, "-export-timings:json Exports compile time stats to JSON.");
+ print_usage_line(3, "-export-timings:csv Exports compile time stats to CSV.");
print_usage_line(0, "");
print_usage_line(1, "-export-timings-file:<filename>");
- print_usage_line(2, "Specify the filename for `-export-timings`");
+ print_usage_line(2, "Specifies the filename for `-export-timings`.");
print_usage_line(2, "Example: -export-timings-file:timings.json");
print_usage_line(0, "");
print_usage_line(1, "-thread-count:<integer>");
- print_usage_line(2, "Override the number of threads the compiler will use to compile with");
+ print_usage_line(2, "Overrides the number of threads the compiler will use to compile with.");
print_usage_line(2, "Example: -thread-count:2");
print_usage_line(0, "");
}
if (check_only) {
print_usage_line(1, "-show-unused");
- print_usage_line(2, "Shows unused package declarations within the current project");
+ print_usage_line(2, "Shows unused package declarations within the current project.");
print_usage_line(0, "");
print_usage_line(1, "-show-unused-with-location");
- print_usage_line(2, "Shows unused package declarations within the current project with the declarations source location");
+ print_usage_line(2, "Shows unused package declarations within the current project with the declarations source location.");
print_usage_line(0, "");
}
if (run_or_build) {
print_usage_line(1, "-keep-temp-files");
- print_usage_line(2, "Keeps the temporary files generated during compilation");
+ print_usage_line(2, "Keeps the temporary files generated during compilation.");
print_usage_line(0, "");
} else if (strip_semicolon) {
print_usage_line(1, "-keep-temp-files");
- print_usage_line(2, "Keeps the temporary files generated during stripping the unneeded semicolons from files");
+ print_usage_line(2, "Keeps the temporary files generated during stripping the unneeded semicolons from files.");
print_usage_line(0, "");
}
if (check) {
print_usage_line(1, "-collection:<name>=<filepath>");
- print_usage_line(2, "Defines a library collection used for imports");
+ print_usage_line(2, "Defines a library collection used for imports.");
print_usage_line(2, "Example: -collection:shared=dir/to/shared");
print_usage_line(2, "Usage in Code:");
print_usage_line(3, "import \"shared:foo\"");
print_usage_line(0, "");
print_usage_line(1, "-define:<name>=<value>");
- print_usage_line(2, "Defines a scalar boolean, integer or string as global constant");
+ print_usage_line(2, "Defines a scalar boolean, integer or string as global constant.");
print_usage_line(2, "Example: -define:SPAM=123");
- print_usage_line(2, "To use: #config(SPAM, default_value)");
+ print_usage_line(2, "Usage in code:");
+ print_usage_line(3, "#config(SPAM, default_value)");
print_usage_line(0, "");
}
if (build) {
print_usage_line(1, "-build-mode:<mode>");
- print_usage_line(2, "Sets the build mode");
+ print_usage_line(2, "Sets the build mode.");
print_usage_line(2, "Available options:");
- print_usage_line(3, "-build-mode:exe Build as an executable");
- print_usage_line(3, "-build-mode:dll Build as a dynamically linked library");
- print_usage_line(3, "-build-mode:shared Build as a dynamically linked library");
- print_usage_line(3, "-build-mode:obj Build as an object file");
- print_usage_line(3, "-build-mode:object Build as an object file");
- print_usage_line(3, "-build-mode:assembly Build as an assembly file");
- print_usage_line(3, "-build-mode:assembler Build as an assembly file");
- print_usage_line(3, "-build-mode:asm Build as an assembly file");
- print_usage_line(3, "-build-mode:llvm-ir Build as an LLVM IR file");
- print_usage_line(3, "-build-mode:llvm Build as an LLVM IR file");
+ print_usage_line(3, "-build-mode:exe Builds as an executable.");
+ print_usage_line(3, "-build-mode:dll Builds as a dynamically linked library.");
+ print_usage_line(3, "-build-mode:shared Builds as a dynamically linked library.");
+ print_usage_line(3, "-build-mode:obj Builds as an object file.");
+ print_usage_line(3, "-build-mode:object Builds as an object file.");
+ print_usage_line(3, "-build-mode:assembly Builds as an assembly file.");
+ print_usage_line(3, "-build-mode:assembler Builds as an assembly file.");
+ print_usage_line(3, "-build-mode:asm Builds as an assembly file.");
+ print_usage_line(3, "-build-mode:llvm-ir Builds as an LLVM IR file.");
+ print_usage_line(3, "-build-mode:llvm Builds as an LLVM IR file.");
print_usage_line(0, "");
}
if (check) {
print_usage_line(1, "-target:<string>");
- print_usage_line(2, "Sets the target for the executable to be built in");
+ print_usage_line(2, "Sets the target for the executable to be built in.");
print_usage_line(0, "");
}
if (run_or_build) {
print_usage_line(1, "-debug");
- print_usage_line(2, "Enabled debug information, and defines the global constant ODIN_DEBUG to be 'true'");
+ print_usage_line(2, "Enables debug information, and defines the global constant ODIN_DEBUG to be 'true'.");
print_usage_line(0, "");
print_usage_line(1, "-disable-assert");
- print_usage_line(2, "Disable the code generation of the built-in run-time 'assert' procedure, and defines the global constant ODIN_DISABLE_ASSERT to be 'true'");
+ print_usage_line(2, "Disables the code generation of the built-in run-time 'assert' procedure, and defines the global constant ODIN_DISABLE_ASSERT to be 'true'.");
print_usage_line(0, "");
print_usage_line(1, "-no-bounds-check");
- print_usage_line(2, "Disables bounds checking program wide");
+ print_usage_line(2, "Disables bounds checking program wide.");
print_usage_line(0, "");
print_usage_line(1, "-no-crt");
- print_usage_line(2, "Disables automatic linking with the C Run Time");
+ print_usage_line(2, "Disables automatic linking with the C Run Time.");
print_usage_line(0, "");
print_usage_line(1, "-no-thread-local");
- print_usage_line(2, "Ignore @thread_local attribute, effectively treating the program as if it is single-threaded");
+ print_usage_line(2, "Ignores @thread_local attribute, effectively treating the program as if it is single-threaded.");
print_usage_line(0, "");
print_usage_line(1, "-lld");
- print_usage_line(2, "Use the LLD linker rather than the default");
+ print_usage_line(2, "Uses the LLD linker rather than the default.");
print_usage_line(0, "");
print_usage_line(1, "-use-separate-modules");
print_usage_line(1, "[EXPERIMENTAL]");
- print_usage_line(2, "The backend generates multiple build units which are then linked together");
- print_usage_line(2, "Normally, a single build unit is generated for a standard project");
+ print_usage_line(2, "The backend generates multiple build units which are then linked together.");
+ print_usage_line(2, "Normally, a single build unit is generated for a standard project.");
print_usage_line(0, "");
}
if (check) {
print_usage_line(1, "-no-threaded-checker");
- print_usage_line(2, "Disabled multithreading in the semantic checker stage");
+ print_usage_line(2, "Disables multithreading in the semantic checker stage.");
print_usage_line(0, "");
}
if (check) {
print_usage_line(1, "-vet");
- print_usage_line(2, "Do extra checks on the code");
+ print_usage_line(2, "Does extra checks on the code.");
print_usage_line(2, "Extra checks include:");
- print_usage_line(2, "-vet-unused");
- print_usage_line(2, "-vet-shadowing");
- print_usage_line(2, "-vet-using-stmt");
+ print_usage_line(3, "-vet-unused");
+ print_usage_line(3, "-vet-shadowing");
+ print_usage_line(3, "-vet-using-stmt");
print_usage_line(0, "");
print_usage_line(1, "-vet-unused");
- print_usage_line(2, "Checks for unused declarations");
+ print_usage_line(2, "Checks for unused declarations.");
print_usage_line(0, "");
print_usage_line(1, "-vet-shadowing");
- print_usage_line(2, "Checks for variable shadowing within procedures");
+ print_usage_line(2, "Checks for variable shadowing within procedures.");
print_usage_line(0, "");
print_usage_line(1, "-vet-using-stmt");
- print_usage_line(2, "Checks for the use of 'using' as a statement");
- print_usage_line(2, "'using' is considered bad practice outside of immediate refactoring");
+ print_usage_line(2, "Checks for the use of 'using' as a statement.");
+ print_usage_line(2, "'using' is considered bad practice outside of immediate refactoring.");
print_usage_line(0, "");
print_usage_line(1, "-vet-using-param");
- print_usage_line(2, "Checks for the use of 'using' on procedure parameters");
- print_usage_line(2, "'using' is considered bad practice outside of immediate refactoring");
+ print_usage_line(2, "Checks for the use of 'using' on procedure parameters.");
+ print_usage_line(2, "'using' is considered bad practice outside of immediate refactoring.");
print_usage_line(0, "");
print_usage_line(1, "-vet-style");
- print_usage_line(2, "Errs on missing trailing commas followed by a newline");
- print_usage_line(2, "Errs on deprecated syntax");
- print_usage_line(2, "Does not err on unneeded tokens (unlike -strict-style)");
+ print_usage_line(2, "Errs on missing trailing commas followed by a newline.");
+ print_usage_line(2, "Errs on deprecated syntax.");
+ print_usage_line(2, "Does not err on unneeded tokens (unlike -strict-style).");
print_usage_line(0, "");
print_usage_line(1, "-vet-semicolon");
- print_usage_line(2, "Errs on unneeded semicolons");
+ print_usage_line(2, "Errs on unneeded semicolons.");
print_usage_line(0, "");
}
if (check) {
print_usage_line(1, "-ignore-unknown-attributes");
- print_usage_line(2, "Ignores unknown attributes");
- print_usage_line(2, "This can be used with metaprogramming tools");
+ print_usage_line(2, "Ignores unknown attributes.");
+ print_usage_line(2, "This can be used with metaprogramming tools.");
print_usage_line(0, "");
if (command != "test") {
print_usage_line(1, "-no-entry-point");
- print_usage_line(2, "Removes default requirement of an entry point (e.g. main procedure)");
+ print_usage_line(2, "Removes default requirement of an entry point (e.g. main procedure).");
print_usage_line(0, "");
}
}
if (test_only) {
print_usage_line(1, "-test-name:<string>");
- print_usage_line(2, "Run specific test only by name");
+ print_usage_line(2, "Runs specific test only by name.");
print_usage_line(0, "");
}
if (run_or_build) {
print_usage_line(1, "-minimum-os-version:<string>");
- print_usage_line(2, "Sets the minimum OS version targeted by the application");
- print_usage_line(2, "e.g. -minimum-os-version:12.0.0");
- print_usage_line(2, "(Only used when target is Darwin)");
+ print_usage_line(2, "Sets the minimum OS version targeted by the application.");
+ print_usage_line(2, "Example: -minimum-os-version:12.0.0");
+ print_usage_line(2, "(Only used when target is Darwin.)");
print_usage_line(0, "");
print_usage_line(1, "-extra-linker-flags:<string>");
- print_usage_line(2, "Adds extra linker specific flags in a string");
+ print_usage_line(2, "Adds extra linker specific flags in a string.");
print_usage_line(0, "");
print_usage_line(1, "-extra-assembler-flags:<string>");
- print_usage_line(2, "Adds extra assembler specific flags in a string");
+ print_usage_line(2, "Adds extra assembler specific flags in a string.");
print_usage_line(0, "");
print_usage_line(1, "-microarch:<string>");
- print_usage_line(2, "Specifies the specific micro-architecture for the build in a string");
+ print_usage_line(2, "Specifies the specific micro-architecture for the build in a string.");
print_usage_line(2, "Examples:");
print_usage_line(3, "-microarch:sandybridge");
print_usage_line(3, "-microarch:native");
+ print_usage_line(3, "-microarch:? for a list");
print_usage_line(0, "");
print_usage_line(1, "-reloc-mode:<string>");
- print_usage_line(2, "Specifies the reloc mode");
- print_usage_line(2, "Options:");
- print_usage_line(3, "default");
- print_usage_line(3, "static");
- print_usage_line(3, "pic");
- print_usage_line(3, "dynamic-no-pic");
+ print_usage_line(2, "Specifies the reloc mode.");
+ print_usage_line(2, "Available options:");
+ print_usage_line(3, "-reloc-mode:default");
+ print_usage_line(3, "-reloc-mode:static");
+ print_usage_line(3, "-reloc-mode:pic");
+ print_usage_line(3, "-reloc-mode:dynamic-no-pic");
print_usage_line(0, "");
print_usage_line(1, "-disable-red-zone");
- print_usage_line(2, "Disable red zone on a supported freestanding target");
+ print_usage_line(2, "Disables red zone on a supported freestanding target.");
print_usage_line(0, "");
print_usage_line(1, "-dynamic-map-calls");
- print_usage_line(2, "Use dynamic map calls to minimize code generation at the cost of runtime execution");
+ print_usage_line(2, "Uses dynamic map calls to minimize code generation at the cost of runtime execution.");
print_usage_line(0, "");
}
if (check) {
print_usage_line(1, "-disallow-do");
- print_usage_line(2, "Disallows the 'do' keyword in the project");
+ print_usage_line(2, "Disallows the 'do' keyword in the project.");
print_usage_line(0, "");
print_usage_line(1, "-default-to-nil-allocator");
- print_usage_line(2, "Sets the default allocator to be the nil_allocator, an allocator which does nothing");
+ print_usage_line(2, "Sets the default allocator to be the nil_allocator, an allocator which does nothing.");
print_usage_line(0, "");
print_usage_line(1, "-strict-style");
- print_usage_line(2, "Errs on unneeded tokens, such as unneeded semicolons");
- print_usage_line(2, "Errs on missing trailing commas followed by a newline");
- print_usage_line(2, "Errs on deprecated syntax");
+ print_usage_line(2, "Errs on unneeded tokens, such as unneeded semicolons.");
+ print_usage_line(2, "Errs on missing trailing commas followed by a newline.");
+ print_usage_line(2, "Errs on deprecated syntax.");
print_usage_line(0, "");
print_usage_line(1, "-ignore-warnings");
- print_usage_line(2, "Ignores warning messages");
+ print_usage_line(2, "Ignores warning messages.");
print_usage_line(0, "");
print_usage_line(1, "-warnings-as-errors");
- print_usage_line(2, "Treats warning messages as error messages");
+ print_usage_line(2, "Treats warning messages as error messages.");
print_usage_line(0, "");
print_usage_line(1, "-terse-errors");
- print_usage_line(2, "Prints a terse error message without showing the code on that line and the location in that line");
+ print_usage_line(2, "Prints a terse error message without showing the code on that line and the location in that line.");
print_usage_line(0, "");
print_usage_line(1, "-error-pos-style:<string>");
- print_usage_line(2, "Options are 'unix', 'odin' and 'default' (odin)");
- print_usage_line(2, "'odin' file/path(45:3)");
- print_usage_line(2, "'unix' file/path:45:3:");
+ print_usage_line(2, "Available options:");
+ print_usage_line(3, "-error-pos-style:unix file/path:45:3:");
+ print_usage_line(3, "-error-pos-style:odin file/path(45:3)");
+ print_usage_line(3, "-error-pos-style:default (Defaults to 'odin'.)");
print_usage_line(0, "");
-
print_usage_line(1, "-max-error-count:<integer>");
- print_usage_line(2, "Set the maximum number of errors that can be displayed before the compiler terminates");
- print_usage_line(2, "Must be an integer >0");
- print_usage_line(2, "If not set, the default max error count is %d", DEFAULT_MAX_ERROR_COLLECTOR_COUNT);
+ print_usage_line(2, "Sets the maximum number of errors that can be displayed before the compiler terminates.");
+ print_usage_line(2, "Must be an integer >0.");
+ print_usage_line(2, "If not set, the default max error count is %d.", DEFAULT_MAX_ERROR_COLLECTOR_COUNT);
print_usage_line(0, "");
print_usage_line(1, "-foreign-error-procedures");
- print_usage_line(2, "States that the error procedues used in the runtime are defined in a separate translation unit");
+ print_usage_line(2, "States that the error procedures used in the runtime are defined in a separate translation unit.");
print_usage_line(0, "");
}
if (run_or_build) {
print_usage_line(1, "-sanitize:<string>");
- print_usage_line(1, "Enables sanitization analysis");
- print_usage_line(1, "Options are 'address', 'memory', and 'thread'");
- print_usage_line(1, "NOTE: This flag can be used multiple times");
+ print_usage_line(2, "Enables sanitization analysis.");
+ print_usage_line(2, "Available options:");
+ print_usage_line(3, "-sanitize:address");
+ print_usage_line(3, "-sanitize:memory");
+ print_usage_line(3, "-sanitize:thread");
+ print_usage_line(2, "NOTE: This flag can be used multiple times.");
print_usage_line(0, "");
}
@@ -1955,27 +1962,27 @@ gb_internal void print_show_help(String const arg0, String const &command) {
#if defined(GB_SYSTEM_WINDOWS)
print_usage_line(1, "-ignore-vs-search");
print_usage_line(2, "[Windows only]");
- print_usage_line(2, "Ignores the Visual Studio search for library paths");
+ print_usage_line(2, "Ignores the Visual Studio search for library paths.");
print_usage_line(0, "");
print_usage_line(1, "-resource:<filepath>");
print_usage_line(2, "[Windows only]");
- print_usage_line(2, "Defines the resource file for the executable");
+ print_usage_line(2, "Defines the resource file for the executable.");
print_usage_line(2, "Example: -resource:path/to/file.rc");
print_usage_line(0, "");
print_usage_line(1, "-pdb-name:<filepath>");
print_usage_line(2, "[Windows only]");
- print_usage_line(2, "Defines the generated PDB name when -debug is enabled");
+ print_usage_line(2, "Defines the generated PDB name when -debug is enabled.");
print_usage_line(2, "Example: -pdb-name:different.pdb");
print_usage_line(0, "");
print_usage_line(1, "-subsystem:<option>");
print_usage_line(2, "[Windows only]");
- print_usage_line(2, "Defines the subsystem for the application");
+ print_usage_line(2, "Defines the subsystem for the application.");
print_usage_line(2, "Available options:");
- print_usage_line(3, "console");
- print_usage_line(3, "windows");
+ print_usage_line(3, "-subsystem:console");
+ print_usage_line(3, "-subsystem:windows");
print_usage_line(0, "");
#endif
@@ -2518,12 +2525,55 @@ int main(int arg_count, char const **arg_ptr) {
// return 1;
// }
+ // Check chosen microarchitecture. If not found or ?, print list.
+ bool print_microarch_list = true;
+ if (build_context.microarch.len == 0) {
+ // Autodetect, no need to print list.
+ print_microarch_list = false;
+ } else {
+ String march_list = target_microarch_list[build_context.metrics.arch];
+ String_Iterator it = {march_list, 0};
+ for (;;) {
+ String str = string_split_iterator(&it, ',');
+ if (str == "") break;
+ if (str == build_context.microarch) {
+ // Found matching microarch
+ print_microarch_list = false;
+ break;
+ }
+ }
+ }
+
+ String default_march = get_default_microarchitecture();
+ if (print_microarch_list) {
+ if (build_context.microarch != "?") {
+ gb_printf("Unknown microarchitecture '%.*s'.\n", LIT(build_context.microarch));
+ }
+ gb_printf("Possible -microarch values for target %.*s are:\n", LIT(target_arch_names[build_context.metrics.arch]));
+ gb_printf("\n");
+
+ String march_list = target_microarch_list[build_context.metrics.arch];
+ String_Iterator it = {march_list, 0};
+
+ for (;;) {
+ String str = string_split_iterator(&it, ',');
+ if (str == "") break;
+ if (str == default_march) {
+ gb_printf("\t%.*s (default)\n", LIT(str));
+ } else {
+ gb_printf("\t%.*s\n", LIT(str));
+ }
+ }
+ return 0;
+ }
+
// Set and check build paths...
if (!init_build_paths(init_filename)) {
return 1;
}
if (build_context.show_debug_messages) {
+ debugf("Selected microarch: %.*s\n", LIT(default_march));
for_array(i, build_context.build_paths) {
String build_path = path_to_string(heap_allocator(), build_context.build_paths[i]);
debugf("build_paths[%ld]: %.*s\n", i, LIT(build_path));
diff --git a/src/string.cpp b/src/string.cpp
index 6eac4f53b..9fb933b1b 100644
--- a/src/string.cpp
+++ b/src/string.cpp
@@ -10,6 +10,10 @@ struct String {
return text[i];
}
};
+struct String_Iterator {
+ String const &str;
+ isize pos;
+};
// NOTE(bill): used for printf style arguments
#define LIT(x) ((int)(x).len), (x).text
#if defined(GB_COMPILER_MSVC) && _MSC_VER < 1700
@@ -201,11 +205,31 @@ gb_internal gb_inline String string_trim_starts_with(String const &s, String con
}
+gb_internal String string_split_iterator(String_Iterator *it, const char sep) {
+ isize start = it->pos;
+ isize end = it->str.len;
+
+ if (start == end) {
+ return str_lit("");
+ }
+
+ isize i = start;
+ for (; i < it->str.len; i++) {
+ if (it->str[i] == sep) {
+ String res = substring(it->str, start, i);
+ it->pos += res.len + 1;
+ return res;
+ }
+ }
+ it->pos = end;
+ return substring(it->str, start, end);
+}
+
gb_internal gb_inline isize string_extension_position(String const &str) {
isize dot_pos = -1;
isize i = str.len;
while (i --> 0) {
- if (str[i] == GB_PATH_SEPARATOR)
+ if (str[i] == '\\' || str[i] == '/')
break;
if (str[i] == '.') {
dot_pos = i;
diff --git a/src/threading.cpp b/src/threading.cpp
index 3ddc05b0a..74aa3eb7e 100644
--- a/src/threading.cpp
+++ b/src/threading.cpp
@@ -660,7 +660,7 @@ gb_internal void futex_broadcast(Futex *addr) {
gb_internal void futex_wait(Futex *addr, Footex val) {
for (;;) {
int ret = _umtx_op(addr, UMTX_OP_WAIT_UINT, val, 0, NULL);
- if (ret == 0) {
+ if (ret == -1) {
if (errno == ETIMEDOUT || errno == EINTR) {
continue;
}