This commit is contained in:
David Gonzalez Martin 2025-06-08 09:07:52 -06:00
parent 04ca049e6c
commit 30574735d4
9 changed files with 3538 additions and 878 deletions

View File

@ -48,6 +48,6 @@ target_link_libraries(llvm_bindings PUBLIC
target_link_libraries(bb PUBLIC llvm_bindings) target_link_libraries(bb PUBLIC llvm_bindings)
add_compile_options(-Wall -Wextra -pedantic -Wpedantic -Werror -Wno-c99-extensions -Wno-unused-function -Wno-missing-designated-field-initializers -funsigned-char -fwrapv -fno-strict-aliasing) add_compile_options(-Wall -Wextra -pedantic -Wpedantic -Werror -Wno-c99-extensions -Wno-unused-function -Wno-missing-designated-field-initializers -fno-signed-char -fwrapv -fno-strict-aliasing)
add_compile_definitions(CMAKE_PREFIX_PATH="${CMAKE_PREFIX_PATH}") add_compile_definitions(CMAKE_PREFIX_PATH="${CMAKE_PREFIX_PATH}")
add_compile_definitions(BB_CI=${BB_CI}) add_compile_definitions(BB_CI=${BB_CI})

File diff suppressed because it is too large Load Diff

View File

@ -440,6 +440,7 @@ global_variable String names[] =
string_literal("bool_pair"), string_literal("bool_pair"),
string_literal("min_max"), string_literal("min_max"),
string_literal("field_parent_pointer"), string_literal("field_parent_pointer"),
string_literal("leading_trailing_zeroes"),
}; };
void entry_point(Slice<char* const> arguments, Slice<char* const> envp) void entry_point(Slice<char* const> arguments, Slice<char* const> envp)

View File

