bloat-buster/src/compiler.h
2025-05-03 11:12:00 -06:00

412 lines
6.7 KiB
C++

#pragma once
#include <lib.h>
#define report_error() trap_raw()
enum class Command
{
compile,
test,
count,
};
enum class BuildMode
{
debug_none,
debug,
soft_optimize,
optimize_for_speed,
optimize_for_size,
aggressively_optimize_for_speed,
aggressively_optimize_for_size,
count,
};
fn String build_mode_to_string(BuildMode build_mode)
{
switch (build_mode)
{
case_to_name(BuildMode, debug_none);
case_to_name(BuildMode, debug);
case_to_name(BuildMode, soft_optimize);
case_to_name(BuildMode, optimize_for_speed);
case_to_name(BuildMode, optimize_for_size);
case_to_name(BuildMode, aggressively_optimize_for_speed);
case_to_name(BuildMode, aggressively_optimize_for_size);
case BuildMode::count: unreachable();
}
}
enum class CPUArchitecture
{
x86_64,
};
enum class OperatingSystem
{
linux_,
};
struct Type;
struct Value;
struct Local;
struct Global;
struct Block;
struct Statement;
struct Target
{
CPUArchitecture cpu;
OperatingSystem os;
};
struct Compile
{
String relative_file_path;
BuildMode build_mode;
bool has_debug_info;
bool silent;
};
#define base_cache_dir "bb-cache"
enum class CallingConvention
{
c,
count,
};
enum class InlineBehavior
{
normal,
always_inline,
no_inline,
inline_hint,
};
struct FunctionAttributes
{
InlineBehavior inline_behavior;
bool naked;
};
enum class TypeId
{
void_type,
noreturn,
forward_declaration,
integer,
function,
pointer,
};
struct TypeInteger
{
u32 bit_count;
bool is_signed;
};
struct TypeFunction
{
Type* semantic_return_type;
Slice<Type*> semantic_argument_types;
CallingConvention calling_convention;
bool is_variable_arguments;
};
struct TypePointer
{
Type* element_type;
Type* next;
};
struct Type
{
union
{
TypeInteger integer;
TypeFunction function;
TypePointer pointer;
};
TypeId id;
String name;
Type* next;
};
enum class ScopeKind
{
global,
function,
local,
for_each,
macro_declaration,
macro_instantiation,
};
struct Scope
{
Scope* parent;
u32 line;
u32 column;
ScopeKind kind;
};
enum class StatementId
{
local,
expression,
return_st,
};
struct Statement
{
union
{
Local* local;
Value* expression;
Value* return_st;
};
Statement* next;
StatementId id;
u32 line;
u32 column;
};
struct Block
{
Local* first_local;
Local* last_local;
Statement* first_statement;
Scope scope;
};
enum class ValueId
{
infer_or_ignore,
external_function,
function,
constant_integer,
};
struct ValueConstantInteger
{
u64 value;
bool is_signed;
};
struct ValueFunction
{
Slice<Local*> arguments;
Scope scope;
Block* block;
FunctionAttributes attributes;
};
enum class ValueKind
{
right,
left,
};
struct Value
{
Type* type;
union
{
ValueConstantInteger constant_integer;
ValueFunction function;
};
ValueId id;
};
struct Variable
{
Value* storage;
Value* initial_value;
Type* type;
Scope* scope;
String name;
u32 line;
u32 column;
};
enum class Linkage
{
internal,
external,
};
struct Global
{
Variable variable;
Linkage linkage;
Global* next;
};
struct Local
{
Variable variable;
};
struct MacroDeclaration
{
};
struct MacroInstantiation
{
};
struct Module
{
Arena& arena;
String content;
u64 offset;
u64 line_offset;
u64 line_character_offset;
Type* first_pointer_type;
Type* first_slice_type;
Type* first_pair_struct_type;
Type* first_array_type;
Type* first_type;
Type* last_type;
Type* va_list_type;
Value* void_value;
Global* first_global;
Global* last_global;
Global* current_function;
MacroDeclaration* current_macro_declaration;
MacroInstantiation* current_macro_instantiation;
Scope scope;
String name;
String path;
String executable;
Slice<String>objects;
Target target;
BuildMode build_mode;
bool has_debug_info;
bool silent;
};
constexpr u64 i128_offset = 64 * 2;
constexpr u64 void_offset = i128_offset + 2;
fn Type* integer_type(Module& module, TypeInteger integer)
{
assert(integer.bit_count);
assert(integer.bit_count <= 64 || integer.bit_count == 128);
auto index = integer.bit_count ? (i128_offset + integer.is_signed) : (integer.bit_count - 1 + (64 * integer.is_signed));
return module.first_type + index;
}
fn Type* void_type(Module& module)
{
return module.first_type + void_offset;
}
fn Type* noreturn_type(Module& module)
{
return void_type(module) + 1;
}
struct Options
{
String content;
String path;
String executable;
String name;
Slice<String> objects;
Target target;
BuildMode build_mode;
bool has_debug_info;
bool silent;
};
fn Type* type_allocate_init(Module& module, Type type)
{
auto* result = &arena_allocate<Type>(module.arena, 1)[0];
*result = type;
if (module.last_type)
{
module.last_type->next = result;
module.last_type = result;
}
else
{
assert(!module.first_type);
module.first_type = result;
module.last_type = result;
}
return result;
}
fn Value* new_value(Module& module)
{
auto* result = &arena_allocate<Value>(module.arena, 1)[0];
return result;
}
fn Global* new_global(Module& module)
{
auto* result = &arena_allocate<Global>(module.arena, 1)[0];
if (module.last_global)
{
module.last_global->next = result;
module.last_global = result;
}
else
{
assert(!module.first_global);
module.first_global = result;
module.last_global = result;
}
return result;
}
fn Type* get_pointer_type(Module& module, Type* element_type)
{
auto last_pointer_type = module.first_pointer_type;
while (last_pointer_type)
{
assert(last_pointer_type->id == TypeId::pointer);
if (last_pointer_type->pointer.element_type == element_type)
{
return last_pointer_type;
}
if (!last_pointer_type->pointer.next)
{
break;
}
last_pointer_type = last_pointer_type->pointer.next;
}
String name_parts[] = {
str("&"),
element_type->name,
};
auto result = type_allocate_init(module, {
.pointer = {
.element_type = element_type,
},
.id = TypeId::pointer,
.name = arena_join_string(module.arena, array_to_slice(name_parts)),
});
return result;
}
void parse(Module& module);
void emit(Module& module);