Odin_Calling_Convention defined in compiler; Allow for main :: proc "contextless" () {} with -bedrock; intrinsics.type_proc_calling_convention

This commit is contained in:
gingerBill
2026-05-05 15:07:42 +01:00
parent 942c1bff17
commit 8ffcdf172a
10 changed files with 101 additions and 20 deletions

View File

@@ -214,6 +214,8 @@ type_proc_return_count :: proc($T: typeid) -> int where type_is_proc(T) ---
type_proc_parameter_type :: proc($T: typeid, index: int) -> typeid where type_is_proc(T) ---
type_proc_return_type :: proc($T: typeid, index: int) -> typeid where type_is_proc(T) ---
type_proc_calling_convention :: proc($T: typeid) -> Odin_Calling_Convention where type_is_proc(T) ---
type_struct_field_count :: proc($T: typeid) -> int where type_is_struct(T) ---
type_struct_has_implicit_padding :: proc($T: typeid) -> bool where type_is_struct(T) ---
@@ -248,6 +250,8 @@ type_integer_to_signed :: proc($T: typeid) -> type where type_is_integer(T), t
type_has_shared_fields :: proc($U, $V: typeid) -> bool where type_is_struct(U), type_is_struct(V) ---
// Returns the canonicalized name of the type, of which is used to produce the pseudo-unique 'typeid'
type_canonical_name :: proc($T: typeid) -> string ---

View File