@ -884,6 +884,8 @@ enum class UnaryId
dereference, dereference,
pointer_from_int, pointer_from_int,
enum_from_int, enum_from_int,
leading_zeroes,
trailing_zeroes,
}; };
struct ValueUnary struct ValueUnary
@ -1197,6 +1199,8 @@ struct LLVMIntrinsicId
enum class IntrinsicIndex enum class IntrinsicIndex
{ {
clz,
ctz,
smax, smax,
smin, smin,
trap, trap,
@ -1209,6 +1213,8 @@ enum class IntrinsicIndex
}; };
global_variable String intrinsic_names[] = { global_variable String intrinsic_names[] = {
string_literal("llvm.ctlz"),
string_literal("llvm.cttz"),
string_literal("llvm.smax"), string_literal("llvm.smax"),
string_literal("llvm.smin"), string_literal("llvm.smin"),
string_literal("llvm.trap"), string_literal("llvm.trap"),

View File

@ -1,6 +1,36 @@
#include <compiler.hpp> #include <compiler.hpp>
#include <llvm.hpp> #include <llvm.hpp>
fn LLVMValueRef llvm_module_create_function(Arena* arena, LLVMModuleRef module, LLVMTypeRef function_type, LLVMLinkage linkage_type, String name)
{
assert(name.pointer[name.length] == 0);
auto function = LLVMAddFunction(module, (char*)name.pointer, function_type);
LLVMSetLinkage(function, linkage_type);
return function;
}
fn LLVMValueRef llvm_module_create_global_variable(LLVMModuleRef module, LLVMTypeRef type, bool is_constant, LLVMLinkage linkage_type, LLVMValueRef initial_value, String name, LLVMThreadLocalMode thread_local_mode, bool externally_initialized, u32 alignment, LLVMUnnamedAddr unnamed_address)
{
assert(name.pointer[name.length] == 0);
auto global = LLVMAddGlobal(module, type, (char*)name.pointer);
LLVMSetGlobalConstant(global, is_constant);
LLVMSetLinkage(global, linkage_type);
LLVMSetInitializer(global, initial_value);
LLVMSetThreadLocalMode(global, thread_local_mode);
LLVMSetExternallyInitialized(global, externally_initialized);
LLVMSetAlignment(global, alignment);
LLVMSetUnnamedAddress(global, unnamed_address);
return global;
}
fn LLVMValueRef llvm_builder_create_alloca(LLVMBuilderRef b, LLVMTypeRef type, u32 alignment, String name)
{
assert(name.pointer[name.length] == 0);
auto alloca = LLVMBuildAlloca(b, type, (char*)name.pointer);
LLVMSetAlignment(alloca, alignment);
return alloca;
}
enum class EvaluationKind enum class EvaluationKind
{ {
scalar, scalar,
@ -106,9 +136,9 @@ fn u64 get_byte_allocation_size(Type* type)
struct LLVMGlobal struct LLVMGlobal
{ {
String host_triple; char* host_triple;
String host_cpu_model; char* host_cpu_model;
String host_cpu_features; char* host_cpu_features;
}; };
global_variable LLVMGlobal llvm_global; global_variable LLVMGlobal llvm_global;
@ -186,9 +216,9 @@ fn void llvm_initialize_all_raw()
LLVMInitializeX86Disassembler(); LLVMInitializeX86Disassembler();
llvm_global = { llvm_global = {
.host_triple = llvm_default_target_triple(), .host_triple = LLVMGetDefaultTargetTriple(),
.host_cpu_model = llvm_host_cpu_name(), .host_cpu_model = LLVMGetHostCPUName(),
.host_cpu_features = llvm_host_cpu_features(), .host_cpu_features = LLVMGetHostCPUFeatures(),
}; };
} }
@ -230,7 +260,8 @@ fn u64 integer_max_value(u32 bit_count, bool is_signed)
fn void dump_module(Module* module) fn void dump_module(Module* module)
{ {
print(llvm_module_to_string(module->llvm.module)); auto module_str = LLVMPrintModuleToString(module->llvm.module);
print(c_string_to_slice(module_str));
} }
fn LLVMCallConv llvm_calling_convention(CallingConvention calling_convention) fn LLVMCallConv llvm_calling_convention(CallingConvention calling_convention)
@ -250,7 +281,7 @@ fn void llvm_initialize(Module* module)
llvm_initialize_all(); llvm_initialize_all();
auto context = LLVMContextCreate(); auto context = LLVMContextCreate();
auto m = llvm_context_create_module(context, module->name); auto m = LLVMModuleCreateWithNameInContext((char*)module->name.pointer, context);
auto builder = LLVMCreateBuilderInContext(context); auto builder = LLVMCreateBuilderInContext(context);
LLVMDIBuilderRef di_builder = 0; LLVMDIBuilderRef di_builder = 0;
@ -279,9 +310,9 @@ fn void llvm_initialize(Module* module)
module->scope.llvm = di_compile_unit; module->scope.llvm = di_compile_unit;
} }
String target_triple = {}; char* target_triple = {};
String cpu_model = {}; char* cpu_model = {};
String cpu_features = {}; char* cpu_features = {};
if (target_compare(module->target, target_get_native())) if (target_compare(module->target, target_get_native()))
{ {
@ -296,8 +327,8 @@ fn void llvm_initialize(Module* module)
} }
auto target_machine_options = LLVMCreateTargetMachineOptions(); auto target_machine_options = LLVMCreateTargetMachineOptions();
LLVMTargetMachineOptionsSetCPU(target_machine_options, (char*)cpu_model.pointer); LLVMTargetMachineOptionsSetCPU(target_machine_options, cpu_model);
LLVMTargetMachineOptionsSetFeatures(target_machine_options, (char*)cpu_features.pointer); LLVMTargetMachineOptionsSetFeatures(target_machine_options, cpu_features);
LLVMCodeGenOptLevel code_generation_optimization_level; LLVMCodeGenOptLevel code_generation_optimization_level;
switch (module->build_mode) switch (module->build_mode)
@ -324,18 +355,18 @@ fn void llvm_initialize(Module* module)
LLVMTargetRef target = 0; LLVMTargetRef target = 0;
char* error_message = 0; char* error_message = 0;
auto result = LLVMGetTargetFromTriple((char*)target_triple.pointer, &target, &error_message); auto result = LLVMGetTargetFromTriple(target_triple, &target, &error_message);
if (result != 0) if (result != 0)
{ {
report_error(); report_error();
} }
assert(!error_message); assert(!error_message);
auto target_machine = LLVMCreateTargetMachineWithOptions(target, (char*)target_triple.pointer, target_machine_options); auto target_machine = LLVMCreateTargetMachineWithOptions(target, target_triple, target_machine_options);
auto target_data = LLVMCreateTargetDataLayout(target_machine); auto target_data = LLVMCreateTargetDataLayout(target_machine);
LLVMSetModuleDataLayout(m, target_data); LLVMSetModuleDataLayout(m, target_data);
LLVMSetTarget(m, (char*)target_triple.pointer); LLVMSetTarget(m, target_triple);
module->llvm = { module->llvm = {
.context = context, .context = context,
@ -353,7 +384,9 @@ fn void llvm_initialize(Module* module)
for (u64 i = 0; i < (u64)IntrinsicIndex::count; i += 1) for (u64 i = 0; i < (u64)IntrinsicIndex::count; i += 1)
{ {
String name = intrinsic_names[i]; String name = intrinsic_names[i];
module->llvm.intrinsic_table[i].n = LLVMLookupIntrinsicID((char*)name.pointer, name.length); auto intrinsic_id = LLVMLookupIntrinsicID((char*)name.pointer, name.length);
assert(intrinsic_id != 0);
module->llvm.intrinsic_table[i].n = intrinsic_id;
} }
for (u64 i = 0; i < (u64)AttributeIndex::count; i += 1) for (u64 i = 0; i < (u64)AttributeIndex::count; i += 1)
@ -754,7 +787,7 @@ fn AbiSystemVClassifyResult abi_system_v_classify_type(Type* type, AbiSystemVCla
case TypeId::structure: case TypeId::structure:
case TypeId::union_type: case TypeId::union_type:
{ {
auto byte_size = type->structure.byte_size; auto byte_size = get_byte_size(type);
if (byte_size <= 64) if (byte_size <= 64)
{ {
@ -1005,7 +1038,8 @@ fn void resolve_type_in_place_debug(Module* module, Type* type)
result = type->llvm.debug; result = type->llvm.debug;
if (!result) if (!result)
{ {
result = LLVMDIBuilderCreatePointerType(module->llvm.di_builder, type->pointer.element_type->llvm.debug, 64, 64, 0, (char*)type->name.pointer, type->name.length); u32 address_space = 0;
result = LLVMDIBuilderCreatePointerType(module->llvm.di_builder, type->pointer.element_type->llvm.debug, get_bit_size(type), get_byte_alignment(type) * 8, address_space, (char*)type->name.pointer, type->name.length);
} }
} break; } break;
case TypeId::array: case TypeId::array:
@ -1027,7 +1061,7 @@ fn void resolve_type_in_place_debug(Module* module, Type* type)
for (u64 i = 0; i < type->enumerator.fields.length; i += 1) for (u64 i = 0; i < type->enumerator.fields.length; i += 1)
{ {
auto& field = type->enumerator.fields[i]; auto& field = type->enumerator.fields[i];
auto enum_field = LLVMDIBuilderCreateEnumerator(module->llvm.di_builder, (char*)field.name.pointer, field.name.length, field.value, type_is_signed(backing_type)); auto enum_field = LLVMDIBuilderCreateEnumerator(module->llvm.di_builder, (char*)field.name.pointer, field.name.length, field.value, !type_is_signed(backing_type));
field_buffer[i] = enum_field; field_buffer[i] = enum_field;
} }
@ -1416,7 +1450,6 @@ fn Type* get_by_value_argument_pair(Module* module, Type* low, Type* high)
return result; return result;
} }
struct IndirectOptions struct IndirectOptions
{ {
Type* semantic_type; Type* semantic_type;
@ -1503,7 +1536,10 @@ fn AbiInformation abi_system_v_get_indirect_result(Module* module, Type* type, u
if (free_gpr == 0 && alignment == 8 && size <= 8) if (free_gpr == 0 && alignment == 8 && size <= 8)
{ {
trap(); return abi_system_v_get_direct(module, {
.semantic_type = type,
.type = integer_type(module, { .bit_count = size * 8, .is_signed = false }),
});
} }
else else
{ {
@ -1823,7 +1859,7 @@ fn LLVMValueRef create_alloca(Module* module, AllocaOptions options)
alignment = get_byte_alignment(abi_type); alignment = get_byte_alignment(abi_type);
} }
auto alloca = llvm_builder_create_alloca(module->llvm.builder, abi_type->llvm.memory, 0, alignment, options.name); auto alloca = llvm_builder_create_alloca(module->llvm.builder, abi_type->llvm.memory, alignment, options.name);
return alloca; return alloca;
} }
@ -2193,6 +2229,8 @@ fn bool unary_is_boolean(UnaryId id)
case UnaryId::dereference: case UnaryId::dereference:
case UnaryId::pointer_from_int: case UnaryId::pointer_from_int:
case UnaryId::enum_from_int: case UnaryId::enum_from_int:
case UnaryId::leading_zeroes:
case UnaryId::trailing_zeroes:
return false; return false;
} }
} }
@ -2364,7 +2402,9 @@ fn Global* get_enum_name_array_global(Module* module, Type* enum_type)
field.name, field.name,
}; };
unsigned address_space = 0; unsigned address_space = 0;
auto name_global = llvm_module_create_global_variable(module->llvm.module, LLVMArrayType2(u8_type->llvm.abi, field.name.length + null_terminate), is_constant, LLVMInternalLinkage, LLVMConstStringInContext2(module->llvm.context, (char*)field.name.pointer, field.name.length, false), arena_join_string(module->arena, array_to_slice(name_parts)), name_before, LLVMNotThreadLocal, address_space, false); auto initial_value = LLVMConstStringInContext2(module->llvm.context, (char*)field.name.pointer, field.name.length, false);
u32 alignment = 1;
auto name_global = llvm_module_create_global_variable(module->llvm.module, LLVMArrayType2(u8_type->llvm.abi, field.name.length + null_terminate), is_constant, LLVMInternalLinkage, initial_value, arena_join_string(module->arena, array_to_slice(name_parts)), LLVMNotThreadLocal, false, alignment, LLVMGlobalUnnamedAddr);
name_before = name_global; name_before = name_global;
LLVMValueRef constants[] = { LLVMValueRef constants[] = {
name_global, name_global,
@ -2380,9 +2420,7 @@ fn Global* get_enum_name_array_global(Module* module, Type* enum_type)
auto name_array_type = LLVMArrayType2(slice_type->llvm.abi, array_element_count); auto name_array_type = LLVMArrayType2(slice_type->llvm.abi, array_element_count);
auto is_constant = true; auto is_constant = true;
unsigned address_space = 0; unsigned address_space = 0;
auto name_array_variable = llvm_module_create_global_variable(module->llvm.module, name_array_type, is_constant, LLVMInternalLinkage, name_array, string_literal("name.array.enum"), name_before, LLVMNotThreadLocal, address_space, false); auto name_array_variable = llvm_module_create_global_variable(module->llvm.module, name_array_type, is_constant, LLVMInternalLinkage, name_array, string_literal("name.array.enum"), LLVMNotThreadLocal, false, get_byte_alignment(slice_type), LLVMGlobalUnnamedAddr);
LLVMSetAlignment(name_array_variable, get_byte_alignment(slice_type));
LLVMSetUnnamedAddress(name_array_variable, LLVMGlobalUnnamedAddr);
auto global_type = get_array_type(module, slice_type, array_element_count); auto global_type = get_array_type(module, slice_type, array_element_count);
resolve_type_in_place(module, global_type); resolve_type_in_place(module, global_type);
@ -2896,13 +2934,13 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, TypeAnal
enum_type->name, enum_type->name,
}; };
auto function_name = arena_join_string(module->arena, array_to_slice(name_parts)); auto function_name = arena_join_string(module->arena, array_to_slice(name_parts));
auto llvm_function = llvm_module_create_function(module->llvm.module, llvm_function_type, LLVMInternalLinkage, 0, function_name); auto llvm_function = llvm_module_create_function(module->arena, module->llvm.module, llvm_function_type, LLVMInternalLinkage, function_name);
LLVMSetFunctionCallConv(llvm_function, LLVMFastCallConv); LLVMSetFunctionCallConv(llvm_function, LLVMFastCallConv);
LLVMValueRef llvm_argument; LLVMValueRef llvm_argument;
LLVMGetParams(llvm_function, &llvm_argument); LLVMGetParams(llvm_function, &llvm_argument);
auto* entry_block = llvm_context_create_basic_block(module->llvm.context, string_literal("entry"), llvm_function); auto* entry_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "entry");
LLVMPositionBuilderAtEnd(module->llvm.builder, entry_block); LLVMPositionBuilderAtEnd(module->llvm.builder, entry_block);
auto alloca = create_alloca(module, { auto alloca = create_alloca(module, {
@ -2910,8 +2948,8 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, TypeAnal
.name = string_literal("retval"), .name = string_literal("retval"),
}); });
auto* return_block = llvm_context_create_basic_block(module->llvm.context, string_literal("return_block"), llvm_function); auto* return_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "return_block");
auto* else_block = llvm_context_create_basic_block(module->llvm.context, string_literal("else_block"), llvm_function); auto* else_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "else_block");
auto enum_fields = enum_type->enumerator.fields; auto enum_fields = enum_type->enumerator.fields;
@ -2923,7 +2961,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, TypeAnal
for (u64 i = 0; i < enum_fields.length; i += 1) for (u64 i = 0; i < enum_fields.length; i += 1)
{ {
auto& field = enum_fields[i]; auto& field = enum_fields[i];
auto* case_block = llvm_context_create_basic_block(module->llvm.context, string_literal("case_block"), llvm_function); auto* case_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "case_block");
auto case_value = LLVMConstInt(backing_type, field.value, false); auto case_value = LLVMConstInt(backing_type, field.value, false);
LLVMAddCase(switch_instruction, case_value, case_block); LLVMAddCase(switch_instruction, case_value, case_block);
@ -3231,6 +3269,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, TypeAnal
if (expected_type->array.element_count == 0) if (expected_type->array.element_count == 0)
{ {
// TODO: use existing types?
expected_type->array.element_count = values.length; expected_type->array.element_count = values.length;
assert(expected_type->name.equal(string_literal(""))); assert(expected_type->name.equal(string_literal("")));
expected_type->name = array_name(module, expected_type->array.element_type, expected_type->array.element_count); expected_type->name = array_name(module, expected_type->array.element_type, expected_type->array.element_count);
@ -3988,7 +4027,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, TypeAnal
enum_type->name, enum_type->name,
}; };
auto function_name = arena_join_string(module->arena, array_to_slice(name_parts)); auto function_name = arena_join_string(module->arena, array_to_slice(name_parts));
auto llvm_function = llvm_module_create_function(module->llvm.module, llvm_function_type, LLVMInternalLinkage, 0, function_name); auto llvm_function = llvm_module_create_function(module->arena, module->llvm.module, llvm_function_type, LLVMInternalLinkage, function_name);
LLVMSetFunctionCallConv(llvm_function, LLVMFastCallConv); LLVMSetFunctionCallConv(llvm_function, LLVMFastCallConv);
auto name_array_global = get_enum_name_array_global(module, enum_type); auto name_array_global = get_enum_name_array_global(module, enum_type);
@ -4006,19 +4045,16 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, TypeAnal
auto value_array = LLVMConstArray2(enum_value_type, value_constant_buffer, array_element_count); auto value_array = LLVMConstArray2(enum_value_type, value_constant_buffer, array_element_count);
auto value_array_variable_type = LLVMArrayType2(enum_value_type, array_element_count); auto value_array_variable_type = LLVMArrayType2(enum_value_type, array_element_count);
auto is_constant = true; auto is_constant = true;
LLVMValueRef before = 0;
LLVMThreadLocalMode thread_local_mode = LLVMNotThreadLocal; LLVMThreadLocalMode thread_local_mode = LLVMNotThreadLocal;
unsigned address_space = 0; unsigned address_space = 0;
auto externally_initialized = false; auto externally_initialized = false;
auto value_array_variable = llvm_module_create_global_variable(module->llvm.module, value_array_variable_type, is_constant, LLVMInternalLinkage, value_array, string_literal("value.array.enum"), before, thread_local_mode, address_space, externally_initialized); auto value_array_variable = llvm_module_create_global_variable(module->llvm.module, value_array_variable_type, is_constant, LLVMInternalLinkage, value_array, string_literal("value.array.enum"), thread_local_mode, externally_initialized, enum_alignment, LLVMGlobalUnnamedAddr);
LLVMSetAlignment(value_array_variable, enum_alignment);
LLVMSetUnnamedAddress(value_array_variable, LLVMGlobalUnnamedAddr);
auto* entry_block = llvm_context_create_basic_block(module->llvm.context, string_literal("entry"), llvm_function); auto* entry_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "entry");
auto* return_block = llvm_context_create_basic_block(module->llvm.context, string_literal("return_block"), llvm_function); auto* return_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "return_block");
auto* loop_entry_block = llvm_context_create_basic_block(module->llvm.context, string_literal("loop.entry"), llvm_function); auto* loop_entry_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "loop.entry");
auto* loop_body_block = llvm_context_create_basic_block(module->llvm.context, string_literal("loop.body"), llvm_function); auto* loop_body_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "loop.body");
auto* loop_exit_block = llvm_context_create_basic_block(module->llvm.context, string_literal("loop.exit"), llvm_function); auto* loop_exit_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "loop.exit");
LLVMPositionBuilderAtEnd(module->llvm.builder, entry_block); LLVMPositionBuilderAtEnd(module->llvm.builder, entry_block);
@ -4082,8 +4118,8 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, TypeAnal
auto length_comparison = LLVMBuildICmp(module->llvm.builder, LLVMIntEQ, slice_length, element_length, ""); auto length_comparison = LLVMBuildICmp(module->llvm.builder, LLVMIntEQ, slice_length, element_length, "");
auto* length_match_block = llvm_context_create_basic_block(module->llvm.context, string_literal("length.match"), llvm_function); auto* length_match_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "length.match");
auto* length_mismatch_block = llvm_context_create_basic_block(module->llvm.context, string_literal("length.mismatch"), llvm_function); auto* length_mismatch_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "length.mismatch");
LLVMBuildCondBr(module->llvm.builder, length_comparison, length_match_block, length_mismatch_block); LLVMBuildCondBr(module->llvm.builder, length_comparison, length_match_block, length_mismatch_block);
LLVMPositionBuilderAtEnd(module->llvm.builder, length_match_block); LLVMPositionBuilderAtEnd(module->llvm.builder, length_match_block);
@ -4103,7 +4139,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, TypeAnal
u64_type->llvm.abi, u64_type->llvm.abi,
}; };
auto llvm_function_type = LLVMFunctionType(s32_type->llvm.abi, arguments, array_length(arguments), false); auto llvm_function_type = LLVMFunctionType(s32_type->llvm.abi, arguments, array_length(arguments), false);
auto llvm_function = llvm_module_create_function(module->llvm.module, llvm_function_type, LLVMExternalLinkage, address_space, string_literal("memcmp")); auto llvm_function = llvm_module_create_function(module->arena, module->llvm.module, llvm_function_type, LLVMExternalLinkage, string_literal("memcmp"));
memcmp = llvm_function; memcmp = llvm_function;
} }
@ -4138,7 +4174,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, TypeAnal
}; };
auto memcmp_return_result = LLVMBuildCall2(module->llvm.builder, LLVMGlobalGetValueType(memcmp), memcmp, memcmp_arguments, array_length(memcmp_arguments), ""); auto memcmp_return_result = LLVMBuildCall2(module->llvm.builder, LLVMGlobalGetValueType(memcmp), memcmp, memcmp_arguments, array_length(memcmp_arguments), "");
auto content_comparison = LLVMBuildICmp(module->llvm.builder, LLVMIntEQ, memcmp_return_result, LLVMConstNull(s32_type->llvm.abi), ""); auto content_comparison = LLVMBuildICmp(module->llvm.builder, LLVMIntEQ, memcmp_return_result, LLVMConstNull(s32_type->llvm.abi), "");
auto* content_match_block = llvm_context_create_basic_block(module->llvm.context, string_literal("content.match"), llvm_function); auto* content_match_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "content.match");
LLVMBuildCondBr(module->llvm.builder, content_comparison, content_match_block, length_mismatch_block); LLVMBuildCondBr(module->llvm.builder, content_comparison, content_match_block, length_mismatch_block);
LLVMPositionBuilderAtEnd(module->llvm.builder, content_match_block); LLVMPositionBuilderAtEnd(module->llvm.builder, content_match_block);
@ -4648,7 +4684,9 @@ fn void create_coerced_store(Module* module, LLVMValueRef source_value, Type* so
auto source_size = get_byte_size(source_type); auto source_size = get_byte_size(source_type);
if (!type_is_abi_equal(module, source_type, destination_type)) // TODO: this smells badly
//destination_type != uint1(module)
if (!type_is_abi_equal(module, source_type, destination_type) && destination_type->id == TypeId::structure)
{ {
auto r = enter_struct_pointer_for_coerced_access(module, destination_value, destination_type, source_size); auto r = enter_struct_pointer_for_coerced_access(module, destination_value, destination_type, source_size);
destination_value = r.value; destination_value = r.value;
@ -4896,9 +4934,8 @@ fn SliceEmitResult emit_string_literal(Module* module, Value* value)
LLVMValueRef before = 0; LLVMValueRef before = 0;
LLVMThreadLocalMode tlm = LLVMNotThreadLocal; LLVMThreadLocalMode tlm = LLVMNotThreadLocal;
bool externally_initialized = false; bool externally_initialized = false;
unsigned address_space = 0; u32 alignment = 1;
auto global = llvm_module_create_global_variable(module->llvm.module, string_type, is_constant, LLVMInternalLinkage, constant_string, string_literal("conststring"), before, tlm, address_space, externally_initialized); auto global = llvm_module_create_global_variable(module->llvm.module, string_type, is_constant, LLVMInternalLinkage, constant_string, string_literal("conststring"), tlm, externally_initialized, alignment, LLVMGlobalUnnamedAddr);
LLVMSetUnnamedAddress(global, LLVMGlobalUnnamedAddr);
auto slice_type = get_slice_type(module, u8_type); auto slice_type = get_slice_type(module, u8_type);
return { global, LLVMConstInt(uint64(module)->llvm.abi, length, false) }; return { global, LLVMConstInt(uint64(module)->llvm.abi, length, false) };
@ -4927,6 +4964,15 @@ fn void invalidate_analysis(Module* module, Value* value)
{ {
invalidate_analysis(module, value->field_access.aggregate); invalidate_analysis(module, value->field_access.aggregate);
} break; } break;
case ValueId::binary:
{
invalidate_analysis(module, value->binary.left);
invalidate_analysis(module, value->binary.right);
} break;
case ValueId::unary:
{
invalidate_analysis(module, value->unary.value);
} break;
default: trap(); default: trap();
} }
@ -5081,11 +5127,6 @@ fn LLVMValueRef emit_call(Module* module, Value* value, LLVMValueRef left_llvm,
}); });
} }
if (get_byte_size(semantic_argument_type) > 60 && argument_abi.flags.kind != AbiKind::indirect)
{
trap();
}
resolve_type_in_place(module, semantic_argument_type); resolve_type_in_place(module, semantic_argument_type);
if (is_named_argument) if (is_named_argument)
@ -5145,6 +5186,15 @@ fn LLVMValueRef emit_call(Module* module, Value* value, LLVMValueRef left_llvm,
trap(); trap();
} }
// TODO: fix this hack and collapse it into the generic path
if (coerce_to_type == uint8(module) && semantic_argument_type == uint1(module))
{
emit_value(module, semantic_call_argument_value, TypeKind::memory, false);
llvm_abi_argument_value_buffer[abi_argument_count] = semantic_call_argument_value->llvm;
abi_argument_count += 1;
}
else
{
auto evaluation_kind = get_evaluation_kind(semantic_argument_type); auto evaluation_kind = get_evaluation_kind(semantic_argument_type);
Value* src = 0; Value* src = 0;
switch (evaluation_kind) switch (evaluation_kind)
@ -5262,12 +5312,9 @@ fn LLVMValueRef emit_call(Module* module, Value* value, LLVMValueRef left_llvm,
LLVMThreadLocalMode thread_local_mode = {}; LLVMThreadLocalMode thread_local_mode = {};
u32 address_space = 0; u32 address_space = 0;
bool externally_initialized = false; bool externally_initialized = false;
auto global = llvm_module_create_global_variable(module->llvm.module, semantic_argument_type->llvm.memory, is_constant, linkage_type, semantic_call_argument_value->llvm, string_literal("conststruct"), before, thread_local_mode, address_space, externally_initialized);
LLVMSetUnnamedAddress(global, LLVMGlobalUnnamedAddr);
auto alignment = get_byte_alignment(semantic_argument_type); auto alignment = get_byte_alignment(semantic_argument_type);
LLVMSetAlignment(global, alignment);
auto global = llvm_module_create_global_variable(module->llvm.module, semantic_argument_type->llvm.memory, is_constant, linkage_type, semantic_call_argument_value->llvm, string_literal("conststruct"), thread_local_mode, externally_initialized, alignment, LLVMGlobalUnnamedAddr);
for (u32 i = 0; i < coerce_fields.length; i += 1) for (u32 i = 0; i < coerce_fields.length; i += 1)
{ {
@ -5337,8 +5384,6 @@ fn LLVMValueRef emit_call(Module* module, Value* value, LLVMValueRef left_llvm,
} }
else else
{ {
assert(src->kind == ValueKind::right);
assert(src->type->id == TypeId::structure);
assert(src->id == ValueId::variable_reference); assert(src->id == ValueId::variable_reference);
assert(src->kind == ValueKind::right); assert(src->kind == ValueKind::right);
reanalyze_type_as_left_value(module, src); reanalyze_type_as_left_value(module, src);
@ -5386,6 +5431,7 @@ fn LLVMValueRef emit_call(Module* module, Value* value, LLVMValueRef left_llvm,
abi_argument_count += 1; abi_argument_count += 1;
} }
} }
}
} break; } break;
case AbiKind::indirect: case AbiKind::indirect:
case AbiKind::indirect_aliased: case AbiKind::indirect_aliased:
@ -5419,12 +5465,9 @@ fn LLVMValueRef emit_call(Module* module, Value* value, LLVMValueRef left_llvm,
LLVMThreadLocalMode thread_local_mode = {}; LLVMThreadLocalMode thread_local_mode = {};
u32 address_space = 0; u32 address_space = 0;
bool externally_initialized = false; bool externally_initialized = false;
auto global = llvm_module_create_global_variable(module->llvm.module, semantic_argument_type->llvm.memory, is_constant, linkage_type, semantic_call_argument_value->llvm, string_literal("conststruct"), before, thread_local_mode, address_space, externally_initialized);
LLVMSetUnnamedAddress(global, LLVMGlobalUnnamedAddr);
auto alignment = get_byte_alignment(semantic_argument_type); auto alignment = get_byte_alignment(semantic_argument_type);
LLVMSetAlignment(global, alignment);
auto global = llvm_module_create_global_variable(module->llvm.module, semantic_argument_type->llvm.memory, is_constant, linkage_type, semantic_call_argument_value->llvm, string_literal("conststruct"), thread_local_mode, externally_initialized, alignment, LLVMGlobalUnnamedAddr);
llvm_abi_argument_value_buffer[abi_argument_count] = global; llvm_abi_argument_value_buffer[abi_argument_count] = global;
abi_argument_count += 1; abi_argument_count += 1;
@ -5759,9 +5802,9 @@ fn LLVMValueRef emit_va_arg(Module* module, Value* value, LLVMValueRef left_llvm
trap(); trap();
} }
auto* in_reg_block = llvm_context_create_basic_block(module->llvm.context, string_literal("va_arg.in_reg"), llvm_function); auto* in_reg_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "va_arg.in_reg");
auto* in_mem_block = llvm_context_create_basic_block(module->llvm.context, string_literal("va_arg.in_mem"), llvm_function); auto* in_mem_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "va_arg.in_mem");
auto* end_block = llvm_context_create_basic_block(module->llvm.context, string_literal("va_arg.end"), llvm_function); auto* end_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "va_arg.end");
LLVMBuildCondBr(module->llvm.builder, in_regs, in_reg_block, in_mem_block); LLVMBuildCondBr(module->llvm.builder, in_regs, in_reg_block, in_mem_block);
emit_block(module, in_reg_block); emit_block(module, in_reg_block);
@ -6174,7 +6217,10 @@ fn void emit_assignment(Module* module, LLVMValueRef left_llvm, Type* left_type,
{ {
auto values = right->array_initialization.values; auto values = right->array_initialization.values;
assert(resolved_value_type->id == TypeId::array); assert(resolved_value_type->id == TypeId::array);
auto element_type = resolved_value_type->array.element_type;
auto element_count = resolved_value_type->array.element_count;
auto uint64_type = uint64(module); auto uint64_type = uint64(module);
assert(values.length == element_count);
resolve_type_in_place(module, uint64_type); resolve_type_in_place(module, uint64_type);
if (right->array_initialization.is_constant) if (right->array_initialization.is_constant)
@ -6187,25 +6233,17 @@ fn void emit_assignment(Module* module, LLVMValueRef left_llvm, Type* left_type,
LLVMThreadLocalMode thread_local_mode = {}; LLVMThreadLocalMode thread_local_mode = {};
u32 address_space = 0; u32 address_space = 0;
bool externally_initialized = false; bool externally_initialized = false;
auto global = llvm_module_create_global_variable(module->llvm.module, value_type->llvm.memory, is_constant, linkage_type, right->llvm, string_literal("constarray"), before, thread_local_mode, address_space, externally_initialized);
LLVMSetUnnamedAddress(global, LLVMGlobalUnnamedAddr);
auto alignment = get_byte_alignment(resolved_value_type); auto alignment = get_byte_alignment(resolved_value_type);
LLVMSetAlignment(global, alignment);
auto element_type = resolved_value_type->array.element_type; auto global = llvm_module_create_global_variable(module->llvm.module, value_type->llvm.memory, is_constant, linkage_type, right->llvm, string_literal("array.init"), thread_local_mode, externally_initialized, alignment, LLVMGlobalUnnamedAddr);
auto element_count = resolved_value_type->array.element_count;
assert(values.length == element_count);
u64 memcpy_size = get_byte_size(element_type) * element_count; u64 memcpy_size = get_byte_size(resolved_value_type);
LLVMBuildMemCpy(module->llvm.builder, left_llvm, alignment, global, alignment, LLVMConstInt(uint64_type->llvm.abi, memcpy_size, false)); LLVMBuildMemCpy(module->llvm.builder, left_llvm, alignment, global, alignment, LLVMConstInt(uint64_type->llvm.abi, memcpy_size, false));
} }
else else
{ {
auto u64_zero = LLVMConstNull(uint64_type->llvm.abi); auto u64_zero = LLVMConstNull(uint64_type->llvm.abi);
auto pointer_to_element_type = get_pointer_type(module, resolved_value_type->array.element_type); auto pointer_to_element_type = get_pointer_type(module, element_type);
for (u64 i = 0; i < values.length; i += 1) for (u64 i = 0; i < values.length; i += 1)
{ {
@ -6272,9 +6310,7 @@ fn void emit_assignment(Module* module, LLVMValueRef left_llvm, Type* left_type,
unsigned address_space = 0; unsigned address_space = 0;
LLVMThreadLocalMode thread_local_mode = LLVMNotThreadLocal; LLVMThreadLocalMode thread_local_mode = LLVMNotThreadLocal;
bool externally_initialized = false; bool externally_initialized = false;
auto global = llvm_module_create_global_variable(module->llvm.module, value_type->llvm.memory, is_constant, linkage_type, right->llvm, string_literal("constarray"), before, thread_local_mode, address_space, externally_initialized); auto global = llvm_module_create_global_variable(module->llvm.module, value_type->llvm.memory, is_constant, linkage_type, right->llvm, string_literal("constarray"), thread_local_mode, externally_initialized, alignment, LLVMGlobalUnnamedAddr);
LLVMSetUnnamedAddress(global, LLVMGlobalUnnamedAddr);
LLVMSetAlignment(global, alignment);
LLVMBuildMemCpy(module->llvm.builder, left_llvm, alignment, global, alignment, byte_size_value); LLVMBuildMemCpy(module->llvm.builder, left_llvm, alignment, global, alignment, byte_size_value);
} }
else else
@ -6720,7 +6756,7 @@ fn void emit_macro_instantiation(Module* module, Value* value)
module->llvm.inlined_at = caller_debug_location; module->llvm.inlined_at = caller_debug_location;
auto llvm_function = current_function->variable.storage->llvm; auto llvm_function = current_function->variable.storage->llvm;
auto* entry_block = llvm_context_create_basic_block(module->llvm.context, string_literal("macro.entry"), llvm_function); auto* entry_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "macro.entry");
LLVMBuildBr(module->llvm.builder, entry_block); LLVMBuildBr(module->llvm.builder, entry_block);
LLVMPositionBuilderAtEnd(module->llvm.builder, entry_block); LLVMPositionBuilderAtEnd(module->llvm.builder, entry_block);
@ -6737,7 +6773,7 @@ fn void emit_macro_instantiation(Module* module, Value* value)
assert(!macro_instantiation->return_alloca); assert(!macro_instantiation->return_alloca);
macro_instantiation->return_alloca = return_alloca; macro_instantiation->return_alloca = return_alloca;
auto* return_block = llvm_context_create_basic_block(module->llvm.context, string_literal("macro.return_block"), llvm_function); auto* return_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "macro.return_block");
assert(!macro_instantiation->return_block); assert(!macro_instantiation->return_block);
macro_instantiation->return_block = return_block; macro_instantiation->return_block = return_block;
@ -7010,6 +7046,17 @@ fn void emit_value(Module* module, Value* value, TypeKind type_kind, bool expect
{ {
llvm_value = llvm_unary_value; llvm_value = llvm_unary_value;
} break; } break;
case UnaryId::leading_zeroes:
case UnaryId::trailing_zeroes:
{
auto intrinsic = unary_id == UnaryId::leading_zeroes ? IntrinsicIndex::clz : IntrinsicIndex::ctz;
auto u1_type = uint1(module);
resolve_type_in_place(module, u1_type);
auto zero_is_poison = LLVMConstNull(u1_type->llvm.abi);
LLVMValueRef values[] = { llvm_unary_value, zero_is_poison };
LLVMTypeRef types[] = { destination_type };
llvm_value = emit_intrinsic_call(module, intrinsic, array_to_slice(types), array_to_slice(values));
} break;
} }
} break; } break;
case ValueId::unary_type: case ValueId::unary_type:
@ -7070,10 +7117,8 @@ fn void emit_value(Module* module, Value* value, TypeKind type_kind, bool expect
auto array_type = resolved_value_type->pointer.element_type; auto array_type = resolved_value_type->pointer.element_type;
assert(array_type->id == TypeId::array); assert(array_type->id == TypeId::array);
resolve_type_in_place(module, array_type); resolve_type_in_place(module, array_type);
auto value_array_variable = llvm_module_create_global_variable(module->llvm.module, array_type->llvm.memory, is_constant, LLVMInternalLinkage, array_value, string_literal("enum.values"), 0, LLVMNotThreadLocal, 0, 0);
auto alignment = get_byte_alignment(resolved_value_type); auto alignment = get_byte_alignment(resolved_value_type);
LLVMSetAlignment(value_array_variable, alignment); auto value_array_variable = llvm_module_create_global_variable(module->llvm.module, array_type->llvm.memory, is_constant, LLVMInternalLinkage, array_value, string_literal("enum.values"), LLVMNotThreadLocal, 0, alignment, LLVMGlobalUnnamedAddr);
LLVMSetUnnamedAddress(value_array_variable, LLVMGlobalUnnamedAddr);
llvm_value = value_array_variable; llvm_value = value_array_variable;
} break; } break;
} }
@ -7112,8 +7157,8 @@ fn void emit_value(Module* module, Value* value, TypeKind type_kind, bool expect
auto llvm_function = module->current_function->variable.storage->llvm; auto llvm_function = module->current_function->variable.storage->llvm;
assert(llvm_function); assert(llvm_function);
auto* right_block = llvm_context_create_basic_block(module->llvm.context, string_literal("shortcircuit.right"), llvm_function); auto* right_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "shortcircuit.right");
auto* end_block = llvm_context_create_basic_block(module->llvm.context, string_literal("shortcircuit.end"), llvm_function); auto* end_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "shortcircuit.end");
LLVMBasicBlockRef true_block; LLVMBasicBlockRef true_block;
LLVMBasicBlockRef false_block; LLVMBasicBlockRef false_block;
@ -7412,7 +7457,7 @@ fn void emit_value(Module* module, Value* value, TypeKind type_kind, bool expect
assert(element_type); assert(element_type);
assert(llvm_index); assert(llvm_index);
LLVMValueRef indices[] = { zero_index, index->llvm }; LLVMValueRef indices[] = { zero_index, llvm_index };
auto gep = create_gep(module, { auto gep = create_gep(module, {
.type = array_type->llvm.memory, .type = array_type->llvm.memory,
.pointer = array_like->llvm, .pointer = array_like->llvm,
@ -8030,13 +8075,13 @@ fn void analyze_statement(Module* module, Scope* scope, Statement* statement, u3
} break; } break;
case StatementId::if_st: case StatementId::if_st:
{ {
auto* taken_block = llvm_context_create_basic_block(module->llvm.context, string_literal("if.taken"), llvm_function); auto* taken_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "if.taken");
auto* not_taken_block = llvm_context_create_basic_block(module->llvm.context, string_literal("if.not_taken"), llvm_function); auto* not_taken_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "if.not_taken");
auto* exit_block = llvm_context_create_basic_block(module->llvm.context, string_literal("if.exit"), llvm_function); auto* exit_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "if.exit");
auto condition = statement->if_st.condition; auto condition = statement->if_st.condition;
analyze_value(module, condition, 0, TypeKind::abi, false); analyze_value(module, condition, 0, TypeKind::abi, false);
auto llvm_condition = emit_condition(module, statement->if_st.condition); auto llvm_condition = emit_condition(module, condition);
LLVMBuildCondBr(module->llvm.builder, llvm_condition, taken_block, not_taken_block); LLVMBuildCondBr(module->llvm.builder, llvm_condition, taken_block, not_taken_block);
LLVMPositionBuilderAtEnd(module->llvm.builder, taken_block); LLVMPositionBuilderAtEnd(module->llvm.builder, taken_block);
@ -8072,13 +8117,13 @@ fn void analyze_statement(Module* module, Scope* scope, Statement* statement, u3
} break; } break;
case StatementId::while_st: case StatementId::while_st:
{ {
auto* entry_block = llvm_context_create_basic_block(module->llvm.context, string_literal("while.entry"), llvm_function); auto* entry_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "while.entry");
LLVMBuildBr(module->llvm.builder, entry_block); LLVMBuildBr(module->llvm.builder, entry_block);
LLVMPositionBuilderAtEnd(module->llvm.builder, entry_block); LLVMPositionBuilderAtEnd(module->llvm.builder, entry_block);
auto body_block = llvm_context_create_basic_block(module->llvm.context, string_literal("while.body"), llvm_function); auto body_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "while.body");
auto continue_block = llvm_context_create_basic_block(module->llvm.context, string_literal("while.continue"), llvm_function); auto continue_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "while.continue");
auto exit_block = llvm_context_create_basic_block(module->llvm.context, string_literal("while.exit"), llvm_function); auto exit_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "while.exit");
auto previous_continue_block = module->llvm.continue_block; auto previous_continue_block = module->llvm.continue_block;
auto previous_exit_block = module->llvm.exit_block; auto previous_exit_block = module->llvm.exit_block;
@ -8125,12 +8170,12 @@ fn void analyze_statement(Module* module, Scope* scope, Statement* statement, u3
LLVMBuildBr(module->llvm.builder, entry_block); LLVMBuildBr(module->llvm.builder, entry_block);
if (llvm_value_use_empty((LLVMValueRef)body_block)) if (!LLVMGetFirstUse((LLVMValueRef)body_block))
{ {
trap(); trap();
} }
if (llvm_value_use_empty((LLVMValueRef)exit_block)) if (!LLVMGetFirstUse((LLVMValueRef)exit_block))
{ {
trap(); trap();
} }
@ -8212,7 +8257,7 @@ fn void analyze_statement(Module* module, Scope* scope, Statement* statement, u3
} break; } break;
case StatementId::switch_st: case StatementId::switch_st:
{ {
auto* exit_block = llvm_context_create_basic_block(module->llvm.context, string_literal("switch.exit"), llvm_function); auto* exit_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "switch.exit");
auto discriminant = statement->switch_st.discriminant; auto discriminant = statement->switch_st.discriminant;
auto clauses = statement->switch_st.clauses; auto clauses = statement->switch_st.clauses;
@ -8239,7 +8284,7 @@ fn void analyze_statement(Module* module, Scope* scope, Statement* statement, u3
for (u64 i = 0; i < clauses.length; i += 1) for (u64 i = 0; i < clauses.length; i += 1)
{ {
auto& clause = clauses[i]; auto& clause = clauses[i];
clause.basic_block = llvm_context_create_basic_block(module->llvm.context, clause.values.length == 0 ? string_literal("switch.else_case_block") : string_literal("switch.case_block"), llvm_function); clause.basic_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, clause.values.length == 0 ? "switch.else_case_block" : "switch.case_block");
discriminant_case_count += clause.values.length; discriminant_case_count += clause.values.length;
if (clause.values.length == 0) if (clause.values.length == 0)
@ -8300,7 +8345,7 @@ fn void analyze_statement(Module* module, Scope* scope, Statement* statement, u3
} }
else else
{ {
else_block = llvm_context_create_basic_block(module->llvm.context, string_literal("switch.else_case_block"), llvm_function); else_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "switch.else_case_block");
} }
auto switch_instruction = LLVMBuildSwitch(module->llvm.builder, discriminant->llvm, else_block, discriminant_case_count); auto switch_instruction = LLVMBuildSwitch(module->llvm.builder, discriminant->llvm, else_block, discriminant_case_count);
@ -8383,10 +8428,10 @@ fn void analyze_statement(Module* module, Scope* scope, Statement* statement, u3
resolve_type_in_place(module, index_type); resolve_type_in_place(module, index_type);
auto index_zero = LLVMConstNull(index_type->llvm.abi); auto index_zero = LLVMConstNull(index_type->llvm.abi);
auto* entry_block = llvm_context_create_basic_block(module->llvm.context, string_literal("for_each.entry"), llvm_function); auto* entry_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "for_each.entry");
auto* body_block = llvm_context_create_basic_block(module->llvm.context, string_literal("for_each.body"), llvm_function); auto* body_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "for_each.body");
auto* continue_block = llvm_context_create_basic_block(module->llvm.context, string_literal("for_each.continue"), llvm_function); auto* continue_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "for_each.continue");
auto* exit_block = llvm_context_create_basic_block(module->llvm.context, string_literal("for_each.exit"), llvm_function); auto* exit_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "for_each.exit");
auto previous_continue_block = module->llvm.continue_block; auto previous_continue_block = module->llvm.continue_block;
auto previous_exit_block = module->llvm.exit_block; auto previous_exit_block = module->llvm.exit_block;
@ -8621,8 +8666,10 @@ fn void analyze_statement(Module* module, Scope* scope, Statement* statement, u3
LLVMValueRef indices[] = { LLVMValueRef indices[] = {
body_index_load, body_index_load,
}; };
auto gep_type = aggregate_type->structure.fields[0].type->pointer.element_type;
resolve_type_in_place(module, gep_type);
auto gep = create_gep(module, { auto gep = create_gep(module, {
.type = aggregate_type->structure.fields[0].type->pointer.element_type->llvm.memory, .type = gep_type->llvm.memory,
.pointer = extract_pointer, .pointer = extract_pointer,
.indices = array_to_slice(indices), .indices = array_to_slice(indices),
}); });
@ -9161,8 +9208,7 @@ void emit(Module* module)
case Linkage::internal: llvm_linkage_type = LLVMInternalLinkage; break; case Linkage::internal: llvm_linkage_type = LLVMInternalLinkage; break;
case Linkage::external: llvm_linkage_type = LLVMExternalLinkage; break; case Linkage::external: llvm_linkage_type = LLVMExternalLinkage; break;
} }
unsigned address_space = 0; auto llvm_function = llvm_module_create_function(module->arena, module->llvm.module, llvm_function_type, llvm_linkage_type, global->variable.name);
auto llvm_function = llvm_module_create_function(module->llvm.module, llvm_function_type, llvm_linkage_type, address_space, global->variable.name);
global->variable.storage->llvm = llvm_function; global->variable.storage->llvm = llvm_function;
LLVMCallConv cc; LLVMCallConv cc;
@ -9248,9 +9294,8 @@ void emit(Module* module)
unsigned address_space = 0; unsigned address_space = 0;
bool externally_initialized = false; bool externally_initialized = false;
auto global_llvm = llvm_module_create_global_variable(module->llvm.module, global_type->llvm.memory, is_constant, linkage, global->variable.initial_value->llvm, global->variable.name, before, thread_local_mode, address_space, externally_initialized);
auto alignment = get_byte_alignment(global_type); auto alignment = get_byte_alignment(global_type);
LLVMSetAlignment(global_llvm, alignment); auto global_llvm = llvm_module_create_global_variable(module->llvm.module, global_type->llvm.memory, is_constant, linkage, global->variable.initial_value->llvm, global->variable.name, thread_local_mode, externally_initialized, alignment, LLVMNoUnnamedAddr);
global->variable.storage->llvm = global_llvm; global->variable.storage->llvm = global_llvm;
global->variable.storage->type = get_pointer_type(module, global_type); global->variable.storage->type = get_pointer_type(module, global_type);
@ -9286,8 +9331,8 @@ void emit(Module* module)
Slice<LLVMValueRef> llvm_abi_arguments = { .pointer = llvm_abi_argument_buffer, .length = function_type->abi.abi_argument_types.length }; Slice<LLVMValueRef> llvm_abi_arguments = { .pointer = llvm_abi_argument_buffer, .length = function_type->abi.abi_argument_types.length };
LLVMGetParams(llvm_function, llvm_abi_argument_buffer); LLVMGetParams(llvm_function, llvm_abi_argument_buffer);
auto* entry_block = llvm_context_create_basic_block(module->llvm.context, string_literal("entry"), llvm_function); auto* entry_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "entry");
auto return_block = llvm_context_create_basic_block(module->llvm.context, string_literal("return_block"), llvm_function); auto return_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "return_block");
global->variable.storage->function.llvm.return_block = return_block; global->variable.storage->function.llvm.return_block = return_block;
LLVMPositionBuilderAtEnd(module->llvm.builder, entry_block); LLVMPositionBuilderAtEnd(module->llvm.builder, entry_block);
@ -9552,7 +9597,7 @@ void emit(Module* module)
{ {
assert(!LLVMGetBasicBlockTerminator(current_basic_block)); assert(!LLVMGetBasicBlockTerminator(current_basic_block));
if (llvm_basic_block_is_empty(current_basic_block) || llvm_value_use_empty((LLVMValueRef)current_basic_block)) if (!LLVMGetFirstInstruction(current_basic_block) || !LLVMGetFirstUse((LLVMValueRef)current_basic_block))
{ {
LLVMReplaceAllUsesWith((LLVMValueRef)return_block, (LLVMValueRef)current_basic_block); LLVMReplaceAllUsesWith((LLVMValueRef)return_block, (LLVMValueRef)current_basic_block);
LLVMDeleteBasicBlock(return_block); LLVMDeleteBasicBlock(return_block);
@ -9633,7 +9678,7 @@ void emit(Module* module)
auto alloca = LLVMGetOperand(store, 1); auto alloca = LLVMGetOperand(store, 1);
assert(alloca == return_alloca); assert(alloca == return_alloca);
LLVMInstructionEraseFromParent(store); LLVMInstructionEraseFromParent(store);
assert(llvm_value_use_empty(alloca)); assert(!LLVMGetFirstUse(alloca));
LLVMInstructionEraseFromParent(alloca); LLVMInstructionEraseFromParent(alloca);
} }
else else
@ -9689,12 +9734,13 @@ void emit(Module* module)
LLVMDIBuilderFinalize(module->llvm.di_builder); LLVMDIBuilderFinalize(module->llvm.di_builder);
} }
String verification_error_message = {}; char* verification_error_message = 0;
if (!llvm_module_verify(module->llvm.module, &verification_error_message)) auto result = LLVMVerifyModule(module->llvm.module, LLVMReturnStatusAction, &verification_error_message) == 0;
if (!result)
{ {
dump_module(module); dump_module(module);
print(string_literal("\n==========================\nLLVM VERIFICATION ERROR\n==========================\n")); print(string_literal("\n==========================\nLLVM VERIFICATION ERROR\n==========================\n"));
print(verification_error_message); print(c_string_to_slice(verification_error_message));
bb_fail(); bb_fail();
} }

