mirror of
https://github.com/Ed94/Odin.git
synced 2026-06-25 15:05:00 -07:00
Merge branch 'odin-lang:master' into master
This commit is contained in:
+66
-12
@@ -824,6 +824,17 @@ gb_internal void report_os_info() {
|
||||
{"20G624", {20, 6, 0}, "macOS", {"Big Sur", {11, 6, 6}}},
|
||||
{"20G630", {20, 6, 0}, "macOS", {"Big Sur", {11, 6, 7}}},
|
||||
{"20G730", {20, 6, 0}, "macOS", {"Big Sur", {11, 6, 8}}},
|
||||
{"20G817", {20, 6, 0}, "macOS", {"Big Sur", {11, 7, 0}}},
|
||||
{"20G918", {20, 6, 0}, "macOS", {"Big Sur", {11, 7, 1}}},
|
||||
{"20G1020", {20, 6, 0}, "macOS", {"Big Sur", {11, 7, 2}}},
|
||||
{"20G1116", {20, 6, 0}, "macOS", {"Big Sur", {11, 7, 3}}},
|
||||
{"20G1120", {20, 6, 0}, "macOS", {"Big Sur", {11, 7, 4}}},
|
||||
{"20G1225", {20, 6, 0}, "macOS", {"Big Sur", {11, 7, 5}}},
|
||||
{"20G1231", {20, 6, 0}, "macOS", {"Big Sur", {11, 7, 6}}},
|
||||
{"20G1345", {20, 6, 0}, "macOS", {"Big Sur", {11, 7, 7}}},
|
||||
{"20G1351", {20, 6, 0}, "macOS", {"Big Sur", {11, 7, 8}}},
|
||||
{"20G1426", {20, 6, 0}, "macOS", {"Big Sur", {11, 7, 9}}},
|
||||
{"20G1427", {20, 6, 0}, "macOS", {"Big Sur", {11, 7, 10}}},
|
||||
{"21A344", {21, 0, 1}, "macOS", {"Monterey", {12, 0, 0}}},
|
||||
{"21A559", {21, 1, 0}, "macOS", {"Monterey", {12, 0, 1}}},
|
||||
{"21C52", {21, 2, 0}, "macOS", {"Monterey", {12, 1, 0}}},
|
||||
@@ -836,6 +847,42 @@ gb_internal void report_os_info() {
|
||||
{"21F2092", {21, 5, 0}, "macOS", {"Monterey", {12, 4, 0}}},
|
||||
{"21G72", {21, 6, 0}, "macOS", {"Monterey", {12, 5, 0}}},
|
||||
{"21G83", {21, 6, 0}, "macOS", {"Monterey", {12, 5, 1}}},
|
||||
{"21G115", {21, 6, 0}, "macOS", {"Monterey", {12, 6, 0}}},
|
||||
{"21G217", {21, 6, 0}, "macOS", {"Monterey", {12, 6, 1}}},
|
||||
{"21G320", {21, 6, 0}, "macOS", {"Monterey", {12, 6, 2}}},
|
||||
{"21G419", {21, 6, 0}, "macOS", {"Monterey", {12, 6, 3}}},
|
||||
{"21G526", {21, 6, 0}, "macOS", {"Monterey", {12, 6, 4}}},
|
||||
{"21G531", {21, 6, 0}, "macOS", {"Monterey", {12, 6, 5}}},
|
||||
{"21G646", {21, 6, 0}, "macOS", {"Monterey", {12, 6, 6}}},
|
||||
{"21G651", {21, 6, 0}, "macOS", {"Monterey", {12, 6, 7}}},
|
||||
{"21G725", {21, 6, 0}, "macOS", {"Monterey", {12, 6, 8}}},
|
||||
{"21G726", {21, 6, 0}, "macOS", {"Monterey", {12, 6, 9}}},
|
||||
{"21G816", {21, 6, 0}, "macOS", {"Monterey", {12, 7, 0}}},
|
||||
{"21G920", {21, 6, 0}, "macOS", {"Monterey", {12, 7, 1}}},
|
||||
{"21G1974", {21, 6, 0}, "macOS", {"Monterey", {12, 7, 2}}},
|
||||
{"22A380", {13, 0, 0}, "macOS", {"Ventura", {22, 1, 0}}},
|
||||
{"22A400", {13, 0, 1}, "macOS", {"Ventura", {22, 1, 0}}},
|
||||
{"22C65", {13, 1, 0}, "macOS", {"Ventura", {22, 2, 0}}},
|
||||
{"22D49", {13, 2, 0}, "macOS", {"Ventura", {22, 3, 0}}},
|
||||
{"22D68", {13, 2, 1}, "macOS", {"Ventura", {22, 3, 0}}},
|
||||
{"22E252", {13, 3, 0}, "macOS", {"Ventura", {22, 4, 0}}},
|
||||
{"22E261", {13, 3, 1}, "macOS", {"Ventura", {22, 4, 0}}},
|
||||
{"22F66", {13, 4, 0}, "macOS", {"Ventura", {22, 5, 0}}},
|
||||
{"22F82", {13, 4, 1}, "macOS", {"Ventura", {22, 5, 0}}},
|
||||
{"22E772610a", {13, 4, 1}, "macOS", {"Ventura", {22, 5, 0}}},
|
||||
{"22F770820d", {13, 4, 1}, "macOS", {"Ventura", {22, 5, 0}}},
|
||||
{"22G74", {13, 5, 0}, "macOS", {"Ventura", {22, 6, 0}}},
|
||||
{"22G90", {13, 5, 1}, "macOS", {"Ventura", {22, 6, 0}}},
|
||||
{"22G91", {13, 5, 2}, "macOS", {"Ventura", {22, 6, 0}}},
|
||||
{"22G120", {13, 6, 0}, "macOS", {"Ventura", {22, 6, 0}}},
|
||||
{"22G313", {13, 6, 1}, "macOS", {"Ventura", {22, 6, 0}}},
|
||||
{"22G320", {13, 6, 2}, "macOS", {"Ventura", {22, 6, 0}}},
|
||||
{"23A344", {23, 0, 0}, "macOS", {"Sonoma", {14, 0, 0}}},
|
||||
{"23B74", {23, 1, 0}, "macOS", {"Sonoma", {14, 1, 0}}},
|
||||
{"23B81", {23, 1, 0}, "macOS", {"Sonoma", {14, 1, 1}}},
|
||||
{"23B92", {23, 1, 0}, "macOS", {"Sonoma", {14, 1, 2}}},
|
||||
{"23C64", {23, 2, 0}, "macOS", {"Sonoma", {14, 2, 0}}},
|
||||
{"23C71", {23, 2, 0}, "macOS", {"Sonoma", {14, 2, 1}}},
|
||||
};
|
||||
|
||||
|
||||
@@ -867,37 +914,44 @@ gb_internal void report_os_info() {
|
||||
|
||||
// Scan table for match on BUILD
|
||||
int macos_release_count = sizeof(macos_release_map) / sizeof(macos_release_map[0]);
|
||||
Darwin_To_Release match = {};
|
||||
|
||||
Darwin_To_Release build_match = {};
|
||||
Darwin_To_Release kernel_match = {};
|
||||
|
||||
for (int build = 0; build < macos_release_count; build++) {
|
||||
Darwin_To_Release rel = macos_release_map[build];
|
||||
|
||||
|
||||
// Do we have an exact match on the BUILD?
|
||||
if (gb_strcmp(rel.build, (const char *)build_buffer) == 0) {
|
||||
match = rel;
|
||||
build_match = rel;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// Do we have an exact Darwin match?
|
||||
if (rel.darwin[0] == major && rel.darwin[1] == minor && rel.darwin[2] == patch) {
|
||||
match = rel;
|
||||
break;
|
||||
kernel_match = rel;
|
||||
}
|
||||
|
||||
|
||||
// Major kernel version needs to match exactly,
|
||||
if (rel.darwin[0] == major) {
|
||||
// No major version match yet.
|
||||
if (!match.os_name) {
|
||||
match = rel;
|
||||
if (!kernel_match.os_name) {
|
||||
kernel_match = rel;
|
||||
}
|
||||
if (minor >= rel.darwin[1]) {
|
||||
match = rel;
|
||||
kernel_match = rel;
|
||||
if (patch >= rel.darwin[2]) {
|
||||
match = rel;
|
||||
kernel_match = rel;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Darwin_To_Release match = {};
|
||||
if(!build_match.build) {
|
||||
match = kernel_match;
|
||||
} else {
|
||||
match = build_match;
|
||||
}
|
||||
|
||||
if (match.os_name) {
|
||||
gb_printf("%s %s %d", match.os_name, match.release.name, match.release.version[0]);
|
||||
|
||||
+60
-21
@@ -56,6 +56,19 @@ enum TargetABIKind : u16 {
|
||||
TargetABI_COUNT,
|
||||
};
|
||||
|
||||
enum Windows_Subsystem : u8 {
|
||||
Windows_Subsystem_BOOT_APPLICATION,
|
||||
Windows_Subsystem_CONSOLE, // Default,
|
||||
Windows_Subsystem_EFI_APPLICATION,
|
||||
Windows_Subsystem_EFI_BOOT_SERVICE_DRIVER,
|
||||
Windows_Subsystem_EFI_ROM,
|
||||
Windows_Subsystem_EFI_RUNTIME_DRIVER,
|
||||
Windows_Subsystem_NATIVE,
|
||||
Windows_Subsystem_POSIX,
|
||||
Windows_Subsystem_WINDOWS,
|
||||
Windows_Subsystem_WINDOWSCE,
|
||||
Windows_Subsystem_COUNT,
|
||||
};
|
||||
|
||||
gb_global String target_os_names[TargetOs_COUNT] = {
|
||||
str_lit(""),
|
||||
@@ -120,6 +133,19 @@ gb_global TargetEndianKind target_endians[TargetArch_COUNT] = {
|
||||
TargetEndian_Little,
|
||||
};
|
||||
|
||||
gb_global String windows_subsystem_names[Windows_Subsystem_COUNT] = {
|
||||
str_lit("BOOT_APPLICATION"),
|
||||
str_lit("CONSOLE"), // Default
|
||||
str_lit("EFI_APPLICATION"),
|
||||
str_lit("EFI_BOOT_SERVICE_DRIVER"),
|
||||
str_lit("EFI_ROM"),
|
||||
str_lit("EFI_RUNTIME_DRIVER"),
|
||||
str_lit("NATIVE"),
|
||||
str_lit("POSIX"),
|
||||
str_lit("WINDOWS"),
|
||||
str_lit("WINDOWSCE"),
|
||||
};
|
||||
|
||||
#ifndef ODIN_VERSION_RAW
|
||||
#define ODIN_VERSION_RAW "dev-unknown-unknown"
|
||||
#endif
|
||||
@@ -287,14 +313,15 @@ enum SanitizerFlags : u32 {
|
||||
// This stores the information for the specify architecture of this build
|
||||
struct BuildContext {
|
||||
// Constants
|
||||
String ODIN_OS; // target operating system
|
||||
String ODIN_ARCH; // target architecture
|
||||
String ODIN_VENDOR; // compiler vendor
|
||||
String ODIN_VERSION; // compiler version
|
||||
String ODIN_ROOT; // Odin ROOT
|
||||
String ODIN_BUILD_PROJECT_NAME; // Odin main/initial package's directory name
|
||||
bool ODIN_DEBUG; // Odin in debug mode
|
||||
bool ODIN_DISABLE_ASSERT; // Whether the default 'assert' et al is disabled in code or not
|
||||
String ODIN_OS; // Target operating system
|
||||
String ODIN_ARCH; // Target architecture
|
||||
String ODIN_VENDOR; // Compiler vendor
|
||||
String ODIN_VERSION; // Compiler version
|
||||
String ODIN_ROOT; // Odin ROOT
|
||||
String ODIN_BUILD_PROJECT_NAME; // Odin main/initial package's directory name
|
||||
String ODIN_WINDOWS_SUBSYSTEM; // Empty string for non-Windows targets
|
||||
bool ODIN_DEBUG; // Odin in debug mode
|
||||
bool ODIN_DISABLE_ASSERT; // Whether the default 'assert' et al is disabled in code or not
|
||||
bool ODIN_DEFAULT_TO_NIL_ALLOCATOR; // Whether the default allocator is a "nil" allocator or not (i.e. it does nothing)
|
||||
bool ODIN_FOREIGN_ERROR_PROCEDURES;
|
||||
bool ODIN_VALGRIND_SUPPORT;
|
||||
@@ -361,12 +388,12 @@ struct BuildContext {
|
||||
bool ignore_warnings;
|
||||
bool warnings_as_errors;
|
||||
bool hide_error_line;
|
||||
bool terse_errors;
|
||||
bool has_ansi_terminal_colours;
|
||||
|
||||
bool ignore_lazy;
|
||||
bool ignore_llvm_build;
|
||||
|
||||
bool use_subsystem_windows;
|
||||
bool ignore_microsoft_magic;
|
||||
bool linker_map_file;
|
||||
|
||||
@@ -581,7 +608,13 @@ gb_global TargetMetrics target_freestanding_amd64_sysv = {
|
||||
TargetABI_SysV,
|
||||
};
|
||||
|
||||
|
||||
gb_global TargetMetrics target_freestanding_arm64 = {
|
||||
TargetOs_freestanding,
|
||||
TargetArch_arm64,
|
||||
8, 8, 8, 16,
|
||||
str_lit("aarch64-none-elf"),
|
||||
str_lit("e-m:o-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"),
|
||||
};
|
||||
|
||||
struct NamedTargetMetrics {
|
||||
String name;
|
||||
@@ -616,6 +649,7 @@ gb_global NamedTargetMetrics named_targets[] = {
|
||||
{ str_lit("wasi_wasm64p32"), &target_wasi_wasm64p32 },
|
||||
|
||||
{ str_lit("freestanding_amd64_sysv"), &target_freestanding_amd64_sysv },
|
||||
{ str_lit("freestanding_arm64"), &target_freestanding_arm64 },
|
||||
};
|
||||
|
||||
gb_global NamedTargetMetrics *selected_target_metrics;
|
||||
@@ -1274,8 +1308,6 @@ gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subta
|
||||
GB_ASSERT(metrics->int_size == 2*metrics->ptr_size);
|
||||
}
|
||||
|
||||
|
||||
|
||||
bc->metrics = *metrics;
|
||||
switch (subtarget) {
|
||||
case Subtarget_Default:
|
||||
@@ -1292,14 +1324,14 @@ gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subta
|
||||
break;
|
||||
}
|
||||
|
||||
bc->ODIN_OS = target_os_names[metrics->os];
|
||||
bc->ODIN_ARCH = target_arch_names[metrics->arch];
|
||||
bc->endian_kind = target_endians[metrics->arch];
|
||||
bc->ptr_size = metrics->ptr_size;
|
||||
bc->int_size = metrics->int_size;
|
||||
bc->max_align = metrics->max_align;
|
||||
bc->max_simd_align = metrics->max_simd_align;
|
||||
bc->link_flags = str_lit(" ");
|
||||
bc->ODIN_OS = target_os_names[metrics->os];
|
||||
bc->ODIN_ARCH = target_arch_names[metrics->arch];
|
||||
bc->endian_kind = target_endians[metrics->arch];
|
||||
bc->ptr_size = metrics->ptr_size;
|
||||
bc->int_size = metrics->int_size;
|
||||
bc->max_align = metrics->max_align;
|
||||
bc->max_simd_align = metrics->max_simd_align;
|
||||
bc->link_flags = str_lit(" ");
|
||||
|
||||
#if defined(DEFAULT_TO_THREADED_CHECKER)
|
||||
bc->threaded_checker = true;
|
||||
@@ -1321,6 +1353,11 @@ gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subta
|
||||
}
|
||||
}
|
||||
|
||||
// Default to subsystem:CONSOLE on Windows targets
|
||||
if (bc->ODIN_WINDOWS_SUBSYSTEM == "" && bc->metrics.os == TargetOs_windows) {
|
||||
bc->ODIN_WINDOWS_SUBSYSTEM = windows_subsystem_names[Windows_Subsystem_CONSOLE];
|
||||
}
|
||||
|
||||
// NOTE(zangent): The linker flags to set the build architecture are different
|
||||
// across OSs. It doesn't make sense to allocate extra data on the heap
|
||||
// here, so I just #defined the linker flags to keep things concise.
|
||||
@@ -1492,7 +1529,7 @@ gb_internal void enable_target_feature(TokenPos pos, String const &target_featur
|
||||
}
|
||||
|
||||
|
||||
gb_internal char const *target_features_set_to_cstring(gbAllocator allocator, bool with_quotes) {
|
||||
gb_internal char const *target_features_set_to_cstring(gbAllocator allocator, bool with_quotes, bool with_plus) {
|
||||
isize len = 0;
|
||||
isize i = 0;
|
||||
for (String const &feature : build_context.target_features_set) {
|
||||
@@ -1501,6 +1538,7 @@ gb_internal char const *target_features_set_to_cstring(gbAllocator allocator, bo
|
||||
}
|
||||
len += feature.len;
|
||||
if (with_quotes) len += 2;
|
||||
if (with_plus) len += 1;
|
||||
i += 1;
|
||||
}
|
||||
char *features = gb_alloc_array(allocator, char, len+1);
|
||||
@@ -1512,6 +1550,7 @@ gb_internal char const *target_features_set_to_cstring(gbAllocator allocator, bo
|
||||
}
|
||||
|
||||
if (with_quotes) features[len++] = '"';
|
||||
if (with_plus) features[len++] = '+';
|
||||
gb_memmove(features + len, feature.text, feature.len);
|
||||
len += feature.len;
|
||||
if (with_quotes) features[len++] = '"';
|
||||
|
||||
+155
-57
@@ -1666,7 +1666,12 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
|
||||
if (ce->args.count > 0) {
|
||||
if (ce->args[0]->kind == Ast_FieldValue) {
|
||||
if (id != BuiltinProc_soa_zip) {
|
||||
switch (id) {
|
||||
case BuiltinProc_soa_zip:
|
||||
case BuiltinProc_quaternion:
|
||||
// okay
|
||||
break;
|
||||
default:
|
||||
error(call, "'field = value' calling is not allowed on built-in procedures");
|
||||
return false;
|
||||
}
|
||||
@@ -2299,61 +2304,150 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
}
|
||||
|
||||
case BuiltinProc_quaternion: {
|
||||
// quaternion :: proc(real, imag, jmag, kmag: float_type) -> complex_type
|
||||
Operand x = *operand;
|
||||
Operand y = {};
|
||||
Operand z = {};
|
||||
Operand w = {};
|
||||
bool first_is_field_value = (ce->args[0]->kind == Ast_FieldValue);
|
||||
|
||||
bool fail = false;
|
||||
for (Ast *arg : ce->args) {
|
||||
bool mix = false;
|
||||
if (first_is_field_value) {
|
||||
mix = arg->kind != Ast_FieldValue;
|
||||
} else {
|
||||
mix = arg->kind == Ast_FieldValue;
|
||||
}
|
||||
if (mix) {
|
||||
error(arg, "Mixture of 'field = value' and value elements in the procedure call '%.*s' is not allowed", LIT(builtin_name));
|
||||
fail = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (fail) {
|
||||
operand->type = t_untyped_quaternion;
|
||||
operand->mode = Addressing_Constant;
|
||||
operand->value = exact_value_quaternion(0.0, 0.0, 0.0, 0.0);
|
||||
break;
|
||||
}
|
||||
|
||||
// quaternion :: proc(imag, jmag, kmag, real: float_type) -> complex_type
|
||||
Operand xyzw[4] = {};
|
||||
|
||||
u32 first_index = 0;
|
||||
|
||||
// NOTE(bill): Invalid will be the default till fixed
|
||||
operand->type = t_invalid;
|
||||
operand->mode = Addressing_Invalid;
|
||||
|
||||
check_expr(c, &y, ce->args[1]);
|
||||
if (y.mode == Addressing_Invalid) {
|
||||
return false;
|
||||
}
|
||||
check_expr(c, &z, ce->args[2]);
|
||||
if (y.mode == Addressing_Invalid) {
|
||||
return false;
|
||||
}
|
||||
check_expr(c, &w, ce->args[3]);
|
||||
if (y.mode == Addressing_Invalid) {
|
||||
return false;
|
||||
}
|
||||
if (first_is_field_value) {
|
||||
u32 fields_set[4] = {}; // 0 unset, 1 xyzw, 2 real/etc
|
||||
|
||||
convert_to_typed(c, &x, y.type); if (x.mode == Addressing_Invalid) return false;
|
||||
convert_to_typed(c, &y, x.type); if (y.mode == Addressing_Invalid) return false;
|
||||
convert_to_typed(c, &z, x.type); if (z.mode == Addressing_Invalid) return false;
|
||||
convert_to_typed(c, &w, x.type); if (w.mode == Addressing_Invalid) return false;
|
||||
if (x.mode == Addressing_Constant &&
|
||||
y.mode == Addressing_Constant &&
|
||||
z.mode == Addressing_Constant &&
|
||||
w.mode == Addressing_Constant) {
|
||||
x.value = exact_value_to_float(x.value);
|
||||
y.value = exact_value_to_float(y.value);
|
||||
z.value = exact_value_to_float(z.value);
|
||||
w.value = exact_value_to_float(w.value);
|
||||
if (is_type_numeric(x.type) && x.value.kind == ExactValue_Float) {
|
||||
x.type = t_untyped_float;
|
||||
auto const check_field = [&fields_set, &builtin_name](CheckerContext *c, Operand *o, Ast *arg, i32 *index) -> bool {
|
||||
*index = -1;
|
||||
|
||||
ast_node(field, FieldValue, arg);
|
||||
String name = {};
|
||||
if (field->field->kind == Ast_Ident) {
|
||||
name = field->field->Ident.token.string;
|
||||
} else {
|
||||
error(field->field, "Expected an identifier for field argument");
|
||||
return false;
|
||||
}
|
||||
|
||||
u32 style = 0;
|
||||
|
||||
if (name == "x") {
|
||||
*index = 0; style = 1;
|
||||
} else if (name == "y") {
|
||||
*index = 1; style = 1;
|
||||
} else if (name == "z") {
|
||||
*index = 2; style = 1;
|
||||
} else if (name == "w") {
|
||||
*index = 3; style = 1;
|
||||
} else if (name == "imag") {
|
||||
*index = 0; style = 2;
|
||||
} else if (name == "jmag") {
|
||||
*index = 1; style = 2;
|
||||
} else if (name == "kmag") {
|
||||
*index = 2; style = 2;
|
||||
} else if (name == "real") {
|
||||
*index = 3; style = 2;
|
||||
} else {
|
||||
error(field->field, "Unknown name for '%.*s', expected (w, x, y, z; or real, imag, jmag, kmag), got '%.*s'", LIT(builtin_name), LIT(name));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fields_set[*index]) {
|
||||
error(field->field, "Previously assigned field: '%.*s'", LIT(name));
|
||||
}
|
||||
fields_set[*index] = style;
|
||||
|
||||
check_expr(c, o, field->value);
|
||||
return o->mode != Addressing_Invalid;
|
||||
};
|
||||
|
||||
Operand *refs[4] = {&xyzw[0], &xyzw[1], &xyzw[2], &xyzw[3]};
|
||||
|
||||
for (i32 i = 0; i < 4; i++) {
|
||||
i32 index = -1;
|
||||
Operand o = {};
|
||||
bool ok = check_field(c, &o, ce->args[i], &index);
|
||||
if (!ok || index < 0) {
|
||||
return false;
|
||||
}
|
||||
first_index = cast(u32)index;
|
||||
*refs[index] = o;
|
||||
}
|
||||
if (is_type_numeric(y.type) && y.value.kind == ExactValue_Float) {
|
||||
y.type = t_untyped_float;
|
||||
|
||||
for (i32 i = 0; i < 4; i++) {
|
||||
GB_ASSERT(fields_set[i]);
|
||||
}
|
||||
if (is_type_numeric(z.type) && z.value.kind == ExactValue_Float) {
|
||||
z.type = t_untyped_float;
|
||||
for (i32 i = 1; i < 4; i++) {
|
||||
if (fields_set[i] != fields_set[i-1]) {
|
||||
error(call, "Mixture of xyzw and real/etc is not allowed with '%.*s'", LIT(builtin_name));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (is_type_numeric(w.type) && w.value.kind == ExactValue_Float) {
|
||||
w.type = t_untyped_float;
|
||||
} else {
|
||||
error(call, "'%.*s' requires that all arguments are named (w, x, y, z; or real, imag, jmag, kmag)", LIT(builtin_name));
|
||||
|
||||
for (i32 i = 0; i < 4; i++) {
|
||||
check_expr(c, &xyzw[i], ce->args[i]);
|
||||
if (xyzw[i].mode == Addressing_Invalid) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!(are_types_identical(x.type, y.type) && are_types_identical(x.type, z.type) && are_types_identical(x.type, w.type))) {
|
||||
gbString tx = type_to_string(x.type);
|
||||
gbString ty = type_to_string(y.type);
|
||||
gbString tz = type_to_string(z.type);
|
||||
gbString tw = type_to_string(w.type);
|
||||
error(call, "Mismatched types to 'quaternion', '%s' vs '%s' vs '%s' vs '%s'", tx, ty, tz, tw);
|
||||
|
||||
for (u32 i = 0; i < 4; i++ ){
|
||||
u32 j = (i + first_index) % 4;
|
||||
if (j == first_index) {
|
||||
convert_to_typed(c, &xyzw[j], xyzw[(first_index+1)%4].type); if (xyzw[j].mode == Addressing_Invalid) return false;
|
||||
} else {
|
||||
convert_to_typed(c, &xyzw[j], xyzw[first_index].type); if (xyzw[j].mode == Addressing_Invalid) return false;
|
||||
}
|
||||
}
|
||||
if (xyzw[0].mode == Addressing_Constant &&
|
||||
xyzw[1].mode == Addressing_Constant &&
|
||||
xyzw[2].mode == Addressing_Constant &&
|
||||
xyzw[3].mode == Addressing_Constant) {
|
||||
for (i32 i = 0; i < 4; i++) {
|
||||
xyzw[i].value = exact_value_to_float(xyzw[i].value);
|
||||
}
|
||||
for (i32 i = 0; i < 4; i++) {
|
||||
if (is_type_numeric(xyzw[i].type) && xyzw[i].value.kind == ExactValue_Float) {
|
||||
xyzw[i].type = t_untyped_float;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!(are_types_identical(xyzw[0].type, xyzw[1].type) &&
|
||||
are_types_identical(xyzw[0].type, xyzw[2].type) &&
|
||||
are_types_identical(xyzw[0].type, xyzw[3].type))) {
|
||||
gbString tx = type_to_string(xyzw[0].type);
|
||||
gbString ty = type_to_string(xyzw[1].type);
|
||||
gbString tz = type_to_string(xyzw[2].type);
|
||||
gbString tw = type_to_string(xyzw[3].type);
|
||||
error(call, "Mismatched types to 'quaternion', 'x=%s' vs 'y=%s' vs 'z=%s' vs 'w=%s'", tx, ty, tz, tw);
|
||||
gb_string_free(tw);
|
||||
gb_string_free(tz);
|
||||
gb_string_free(ty);
|
||||
@@ -2361,31 +2455,35 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!is_type_float(x.type)) {
|
||||
gbString s = type_to_string(x.type);
|
||||
if (!is_type_float(xyzw[0].type)) {
|
||||
gbString s = type_to_string(xyzw[0].type);
|
||||
error(call, "Arguments have type '%s', expected a floating point", s);
|
||||
gb_string_free(s);
|
||||
return false;
|
||||
}
|
||||
if (is_type_endian_specific(x.type)) {
|
||||
gbString s = type_to_string(x.type);
|
||||
if (is_type_endian_specific(xyzw[0].type)) {
|
||||
gbString s = type_to_string(xyzw[0].type);
|
||||
error(call, "Arguments with a specified endian are not allow, expected a normal floating point, got '%s'", s);
|
||||
gb_string_free(s);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (x.mode == Addressing_Constant && y.mode == Addressing_Constant && z.mode == Addressing_Constant && w.mode == Addressing_Constant) {
|
||||
f64 r = exact_value_to_float(x.value).value_float;
|
||||
f64 i = exact_value_to_float(y.value).value_float;
|
||||
f64 j = exact_value_to_float(z.value).value_float;
|
||||
f64 k = exact_value_to_float(w.value).value_float;
|
||||
|
||||
operand->mode = Addressing_Value;
|
||||
|
||||
if (xyzw[0].mode == Addressing_Constant &&
|
||||
xyzw[1].mode == Addressing_Constant &&
|
||||
xyzw[2].mode == Addressing_Constant &&
|
||||
xyzw[3].mode == Addressing_Constant) {
|
||||
f64 r = exact_value_to_float(xyzw[3].value).value_float;
|
||||
f64 i = exact_value_to_float(xyzw[0].value).value_float;
|
||||
f64 j = exact_value_to_float(xyzw[1].value).value_float;
|
||||
f64 k = exact_value_to_float(xyzw[2].value).value_float;
|
||||
operand->value = exact_value_quaternion(r, i, j, k);
|
||||
operand->mode = Addressing_Constant;
|
||||
} else {
|
||||
operand->mode = Addressing_Value;
|
||||
}
|
||||
|
||||
BasicKind kind = core_type(x.type)->Basic.kind;
|
||||
BasicKind kind = core_type(xyzw[first_index].type)->Basic.kind;
|
||||
switch (kind) {
|
||||
case Basic_f16: operand->type = t_quaternion64; break;
|
||||
case Basic_f32: operand->type = t_quaternion128; break;
|
||||
@@ -3092,7 +3190,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
mix = arg->kind == Ast_FieldValue;
|
||||
}
|
||||
if (mix) {
|
||||
error(arg, "Mixture of 'field = value' and value elements in the procedure call 'soa_zip' is not allowed");
|
||||
error(arg, "Mixture of 'field = value' and value elements in the procedure call '%.*s' is not allowed", LIT(builtin_name));
|
||||
fail = true;
|
||||
break;
|
||||
}
|
||||
|
||||
+87
-4
@@ -138,11 +138,10 @@ gb_internal void check_init_variables(CheckerContext *ctx, Entity **lhs, isize l
|
||||
}
|
||||
|
||||
if (o->type && is_type_no_copy(o->type)) {
|
||||
begin_error_block();
|
||||
ERROR_BLOCK();
|
||||
if (check_no_copy_assignment(*o, str_lit("initialization"))) {
|
||||
error_line("\tInitialization of a #no_copy type must be either implicitly zero, a constant literal, or a return value from a call expression");
|
||||
}
|
||||
end_error_block();
|
||||
}
|
||||
}
|
||||
if (rhs_count > 0 && lhs_count != rhs_count) {
|
||||
@@ -908,7 +907,91 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
|
||||
break;
|
||||
}
|
||||
|
||||
e->Procedure.entry_point_only = ac.entry_point_only;
|
||||
e->Procedure.is_export = ac.is_export;
|
||||
|
||||
bool has_instrumentation = false;
|
||||
if (pl->body == nullptr) {
|
||||
has_instrumentation = false;
|
||||
if (ac.no_instrumentation != Instrumentation_Default) {
|
||||
error(e->token, "@(no_instrumentation) is not allowed on foreign procedures");
|
||||
}
|
||||
} else {
|
||||
AstFile *file = e->token.pos.file_id ? global_files[e->token.pos.file_id] : nullptr;
|
||||
if (file) {
|
||||
has_instrumentation = (file->flags & AstFile_NoInstrumentation) == 0;
|
||||
}
|
||||
|
||||
switch (ac.no_instrumentation) {
|
||||
case Instrumentation_Enabled: has_instrumentation = true; break;
|
||||
case Instrumentation_Default: break;
|
||||
case Instrumentation_Disabled: has_instrumentation = false; break;
|
||||
}
|
||||
}
|
||||
|
||||
auto const is_valid_instrumentation_call = [](Type *type) -> bool {
|
||||
if (type == nullptr || type->kind != Type_Proc) {
|
||||
return false;
|
||||
}
|
||||
if (type->Proc.calling_convention != ProcCC_Contextless) {
|
||||
return false;
|
||||
}
|
||||
if (type->Proc.result_count != 0) {
|
||||
return false;
|
||||
}
|
||||
if (type->Proc.param_count != 3) {
|
||||
return false;
|
||||
}
|
||||
Type *p0 = type->Proc.params->Tuple.variables[0]->type;
|
||||
Type *p1 = type->Proc.params->Tuple.variables[1]->type;
|
||||
Type *p3 = type->Proc.params->Tuple.variables[2]->type;
|
||||
return is_type_rawptr(p0) && is_type_rawptr(p1) && are_types_identical(p3, t_source_code_location);
|
||||
};
|
||||
|
||||
static char const *instrumentation_proc_type_str = "proc \"contextless\" (proc_address: rawptr, call_site_return_address: rawptr, loc: runtime.Source_Code_Location)";
|
||||
|
||||
if (ac.instrumentation_enter && ac.instrumentation_exit) {
|
||||
error(e->token, "A procedure cannot be marked with both @(instrumentation_enter) and @(instrumentation_exit)");
|
||||
|
||||
has_instrumentation = false;
|
||||
e->flags |= EntityFlag_Require;
|
||||
} else if (ac.instrumentation_enter) {
|
||||
if (!is_valid_instrumentation_call(e->type)) {
|
||||
init_core_source_code_location(ctx->checker);
|
||||
gbString s = type_to_string(e->type);
|
||||
error(e->token, "@(instrumentation_enter) procedures must have the type '%s', got %s", instrumentation_proc_type_str, s);
|
||||
gb_string_free(s);
|
||||
}
|
||||
MUTEX_GUARD(&ctx->info->instrumentation_mutex);
|
||||
if (ctx->info->instrumentation_enter_entity != nullptr) {
|
||||
error(e->token, "@(instrumentation_enter) has already been set");
|
||||
} else {
|
||||
ctx->info->instrumentation_enter_entity = e;
|
||||
}
|
||||
|
||||
has_instrumentation = false;
|
||||
e->flags |= EntityFlag_Require;
|
||||
} else if (ac.instrumentation_exit) {
|
||||
init_core_source_code_location(ctx->checker);
|
||||
if (!is_valid_instrumentation_call(e->type)) {
|
||||
gbString s = type_to_string(e->type);
|
||||
error(e->token, "@(instrumentation_exit) procedures must have the type '%s', got %s", instrumentation_proc_type_str, s);
|
||||
gb_string_free(s);
|
||||
}
|
||||
MUTEX_GUARD(&ctx->info->instrumentation_mutex);
|
||||
if (ctx->info->instrumentation_exit_entity != nullptr) {
|
||||
error(e->token, "@(instrumentation_exit) has already been set");
|
||||
} else {
|
||||
ctx->info->instrumentation_exit_entity = e;
|
||||
}
|
||||
|
||||
has_instrumentation = false;
|
||||
e->flags |= EntityFlag_Require;
|
||||
}
|
||||
|
||||
e->Procedure.has_instrumentation = has_instrumentation;
|
||||
|
||||
|
||||
e->deprecated_message = ac.deprecated_message;
|
||||
e->warning_message = ac.warning_message;
|
||||
ac.link_name = handle_link_name(ctx, e->token, ac.link_name, ac.link_prefix);
|
||||
@@ -1300,8 +1383,8 @@ gb_internal void check_proc_group_decl(CheckerContext *ctx, Entity *pg_entity, D
|
||||
continue;
|
||||
}
|
||||
|
||||
begin_error_block();
|
||||
defer (end_error_block());
|
||||
|
||||
ERROR_BLOCK();
|
||||
|
||||
ProcTypeOverloadKind kind = are_proc_types_overload_safe(p->type, q->type);
|
||||
bool both_have_where_clauses = false;
|
||||
|
||||
+51
-31
@@ -184,6 +184,8 @@ gb_internal void populate_check_did_you_mean_objc_entity(StringSet *set, Entity
|
||||
|
||||
|
||||
gb_internal void check_did_you_mean_objc_entity(String const &name, Entity *e, bool is_type, char const *prefix = "") {
|
||||
if (build_context.terse_errors) { return; }
|
||||
|
||||
ERROR_BLOCK();
|
||||
GB_ASSERT(e->kind == Entity_TypeName);
|
||||
GB_ASSERT(e->TypeName.objc_metadata != nullptr);
|
||||
@@ -204,6 +206,8 @@ gb_internal void check_did_you_mean_objc_entity(String const &name, Entity *e, b
|
||||
}
|
||||
|
||||
gb_internal void check_did_you_mean_type(String const &name, Array<Entity *> const &fields, char const *prefix = "") {
|
||||
if (build_context.terse_errors) { return; }
|
||||
|
||||
ERROR_BLOCK();
|
||||
|
||||
DidYouMeanAnswers d = did_you_mean_make(heap_allocator(), fields.count, name);
|
||||
@@ -217,6 +221,8 @@ gb_internal void check_did_you_mean_type(String const &name, Array<Entity *> con
|
||||
|
||||
|
||||
gb_internal void check_did_you_mean_type(String const &name, Slice<Entity *> const &fields, char const *prefix = "") {
|
||||
if (build_context.terse_errors) { return; }
|
||||
|
||||
ERROR_BLOCK();
|
||||
|
||||
DidYouMeanAnswers d = did_you_mean_make(heap_allocator(), fields.count, name);
|
||||
@@ -229,6 +235,8 @@ gb_internal void check_did_you_mean_type(String const &name, Slice<Entity *> con
|
||||
}
|
||||
|
||||
gb_internal void check_did_you_mean_scope(String const &name, Scope *scope, char const *prefix = "") {
|
||||
if (build_context.terse_errors) { return; }
|
||||
|
||||
ERROR_BLOCK();
|
||||
|
||||
DidYouMeanAnswers d = did_you_mean_make(heap_allocator(), scope->elements.count, name);
|
||||
@@ -2203,7 +2211,6 @@ gb_internal bool check_is_expressible(CheckerContext *ctx, Operand *o, Type *typ
|
||||
|
||||
ERROR_BLOCK();
|
||||
|
||||
|
||||
if (is_type_numeric(o->type) && is_type_numeric(type)) {
|
||||
if (!is_type_integer(o->type) && is_type_integer(type)) {
|
||||
error(o->expr, "'%s' truncated to '%s', got %s", a, b, s);
|
||||
@@ -2264,8 +2271,7 @@ gb_internal void check_old_for_or_switch_value_usage(Ast *expr) {
|
||||
if (e != nullptr && (e->flags & EntityFlag_OldForOrSwitchValue) != 0) {
|
||||
GB_ASSERT(e->kind == Entity_Variable);
|
||||
|
||||
begin_error_block();
|
||||
defer (end_error_block());
|
||||
ERROR_BLOCK();
|
||||
|
||||
if ((e->flags & EntityFlag_ForValue) != 0) {
|
||||
Type *parent_type = type_deref(e->Variable.for_loop_parent_type);
|
||||
@@ -2309,8 +2315,7 @@ gb_internal void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast *
|
||||
break;
|
||||
default:
|
||||
{
|
||||
begin_error_block();
|
||||
defer (end_error_block());
|
||||
ERROR_BLOCK();
|
||||
error(op, "Cannot take the pointer address of '%s'", str);
|
||||
if (e != nullptr && (e->flags & EntityFlag_ForValue) != 0) {
|
||||
Type *parent_type = type_deref(e->Variable.for_loop_parent_type);
|
||||
@@ -2983,6 +2988,9 @@ gb_internal bool check_is_castable_to(CheckerContext *c, Operand *operand, Type
|
||||
}
|
||||
// proc <-> proc
|
||||
if (is_type_proc(src) && is_type_proc(dst)) {
|
||||
if (is_type_polymorphic(src) || is_type_polymorphic(dst)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -3062,7 +3070,6 @@ gb_internal void check_cast(CheckerContext *c, Operand *x, Type *type) {
|
||||
|
||||
bool is_const_expr = x->mode == Addressing_Constant;
|
||||
bool can_convert = check_cast_internal(c, x, type);
|
||||
|
||||
if (!can_convert) {
|
||||
TEMPORARY_ALLOCATOR_GUARD();
|
||||
gbString expr_str = expr_to_string(x->expr, temporary_allocator());
|
||||
@@ -3071,7 +3078,7 @@ gb_internal void check_cast(CheckerContext *c, Operand *x, Type *type) {
|
||||
|
||||
x->mode = Addressing_Invalid;
|
||||
|
||||
begin_error_block();
|
||||
ERROR_BLOCK();
|
||||
error(x->expr, "Cannot cast '%s' as '%s' from '%s'", expr_str, to_type, from_type);
|
||||
if (is_const_expr) {
|
||||
gbString val_str = exact_value_to_string(x->value);
|
||||
@@ -3094,8 +3101,6 @@ gb_internal void check_cast(CheckerContext *c, Operand *x, Type *type) {
|
||||
}
|
||||
check_cast_error_suggestion(c, x, type);
|
||||
|
||||
end_error_block();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -4047,8 +4052,7 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar
|
||||
if (check_is_assignable_to(c, operand, elem)) {
|
||||
if (t->Matrix.row_count != t->Matrix.column_count) {
|
||||
operand->mode = Addressing_Invalid;
|
||||
begin_error_block();
|
||||
defer (end_error_block());
|
||||
ERROR_BLOCK();
|
||||
|
||||
convert_untyped_error(c, operand, target_type);
|
||||
error_line("\tNote: Only a square matrix types can be initialized with a scalar value\n");
|
||||
@@ -4109,8 +4113,7 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar
|
||||
target_type = t->Union.variants[first_success_index];
|
||||
break;
|
||||
} else if (valid_count > 1) {
|
||||
begin_error_block();
|
||||
defer (end_error_block());
|
||||
ERROR_BLOCK();
|
||||
|
||||
GB_ASSERT(first_success_index >= 0);
|
||||
operand->mode = Addressing_Invalid;
|
||||
@@ -4136,8 +4139,7 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar
|
||||
} else if (is_type_untyped_uninit(operand->type)) {
|
||||
target_type = t_untyped_uninit;
|
||||
} else if (!is_type_untyped_nil(operand->type) || !type_has_nil(target_type)) {
|
||||
begin_error_block();
|
||||
defer (end_error_block());
|
||||
ERROR_BLOCK();
|
||||
|
||||
operand->mode = Addressing_Invalid;
|
||||
convert_untyped_error(c, operand, target_type);
|
||||
@@ -4714,6 +4716,7 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod
|
||||
entity = scope_lookup_current(import_scope, entity_name);
|
||||
bool allow_builtin = false;
|
||||
if (!is_entity_declared_for_selector(entity, import_scope, &allow_builtin)) {
|
||||
ERROR_BLOCK();
|
||||
error(node, "'%.*s' is not declared by '%.*s'", LIT(entity_name), LIT(import_name));
|
||||
operand->mode = Addressing_Invalid;
|
||||
operand->expr = node;
|
||||
@@ -4914,6 +4917,8 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod
|
||||
error(op_expr, "Type '%s' has no field '%s'", op_str, sel_str);
|
||||
}
|
||||
} else {
|
||||
ERROR_BLOCK();
|
||||
|
||||
error(op_expr, "'%s' of type '%s' has no field '%s'", op_str, type_str, sel_str);
|
||||
|
||||
if (operand->type != nullptr && selector->kind == Ast_Ident) {
|
||||
@@ -6338,8 +6343,7 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c,
|
||||
};
|
||||
|
||||
if (valids.count == 0) {
|
||||
begin_error_block();
|
||||
defer (end_error_block());
|
||||
ERROR_BLOCK();
|
||||
|
||||
error(operand->expr, "No procedures or ambiguous call for procedure group '%s' that match with the given arguments", expr_name);
|
||||
if (positional_operands.count == 0 && named_operands.count == 0) {
|
||||
@@ -6429,8 +6433,7 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c,
|
||||
|
||||
data.result_type = t_invalid;
|
||||
} else if (valids.count > 1) {
|
||||
begin_error_block();
|
||||
defer (end_error_block());
|
||||
ERROR_BLOCK();
|
||||
|
||||
error(operand->expr, "Ambiguous procedure group call '%s' that match with the given arguments", expr_name);
|
||||
print_argument_types();
|
||||
@@ -7195,6 +7198,14 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c
|
||||
}
|
||||
}
|
||||
add_entity_use(c, operand->expr, initial_entity);
|
||||
|
||||
if (initial_entity->Procedure.entry_point_only) {
|
||||
if (c->curr_proc_decl && c->curr_proc_decl->entity == c->info->entry_point) {
|
||||
// Okay
|
||||
} else {
|
||||
error(operand->expr, "Procedures with the attribute '@(entry_point_only)' can only be called directly from the user-level entry point procedure");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (operand->mode != Addressing_ProcGroup) {
|
||||
@@ -7641,6 +7652,8 @@ gb_internal ExprKind check_implicit_selector_expr(CheckerContext *c, Operand *o,
|
||||
String name = ise->selector->Ident.token.string;
|
||||
|
||||
if (is_type_enum(th)) {
|
||||
ERROR_BLOCK();
|
||||
|
||||
Type *bt = base_type(th);
|
||||
GB_ASSERT(bt->kind == Type_Enum);
|
||||
|
||||
@@ -7884,7 +7897,7 @@ gb_internal ExprKind check_basic_directive_expr(CheckerContext *c, Operand *o, A
|
||||
} else {
|
||||
if (name == "location") {
|
||||
init_core_source_code_location(c->checker);
|
||||
error(node, "'#%.*s' must be used in a call expression", LIT(name));
|
||||
error(node, "'#location' must be used as a call, i.e. #location(proc), where #location() defaults to the procedure in which it was used.");
|
||||
o->type = t_source_code_location;
|
||||
o->mode = Addressing_Value;
|
||||
} else if (
|
||||
@@ -9042,8 +9055,7 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
|
||||
}
|
||||
|
||||
if (unhandled.count > 0) {
|
||||
begin_error_block();
|
||||
defer (end_error_block());
|
||||
ERROR_BLOCK();
|
||||
|
||||
if (unhandled.count == 1) {
|
||||
error_no_newline(node, "Unhandled enumerated array case: %.*s", LIT(unhandled[0]->token.string));
|
||||
@@ -9054,9 +9066,11 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
|
||||
error_line("\t%.*s\n", LIT(f->token.string));
|
||||
}
|
||||
}
|
||||
error_line("\n");
|
||||
|
||||
error_line("\tSuggestion: Was '#partial %s{...}' wanted?\n", type_to_string(type));
|
||||
if (!build_context.terse_errors) {
|
||||
error_line("\n");
|
||||
error_line("\tSuggestion: Was '#partial %s{...}' wanted?\n", type_to_string(type));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9680,7 +9694,9 @@ gb_internal ExprKind check_index_expr(CheckerContext *c, Operand *o, Ast *node,
|
||||
if (index < 0) {
|
||||
gbString str = expr_to_string(o->expr);
|
||||
error(o->expr, "Cannot index a constant '%s'", str);
|
||||
error_line("\tSuggestion: store the constant into a variable in order to index it with a variable index\n");
|
||||
if (!build_context.terse_errors) {
|
||||
error_line("\tSuggestion: store the constant into a variable in order to index it with a variable index\n");
|
||||
}
|
||||
gb_string_free(str);
|
||||
o->mode = Addressing_Invalid;
|
||||
o->expr = node;
|
||||
@@ -9694,7 +9710,9 @@ gb_internal ExprKind check_index_expr(CheckerContext *c, Operand *o, Ast *node,
|
||||
if (!success) {
|
||||
gbString str = expr_to_string(o->expr);
|
||||
error(o->expr, "Cannot index a constant '%s' with index %lld", str, cast(long long)index);
|
||||
error_line("\tSuggestion: store the constant into a variable in order to index it with a variable index\n");
|
||||
if (!build_context.terse_errors) {
|
||||
error_line("\tSuggestion: store the constant into a variable in order to index it with a variable index\n");
|
||||
}
|
||||
gb_string_free(str);
|
||||
o->mode = Addressing_Invalid;
|
||||
o->expr = node;
|
||||
@@ -9882,7 +9900,9 @@ gb_internal ExprKind check_slice_expr(CheckerContext *c, Operand *o, Ast *node,
|
||||
if (!all_constant) {
|
||||
gbString str = expr_to_string(o->expr);
|
||||
error(o->expr, "Cannot slice '%s' with non-constant indices", str);
|
||||
error_line("\tSuggestion: store the constant into a variable in order to index it with a variable index\n");
|
||||
if (!build_context.terse_errors) {
|
||||
error_line("\tSuggestion: store the constant into a variable in order to index it with a variable index\n");
|
||||
}
|
||||
gb_string_free(str);
|
||||
o->mode = Addressing_Value; // NOTE(bill): Keep subsequent values going without erring
|
||||
o->expr = node;
|
||||
@@ -10238,15 +10258,15 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast
|
||||
} else {
|
||||
gbString str = expr_to_string(o->expr);
|
||||
gbString typ = type_to_string(o->type);
|
||||
begin_error_block();
|
||||
ERROR_BLOCK();
|
||||
|
||||
error(o->expr, "Cannot dereference '%s' of type '%s'", str, typ);
|
||||
if (o->type && is_type_multi_pointer(o->type)) {
|
||||
error_line("\tDid you mean '%s[0]'?\n", str);
|
||||
if (!build_context.terse_errors) {
|
||||
error_line("\tDid you mean '%s[0]'?\n", str);
|
||||
}
|
||||
}
|
||||
|
||||
end_error_block();
|
||||
|
||||
gb_string_free(typ);
|
||||
gb_string_free(str);
|
||||
o->mode = Addressing_Invalid;
|
||||
|
||||
+2
-4
@@ -1085,8 +1085,7 @@ gb_internal void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags
|
||||
}
|
||||
|
||||
if (unhandled.count > 0) {
|
||||
begin_error_block();
|
||||
defer (end_error_block());
|
||||
ERROR_BLOCK();
|
||||
|
||||
if (unhandled.count == 1) {
|
||||
error_no_newline(node, "Unhandled switch case: %.*s", LIT(unhandled[0]->token.string));
|
||||
@@ -1813,7 +1812,7 @@ gb_internal void check_value_decl_stmt(CheckerContext *ctx, Ast *node, u32 mod_f
|
||||
}
|
||||
|
||||
if (new_name_count == 0) {
|
||||
begin_error_block();
|
||||
ERROR_BLOCK();
|
||||
error(node, "No new declarations on the left hand side");
|
||||
bool all_underscore = true;
|
||||
for (Ast *name : vd->names) {
|
||||
@@ -1831,7 +1830,6 @@ gb_internal void check_value_decl_stmt(CheckerContext *ctx, Ast *node, u32 mod_f
|
||||
error_line("\tSuggestion: Try changing the declaration (:=) to an assignment (=)\n");
|
||||
}
|
||||
|
||||
end_error_block();
|
||||
}
|
||||
|
||||
Type *init_type = nullptr;
|
||||
|
||||
+1
-2
@@ -2702,14 +2702,13 @@ gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, T
|
||||
check_expr_or_type(&c, &o, pt->type);
|
||||
if (o.mode != Addressing_Invalid && o.mode != Addressing_Type) {
|
||||
// NOTE(bill): call check_type_expr again to get a consistent error message
|
||||
begin_error_block();
|
||||
ERROR_BLOCK();
|
||||
elem = check_type_expr(&c, pt->type, nullptr);
|
||||
if (o.mode == Addressing_Variable) {
|
||||
gbString s = expr_to_string(pt->type);
|
||||
error_line("\tSuggestion: ^ is used for pointer types, did you mean '&%s'?\n", s);
|
||||
gb_string_free(s);
|
||||
}
|
||||
end_error_block();
|
||||
} else {
|
||||
elem = o.type;
|
||||
}
|
||||
|
||||
+54
-8
@@ -968,10 +968,11 @@ gb_internal void init_universal(void) {
|
||||
add_global_bool_constant("true", true);
|
||||
add_global_bool_constant("false", false);
|
||||
|
||||
add_global_string_constant("ODIN_VENDOR", bc->ODIN_VENDOR);
|
||||
add_global_string_constant("ODIN_VERSION", bc->ODIN_VERSION);
|
||||
add_global_string_constant("ODIN_ROOT", bc->ODIN_ROOT);
|
||||
add_global_string_constant("ODIN_VENDOR", bc->ODIN_VENDOR);
|
||||
add_global_string_constant("ODIN_VERSION", bc->ODIN_VERSION);
|
||||
add_global_string_constant("ODIN_ROOT", bc->ODIN_ROOT);
|
||||
add_global_string_constant("ODIN_BUILD_PROJECT_NAME", bc->ODIN_BUILD_PROJECT_NAME);
|
||||
add_global_string_constant("ODIN_WINDOWS_SUBSYSTEM", bc->ODIN_WINDOWS_SUBSYSTEM);
|
||||
|
||||
{
|
||||
GlobalEnumValue values[TargetOs_COUNT] = {
|
||||
@@ -1084,7 +1085,7 @@ gb_internal void init_universal(void) {
|
||||
|
||||
add_global_constant("ODIN_COMPILE_TIMESTAMP", t_untyped_integer, exact_value_i64(odin_compile_timestamp()));
|
||||
|
||||
add_global_bool_constant("__ODIN_LLVM_F16_SUPPORTED", lb_use_new_pass_system());
|
||||
add_global_bool_constant("__ODIN_LLVM_F16_SUPPORTED", lb_use_new_pass_system() && !is_arch_wasm());
|
||||
|
||||
{
|
||||
GlobalEnumValue values[3] = {
|
||||
@@ -2581,6 +2582,9 @@ gb_internal void generate_minimum_dependency_set(Checker *c, Entity *start) {
|
||||
str_lit("multi_pointer_slice_expr_error"),
|
||||
);
|
||||
|
||||
add_dependency_to_set(c, c->info.instrumentation_enter_entity);
|
||||
add_dependency_to_set(c, c->info.instrumentation_exit_entity);
|
||||
|
||||
generate_minimum_dependency_set_internal(c, start);
|
||||
|
||||
|
||||
@@ -3413,6 +3417,39 @@ gb_internal DECL_ATTRIBUTE_PROC(proc_decl_attribute) {
|
||||
error(elem, "Expected a string value for '%.*s'", LIT(name));
|
||||
}
|
||||
return true;
|
||||
} else if (name == "entry_point_only") {
|
||||
if (value != nullptr) {
|
||||
error(value, "'%.*s' expects no parameter", LIT(name));
|
||||
}
|
||||
ac->entry_point_only = true;
|
||||
return true;
|
||||
} else if (name == "no_instrumentation") {
|
||||
ExactValue ev = check_decl_attribute_value(c, value);
|
||||
if (ev.kind == ExactValue_Invalid) {
|
||||
ac->no_instrumentation = Instrumentation_Disabled;
|
||||
} else if (ev.kind == ExactValue_Bool) {
|
||||
if (ev.value_bool) {
|
||||
ac->no_instrumentation = Instrumentation_Disabled;
|
||||
} else {
|
||||
ac->no_instrumentation = Instrumentation_Enabled;
|
||||
}
|
||||
} else {
|
||||
error(value, "Expected either a boolean or no parameter for '%.*s'", LIT(name));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} else if (name == "instrumentation_enter") {
|
||||
if (value != nullptr) {
|
||||
error(value, "'%.*s' expects no parameter", LIT(name));
|
||||
}
|
||||
ac->instrumentation_enter = true;
|
||||
return true;
|
||||
} else if (name == "instrumentation_exit") {
|
||||
if (value != nullptr) {
|
||||
error(value, "'%.*s' expects no parameter", LIT(name));
|
||||
}
|
||||
ac->instrumentation_exit = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -4022,12 +4059,11 @@ gb_internal void check_collect_value_decl(CheckerContext *c, Ast *decl) {
|
||||
if (c->foreign_context.default_cc > 0) {
|
||||
cc = c->foreign_context.default_cc;
|
||||
} else if (is_arch_wasm()) {
|
||||
begin_error_block();
|
||||
ERROR_BLOCK();
|
||||
error(init, "For wasm related targets, it is required that you either define the"
|
||||
" @(default_calling_convention=<string>) on the foreign block or"
|
||||
" explicitly assign it on the procedure signature");
|
||||
error_line("\tSuggestion: when dealing with normal Odin code (e.g. js_wasm32), use \"contextless\"; when dealing with Emscripten like code, use \"c\"\n");
|
||||
end_error_block();
|
||||
}
|
||||
}
|
||||
e->Procedure.link_prefix = c->foreign_context.link_prefix;
|
||||
@@ -4074,8 +4110,7 @@ gb_internal void check_collect_value_decl(CheckerContext *c, Ast *decl) {
|
||||
|
||||
if (e->kind != Entity_Procedure) {
|
||||
if (fl != nullptr) {
|
||||
begin_error_block();
|
||||
defer (end_error_block());
|
||||
ERROR_BLOCK();
|
||||
|
||||
AstKind kind = init->kind;
|
||||
error(name, "Only procedures and variables are allowed to be in a foreign block, got %.*s", LIT(ast_strings[kind]));
|
||||
@@ -6215,6 +6250,17 @@ gb_internal void check_parsed_files(Checker *c) {
|
||||
GB_ASSERT(c->info.entity_queue.count.load(std::memory_order_relaxed) == 0);
|
||||
GB_ASSERT(c->info.definition_queue.count.load(std::memory_order_relaxed) == 0);
|
||||
|
||||
TIME_SECTION("check instrumentation calls");
|
||||
{
|
||||
if ((c->info.instrumentation_enter_entity != nullptr) ^
|
||||
(c->info.instrumentation_exit_entity != nullptr)) {
|
||||
Entity *e = c->info.instrumentation_enter_entity;
|
||||
if (!e) e = c->info.instrumentation_exit_entity;
|
||||
error(e->token, "Both @(instrumentation_enter) and @(instrumentation_exit) must be defined");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TIME_SECTION("add untyped expression values");
|
||||
// Add untyped expression values
|
||||
for (UntypedExprInfo u = {}; mpsc_dequeue(&c->global_untyped_queue, &u); /**/) {
|
||||
|
||||
+24
-10
@@ -103,6 +103,12 @@ struct DeferredProcedure {
|
||||
};
|
||||
|
||||
|
||||
enum InstrumentationFlag : i32 {
|
||||
Instrumentation_Enabled = -1,
|
||||
Instrumentation_Default = 0,
|
||||
Instrumentation_Disabled = +1,
|
||||
};
|
||||
|
||||
struct AttributeContext {
|
||||
String link_name;
|
||||
String link_prefix;
|
||||
@@ -113,19 +119,23 @@ struct AttributeContext {
|
||||
String deprecated_message;
|
||||
String warning_message;
|
||||
DeferredProcedure deferred_procedure;
|
||||
bool is_export : 1;
|
||||
bool is_static : 1;
|
||||
bool require_results : 1;
|
||||
bool require_declaration : 1;
|
||||
bool has_disabled_proc : 1;
|
||||
bool disabled_proc : 1;
|
||||
bool test : 1;
|
||||
bool init : 1;
|
||||
bool fini : 1;
|
||||
bool set_cold : 1;
|
||||
bool is_export : 1;
|
||||
bool is_static : 1;
|
||||
bool require_results : 1;
|
||||
bool require_declaration : 1;
|
||||
bool has_disabled_proc : 1;
|
||||
bool disabled_proc : 1;
|
||||
bool test : 1;
|
||||
bool init : 1;
|
||||
bool fini : 1;
|
||||
bool set_cold : 1;
|
||||
bool entry_point_only : 1;
|
||||
bool instrumentation_enter : 1;
|
||||
bool instrumentation_exit : 1;
|
||||
u32 optimization_mode; // ProcedureOptimizationMode
|
||||
i64 foreign_import_priority_index;
|
||||
String extra_linker_flags;
|
||||
InstrumentationFlag no_instrumentation;
|
||||
|
||||
String objc_class;
|
||||
String objc_name;
|
||||
@@ -402,6 +412,10 @@ struct CheckerInfo {
|
||||
|
||||
BlockingMutex all_procedures_mutex;
|
||||
Array<ProcInfo *> all_procedures;
|
||||
|
||||
BlockingMutex instrumentation_mutex;
|
||||
Entity *instrumentation_enter_entity;
|
||||
Entity *instrumentation_exit_entity;
|
||||
};
|
||||
|
||||
struct CheckerContext {
|
||||
|
||||
@@ -250,6 +250,8 @@ struct Entity {
|
||||
bool is_export : 1;
|
||||
bool generated_from_polymorphic : 1;
|
||||
bool target_feature_disabled : 1;
|
||||
bool entry_point_only : 1;
|
||||
bool has_instrumentation : 1;
|
||||
String target_feature;
|
||||
} Procedure;
|
||||
struct {
|
||||
|
||||
+20
-4
@@ -174,7 +174,7 @@ gb_internal ExactValue exact_value_integer_from_string(String const &string) {
|
||||
|
||||
|
||||
|
||||
gb_internal f64 float_from_string(String const &string) {
|
||||
gb_internal f64 float_from_string(String const &string, bool *success = nullptr) {
|
||||
if (string.len < 128) {
|
||||
char buf[128] = {};
|
||||
isize n = 0;
|
||||
@@ -187,7 +187,13 @@ gb_internal f64 float_from_string(String const &string) {
|
||||
buf[n++] = cast(char)c;
|
||||
}
|
||||
buf[n] = 0;
|
||||
return atof(buf);
|
||||
|
||||
char *end_ptr;
|
||||
f64 f = strtod(buf, &end_ptr);
|
||||
if (success != nullptr) {
|
||||
*success = *end_ptr == '\0';
|
||||
}
|
||||
return f;
|
||||
} else {
|
||||
TEMPORARY_ALLOCATOR_GUARD();
|
||||
char *buf = gb_alloc_array(temporary_allocator(), char, string.len+1);
|
||||
@@ -201,7 +207,13 @@ gb_internal f64 float_from_string(String const &string) {
|
||||
buf[n++] = cast(char)c;
|
||||
}
|
||||
buf[n] = 0;
|
||||
return atof(buf);
|
||||
|
||||
char *end_ptr;
|
||||
f64 f = strtod(buf, &end_ptr);
|
||||
if (success != nullptr) {
|
||||
*success = *end_ptr == '\0';
|
||||
}
|
||||
return f;
|
||||
}
|
||||
/*
|
||||
isize i = 0;
|
||||
@@ -313,7 +325,11 @@ gb_internal ExactValue exact_value_float_from_string(String string) {
|
||||
return exact_value_integer_from_string(string);
|
||||
}
|
||||
|
||||
f64 f = float_from_string(string);
|
||||
bool success;
|
||||
f64 f = float_from_string(string, &success);
|
||||
if (!success) {
|
||||
return {ExactValue_Invalid};
|
||||
}
|
||||
return exact_value_float(f);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -448,7 +448,7 @@ typedef i32 b32; // NOTE(bill): Prefer this!!!
|
||||
#define gb_inline __forceinline
|
||||
#endif
|
||||
#else
|
||||
#define gb_inline __attribute__ ((__always_inline__))
|
||||
#define gb_inline inline __attribute__ ((__always_inline__))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
+15
-5
@@ -233,7 +233,6 @@ gb_internal i32 linker_stage(LinkerData *gen) {
|
||||
String windows_sdk_bin_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_Win_SDK_Bin_Path]);
|
||||
defer (gb_free(heap_allocator(), windows_sdk_bin_path.text));
|
||||
|
||||
char const *subsystem_str = build_context.use_subsystem_windows ? "WINDOWS" : "CONSOLE";
|
||||
if (!build_context.use_lld) { // msvc
|
||||
String res_path = {};
|
||||
defer (gb_free(heap_allocator(), res_path.text));
|
||||
@@ -265,14 +264,14 @@ gb_internal i32 linker_stage(LinkerData *gen) {
|
||||
|
||||
result = system_exec_command_line_app("msvc-link",
|
||||
"\"%.*slink.exe\" %s %.*s -OUT:\"%.*s\" %s "
|
||||
"/nologo /incremental:no /opt:ref /subsystem:%s "
|
||||
"/nologo /incremental:no /opt:ref /subsystem:%.*s "
|
||||
"%.*s "
|
||||
"%.*s "
|
||||
"%s "
|
||||
"",
|
||||
LIT(vs_exe_path), object_files, LIT(res_path), LIT(output_filename),
|
||||
link_settings,
|
||||
subsystem_str,
|
||||
LIT(build_context.ODIN_WINDOWS_SUBSYSTEM),
|
||||
LIT(build_context.link_flags),
|
||||
LIT(build_context.extra_linker_flags),
|
||||
lib_str
|
||||
@@ -283,14 +282,14 @@ gb_internal i32 linker_stage(LinkerData *gen) {
|
||||
} else { // lld
|
||||
result = system_exec_command_line_app("msvc-lld-link",
|
||||
"\"%.*s\\bin\\lld-link\" %s -OUT:\"%.*s\" %s "
|
||||
"/nologo /incremental:no /opt:ref /subsystem:%s "
|
||||
"/nologo /incremental:no /opt:ref /subsystem:%.*s "
|
||||
"%.*s "
|
||||
"%.*s "
|
||||
"%s "
|
||||
"",
|
||||
LIT(build_context.ODIN_ROOT), object_files, LIT(output_filename),
|
||||
link_settings,
|
||||
subsystem_str,
|
||||
LIT(build_context.ODIN_WINDOWS_SUBSYSTEM),
|
||||
LIT(build_context.link_flags),
|
||||
LIT(build_context.extra_linker_flags),
|
||||
lib_str
|
||||
@@ -484,6 +483,17 @@ gb_internal i32 linker_stage(LinkerData *gen) {
|
||||
defer (gb_string_free(platform_lib_str));
|
||||
if (build_context.metrics.os == TargetOs_darwin) {
|
||||
platform_lib_str = gb_string_appendc(platform_lib_str, "-Wl,-syslibroot /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk -L/usr/local/lib");
|
||||
|
||||
// Homebrew's default library path, checking if it exists to avoid linking warnings.
|
||||
if (gb_file_exists("/opt/homebrew/lib")) {
|
||||
platform_lib_str = gb_string_appendc(platform_lib_str, " -L/opt/homebrew/lib");
|
||||
}
|
||||
|
||||
// MacPort's default library path, checking if it exists to avoid linking warnings.
|
||||
if (gb_file_exists("/opt/local/lib")) {
|
||||
platform_lib_str = gb_string_appendc(platform_lib_str, " -L/opt/local/lib");
|
||||
}
|
||||
|
||||
#if defined(GB_SYSTEM_OSX)
|
||||
if(!build_context.no_crt) {
|
||||
platform_lib_str = gb_string_appendc(platform_lib_str, " -lm ");
|
||||
|
||||
+41
-4
@@ -1497,8 +1497,6 @@ gb_internal WORKER_TASK_PROC(lb_llvm_module_pass_worker_proc) {
|
||||
auto passes = array_make<char const *>(heap_allocator(), 0, 64);
|
||||
defer (array_free(&passes));
|
||||
|
||||
|
||||
|
||||
LLVMPassBuilderOptionsRef pb_options = LLVMCreatePassBuilderOptions();
|
||||
defer (LLVMDisposePassBuilderOptions(pb_options));
|
||||
|
||||
@@ -2505,7 +2503,7 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
|
||||
LLVMCodeModel code_mode = LLVMCodeModelDefault;
|
||||
if (is_arch_wasm()) {
|
||||
code_mode = LLVMCodeModelJITDefault;
|
||||
} else if (build_context.metrics.os == TargetOs_freestanding) {
|
||||
} else if (is_arch_x86() && build_context.metrics.os == TargetOs_freestanding) {
|
||||
code_mode = LLVMCodeModelKernel;
|
||||
}
|
||||
|
||||
@@ -2531,7 +2529,46 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
|
||||
*/
|
||||
|
||||
if (build_context.target_features_set.entries.count != 0) {
|
||||
llvm_features = target_features_set_to_cstring(permanent_allocator(), false);
|
||||
// Prefix all of the features with a `+`, because we are
|
||||
// enabling additional features.
|
||||
char const *additional_features = target_features_set_to_cstring(permanent_allocator(), false, true);
|
||||
|
||||
String f_string = make_string_c(llvm_features);
|
||||
String a_string = make_string_c(additional_features);
|
||||
isize f_len = f_string.len;
|
||||
|
||||
if (f_len == 0) {
|
||||
// The common case is that llvm_features is empty, so
|
||||
// the target_features_set additions can be used as is.
|
||||
llvm_features = additional_features;
|
||||
} else {
|
||||
// The user probably specified `-microarch:native`, so
|
||||
// llvm_features is populated by LLVM's idea of what
|
||||
// the host CPU supports.
|
||||
//
|
||||
// As far as I can tell, (which is barely better than
|
||||
// wild guessing), a bitset is formed by parsing the
|
||||
// string left to right.
|
||||
//
|
||||
// So, llvm_features + ',' + additonal_features, will
|
||||
// makes the target_features_set override llvm_features.
|
||||
|
||||
char *tmp = gb_alloc_array(permanent_allocator(), char, f_len + 1 + a_string.len + 1);
|
||||
isize len = 0;
|
||||
|
||||
// tmp = f_string
|
||||
gb_memmove(tmp, f_string.text, f_string.len);
|
||||
len += f_string.len;
|
||||
// tmp += ','
|
||||
tmp[len++] = ',';
|
||||
// tmp += a_string
|
||||
gb_memmove(tmp + len, a_string.text, a_string.len);
|
||||
len += a_string.len;
|
||||
// tmp += NUL
|
||||
tmp[len++] = 0;
|
||||
|
||||
llvm_features = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
// GB_ASSERT_MSG(LLVMTargetHasAsmBackend(target));
|
||||
|
||||
@@ -563,7 +563,9 @@ gb_internal LLVMTypeRef OdinLLVMGetVectorElementType(LLVMTypeRef type);
|
||||
|
||||
gb_internal String lb_filepath_ll_for_module(lbModule *m);
|
||||
|
||||
gb_internal LLVMTypeRef lb_type_internal_for_procedures_raw(lbModule *m, Type *type);
|
||||
|
||||
gb_internal lbValue lb_emit_source_code_location_as_global_ptr(lbProcedure *p, String const &procedure, TokenPos const &pos);
|
||||
|
||||
gb_internal LLVMTypeRef llvm_array_type(LLVMTypeRef ElementType, uint64_t ElementCount) {
|
||||
#if LB_USE_NEW_PASS_SYSTEM
|
||||
|
||||
@@ -2348,6 +2348,15 @@ gb_internal LLVMAttributeRef lb_create_enum_attribute(LLVMContextRef ctx, char c
|
||||
return LLVMCreateEnumAttribute(ctx, kind, value);
|
||||
}
|
||||
|
||||
gb_internal LLVMAttributeRef lb_create_string_attribute(LLVMContextRef ctx, String const &key, String const &value) {
|
||||
LLVMAttributeRef attr = LLVMCreateStringAttribute(
|
||||
ctx,
|
||||
cast(char const *)key.text, cast(unsigned)key.len,
|
||||
cast(char const *)value.text, cast(unsigned)value.len);
|
||||
return attr;
|
||||
}
|
||||
|
||||
|
||||
gb_internal void lb_add_proc_attribute_at_index(lbProcedure *p, isize index, char const *name, u64 value) {
|
||||
LLVMAttributeRef attr = lb_create_enum_attribute(p->module->ctx, name, value);
|
||||
GB_ASSERT(attr != nullptr);
|
||||
@@ -2361,6 +2370,10 @@ gb_internal void lb_add_proc_attribute_at_index(lbProcedure *p, isize index, cha
|
||||
gb_internal void lb_add_attribute_to_proc(lbModule *m, LLVMValueRef proc_value, char const *name, u64 value=0) {
|
||||
LLVMAddAttributeAtIndex(proc_value, LLVMAttributeIndex_FunctionIndex, lb_create_enum_attribute(m->ctx, name, value));
|
||||
}
|
||||
gb_internal void lb_add_attribute_to_proc_with_string(lbModule *m, LLVMValueRef proc_value, String const &name, String const &value) {
|
||||
LLVMAttributeRef attr = lb_create_string_attribute(m->ctx, name, value);
|
||||
LLVMAddAttributeAtIndex(proc_value, LLVMAttributeIndex_FunctionIndex, attr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -380,6 +380,86 @@ gb_internal void lb_run_remove_dead_instruction_pass(lbProcedure *p) {
|
||||
}
|
||||
}
|
||||
|
||||
gb_internal LLVMValueRef lb_run_instrumentation_pass_insert_call(lbProcedure *p, Entity *entity, LLVMBuilderRef dummy_builder) {
|
||||
lbModule *m = p->module;
|
||||
|
||||
lbValue cc = lb_find_procedure_value_from_entity(m, entity);
|
||||
|
||||
LLVMValueRef args[3] = {};
|
||||
args[0] = p->value;
|
||||
|
||||
LLVMValueRef returnaddress_args[1] = {};
|
||||
|
||||
returnaddress_args[0] = LLVMConstInt(LLVMInt32TypeInContext(m->ctx), 0, false);
|
||||
|
||||
char const *instrinsic_name = "llvm.returnaddress";
|
||||
unsigned id = LLVMLookupIntrinsicID(instrinsic_name, gb_strlen(instrinsic_name));
|
||||
GB_ASSERT_MSG(id != 0, "Unable to find %s", instrinsic_name);
|
||||
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(m->mod, id, nullptr, 0);
|
||||
LLVMTypeRef call_type = LLVMIntrinsicGetType(m->ctx, id, nullptr, 0);
|
||||
args[1] = LLVMBuildCall2(dummy_builder, call_type, ip, returnaddress_args, gb_count_of(returnaddress_args), "");
|
||||
|
||||
Token name = {};
|
||||
if (p->entity) {
|
||||
name = p->entity->token;
|
||||
}
|
||||
args[2] = lb_emit_source_code_location_as_global_ptr(p, name.string, name.pos).value;
|
||||
|
||||
LLVMTypeRef fnp = lb_type_internal_for_procedures_raw(p->module, entity->type);
|
||||
return LLVMBuildCall2(dummy_builder, fnp, cc.value, args, gb_count_of(args), "");
|
||||
}
|
||||
|
||||
|
||||
gb_internal void lb_run_instrumentation_pass(lbProcedure *p) {
|
||||
lbModule *m = p->module;
|
||||
Entity *enter = m->info->instrumentation_enter_entity;
|
||||
Entity *exit = m->info->instrumentation_exit_entity;
|
||||
if (enter == nullptr || exit == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (!(p->entity &&
|
||||
p->entity->kind == Entity_Procedure &&
|
||||
p->entity->Procedure.has_instrumentation)) {
|
||||
return;
|
||||
}
|
||||
|
||||
#define LLVM_V_NAME(x) x, cast(unsigned)(gb_count_of(x)-1)
|
||||
|
||||
LLVMBuilderRef dummy_builder = LLVMCreateBuilderInContext(m->ctx);
|
||||
defer (LLVMDisposeBuilder(dummy_builder));
|
||||
|
||||
LLVMBasicBlockRef entry_bb = p->entry_block->block;
|
||||
LLVMPositionBuilder(dummy_builder, entry_bb, LLVMGetFirstInstruction(entry_bb));
|
||||
lb_run_instrumentation_pass_insert_call(p, enter, dummy_builder);
|
||||
LLVMRemoveStringAttributeAtIndex(p->value, LLVMAttributeIndex_FunctionIndex, LLVM_V_NAME("instrument-function-entry"));
|
||||
|
||||
unsigned bb_count = LLVMCountBasicBlocks(p->value);
|
||||
LLVMBasicBlockRef *bbs = gb_alloc_array(temporary_allocator(), LLVMBasicBlockRef, bb_count);
|
||||
LLVMGetBasicBlocks(p->value, bbs);
|
||||
for (unsigned i = 0; i < bb_count; i++) {
|
||||
LLVMBasicBlockRef bb = bbs[i];
|
||||
LLVMValueRef terminator = LLVMGetBasicBlockTerminator(bb);
|
||||
if (terminator == nullptr ||
|
||||
!LLVMIsAReturnInst(terminator)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO(bill): getTerminatingMustTailCall()
|
||||
// If T is preceded by a musttail call, that's the real terminator.
|
||||
// if (CallInst *CI = BB.getTerminatingMustTailCall())
|
||||
// T = CI;
|
||||
|
||||
|
||||
LLVMPositionBuilderBefore(dummy_builder, terminator);
|
||||
lb_run_instrumentation_pass_insert_call(p, exit, dummy_builder);
|
||||
}
|
||||
|
||||
LLVMRemoveStringAttributeAtIndex(p->value, LLVMAttributeIndex_FunctionIndex, LLVM_V_NAME("instrument-function-exit"));
|
||||
|
||||
#undef LLVM_V_NAME
|
||||
}
|
||||
|
||||
|
||||
|
||||
gb_internal void lb_run_function_pass_manager(LLVMPassManagerRef fpm, lbProcedure *p, lbFunctionPassManagerKind pass_manager_kind) {
|
||||
if (p == nullptr) {
|
||||
@@ -401,6 +481,7 @@ gb_internal void lb_run_function_pass_manager(LLVMPassManagerRef fpm, lbProcedur
|
||||
}
|
||||
break;
|
||||
}
|
||||
lb_run_instrumentation_pass(p);
|
||||
|
||||
LLVMRunFunctionPassManager(fpm, p->value);
|
||||
}
|
||||
@@ -552,3 +633,5 @@ gb_internal void lb_run_remove_unused_globals_pass(lbModule *m) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
+42
-13
@@ -329,6 +329,18 @@ gb_internal lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool i
|
||||
}
|
||||
}
|
||||
|
||||
if (p->body && entity->Procedure.has_instrumentation) {
|
||||
Entity *instrumentation_enter = m->info->instrumentation_enter_entity;
|
||||
Entity *instrumentation_exit = m->info->instrumentation_exit_entity;
|
||||
if (instrumentation_enter && instrumentation_exit) {
|
||||
String enter = lb_get_entity_name(m, instrumentation_enter);
|
||||
String exit = lb_get_entity_name(m, instrumentation_exit);
|
||||
|
||||
lb_add_attribute_to_proc_with_string(m, p->value, make_string_c("instrument-function-entry"), enter);
|
||||
lb_add_attribute_to_proc_with_string(m, p->value, make_string_c("instrument-function-exit"), exit);
|
||||
}
|
||||
}
|
||||
|
||||
lbValue proc_value = {p->value, p->type};
|
||||
lb_add_entity(m, entity, proc_value);
|
||||
lb_add_member(m, p->name, proc_value);
|
||||
@@ -1826,24 +1838,41 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
|
||||
}
|
||||
|
||||
case BuiltinProc_quaternion: {
|
||||
lbValue real = lb_build_expr(p, ce->args[0]);
|
||||
lbValue imag = lb_build_expr(p, ce->args[1]);
|
||||
lbValue jmag = lb_build_expr(p, ce->args[2]);
|
||||
lbValue kmag = lb_build_expr(p, ce->args[3]);
|
||||
lbValue xyzw[4] = {};
|
||||
for (i32 i = 0; i < 4; i++) {
|
||||
ast_node(f, FieldValue, ce->args[i]);
|
||||
GB_ASSERT(f->field->kind == Ast_Ident);
|
||||
String name = f->field->Ident.token.string;
|
||||
i32 index = -1;
|
||||
|
||||
// @QuaternionLayout
|
||||
if (name == "x" || name == "imag") {
|
||||
index = 0;
|
||||
} else if (name == "y" || name == "jmag") {
|
||||
index = 1;
|
||||
} else if (name == "z" || name == "kmag") {
|
||||
index = 2;
|
||||
} else if (name == "w" || name == "real") {
|
||||
index = 3;
|
||||
}
|
||||
GB_ASSERT(index >= 0);
|
||||
|
||||
xyzw[index] = lb_build_expr(p, f->value);
|
||||
}
|
||||
|
||||
|
||||
// @QuaternionLayout
|
||||
lbAddr dst_addr = lb_add_local_generated(p, tv.type, false);
|
||||
lbValue dst = lb_addr_get_ptr(p, dst_addr);
|
||||
|
||||
Type *ft = base_complex_elem_type(tv.type);
|
||||
real = lb_emit_conv(p, real, ft);
|
||||
imag = lb_emit_conv(p, imag, ft);
|
||||
jmag = lb_emit_conv(p, jmag, ft);
|
||||
kmag = lb_emit_conv(p, kmag, ft);
|
||||
lb_emit_store(p, lb_emit_struct_ep(p, dst, 3), real);
|
||||
lb_emit_store(p, lb_emit_struct_ep(p, dst, 0), imag);
|
||||
lb_emit_store(p, lb_emit_struct_ep(p, dst, 1), jmag);
|
||||
lb_emit_store(p, lb_emit_struct_ep(p, dst, 2), kmag);
|
||||
xyzw[0] = lb_emit_conv(p, xyzw[0], ft);
|
||||
xyzw[1] = lb_emit_conv(p, xyzw[1], ft);
|
||||
xyzw[2] = lb_emit_conv(p, xyzw[2], ft);
|
||||
xyzw[3] = lb_emit_conv(p, xyzw[3], ft);
|
||||
lb_emit_store(p, lb_emit_struct_ep(p, dst, 0), xyzw[0]);
|
||||
lb_emit_store(p, lb_emit_struct_ep(p, dst, 1), xyzw[1]);
|
||||
lb_emit_store(p, lb_emit_struct_ep(p, dst, 2), xyzw[2]);
|
||||
lb_emit_store(p, lb_emit_struct_ep(p, dst, 3), xyzw[3]);
|
||||
|
||||
return lb_emit_load(p, dst);
|
||||
}
|
||||
|
||||
+37
-8
@@ -1160,10 +1160,12 @@ gb_internal bool parse_build_flags(Array<String> args) {
|
||||
|
||||
case BuildFlag_TerseErrors:
|
||||
build_context.hide_error_line = true;
|
||||
build_context.terse_errors = true;
|
||||
break;
|
||||
case BuildFlag_VerboseErrors:
|
||||
gb_printf_err("-verbose-errors is not the default, -terse-errors can now disable it\n");
|
||||
build_context.hide_error_line = false;
|
||||
build_context.terse_errors = false;
|
||||
break;
|
||||
|
||||
case BuildFlag_ErrorPosStyle:
|
||||
@@ -1268,16 +1270,43 @@ gb_internal bool parse_build_flags(Array<String> args) {
|
||||
}
|
||||
|
||||
case BuildFlag_Subsystem: {
|
||||
// TODO(Jeroen): Parse optional "[,major[.minor]]"
|
||||
|
||||
GB_ASSERT(value.kind == ExactValue_String);
|
||||
String subsystem = value.value_string;
|
||||
if (str_eq_ignore_case(subsystem, str_lit("console"))) {
|
||||
build_context.use_subsystem_windows = false;
|
||||
} else if (str_eq_ignore_case(subsystem, str_lit("window"))) {
|
||||
build_context.use_subsystem_windows = true;
|
||||
} else if (str_eq_ignore_case(subsystem, str_lit("windows"))) {
|
||||
build_context.use_subsystem_windows = true;
|
||||
} else {
|
||||
gb_printf_err("Invalid -subsystem string, got %.*s, expected either 'console' or 'windows'\n", LIT(subsystem));
|
||||
bool subsystem_found = false;
|
||||
for (int i = 0; i < Windows_Subsystem_COUNT; i++) {
|
||||
if (str_eq_ignore_case(subsystem, windows_subsystem_names[i])) {
|
||||
build_context.ODIN_WINDOWS_SUBSYSTEM = windows_subsystem_names[i];
|
||||
subsystem_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// WINDOW is a hidden alias for WINDOWS. Check it.
|
||||
String subsystem_windows_alias = str_lit("WINDOW");
|
||||
if (!subsystem_found && str_eq_ignore_case(subsystem, subsystem_windows_alias)) {
|
||||
build_context.ODIN_WINDOWS_SUBSYSTEM = windows_subsystem_names[Windows_Subsystem_WINDOWS];
|
||||
subsystem_found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!subsystem_found) {
|
||||
gb_printf_err("Invalid -subsystem string, got %.*s. Expected one of:\n", LIT(subsystem));
|
||||
gb_printf_err("\t");
|
||||
for (int i = 0; i < Windows_Subsystem_COUNT; i++) {
|
||||
if (i > 0) {
|
||||
gb_printf_err(", ");
|
||||
}
|
||||
gb_printf_err("%.*s", LIT(windows_subsystem_names[i]));
|
||||
if (i == Windows_Subsystem_CONSOLE) {
|
||||
gb_printf_err(" (default)");
|
||||
}
|
||||
if (i == Windows_Subsystem_WINDOWS) {
|
||||
gb_printf_err(" (or WINDOW)");
|
||||
}
|
||||
}
|
||||
gb_printf_err("\n");
|
||||
bad_flags = true;
|
||||
}
|
||||
break;
|
||||
|
||||
+3
-1
@@ -5919,7 +5919,7 @@ gb_internal bool parse_file(Parser *p, AstFile *f) {
|
||||
f->vet_flags = parse_vet_tag(tok, lc);
|
||||
f->vet_flags_set = true;
|
||||
} else if (string_starts_with(lc, str_lit("+ignore"))) {
|
||||
return false;
|
||||
return false;
|
||||
} else if (string_starts_with(lc, str_lit("+private"))) {
|
||||
f->flags |= AstFile_IsPrivatePkg;
|
||||
String command = string_trim_starts_with(lc, str_lit("+private "));
|
||||
@@ -5941,6 +5941,8 @@ gb_internal bool parse_file(Parser *p, AstFile *f) {
|
||||
} else {
|
||||
f->flags |= AstFile_IsLazy;
|
||||
}
|
||||
} else if (lc == "+no-instrumentation") {
|
||||
f->flags |= AstFile_NoInstrumentation;
|
||||
} else {
|
||||
warning(tok, "Ignoring unknown tag '%.*s'", LIT(lc));
|
||||
}
|
||||
|
||||
@@ -76,6 +76,8 @@ enum AstFileFlag : u32 {
|
||||
|
||||
AstFile_IsTest = 1<<3,
|
||||
AstFile_IsLazy = 1<<4,
|
||||
|
||||
AstFile_NoInstrumentation = 1<<5,
|
||||
};
|
||||
|
||||
enum AstDelayQueueKind {
|
||||
|
||||
+1
-1
@@ -210,7 +210,7 @@ gb_internal void semaphore_wait(Semaphore *s) {
|
||||
original_count = s->count().load(std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
if (!s->count().compare_exchange_strong(original_count, original_count-1, std::memory_order_acquire, std::memory_order_acquire)) {
|
||||
if (s->count().compare_exchange_strong(original_count, original_count-1, std::memory_order_acquire, std::memory_order_acquire)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
+3
-1
@@ -825,11 +825,13 @@ gb_internal void type_path_pop(TypePath *tp) {
|
||||
#define FAILURE_SIZE 0
|
||||
#define FAILURE_ALIGNMENT 0
|
||||
|
||||
gb_internal bool type_ptr_set_exists(PtrSet<Type *> *s, Type *t);
|
||||
|
||||
gb_internal bool type_ptr_set_update(PtrSet<Type *> *s, Type *t) {
|
||||
if (t == nullptr) {
|
||||
return true;
|
||||
}
|
||||
if (ptr_set_exists(s, t)) {
|
||||
if (type_ptr_set_exists(s, t)) {
|
||||
return true;
|
||||
}
|
||||
ptr_set_add(s, t);
|
||||
|
||||
Reference in New Issue
Block a user