mirror of
https://github.com/odin-lang/Odin.git
synced 2026-06-13 13:53:43 +00:00
Odin_Calling_Convention defined in compiler; Allow for main :: proc "contextless" () {} with -bedrock; intrinsics.type_proc_calling_convention
This commit is contained in:
@@ -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 ---
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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'");
|
||||
|
||||
@@ -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 != "") {
|
||||
|
||||
@@ -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},
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user