Files
Odin/core/_preload.odin
Ginger Bill 77e219d442 Change var decl syntax
`var x int;` from `x: int;`
2016-12-18 22:32:18 +00:00

349 lines
8.1 KiB
Odin

#shared_global_scope;
#import "os.odin";
#import "fmt.odin";
#import "mem.odin";
// IMPORTANT NOTE(bill): `type_info` & `type_info_val` cannot be used within a
// #shared_global_scope due to the internals of the compiler.
// This could change at a later date if the all these data structures are
// implemented within the compiler rather than in this "preload" file
// IMPORTANT NOTE(bill): Do not change the order of any of this data
// The compiler relies upon this _exact_ order
type Type_Info_Member struct #ordered {
name string; // can be empty if tuple
type_info ^Type_Info;
offset int; // offsets are not used in tuples
}
type Type_Info_Record struct #ordered {
fields []Type_Info_Member;
size int; // in bytes
align int; // in bytes
packed bool;
ordered bool;
}
type Type_Info union {
Named struct #ordered {
name string;
base ^Type_Info; // This will _not_ be a Type_Info.Named
};
Integer struct #ordered {
size int; // in bytes
signed bool;
};
Float struct #ordered {
size int; // in bytes
};
Any struct #ordered {};
String struct #ordered {};
Boolean struct #ordered {};
Pointer struct #ordered {
elem ^Type_Info; // nil -> rawptr
};
Maybe struct #ordered {
elem ^Type_Info;
};
Procedure struct #ordered {
params ^Type_Info; // Type_Info.Tuple
results ^Type_Info; // Type_Info.Tuple
variadic bool;
};
Array struct #ordered {
elem ^Type_Info;
elem_size int;
count int;
};
Slice struct #ordered {
elem ^Type_Info;
elem_size int;
};
Vector struct #ordered {
elem ^Type_Info;
elem_size int;
count int;
align int;
};
Tuple Type_Info_Record;
Struct Type_Info_Record;
Union Type_Info_Record;
Raw_Union Type_Info_Record;
Enum struct #ordered {
base ^Type_Info;
values []i64;
names []string;
};
};
proc type_info_base(info ^Type_Info) -> ^Type_Info {
if info == nil {
return nil;
}
var base = info;
match type i : base {
case Type_Info.Named:
base = i.base;
}
return base;
}
proc assume(cond bool) #foreign "llvm.assume"
proc __debug_trap () #foreign "llvm.debugtrap"
proc __trap () #foreign "llvm.trap"
proc read_cycle_counter() -> u64 #foreign "llvm.readcyclecounter"
proc bit_reverse16(b u16) -> u16 #foreign "llvm.bitreverse.i16"
proc bit_reverse32(b u32) -> u32 #foreign "llvm.bitreverse.i32"
proc bit_reverse64(b u64) -> u64 #foreign "llvm.bitreverse.i64"
proc byte_swap16(b u16) -> u16 #foreign "llvm.bswap.i16"
proc byte_swap32(b u32) -> u32 #foreign "llvm.bswap.i32"
proc byte_swap64(b u64) -> u64 #foreign "llvm.bswap.i64"
proc fmuladd32(a, b, c f32) -> f32 #foreign "llvm.fmuladd.f32"
proc fmuladd64(a, b, c f64) -> f64 #foreign "llvm.fmuladd.f64"
type Allocator_Mode enum {
ALLOC,
FREE,
FREE_ALL,
RESIZE,
}
type Allocator_Proc proc(allocator_data rawptr, mode Allocator_Mode,
size, alignment int,
old_memory rawptr, old_size int, flags u64) -> rawptr;
type Allocator struct #ordered {
procedure Allocator_Proc;
data rawptr;
}
type Context struct #ordered {
thread_id int;
allocator Allocator;
user_data rawptr;
user_index int;
}
#thread_local var __context Context;
const DEFAULT_ALIGNMENT = align_of([vector 4]f32);
proc __check_context() {
var c = ^__context;
if c.allocator.procedure == nil {
c.allocator = default_allocator();
}
if c.thread_id == 0 {
c.thread_id = os.current_thread_id();
}
}
proc alloc(size int) -> rawptr #inline { return alloc_align(size, DEFAULT_ALIGNMENT); }
proc alloc_align(size, alignment int) -> rawptr #inline {
__check_context();
var a = context.allocator;
return a.procedure(a.data, Allocator_Mode.ALLOC, size, alignment, nil, 0, 0);
}
proc free(ptr rawptr) #inline {
__check_context();
var a = context.allocator;
if ptr != nil {
a.procedure(a.data, Allocator_Mode.FREE, 0, 0, ptr, 0, 0);
}
}
proc free_all() #inline {
__check_context();
var a = context.allocator;
a.procedure(a.data, Allocator_Mode.FREE_ALL, 0, 0, nil, 0, 0);
}
proc resize (ptr rawptr, old_size, new_size int) -> rawptr #inline { return resize_align(ptr, old_size, new_size, DEFAULT_ALIGNMENT); }
proc resize_align(ptr rawptr, old_size, new_size, alignment int) -> rawptr #inline {
__check_context();
var a = context.allocator;
return a.procedure(a.data, Allocator_Mode.RESIZE, new_size, alignment, ptr, old_size, 0);
}
proc default_resize_align(old_memory rawptr, old_size, new_size, alignment int) -> rawptr {
if old_memory == nil {
return alloc_align(new_size, alignment);
}
if new_size == 0 {
free(old_memory);
return nil;
}
if new_size == old_size {
return old_memory;
}
var new_memory = alloc_align(new_size, alignment);
if new_memory == nil {
return nil;
}
mem.copy(new_memory, old_memory, min(old_size, new_size));;
free(old_memory);
return new_memory;
}
proc default_allocator_proc(allocator_data rawptr, mode Allocator_Mode,
size, alignment int,
old_memory rawptr, old_size int, flags u64) -> rawptr {
using Allocator_Mode;
when false {
match mode {
case ALLOC:
var total_size = size + alignment + size_of(mem.AllocationHeader);
var ptr = os.heap_alloc(total_size);
var header = ptr as ^mem.AllocationHeader;
ptr = mem.align_forward(header+1, alignment);
mem.allocation_header_fill(header, ptr, size);
return mem.zero(ptr, size);
case FREE:
os.heap_free(mem.allocation_header(old_memory));
return nil;
case FREE_ALL:
// NOTE(bill): Does nothing
case RESIZE:
var total_size = size + alignment + size_of(mem.AllocationHeader);
var ptr = os.heap_resize(mem.allocation_header(old_memory), total_size);
var header = ptr as ^mem.AllocationHeader;
ptr = mem.align_forward(header+1, alignment);
mem.allocation_header_fill(header, ptr, size);
return mem.zero(ptr, size);
}
} else {
match mode {
case ALLOC:
return os.heap_alloc(size);
case FREE:
os.heap_free(old_memory);
return nil;
case FREE_ALL:
// NOTE(bill): Does nothing
case RESIZE:
return os.heap_resize(old_memory, size);
}
}
return nil;
}
proc default_allocator() -> Allocator {
return Allocator{
procedure = default_allocator_proc,
data = nil,
};
}
proc __string_eq(a, b string) -> bool {
if a.count != b.count {
return false;
}
if a.data == b.data {
return true;
}
return mem.compare(a.data, b.data, a.count) == 0;
}
proc __string_cmp(a, b string) -> int {
return mem.compare(a.data, b.data, min(a.count, b.count));
}
proc __string_ne(a, b string) -> bool #inline { return !__string_eq(a, b); }
proc __string_lt(a, b string) -> bool #inline { return __string_cmp(a, b) < 0; }
proc __string_gt(a, b string) -> bool #inline { return __string_cmp(a, b) > 0; }
proc __string_le(a, b string) -> bool #inline { return __string_cmp(a, b) <= 0; }
proc __string_ge(a, b string) -> bool #inline { return __string_cmp(a, b) >= 0; }
proc __assert(file string, line, column int, msg string) #inline {
fmt.fprintf(os.stderr, "%(%:%) Runtime assertion: %\n",
file, line, column, msg);
__debug_trap();
}
proc __bounds_check_error(file string, line, column int, index, count int) {
if 0 <= index && index < count {
return;
}
fmt.fprintf(os.stderr, "%(%:%) Index % is out of bounds range [0, %)\n",
file, line, column, index, count);
__debug_trap();
}
proc __slice_expr_error(file string, line, column int, low, high, max int) {
if 0 <= low && low <= high && high <= max {
return;
}
fmt.fprintf(os.stderr, "%(%:%) Invalid slice indices: [%:%:%]\n",
file, line, column, low, high, max);
__debug_trap();
}
proc __substring_expr_error(file string, line, column int, low, high int) {
if 0 <= low && low <= high {
return;
}
fmt.fprintf(os.stderr, "%(%:%) Invalid substring indices: [%:%:%]\n",
file, line, column, low, high);
__debug_trap();
}
proc __enum_to_string(info ^Type_Info, value i64) -> string {
match type ti : type_info_base(info) {
case Type_Info.Enum:
// TODO(bill): Search faster than linearly
for var i = 0; i < ti.values.count; i++ {
if ti.values[i] == value {
return ti.names[i];
}
}
}
return "";
}