@@ -24,7 +24,9 @@ package runtime
import "base:intrinsics"
// NOTE(bill): This must match the compiler's
Calling_Convention :: enum u8 {
/*
enum u8 {
Invalid = 0,
Odin = 1,
Contextless = 2,
@@ -44,6 +46,8 @@ Calling_Convention :: enum u8 {
Preserve_Most = 12,
Preserve_All = 13,
}
*/
Calling_Convention :: type_of(ODIN_DEFAULT_CALLING_CONVENTION)
Type_Info_Enum_Value :: distinct i64

View File

@@ -2,6 +2,8 @@ package runtime
import "base:intrinsics"
MAP_ENABLED :: !ODIN_BEDROCK
@builtin
Maybe :: union($T: typeid) {T}
@@ -65,7 +67,7 @@ when !NO_DEFAULT_TEMP_ALLOCATOR {
// Initializes the global temporary allocator used as the default `context.temp_allocator`.
// This is ignored when `NO_DEFAULT_TEMP_ALLOCATOR` is true.
@(builtin, disabled=NO_DEFAULT_TEMP_ALLOCATOR)
init_global_temporary_allocator :: proc(size: int, backup_allocator := context.allocator) {
init_global_temporary_allocator :: proc "odin" (size: int, backup_allocator := context.allocator) {
when !NO_DEFAULT_TEMP_ALLOCATOR {
default_temp_allocator_init(&global_default_temp_allocator_data, size, backup_allocator)
}
@@ -387,7 +389,7 @@ pop_front_safe :: proc {
@builtin
clear :: proc{
clear_dynamic_array,
clear_map where !ODIN_BEDROCK,
clear_map where MAP_ENABLED,
clear_fixed_capacity_dynamic_array,
clear_soa_dynamic_array,
@@ -397,7 +399,7 @@ clear :: proc{
@builtin
reserve :: proc{
reserve_dynamic_array,
reserve_map where !ODIN_BEDROCK,
reserve_map where MAP_ENABLED,
reserve_soa,
}
@@ -430,7 +432,7 @@ non_zero_resize :: proc{
@builtin
shrink :: proc{
shrink_dynamic_array,
shrink_map where !ODIN_BEDROCK,
shrink_map where MAP_ENABLED,
}
// `free` will try to free the passed pointer, with the given `allocator` if the allocator supports this operation.
@@ -481,7 +483,7 @@ delete_cstring16 :: proc(str: cstring16, allocator := context.allocator, loc :=
return mem_free((^u16)(str), allocator, loc)
}
when !ODIN_BEDROCK {
when MAP_ENABLED {
// `delete_map` will try to free the underlying data of the passed map, with the given `allocator` if the allocator supports this operation.
//
// Note: Prefer the procedure group `delete`.
@@ -500,7 +502,7 @@ delete :: proc{
delete_cstring,
delete_dynamic_array,
delete_slice,
delete_map where !ODIN_BEDROCK,
delete_map where MAP_ENABLED,
delete_soa_slice,
delete_soa_dynamic_array,
delete_string16,
@@ -599,7 +601,7 @@ _make_dynamic_array_len_cap :: proc(array: ^Raw_Dynamic_Array, size_of_elem, ali
return
}
when !ODIN_BEDROCK {
when MAP_ENABLED {
// `make_map` initializes a map with an allocator. Like `new`, the first argument is a type, not a value.
// Unlike `new`, `make`'s return value is the same as the type of its argument, not a pointer to it.
//
@@ -654,8 +656,8 @@ make :: proc{
make_dynamic_array,
make_dynamic_array_len,
make_dynamic_array_len_cap,
make_map where !ODIN_BEDROCK,
make_map_cap where !ODIN_BEDROCK,
make_map where MAP_ENABLED,
make_map_cap where MAP_ENABLED,
make_multi_pointer,
make_soa_slice,
@@ -664,7 +666,7 @@ make :: proc{
make_soa_dynamic_array_len_cap,
}
when !ODIN_BEDROCK {
when MAP_ENABLED {
// `clear_map` will set the length of a passed map to `0`
//
@@ -1476,7 +1478,7 @@ _shrink_dynamic_array :: proc(a: ^Raw_Dynamic_Array, size_of_elem, align_of_elem
return true, nil
}
when !ODIN_BEDROCK {
when MAP_ENABLED {
@builtin
map_insert :: proc(m: ^$T/map[$K]$V, key: K, value: V, loc := #caller_location) -> (ptr: ^V) {

View File

@@ -7,7 +7,7 @@ when NO_DEFAULT_TEMP_ALLOCATOR {
// `Default_Temp_Allocator` is a `nil_allocator` when `NO_DEFAULT_TEMP_ALLOCATOR` is `true`.
Default_Temp_Allocator :: struct {}
default_temp_allocator_init :: proc(s: ^Default_Temp_Allocator, size: int, backing_allocator := context.allocator) {}
default_temp_allocator_init :: proc(s: ^Default_Temp_Allocator, size: int, backing_allocator: Allocator) {}
default_temp_allocator_destroy :: proc "contextless" (s: ^Default_Temp_Allocator) {}
@@ -30,7 +30,7 @@ when NO_DEFAULT_TEMP_ALLOCATOR {
arena: Arena,
}
default_temp_allocator_init :: proc(s: ^Default_Temp_Allocator, size: int, backing_allocator := context.allocator) {
default_temp_allocator_init :: proc(s: ^Default_Temp_Allocator, size: int, backing_allocator: Allocator) {
_ = arena_init(&s.arena, uint(size), backing_allocator)
}

View File

@@ -7699,6 +7699,28 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
break;
case BuiltinProc_type_proc_calling_convention:
if (operand->mode != Addressing_Type || !is_type_proc(operand->type)) {
error(operand->expr, "Expected a procedure type for '%.*s'", LIT(builtin_name));
return false;
} else {
if (is_type_polymorphic(operand->type)) {
error(operand->expr, "Expected a non-polymorphic procedure type for '%.*s'", LIT(builtin_name));
return false;
}
Type *pt = base_type(operand->type);
GB_ASSERT(pt->kind == Type_Proc);
ProcCallingConvention cc = pt->Proc.calling_convention;
operand->mode = Addressing_Constant;
operand->type = t_odin_calling_convention;
operand->value = exact_value_i64(cc);
}
break;
case BuiltinProc_type_polymorphic_record_parameter_count:
operand->value = exact_value_i64(0);
if (operand->mode != Addressing_Type) {

View File

@@ -1527,10 +1527,26 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
error(e->token, "Procedure type of 'main' was expected to be 'proc()', got %s", str);
gb_string_free(str);
}
if (pt->calling_convention != default_calling_convention()) {
error(e->token, "Procedure 'main' cannot have a custom calling convention");
if (build_context.bedrock) {
switch (pt->calling_convention) {
case ProcCC_Odin:
case ProcCC_Contextless:
// Okay
break;
default:
error(e->token, "Procedure 'main' cannot have a custom calling convention beyond \"odin\" and \"contextless\" with '-bedrock'");
pt->calling_convention = ProcCC_Odin;
break;
}
} else {
if (pt->calling_convention != default_calling_convention()) {
error(e->token, "Procedure 'main' cannot have a custom calling convention");
}
pt->calling_convention = default_calling_convention();
}
pt->calling_convention = default_calling_convention();
if (e->pkg->kind == Package_Init) {
if (ctx->info->entry_point != nullptr) {
error(e->token, "Redeclaration of the entry pointer procedure 'main'");

View File

@@ -1042,14 +1042,14 @@ struct GlobalEnumValue {
i64 value;
};
gb_internal Slice<Entity *> add_global_enum_type(String const &type_name, GlobalEnumValue *values, isize value_count, Type **enum_type_ = nullptr) {
gb_internal Slice<Entity *> add_global_enum_type(String const &type_name, GlobalEnumValue *values, isize value_count, Type **enum_type_ = nullptr, Type *base_type = t_int) {
Scope *scope = create_scope(nullptr, builtin_pkg->scope);
Entity *entity = alloc_entity_type_name(scope, make_token_ident(type_name), nullptr, EntityState_Resolved);
Type *enum_type = alloc_type_enum();
Type *named_type = alloc_type_named(type_name, enum_type, entity);
set_base_type(named_type, enum_type);
enum_type->Enum.base_type = t_int;
enum_type->Enum.base_type = base_type;
enum_type->Enum.scope = scope;
entity->type = named_type;
@@ -1276,6 +1276,32 @@ gb_internal void init_universal(void) {
scope_insert(intrinsics_pkg->scope, t_atomic_memory_order->Named.type_name);
}
{
GlobalEnumValue values[ProcCC_MAX] = {
{"Invalid", ProcCC_Invalid},
{"Odin", ProcCC_Odin},
{"Contextless", ProcCC_Contextless},
{"CDecl", ProcCC_CDecl},
{"Std_Call", ProcCC_StdCall},
{"Fast_Call", ProcCC_FastCall},
{"None", ProcCC_None},
{"Naked", ProcCC_Naked},
{"_", ProcCC_InlineAsm},
{"Win64", ProcCC_Win64},
{"SysV", ProcCC_SysV},
{"PreserveNone", ProcCC_PreserveNone},
{"PreserveMost", ProcCC_PreserveMost},
{"PreserveAll", ProcCC_PreserveAll},
};
auto fields = add_global_enum_type(str_lit("Odin_Calling_Convention"), values, gb_count_of(values), &t_odin_calling_convention, t_u8);
add_global_enum_constant(fields, "ODIN_DEFAULT_CALLING_CONVENTION", default_calling_convention());
}
{
int minimum_os_version = 0;
if (build_context.minimum_os_version_string != "") {

View File

@@ -350,6 +350,8 @@ BuiltinProc__type_simple_boolean_end,
BuiltinProc_type_proc_parameter_type,
BuiltinProc_type_proc_return_type,
BuiltinProc_type_proc_calling_convention,
BuiltinProc_type_polymorphic_record_parameter_count,
BuiltinProc_type_polymorphic_record_parameter_value,
@@ -748,6 +750,8 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
{STR_LIT("type_proc_parameter_type"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_proc_return_type"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_proc_calling_convention"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_polymorphic_record_parameter_count"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_polymorphic_record_parameter_value"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},

View File

@@ -632,7 +632,7 @@ gb_internal bool parse_build_flags(Array<String> args) {
add_flag(&build_flags, BuildFlag_BuildDiagnostics, str_lit("build-diagnostics"), BuildFlagParam_None, Command__does_build);
add_flag(&build_flags, BuildFlag_Bedrock, str_lit("bedrock"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_DisableNonConstantGlobals, str_lit("disable-non-constant-globals"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_DisableNonConstantGlobals, str_lit("disable-non-constant-globals"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_DisableInitFini, str_lit("disable-init-fini"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_InternalFastISel, str_lit("internal-fast-isel"), BuildFlagParam_None, Command_all);

View File

@@ -781,6 +781,9 @@ gb_global Type *t_c_va_list = nullptr;
gb_global Type *t_c_va_list_ptr = nullptr;
gb_global Type *t_odin_calling_convention = nullptr;
enum OdinAtomicMemoryOrder : i32 {
OdinAtomicMemoryOrder_relaxed = 0, // unordered
OdinAtomicMemoryOrder_consume = 1, // monotonic