View File

@ -26,83 +26,12 @@
#include "lld/Common/CommonLinkerContext.h" #include "lld/Common/CommonLinkerContext.h"
fn llvm::StringRef string_ref(String string)
{
return llvm::StringRef((char*)string.pointer, string.length);
}
EXPORT LLVMModuleRef llvm_context_create_module(LLVMContextRef context, String name)
{
auto module = new llvm::Module(string_ref(name), *llvm::unwrap(context));
return wrap(module);
}
EXPORT LLVMValueRef llvm_module_create_global_variable(LLVMModuleRef module, LLVMTypeRef type, bool is_constant, LLVMLinkage linkage_type, LLVMValueRef initial_value, String name, LLVMValueRef before, LLVMThreadLocalMode thread_local_mode, unsigned address_space, bool externally_initialized)
{
llvm::GlobalValue::LinkageTypes linkage;
switch (linkage_type)
{
case LLVMExternalLinkage: linkage = llvm::GlobalValue::ExternalLinkage; break;
case LLVMInternalLinkage: linkage = llvm::GlobalValue::InternalLinkage; break;
default: trap();
}
llvm::GlobalValue::ThreadLocalMode tlm;
switch (thread_local_mode)
{
case LLVMNotThreadLocal: tlm = llvm::GlobalValue::NotThreadLocal; break;
default: trap();
}
auto* global = new llvm::GlobalVariable(*llvm::unwrap(module), llvm::unwrap(type), is_constant, linkage, llvm::unwrap<llvm::Constant>(initial_value), string_ref(name), before ? llvm::unwrap<llvm::GlobalVariable>(before) : 0, tlm, address_space, externally_initialized);
return wrap(global);
}
EXPORT void llvm_subprogram_replace_type(LLVMMetadataRef subprogram, LLVMMetadataRef subroutine_type) EXPORT void llvm_subprogram_replace_type(LLVMMetadataRef subprogram, LLVMMetadataRef subroutine_type)
{ {
auto sp = llvm::unwrap<llvm::DISubprogram>(subprogram); auto sp = llvm::unwrap<llvm::DISubprogram>(subprogram);
sp->replaceType(llvm::unwrap<llvm::DISubroutineType>(subroutine_type)); sp->replaceType(llvm::unwrap<llvm::DISubroutineType>(subroutine_type));
} }
EXPORT LLVMValueRef llvm_module_create_function(LLVMModuleRef module, LLVMTypeRef function_type, LLVMLinkage linkage_type, unsigned address_space, String name)
{
llvm::GlobalValue::LinkageTypes llvm_linkage_type;
switch (linkage_type)
{
case LLVMExternalLinkage:
llvm_linkage_type = llvm::GlobalValue::LinkageTypes::ExternalLinkage; break;
case LLVMAvailableExternallyLinkage:
llvm_linkage_type = llvm::GlobalValue::LinkageTypes::AvailableExternallyLinkage; break;
case LLVMLinkOnceAnyLinkage:
llvm_linkage_type = llvm::GlobalValue::LinkageTypes::LinkOnceAnyLinkage; break;
case LLVMLinkOnceODRLinkage:
llvm_linkage_type = llvm::GlobalValue::LinkageTypes::LinkOnceODRLinkage; break;
case LLVMWeakAnyLinkage:
llvm_linkage_type = llvm::GlobalValue::LinkageTypes::WeakAnyLinkage; break;
case LLVMWeakODRLinkage:
llvm_linkage_type = llvm::GlobalValue::LinkageTypes::WeakODRLinkage; break;
case LLVMAppendingLinkage:
llvm_linkage_type = llvm::GlobalValue::LinkageTypes::AppendingLinkage; break;
case LLVMInternalLinkage:
llvm_linkage_type = llvm::GlobalValue::LinkageTypes::InternalLinkage; break;
case LLVMPrivateLinkage:
llvm_linkage_type = llvm::GlobalValue::LinkageTypes::PrivateLinkage; break;
case LLVMExternalWeakLinkage:
llvm_linkage_type = llvm::GlobalValue::LinkageTypes::ExternalWeakLinkage; break;
case LLVMCommonLinkage:
llvm_linkage_type = llvm::GlobalValue::LinkageTypes::CommonLinkage; break;
default:
trap();
}
auto* function = llvm::Function::Create(llvm::unwrap<llvm::FunctionType>(function_type), llvm_linkage_type, address_space, string_ref(name), llvm::unwrap(module));
return wrap(function);
}
EXPORT LLVMBasicBlockRef llvm_context_create_basic_block(LLVMContextRef context, String name, LLVMValueRef parent_function)
{
auto* basic_block = llvm::BasicBlock::Create(*llvm::unwrap(context), string_ref(name), parent_function ? llvm::unwrap<llvm::Function>(parent_function) : 0);
return wrap(basic_block);
}
// If there are multiple uses of the return-value slot, just check // If there are multiple uses of the return-value slot, just check
// for something immediately preceding the IP. Sometimes this can // for something immediately preceding the IP. Sometimes this can
// happen with how we generate implicit-returns; it can also happen // happen with how we generate implicit-returns; it can also happen
@ -169,142 +98,6 @@ EXPORT LLVMValueRef llvm_find_return_value_dominating_store(LLVMBuilderRef b, LL
return wrap(store); return wrap(store);
} }
EXPORT bool llvm_value_use_empty(LLVMValueRef value)
{
return llvm::unwrap(value)->use_empty();
}
EXPORT bool llvm_basic_block_is_empty(LLVMBasicBlockRef basic_block)
{
return llvm::unwrap(basic_block)->empty();
}
EXPORT LLVMValueRef llvm_builder_create_alloca(LLVMBuilderRef b, LLVMTypeRef type, unsigned address_space, u32 alignment, String name)
{
auto& builder = *llvm::unwrap(b);
auto llvm_alignment = llvm::Align(alignment);
return wrap(builder.Insert(new llvm::AllocaInst(llvm::unwrap(type), address_space, 0, llvm_alignment), string_ref(name)));
}
fn String stream_to_string(llvm::raw_string_ostream& stream)
{
// No need to call stream.flush(); because it's string-based
stream.flush();
auto string = stream.str();
auto length = string.length();
u8* result = 0;
if (length)
{
result = new u8[length + 1];
memcpy(result, string.c_str(), length);
result[length] = 0;
}
return String{ result, length };
}
EXPORT String llvm_function_to_string(llvm::Function& function)
{
std::string buffer;
llvm::raw_string_ostream os(buffer);
function.print(os);
os.flush();
auto result = stream_to_string(os);
return result;
}
EXPORT bool llvm_function_verify(LLVMValueRef function_value, String* error_message)
{
std::string message_buffer;
llvm::raw_string_ostream message_stream(message_buffer);
auto& function = *llvm::unwrap<llvm::Function>(function_value);
bool result = verifyFunction(function, &message_stream);
*error_message = stream_to_string(message_stream);
// We invert the condition because LLVM conventions are just stupid
return !result;
}
EXPORT bool llvm_module_verify(LLVMModuleRef m, String* error_message)
{
std::string message_buffer;
llvm::raw_string_ostream message_stream(message_buffer);
const auto& module = *llvm::unwrap(m);
bool result = llvm::verifyModule(module, &message_stream);
*error_message = stream_to_string(message_stream);
// We invert the condition because LLVM conventions are just stupid
return !result;
}
EXPORT String llvm_module_to_string(LLVMModuleRef module)
{
std::string buffer;
llvm::raw_string_ostream stream(buffer);
llvm::unwrap(module)->print(stream, 0);
return stream_to_string(stream);
}
EXPORT String llvm_default_target_triple()
{
auto triple = llvm::sys::getDefaultTargetTriple();
auto length = triple.length();
u8* pointer = 0;
if (length)
{
pointer = new u8[length + 1];
memcpy(pointer, triple.c_str(), length);
pointer[length] = 0;
}
return { pointer, length };
}
EXPORT String llvm_host_cpu_name()
{
auto cpu = llvm::sys::getHostCPUName();
auto result = String { (u8*)cpu.data(), cpu.size() };
assert(result.pointer[result.length] == 0);
return result;
}
EXPORT String llvm_host_cpu_features()
{
llvm::SubtargetFeatures Features;
#if LLVM_VERSION_MAJOR >= 19
auto host_cpu_features = llvm::sys::getHostCPUFeatures();
#else
StringMap<bool> host_cpu_features;
if (!sys::getHostCPUFeatures(host_cpu_features)) {
return {};
}
#endif
for (const auto &[Feature, IsEnabled] : host_cpu_features)
{
Features.AddFeature(Feature, IsEnabled);
}
auto feature_string = Features.getString();
auto length = feature_string.length();
u8* result = 0;
if (length)
{
result = new u8[length + 1];
memcpy(result, feature_string.c_str(), length + 1);
result[length] = 0;
}
return { result, length };
}
EXPORT void llvm_module_run_optimization_pipeline(LLVMModuleRef m, LLVMTargetMachineRef tm, BBLLVMOptimizationPipelineOptions options) EXPORT void llvm_module_run_optimization_pipeline(LLVMModuleRef m, LLVMTargetMachineRef tm, BBLLVMOptimizationPipelineOptions options)
{ {
auto module = llvm::unwrap(m); auto module = llvm::unwrap(m);
@ -423,7 +216,7 @@ EXPORT BBLLVMCodeGenerationPipelineResult llvm_module_run_code_generation_pipeli
{ {
std::error_code error_code; std::error_code error_code;
stream = std::make_unique<llvm::raw_fd_ostream>(string_ref(options->output_file_path), error_code, llvm::sys::fs::OF_None); stream = std::make_unique<llvm::raw_fd_ostream>(llvm::StringRef((char*)options->output_file_path.pointer, options->output_file_path.length), error_code, llvm::sys::fs::OF_None);
if (error_code) if (error_code)
{ {

View File

@ -117,33 +117,12 @@ enum class DwarfType
HP_VAX_complex_float_d = 0x90, // D floating complex. HP_VAX_complex_float_d = 0x90, // D floating complex.
}; };
fn bool llvm_initialized = false; fn bool llvm_initialized = false;
extern "C" String llvm_default_target_triple();
extern "C" String llvm_host_cpu_name();
extern "C" String llvm_host_cpu_features();
extern "C" LLVMModuleRef llvm_context_create_module(LLVMContextRef context, String name);
extern "C" LLVMValueRef llvm_module_create_function(LLVMModuleRef module, LLVMTypeRef function_type, LLVMLinkage linkage_type, unsigned address_space, String name);
extern "C" LLVMBasicBlockRef llvm_context_create_basic_block(LLVMContextRef context, String name, LLVMValueRef parent_function);
extern "C" LLVMValueRef llvm_module_create_global_variable(LLVMModuleRef module, LLVMTypeRef type, bool is_constant, LLVMLinkage linkage_type, LLVMValueRef initial_value, String name, LLVMValueRef before, LLVMThreadLocalMode thread_local_mode, unsigned address_space, bool externally_initialized);
extern "C" LLVMValueRef llvm_builder_create_alloca(LLVMBuilderRef builder, LLVMTypeRef type, unsigned address_space, u32 alignment, String name);
extern "C" bool llvm_basic_block_is_empty(LLVMBasicBlockRef basic_block);
extern "C" LLVMValueRef llvm_find_return_value_dominating_store(LLVMBuilderRef b, LLVMValueRef ra, LLVMTypeRef et); extern "C" LLVMValueRef llvm_find_return_value_dominating_store(LLVMBuilderRef b, LLVMValueRef ra, LLVMTypeRef et);
extern "C" bool llvm_value_use_empty(LLVMValueRef value);
extern "C" bool llvm_function_verify(LLVMValueRef function_value, String* error_message);
extern "C" bool llvm_module_verify(LLVMModuleRef m, String* error_message);
extern "C" void llvm_subprogram_replace_type(LLVMMetadataRef subprogram, LLVMMetadataRef subroutine_type); extern "C" void llvm_subprogram_replace_type(LLVMMetadataRef subprogram, LLVMMetadataRef subroutine_type);
extern "C" String llvm_module_to_string(LLVMModuleRef module);
extern "C" void llvm_module_run_optimization_pipeline(LLVMModuleRef module, LLVMTargetMachineRef target_machine, BBLLVMOptimizationPipelineOptions options); extern "C" void llvm_module_run_optimization_pipeline(LLVMModuleRef module, LLVMTargetMachineRef target_machine, BBLLVMOptimizationPipelineOptions options);
extern "C" BBLLVMCodeGenerationPipelineResult llvm_module_run_code_generation_pipeline(LLVMModuleRef m, LLVMTargetMachineRef tm, const BBLLVMCodeGenerationPipelineOptions* options); extern "C" BBLLVMCodeGenerationPipelineResult llvm_module_run_code_generation_pipeline(LLVMModuleRef m, LLVMTargetMachineRef tm, const BBLLVMCodeGenerationPipelineOptions* options);

View File

@ -14,12 +14,14 @@ enum class ValueIntrinsic
integer_max, integer_max,
int_from_enum, int_from_enum,
int_from_pointer, int_from_pointer,
leading_zeroes,
max, max,
min, min,
pointer_cast, pointer_cast,
pointer_from_int, pointer_from_int,
select, select,
string_to_enum, string_to_enum,
trailing_zeroes,
trap, trap,
truncate, truncate,
va_start, va_start,
@ -670,7 +672,7 @@ fn FunctionHeaderParsing parse_function_header(Module* module, Scope* scope, boo
if (mandate_argument_names) if (mandate_argument_names)
{ {
argument_name = parse_identifier(module); argument_name = arena_duplicate_string(module->arena, parse_identifier(module));
skip_space(module); skip_space(module);
@ -1056,6 +1058,7 @@ fn u8 escape_character(u8 ch)
case 't': return '\t'; case 't': return '\t';
case 'r': return '\r'; case 'r': return '\r';
case '\'': return '\''; case '\'': return '\'';
case '\\': return '\\';
default: report_error(); default: report_error();
} }
} }
@ -1168,12 +1171,14 @@ fn Token tokenize(Module* module)
string_literal("integer_max"), string_literal("integer_max"),
string_literal("int_from_enum"), string_literal("int_from_enum"),
string_literal("int_from_pointer"), string_literal("int_from_pointer"),
string_literal("leading_zeroes"),
string_literal("max"), string_literal("max"),
string_literal("min"), string_literal("min"),
string_literal("pointer_cast"), string_literal("pointer_cast"),
string_literal("pointer_from_int"), string_literal("pointer_from_int"),
string_literal("select"), string_literal("select"),
string_literal("string_to_enum"), string_literal("string_to_enum"),
string_literal("trailing_zeroes"),
string_literal("trap"), string_literal("trap"),
string_literal("truncate"), string_literal("truncate"),
string_literal("va_start"), string_literal("va_start"),
@ -1682,9 +1687,11 @@ fn Value* parse_left(Module* module, Scope* scope, ValueBuilder builder)
case ValueIntrinsic::extend: case ValueIntrinsic::extend:
case ValueIntrinsic::int_from_enum: case ValueIntrinsic::int_from_enum:
case ValueIntrinsic::int_from_pointer: case ValueIntrinsic::int_from_pointer:
case ValueIntrinsic::leading_zeroes:
case ValueIntrinsic::truncate: case ValueIntrinsic::truncate:
case ValueIntrinsic::pointer_cast: case ValueIntrinsic::pointer_cast:
case ValueIntrinsic::pointer_from_int: case ValueIntrinsic::pointer_from_int:
case ValueIntrinsic::trailing_zeroes:
case ValueIntrinsic::va_end: case ValueIntrinsic::va_end:
{ {
UnaryId id; UnaryId id;
@ -1695,9 +1702,11 @@ fn Value* parse_left(Module* module, Scope* scope, ValueBuilder builder)
case ValueIntrinsic::extend: id = UnaryId::extend; break; case ValueIntrinsic::extend: id = UnaryId::extend; break;
case ValueIntrinsic::int_from_enum: id = UnaryId::int_from_enum; break; case ValueIntrinsic::int_from_enum: id = UnaryId::int_from_enum; break;
case ValueIntrinsic::int_from_pointer: id = UnaryId::int_from_pointer; break; case ValueIntrinsic::int_from_pointer: id = UnaryId::int_from_pointer; break;
case ValueIntrinsic::leading_zeroes: id = UnaryId::leading_zeroes; break;
case ValueIntrinsic::truncate: id = UnaryId::truncate; break; case ValueIntrinsic::truncate: id = UnaryId::truncate; break;
case ValueIntrinsic::pointer_cast: id = UnaryId::pointer_cast; break; case ValueIntrinsic::pointer_cast: id = UnaryId::pointer_cast; break;
case ValueIntrinsic::pointer_from_int: id = UnaryId::pointer_from_int; break; case ValueIntrinsic::pointer_from_int: id = UnaryId::pointer_from_int; break;
case ValueIntrinsic::trailing_zeroes: id = UnaryId::trailing_zeroes; break;
case ValueIntrinsic::va_end: id = UnaryId::va_end; break; case ValueIntrinsic::va_end: id = UnaryId::va_end; break;
default: unreachable(); default: unreachable();
} }
@ -2573,7 +2582,7 @@ fn Statement* parse_statement(Module* module, Scope* scope)
module->offset += 1; module->offset += 1;
skip_space(module); skip_space(module);
auto local_name = parse_identifier(module); auto local_name = arena_duplicate_string(module->arena, parse_identifier(module));
skip_space(module); skip_space(module);
Type* local_type = 0; Type* local_type = 0;
@ -2761,7 +2770,7 @@ fn Statement* parse_statement(Module* module, Scope* scope)
if (is_identifier_start(module->content[module->offset])) if (is_identifier_start(module->content[module->offset]))
{ {
auto local_name = parse_identifier(module); auto local_name = arena_duplicate_string(module->arena, parse_identifier(module));
auto local = new_local(module, scope); auto local = new_local(module, scope);
*local = { *local = {
.variable = { .variable = {
@ -3217,7 +3226,7 @@ void parse(Module* module)
skip_space(module); skip_space(module);
} }
auto global_name = parse_identifier(module); auto global_name = arena_duplicate_string(module->arena, parse_identifier(module));
Global* global_forward_declaration = 0; Global* global_forward_declaration = 0;
Global* last_global = module->first_global; Global* last_global = module->first_global;
@ -3444,8 +3453,6 @@ void parse(Module* module)
u64 int_value_buffer[64]; u64 int_value_buffer[64];
bool is_resolved = true; bool is_resolved = true;
bool implicit_value = false;
unused(implicit_value);
while (1) while (1)
{ {
@ -3674,7 +3681,7 @@ void parse(Module* module)
break; break;
} }
auto argument_name = parse_identifier(module); auto argument_name = arena_duplicate_string(module->arena, parse_identifier(module));
skip_space(module); skip_space(module);
@ -3757,7 +3764,7 @@ void parse(Module* module)
auto argument_line = get_line(module); auto argument_line = get_line(module);
auto argument_column = get_column(module); auto argument_column = get_column(module);
auto argument_name = parse_identifier(module); auto argument_name = arena_duplicate_string(module->arena, parse_identifier(module));
skip_space(module); skip_space(module);
expect_character(module, ':'); expect_character(module, ':');

View File

@ -0,0 +1,10 @@
[export] main = fn [cc(c)] () s32
{
>a: u32 = 0b111;
if (#leading_zeroes(a) != 29) #trap();
if (#trailing_zeroes(a) != 0) #trap();
>b: u8 = 0b11010;
if (#leading_zeroes(b) != 3) #trap();
if (#trailing_zeroes(b) != 1) #trap();
return 0;
}