LLVM initialization
Some checks failed
CI / ci (MinSizeRel, ubuntu-latest) (push) Failing after 25s
CI / ci (RelWithDebInfo, ubuntu-latest) (push) Failing after 25s
CI / ci (Release, ubuntu-latest) (push) Failing after 24s
CI / ci (Debug, ubuntu-latest) (push) Failing after 56s

This commit is contained in:
David Gonzalez Martin 2025-05-31 17:19:15 -06:00
parent 7ad2bca45c
commit 9b1c5ce7b0
4 changed files with 329 additions and 80 deletions

View File

@ -531,6 +531,32 @@ fail = fn () noreturn
exit(1);
}
LLVMContext = opaque;
LLVMModule = opaque;
LLVMBuilder = opaque;
LLVMValue = opaque;
LLVMType = opaque;
LLVMBasicBlock = opaque;
LLVMIntrinsicId = typealias u32;
LLVMMetadata = opaque;
LLVMDIBuilder = opaque;
LLVMTarget = opaque;
LLVMTargetDataLayout = opaque;
LLVMTargetMachine = opaque;
LLVMTargetMachineOptions = opaque;
LLVMIntrinsicIndex = enum u32
{
trap,
va_start,
va_end,
va_copy,
}
CompilerCommand = enum
{
compile,
@ -548,6 +574,15 @@ BuildMode = enum
aggressively_optimize_for_size,
}
build_mode_is_optimized = fn (build_mode: BuildMode) u1
{
switch (build_mode)
{
.debug_none, .debug => { return 0; },
else => { return 1; },
}
}
CompileFile = struct
{
relative_file_path: []u8,
@ -644,6 +679,7 @@ Scope = struct
{
types: TypeList,
parent: &Scope,
llvm: &LLVMMetadata,
line: u32,
column: u32,
kind: ScopeKind,
@ -821,31 +857,6 @@ MacroInstantiation = struct
foo: u32,
}
LLVMContext = opaque;
LLVMModule = opaque;
LLVMBuilder = opaque;
LLVMValue = opaque;
LLVMType = opaque;
LLVMBasicBlock = opaque;
LLVMIntrinsicId = typealias u32;
LLVMMetadata = opaque;
LLVMDIBuilder = opaque;
LLVMTarget = opaque;
LLVMTargetMachine = opaque;
LLVMTargetMachineOptions = opaque;
LLVMIntrinsicIndex = enum
{
trap,
va_start,
va_end,
va_copy,
}
[extern] LLVMInitializeX86TargetInfo = fn [cc(c)] () void;
[extern] LLVMInitializeX86Target = fn [cc(c)] () void;
[extern] LLVMInitializeX86TargetMC = fn [cc(c)] () void;
@ -882,7 +893,7 @@ llvm_initialize_targets = fn () void
}
}
LLVMCodeGenerationOptimizationLevel = enum
LLVMCodeGenerationOptimizationLevel = enum u32
{
none = 0,
less = 1,
@ -890,16 +901,109 @@ LLVMCodeGenerationOptimizationLevel = enum
aggressive = 3,
}
LLVMDwarfSourceLanguage = enum u32
{
C89,
C,
Ada83,
C_plus_plus,
Cobol74,
Cobol85,
Fortran77,
Fortran90,
Pascal83,
Modula2,
// New in DWARF v3:
Java,
C99,
Ada95,
Fortran95,
PLI,
ObjC,
ObjC_plus_plus,
UPC,
D,
// New in DWARF v4:
Python,
// New in DWARF v5:
OpenCL,
Go,
Modula3,
Haskell,
C_plus_plus_03,
C_plus_plus_11,
OCaml,
Rust,
C11,
Swift,
Julia,
Dylan,
C_plus_plus_14,
Fortran03,
Fortran08,
RenderScript,
BLISS,
Kotlin,
Zig,
Crystal,
C_plus_plus_17,
C_plus_plus_20,
C17,
Fortran18,
Ada2005,
Ada2012,
HIP,
Assembly,
C_sharp,
Mojo,
GLSL,
GLSL_ES,
HLSL,
OpenCL_CPP,
CPP_for_OpenCL,
SYCL,
Ruby,
Move,
Hylo,
Metal,
// Vendor extensions:
Mips_Assembler,
GOOGLE_RenderScript,
BORLAND_Delphi
}
LLVMDwarfEmissionKind = enum u32
{
none,
full,
line_tables_only,
}
[extern] LLVMContextCreate = fn [cc(c)] () &LLVMContext;
[extern] llvm_context_create_module = fn (context: &LLVMContext, name: []u8) &LLVMModule;
[extern] LLVMCreateBuilderInContext = fn (context: &LLVMContext) &LLVMBuilder;
[extern] LLVMVoidTypeInContext = fn [cc(c)] (context: &LLVMContext) &LLVMType;
[extern] LLVMPointerTypeInContext = fn [cc(c)] (context: &LLVMContext, address_space: u32) &LLVMType;
[extern] LLVMCreateDIBuilder = fn (module: &LLVMModule) &LLVMDIBuilder;
[extern] LLVMDIBuilderCreateFile = fn (di_builder: &LLVMDIBuilder, file_pointer: &u8, file_length: u64, directory_pointer: &u8, directory_length: u64) &LLVMMetadata;
[extern] LLVMDIBuilderCreateCompileUnit = fn (di_builder: &LLVMDIBuilder, language: LLVMDwarfSourceLanguage, file: &LLVMMetadata, producer_name_pointer: &u8, producer_name_length: u64, is_optimized: s32, flags_pointer: &u8, flags_length: u64, runtime_version: u32, split_name_pointer: &u8, split_name_length: u64, emission_kind: LLVMDwarfEmissionKind, dwo_id: u32, split_debug_inlining: s32, debug_info_for_profiling: s32, sysroot_pointer: &u8, sysroot_length: u64, sdk_pointer: &u8, sdk_length: u64) &LLVMMetadata;
[extern] LLVMLookupIntrinsicID = fn [cc(c)] (name_pointer: &u8, name_length: u64) LLVMIntrinsicId;
[extern] LLVMCreateTargetMachineOptions = fn () &LLVMTargetMachineOptions;
[extern] LLVMTargetMachineOptionsSetCPU = fn (target_machine_options: &LLVMTargetMachineOptions, cpu: &u8) void;
[extern] LLVMTargetMachineOptionsSetFeatures = fn (target_machine_options: &LLVMTargetMachineOptions, features: &u8) void;
[extern] LLVMTargetMachineOptionsSetCodeGenOptLevel = fn (target_machine_options: &LLVMTargetMachineOptions, optimization_level: LLVMCodeGenerationOptimizationLevel) void;
[extern] LLVMGetTargetFromTriple = fn (target_triple: &u8, target_pointer: &&LLVMTarget, error_message_pointer: &&u8) s32;
[extern] LLVMCreateTargetMachineWithOptions = fn (target: &LLVMTarget, target_triple: &u8, target_machine_options: &LLVMTargetMachineOptions) &LLVMTargetMachine;
[extern] LLVMCreateTargetDataLayout = fn (target_machine: &LLVMTargetMachine) &LLVMTargetDataLayout;
[extern] LLVMSetModuleDataLayout = fn (module: &LLVMModule, target_data_layout: &LLVMTargetDataLayout) void;
[extern] LLVMSetTarget = fn (module: &LLVMModule, target_triple: &u8) void;
default_address_space: u32 = 0;
ModuleLLVM = struct
{
@ -908,7 +1012,8 @@ ModuleLLVM = struct
builder: &LLVMBuilder,
di_builder: &LLVMDIBuilder,
file: &LLVMMetadata,
compile_unit: &LLVMMetadata,
target_machine: &LLVMTargetMachine,
target_data_layout: &LLVMTargetDataLayout,
pointer_type: &LLVMType,
void_type: &LLVMType,
intrinsic_table: enum_array[LLVMIntrinsicIndex](LLVMIntrinsicId),
@ -2689,6 +2794,36 @@ emit = fn (module: &Module) void
>m = llvm_context_create_module(context, module.name);
>builder = LLVMCreateBuilderInContext(context);
>di_builder: &LLVMDIBuilder = zero;
>di_file: &LLVMMetadata = zero;
if (module.has_debug_info)
{
di_builder = LLVMCreateDIBuilder(m);
>last_slash = string_last_character(module.path, '/');
if (last_slash == string_no_match)
{
report_error();
}
>directory = module.path[..last_slash];
>file_name = module.path[last_slash + 1..];
>di_file = LLVMDIBuilderCreateFile(di_builder, file_name.pointer, file_name.length, directory.pointer, directory.length);
>language: LLVMDwarfSourceLanguage = .C17;
>producer_name = "bloat buster";
>is_optimized = build_mode_is_optimized(module.build_mode);
>flags = "";
>emission_kind: LLVMDwarfEmissionKind = .full;
>runtime_version: u32 = 0;
>split_name = "";
>sysroot = "";
>sdk = "";
module.scope.llvm = LLVMDIBuilderCreateCompileUnit(di_builder, language, di_file, producer_name.pointer, producer_name.length, #extend(is_optimized), flags.pointer, flags.length, runtime_version, split_name.pointer, split_name.length, emission_kind, 0, 0, #extend(is_optimized), sysroot.pointer, sysroot.length, sdk.pointer, sdk.length);
}
>target_triple: []u8 = undefined;
>cpu_model: []u8 = undefined;
>cpu_features: []u8 = undefined;
@ -2729,7 +2864,31 @@ emit = fn (module: &Module) void
assert(!error_message);
LLVMCreateTargetMachineWithOptions(target, target_triple.pointer, target_machine_options);
>target_machine = LLVMCreateTargetMachineWithOptions(target, target_triple.pointer, target_machine_options);
>target_data_layout = LLVMCreateTargetDataLayout(target_machine);
LLVMSetModuleDataLayout(m, target_data_layout);
LLVMSetTarget(m, target_triple.pointer);
module.llvm = {
.context = context,
.module = m,
.builder = builder,
.di_builder = di_builder,
.file = di_file,
.target_machine = target_machine,
.target_data_layout = target_data_layout,
.pointer_type = LLVMPointerTypeInContext(context, default_address_space),
.void_type = LLVMVoidTypeInContext(context),
zero,
};
for (i: 0..module.llvm.intrinsic_table.length)
{
>e: LLVMIntrinsicIndex = #enum_from_int(i);
>name = #enum_name(e);
module.llvm.intrinsic_table[i] = LLVMLookupIntrinsicID(name.pointer, name.length);
}
}
compile = fn (arena: &Arena, options: CompileOptions) void

View File

@ -597,6 +597,7 @@ fn u32 get_byte_alignment(Type* type)
return result;
} break;
case TypeId::pointer:
case TypeId::opaque:
{
return 8;
} break;
@ -860,6 +861,7 @@ enum class UnaryId
bitwise_not,
dereference,
pointer_from_int,
enum_from_int,
};
struct ValueUnary

View File

@ -176,6 +176,7 @@ fn bool is_promotable_integer_type_for_abi(Type* type)
case TypeId::bits: return is_promotable_integer_type_for_abi(type->bits.backing_type);
case TypeId::alias: return is_promotable_integer_type_for_abi(type->alias.type);
case TypeId::enumerator: return is_promotable_integer_type_for_abi(type->enumerator.backing_type);
case TypeId::pointer: return false;
default: unreachable();
}
}
@ -927,6 +928,7 @@ fn void resolve_type_in_place_abi(Module* module, Type* type)
result = LLVMIntTypeInContext(module->llvm.context, type->integer.bit_count);
break;
case TypeId::pointer:
case TypeId::opaque:
result = module->llvm.pointer_type;
break;
case TypeId::array:
@ -1015,6 +1017,7 @@ fn void resolve_type_in_place_memory(Module* module, Type* type)
case TypeId::void_type:
case TypeId::noreturn:
case TypeId::pointer:
case TypeId::opaque:
case TypeId::array:
case TypeId::structure:
case TypeId::enum_array:
@ -2220,6 +2223,7 @@ fn bool unary_is_boolean(UnaryId id)
case UnaryId::bitwise_not:
case UnaryId::dereference:
case UnaryId::pointer_from_int:
case UnaryId::enum_from_int:
return false;
}
}
@ -2265,7 +2269,20 @@ fn bool binary_is_shortcircuiting(BinaryId id)
}
}
fn void analyze_type(Module* module, Value* value, Type* expected_type, bool must_be_constant);
enum class IndexType
{
none,
array,
enum_array,
};
struct TypeAnalysis
{
bool must_be_constant;
bool is_index;
};
fn void analyze_type(Module* module, Value* value, Type* expected_type, TypeAnalysis analysis);
fn void analyze_binary_type(Module* module, Value* left, Value* right, bool is_boolean, Type* expected_type, bool must_be_constant)
{
@ -2296,19 +2313,19 @@ fn void analyze_binary_type(Module* module, Value* left, Value* right, bool is_b
{
if (left_constant)
{
analyze_type(module, right, 0, must_be_constant);
analyze_type(module, left, right->type, must_be_constant);
analyze_type(module, right, 0, { .must_be_constant = must_be_constant });
analyze_type(module, left, right->type, { .must_be_constant = must_be_constant });
}
else
{
analyze_type(module, left, 0, must_be_constant);
analyze_type(module, right, left->type, must_be_constant);
analyze_type(module, left, 0, { .must_be_constant = must_be_constant });
analyze_type(module, right, left->type, { .must_be_constant = must_be_constant });
}
}
else if (!is_boolean && expected_type)
{
analyze_type(module, left, expected_type, must_be_constant);
analyze_type(module, right, expected_type, must_be_constant);
analyze_type(module, left, expected_type, { .must_be_constant = must_be_constant });
analyze_type(module, right, expected_type, { .must_be_constant = must_be_constant });
}
else
{
@ -2622,9 +2639,8 @@ fn void copy_block(Module* module, Scope* parent_scope, BlockCopy copy)
}
}
fn void analyze_type(Module* module, Value* value, Type* expected_type, bool must_be_constant)
fn void analyze_type(Module* module, Value* value, Type* expected_type, TypeAnalysis analysis)
{
unused(must_be_constant);
assert(!value->type);
assert(!value->llvm);
@ -2674,6 +2690,14 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus
{
case ValueId::constant_integer:
{
if (!expected_type)
{
if (analysis.is_index)
{
expected_type = uint64(module);
}
}
if (!expected_type)
{
report_error();
@ -2726,7 +2750,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus
}
auto extended_value = unary_value;
analyze_type(module, extended_value, 0, must_be_constant);
analyze_type(module, extended_value, 0, { .must_be_constant = analysis.must_be_constant });
auto source = extended_value->type;
assert(source);
@ -2750,7 +2774,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus
report_error();
}
analyze_type(module, unary_value, 0, must_be_constant);
analyze_type(module, unary_value, 0, { .must_be_constant = analysis.must_be_constant });
auto expected_bit_size = get_bit_size(expected_type);
auto source_bit_size = get_bit_size(unary_value->type);
@ -2763,7 +2787,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus
} break;
case UnaryId::dereference:
{
analyze_type(module, unary_value, 0, must_be_constant);
analyze_type(module, unary_value, 0, { .must_be_constant = analysis.must_be_constant });
if (value->kind == ValueKind::left)
{
report_error();
@ -2777,7 +2801,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus
} break;
case UnaryId::int_from_enum:
{
analyze_type(module, unary_value, 0, must_be_constant);
analyze_type(module, unary_value, 0, { .must_be_constant = analysis.must_be_constant });
auto value_enum_type = unary_value->type;
if (value_enum_type->id != TypeId::enumerator)
@ -2792,7 +2816,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus
} break;
case UnaryId::int_from_pointer:
{
analyze_type(module, unary_value, 0, must_be_constant);
analyze_type(module, unary_value, 0, { .must_be_constant = analysis.must_be_constant });
auto value_enum_type = unary_value->type;
if (value_enum_type->id != TypeId::pointer)
@ -2815,7 +2839,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus
report_error();
}
analyze_type(module, unary_value, 0, must_be_constant);
analyze_type(module, unary_value, 0, { .must_be_constant = analysis.must_be_constant });
auto value_pointer_type = unary_value->type;
if (value_pointer_type == expected_type)
{
@ -2833,7 +2857,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus
{
auto string_type = get_slice_type(module, uint8(module));
typecheck(module, expected_type, string_type);
analyze_type(module, unary_value, 0, must_be_constant);
analyze_type(module, unary_value, 0, { .must_be_constant = analysis.must_be_constant });
auto enum_type = unary_value->type;
if (enum_type->id != TypeId::enumerator)
{
@ -2948,7 +2972,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus
report_error();
}
analyze_type(module, unary_value, 0, must_be_constant);
analyze_type(module, unary_value, 0, { .must_be_constant = analysis.must_be_constant });
auto unary_value_type = unary_value->type;
if (unary_value_type->id != TypeId::integer)
{
@ -2961,6 +2985,32 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus
report_error();
}
value_type = expected_type;
} break;
case UnaryId::enum_from_int:
{
if (!expected_type)
{
report_error();
}
if (expected_type->id != TypeId::enumerator)
{
report_error();
}
analyze_type(module, unary_value, expected_type->enumerator.backing_type, { .must_be_constant = analysis.must_be_constant });
auto unary_value_type = unary_value->type;
if (unary_value_type->id != TypeId::integer)
{
report_error();
}
if (get_bit_size(unary_value_type) != get_bit_size(expected_type))
{
report_error();
}
value_type = expected_type;
} break;
default:
@ -2968,12 +3018,12 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus
auto is_boolean = unary_is_boolean(unary_id);
if (is_boolean)
{
analyze_type(module, unary_value, 0, must_be_constant);
analyze_type(module, unary_value, 0, { .must_be_constant = analysis.must_be_constant });
value_type = uint1(module);
}
else
{
analyze_type(module, unary_value, expected_type, must_be_constant);
analyze_type(module, unary_value, expected_type, { .must_be_constant = analysis.must_be_constant });
value_type = unary_value->type;
}
@ -3031,7 +3081,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus
case ValueId::binary:
{
auto is_boolean = binary_is_boolean(value->binary.id);
analyze_binary_type(module, value->binary.left, value->binary.right, is_boolean, expected_type, must_be_constant);
analyze_binary_type(module, value->binary.left, value->binary.right, is_boolean, expected_type, analysis.must_be_constant);
check_types(module, value->binary.left->type, value->binary.right->type);
value_type = is_boolean ? uint1(module) : value->binary.left->type;
@ -3050,7 +3100,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus
{
auto call = &value->call;
auto callable = call->callable;
analyze_type(module, callable, 0, must_be_constant);
analyze_type(module, callable, 0, { .must_be_constant = analysis.must_be_constant });
Type* function_type = 0;
switch (callable->id)
{
@ -3101,14 +3151,14 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus
{
auto* argument_type = semantic_argument_types[i];
auto* call_argument = call_arguments[i];
analyze_type(module, call_argument, argument_type, must_be_constant);
analyze_type(module, call_argument, argument_type, { .must_be_constant = analysis.must_be_constant });
check_types(module, argument_type, call_argument->type);
}
for (u64 i = semantic_argument_types.length; i < call_arguments.length; i += 1)
{
auto* call_argument = call_arguments[i];
analyze_type(module, call_argument, 0, must_be_constant);
analyze_type(module, call_argument, 0, { .must_be_constant = analysis.must_be_constant });
}
auto semantic_return_type = function_type->function.semantic_return_type;
@ -3144,7 +3194,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus
auto* element_type = expected_type->array.element_type;
for (auto value : values)
{
analyze_type(module, value, element_type, must_be_constant);
analyze_type(module, value, element_type, { .must_be_constant = analysis.must_be_constant });
is_constant = is_constant && value->is_constant();
}
@ -3169,7 +3219,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus
for (auto value : values)
{
analyze_type(module, value, expected_type, must_be_constant);
analyze_type(module, value, expected_type, { .must_be_constant = analysis.must_be_constant });
is_constant = is_constant && value->is_constant();
@ -3209,7 +3259,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus
{
auto array_like = value->array_expression.array_like;
array_like->kind = ValueKind::left;
analyze_type(module, array_like, 0, must_be_constant);
analyze_type(module, array_like, 0, { .must_be_constant = analysis.must_be_constant });
assert(array_like->kind == ValueKind::left);
auto array_like_type = array_like->type;
if (array_like_type->id != TypeId::pointer)
@ -3218,7 +3268,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus
}
auto pointer_element_type = array_like_type->pointer.element_type;
analyze_type(module, value->array_expression.index, pointer_element_type->id == TypeId::enum_array ? pointer_element_type->enum_array.enum_type : uint64(module), must_be_constant);
analyze_type(module, value->array_expression.index, 0, { .must_be_constant = analysis.must_be_constant, .is_index = true });
Type* element_type = 0;
switch (pointer_element_type->id)
@ -3281,7 +3331,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus
{
auto aggregate = value->field_access.aggregate;
auto field_name = value->field_access.field_name;
analyze_type(module, aggregate, 0, must_be_constant);
analyze_type(module, aggregate, 0, { .must_be_constant = analysis.must_be_constant });
if (aggregate->kind == ValueKind::right)
{
@ -3373,6 +3423,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus
auto field = fields[i];
value_type = field.type;
} break;
case TypeId::enum_array:
case TypeId::array:
{
if (!field_name.equal(string_literal("length")))
@ -3391,7 +3442,16 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus
}
else
{
trap();
if (resolved_aggregate_type->id == TypeId::enum_array)
{
auto enum_type = resolved_aggregate_type->enum_array.enum_type;
auto backing_type = enum_type->enumerator.backing_type;
value_type = backing_type;
}
else
{
report_error();
}
}
} break;
case TypeId::pointer: report_error(); // Double indirection is not allowed
@ -3413,7 +3473,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus
report_error();
}
analyze_type(module, array_like, 0, must_be_constant);
analyze_type(module, array_like, 0, { .must_be_constant = analysis.must_be_constant });
auto pointer_type = array_like->type;
if (pointer_type->id != TypeId::pointer)
@ -3462,7 +3522,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus
{
if (index)
{
analyze_type(module, index, index_type, must_be_constant);
analyze_type(module, index, index_type, { .must_be_constant = analysis.must_be_constant });
if (index->type->id != TypeId::integer)
{
@ -3487,7 +3547,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus
} break;
case ValueId::va_arg:
{
analyze_type(module, value->va_arg.va_list, get_pointer_type(module, get_va_list_type(module)), must_be_constant);
analyze_type(module, value->va_arg.va_list, get_pointer_type(module, get_va_list_type(module)), { .must_be_constant = analysis.must_be_constant });
value_type = value->va_arg.type;
typecheck(module, expected_type, value_type);
} break;
@ -3569,7 +3629,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus
auto field = fields[declaration_index];
auto declaration_type = field.type;
analyze_type(module, value, declaration_type, must_be_constant);
analyze_type(module, value, declaration_type, { .must_be_constant = analysis.must_be_constant });
is_constant = is_constant && value->is_constant();
}
@ -3627,7 +3687,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus
auto field = fields[declaration_index];
auto declaration_type = field.type;
analyze_type(module, value, declaration_type, must_be_constant);
analyze_type(module, value, declaration_type, { .must_be_constant = analysis.must_be_constant });
is_constant = is_constant && value->is_constant();
}
@ -3660,7 +3720,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus
}
auto field = &fields[i];
analyze_type(module, initialization_value, field->type, must_be_constant);
analyze_type(module, initialization_value, field->type, { .must_be_constant = analysis.must_be_constant });
} break;
case TypeId::enum_array:
{
@ -3719,7 +3779,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus
is_ordered = is_ordered && declaration_index == initialization_index;
analyze_type(module, value, element_type, must_be_constant);
analyze_type(module, value, element_type, { .must_be_constant = analysis.must_be_constant });
is_constant = is_constant && value->is_constant();
}
@ -3747,9 +3807,9 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus
auto condition = value->select.condition;
auto true_value = value->select.true_value;
auto false_value = value->select.false_value;
analyze_type(module, condition, 0, must_be_constant);
analyze_type(module, condition, 0, { .must_be_constant = analysis.must_be_constant });
auto is_boolean = false;
analyze_binary_type(module, true_value, false_value, is_boolean, expected_type, must_be_constant);
analyze_binary_type(module, true_value, false_value, is_boolean, expected_type, analysis.must_be_constant);
auto left_type = true_value->type;
auto right_type = false_value->type;
@ -4081,7 +4141,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus
auto string_type = get_slice_type(module, uint8(module));
analyze_type(module, enum_string_value, string_type, must_be_constant);
analyze_type(module, enum_string_value, string_type, { .must_be_constant = analysis.must_be_constant });
value_type = struct_type;
} break;
case ValueId::undefined:
@ -4219,7 +4279,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus
auto argument_type = declaration_argument.variable.type;
assert(argument_type);
analyze_type(module, instantiation_argument, argument_type, must_be_constant);
analyze_type(module, instantiation_argument, argument_type, { .must_be_constant = analysis.must_be_constant });
}
LLVMMetadataRef type_buffer[64];
@ -4263,7 +4323,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, bool mus
auto argument_type = declaration_argument.variable.type;
assert(argument_type);
analyze_type(module, instantiation_argument, argument_type, must_be_constant);
analyze_type(module, instantiation_argument, argument_type, { .must_be_constant = analysis.must_be_constant });
}
}
@ -4918,7 +4978,7 @@ fn LLVMValueRef emit_call(Module* module, Value* value, LLVMValueRef left_llvm,
{
src->type = 0;
src->kind = ValueKind::left;
analyze_type(module, src, 0, false);
analyze_type(module, src, 0, {});
}
}
@ -5066,7 +5126,7 @@ fn LLVMValueRef emit_call(Module* module, Value* value, LLVMValueRef left_llvm,
assert(src->kind == ValueKind::right);
src->type = 0;
src->kind = ValueKind::left;
analyze_type(module, src, pointer_type, false);
analyze_type(module, src, pointer_type, {});
}
}
else
@ -5771,11 +5831,31 @@ fn LLVMValueRef emit_field_access(Module* module, Value* value, LLVMValueRef lef
return trunc;
} break;
case TypeId::enum_array:
case TypeId::array:
{
assert(value->field_access.field_name.equal(string_literal("length")));
auto array_length_type = get_llvm_type(value->type, type_kind);
auto result = LLVMConstInt(array_length_type, resolved_aggregate_type->array.element_count, false);
u64 array_element_count = 0;
switch (resolved_aggregate_type->id)
{
case TypeId::enum_array:
{
auto enum_type = resolved_aggregate_type->enum_array.enum_type;
assert(enum_type->id == TypeId::enumerator);
array_element_count = enum_type->enumerator.fields.length;
} break;
case TypeId::array:
{
array_element_count = resolved_aggregate_type->array.element_count;
} break;
default: unreachable();
}
assert(array_element_count);
auto result = LLVMConstInt(array_length_type, array_element_count, false);
return result;
} break;
default: unreachable();
@ -6619,6 +6699,10 @@ fn void emit_value(Module* module, Value* value, TypeKind type_kind, bool expect
{
llvm_value = LLVMBuildIntToPtr(module->llvm.builder, llvm_unary_value, resolved_value_type->llvm.abi, "");
} break;
case UnaryId::enum_from_int:
{
llvm_value = llvm_unary_value;
} break;
}
} break;
case ValueId::unary_type:
@ -7375,7 +7459,7 @@ fn void emit_value(Module* module, Value* value, TypeKind type_kind, bool expect
fn void analyze_value(Module* module, Value* value, Type* expected_type, TypeKind type_kind, bool must_be_constant)
{
analyze_type(module, value, expected_type, must_be_constant);
analyze_type(module, value, expected_type, { .must_be_constant = must_be_constant });
emit_value(module, value, type_kind, must_be_constant);
}
@ -7453,7 +7537,7 @@ fn void analyze_statement(Module* module, Scope* scope, Statement* statement, u3
report_error();
}
analyze_type(module, return_value, return_abi.semantic_type, false);
analyze_type(module, return_value, return_abi.semantic_type, {});
auto pointer_type = get_pointer_type(module, return_abi.semantic_type);
emit_assignment(module, return_alloca, pointer_type, return_value);
} break;
@ -7468,7 +7552,7 @@ fn void analyze_statement(Module* module, Scope* scope, Statement* statement, u3
auto macro_instantiation = module->current_macro_instantiation;
auto return_type = macro_instantiation->return_type;
assert(return_type);
analyze_type(module, return_value, return_type, false);
analyze_type(module, return_value, return_type, {});
emit_assignment(module, macro_instantiation->return_alloca, get_pointer_type(module, return_type), return_value);
LLVMBuildBr(module->llvm.builder, macro_instantiation->return_block);
LLVMClearInsertionPosition(module->llvm.builder);
@ -7483,7 +7567,7 @@ fn void analyze_statement(Module* module, Scope* scope, Statement* statement, u3
auto local = statement->local;
auto expected_type = local->variable.type;
assert(!local->variable.storage);
analyze_type(module, local->variable.initial_value, expected_type, false);
analyze_type(module, local->variable.initial_value, expected_type, {});
local->variable.type = expected_type ? expected_type : local->variable.initial_value->type;
assert(local->variable.type);
if (expected_type)
@ -7624,7 +7708,7 @@ fn void analyze_statement(Module* module, Scope* scope, Statement* statement, u3
{
case StatementAssignmentId::assign:
{
analyze_type(module, right, element_type, false);
analyze_type(module, right, element_type, {});
emit_assignment(module, left_llvm, left_type, right);
} break;
case StatementAssignmentId::assign_add:
@ -7875,7 +7959,7 @@ fn void analyze_statement(Module* module, Scope* scope, Statement* statement, u3
auto kind = left_values[i];
auto right = right_values[i];
analyze_type(module, right, 0, false);
analyze_type(module, right, 0, {});
Type* aggregate_type = 0;
@ -8178,7 +8262,7 @@ fn void analyze_statement(Module* module, Scope* scope, Statement* statement, u3
} break;
default:
{
analyze_type(module, end, 0, false);
analyze_type(module, end, 0, {});
auto end_type = end->type;
assert(end_type);
start->type = end_type;
@ -8195,7 +8279,7 @@ fn void analyze_statement(Module* module, Scope* scope, Statement* statement, u3
{
if (!right->type)
{
analyze_type(module, right, local_type, false);
analyze_type(module, right, local_type, {});
}
}

View File

@ -4,6 +4,7 @@ enum class ValueIntrinsic
{
align_of,
byte_size,
enum_from_int,
enum_name,
extend,
integer_max,
@ -855,6 +856,7 @@ fn Token tokenize(Module* module)
String value_intrinsics[] = {
string_literal("align_of"),
string_literal("byte_size"),
string_literal("enum_from_int"),
string_literal("enum_name"),
string_literal("extend"),
string_literal("integer_max"),
@ -1363,6 +1365,7 @@ fn Value* parse_left(Module* module, Scope* scope, ValueBuilder builder)
switch (intrinsic)
{
case ValueIntrinsic::enum_from_int:
case ValueIntrinsic::enum_name:
case ValueIntrinsic::extend:
case ValueIntrinsic::int_from_enum:
@ -1375,6 +1378,7 @@ fn Value* parse_left(Module* module, Scope* scope, ValueBuilder builder)
UnaryId id;
switch (intrinsic)
{
case ValueIntrinsic::enum_from_int: id = UnaryId::enum_from_int; break;
case ValueIntrinsic::enum_name: id = UnaryId::enum_name; break;
case ValueIntrinsic::extend: id = UnaryId::extend; break;
case ValueIntrinsic::int_from_enum: id = UnaryId::int_from_enum; break;