Pass struct test
All checks were successful
CI / ci (Release, ubuntu-latest) (pull_request) Successful in 1m38s
CI / ci (MinSizeRel, ubuntu-latest) (pull_request) Successful in 1m43s
CI / ci (RelWithDebInfo, ubuntu-latest) (pull_request) Successful in 1m41s
CI / ci (Debug, ubuntu-latest) (pull_request) Successful in 7m52s
CI / ci (Release, ubuntu-latest) (push) Successful in 1m38s
CI / ci (MinSizeRel, ubuntu-latest) (push) Successful in 1m43s
CI / ci (RelWithDebInfo, ubuntu-latest) (push) Successful in 1m41s
CI / ci (Debug, ubuntu-latest) (push) Successful in 7m54s
All checks were successful
CI / ci (Release, ubuntu-latest) (pull_request) Successful in 1m38s
CI / ci (MinSizeRel, ubuntu-latest) (pull_request) Successful in 1m43s
CI / ci (RelWithDebInfo, ubuntu-latest) (pull_request) Successful in 1m41s
CI / ci (Debug, ubuntu-latest) (pull_request) Successful in 7m52s
CI / ci (Release, ubuntu-latest) (push) Successful in 1m38s
CI / ci (MinSizeRel, ubuntu-latest) (push) Successful in 1m43s
CI / ci (RelWithDebInfo, ubuntu-latest) (push) Successful in 1m41s
CI / ci (Debug, ubuntu-latest) (push) Successful in 7m54s
This commit is contained in:
parent
8e477e3c8d
commit
95154512da
203
src/compiler.bbb
203
src/compiler.bbb
@ -2501,6 +2501,7 @@ llvm_create_global_variable = fn (module: &LLVMModule, type: &LLVMType, is_const
|
|||||||
[extern] LLVMConstNeg = fn [cc(c)] (value: &LLVMValue) &LLVMValue;
|
[extern] LLVMConstNeg = fn [cc(c)] (value: &LLVMValue) &LLVMValue;
|
||||||
[extern] LLVMConstArray2 = fn [cc(c)] (element_type: &LLVMType, value_pointer: &&LLVMValue, value_count: u64) &LLVMValue;
|
[extern] LLVMConstArray2 = fn [cc(c)] (element_type: &LLVMType, value_pointer: &&LLVMValue, value_count: u64) &LLVMValue;
|
||||||
[extern] LLVMConstStringInContext2 = fn [cc(c)] (context: &LLVMContext, pointer: &u8, length: u64, dont_null_terminate: s32) &LLVMValue;
|
[extern] LLVMConstStringInContext2 = fn [cc(c)] (context: &LLVMContext, pointer: &u8, length: u64, dont_null_terminate: s32) &LLVMValue;
|
||||||
|
[extern] LLVMConstNamedStruct = fn [cc(c)] (type: &LLVMType, constant_pointer: &&LLVMValue, constant_count: u32) &LLVMValue;
|
||||||
|
|
||||||
[extern] LLVMInstructionEraseFromParent = fn [cc(c)] (value: &LLVMValue) void;
|
[extern] LLVMInstructionEraseFromParent = fn [cc(c)] (value: &LLVMValue) void;
|
||||||
[extern] LLVMGetOperand = fn [cc(c)] (value: &LLVMValue, index: u32) &LLVMValue;
|
[extern] LLVMGetOperand = fn [cc(c)] (value: &LLVMValue, index: u32) &LLVMValue;
|
||||||
@ -2515,6 +2516,7 @@ llvm_create_global_variable = fn (module: &LLVMModule, type: &LLVMType, is_const
|
|||||||
[extern] LLVMDeleteBasicBlock = fn [cc(c)] (basic_block: &LLVMBasicBlock) void;
|
[extern] LLVMDeleteBasicBlock = fn [cc(c)] (basic_block: &LLVMBasicBlock) void;
|
||||||
|
|
||||||
[extern] LLVMIsABranchInst = fn [cc(c)] (value: &LLVMValue) &LLVMValue;
|
[extern] LLVMIsABranchInst = fn [cc(c)] (value: &LLVMValue) &LLVMValue;
|
||||||
|
[extern] LLVMIsAConstant = fn [cc(c)] (value: &LLVMValue) s32;
|
||||||
[extern] LLVMIsConditional = fn [cc(c)] (value: &LLVMValue) s32;
|
[extern] LLVMIsConditional = fn [cc(c)] (value: &LLVMValue) s32;
|
||||||
[extern] LLVMGetSuccessor = fn [cc(c)] (value: &LLVMValue, index: u32) &LLVMBasicBlock;
|
[extern] LLVMGetSuccessor = fn [cc(c)] (value: &LLVMValue, index: u32) &LLVMBasicBlock;
|
||||||
|
|
||||||
@ -6070,7 +6072,7 @@ parse = fn (module: &Module) void
|
|||||||
}
|
}
|
||||||
|
|
||||||
>type_it = module.scope.types.first;
|
>type_it = module.scope.types.first;
|
||||||
>forward_declaration: &Type = zero;
|
>type_forward_declaration: &Type = zero;
|
||||||
|
|
||||||
while (type_it)
|
while (type_it)
|
||||||
{
|
{
|
||||||
@ -6078,7 +6080,7 @@ parse = fn (module: &Module) void
|
|||||||
{
|
{
|
||||||
if (type_it.id == .forward_declaration)
|
if (type_it.id == .forward_declaration)
|
||||||
{
|
{
|
||||||
forward_declaration = type_it;
|
type_forward_declaration = type_it;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -6461,7 +6463,102 @@ parse = fn (module: &Module) void
|
|||||||
},
|
},
|
||||||
.struct =>
|
.struct =>
|
||||||
{
|
{
|
||||||
#trap();
|
skip_space(module);
|
||||||
|
|
||||||
|
>struct_type: &Type = undefined;
|
||||||
|
if (type_forward_declaration)
|
||||||
|
{
|
||||||
|
struct_type = type_forward_declaration;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
struct_type = new_type(module, {
|
||||||
|
.id = .forward_declaration,
|
||||||
|
.name = global_name,
|
||||||
|
.scope = &module.scope,
|
||||||
|
zero,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (consume_character_if_match(module, left_brace))
|
||||||
|
{
|
||||||
|
>field_buffer: [256]Field = undefined;
|
||||||
|
|
||||||
|
>byte_size: u64 = 0;
|
||||||
|
>byte_alignment: u32 = 1;
|
||||||
|
>field_count: u64 = 0;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
skip_space(module);
|
||||||
|
|
||||||
|
if (consume_character_if_match(module, right_brace))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
>field_index = field_count;
|
||||||
|
>field_line = get_line(module);
|
||||||
|
>field_name = parse_identifier(module);
|
||||||
|
|
||||||
|
skip_space(module);
|
||||||
|
expect_character(module, ':');
|
||||||
|
skip_space(module);
|
||||||
|
|
||||||
|
>field_type = parse_type(module, scope);
|
||||||
|
|
||||||
|
>field_byte_size = get_byte_size(field_type);
|
||||||
|
>field_byte_alignment = get_byte_alignment(field_type);
|
||||||
|
// Align struct size by field alignment
|
||||||
|
>field_byte_offset = align_forward(byte_size, #extend(field_byte_alignment));
|
||||||
|
|
||||||
|
field_buffer[field_index] = {
|
||||||
|
.name = field_name,
|
||||||
|
.type = field_type,
|
||||||
|
.offset = field_byte_offset,
|
||||||
|
.line = field_line,
|
||||||
|
};
|
||||||
|
|
||||||
|
byte_size = field_byte_offset + field_byte_size;
|
||||||
|
byte_alignment = #max(byte_alignment, field_byte_alignment);
|
||||||
|
|
||||||
|
skip_space(module);
|
||||||
|
|
||||||
|
consume_character_if_match(module, ',');
|
||||||
|
|
||||||
|
field_count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte_size = align_forward(byte_size, #extend(byte_alignment));
|
||||||
|
assert(byte_size % #extend(byte_alignment) == 0);
|
||||||
|
|
||||||
|
skip_space(module);
|
||||||
|
consume_character_if_match(module, ';');
|
||||||
|
|
||||||
|
>fields = arena_allocate_slice[Field](module.arena, field_count);
|
||||||
|
memcpy(#pointer_cast(fields.pointer), #pointer_cast(&field_buffer), field_count * #byte_size(Field));
|
||||||
|
|
||||||
|
struct_type.content = {
|
||||||
|
.struct = {
|
||||||
|
.fields = fields,
|
||||||
|
.byte_size = byte_size,
|
||||||
|
.byte_alignment = byte_alignment,
|
||||||
|
.line = global_line,
|
||||||
|
.is_slice = 0,
|
||||||
|
.next = zero,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
struct_type.id = .struct;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (type_forward_declaration)
|
||||||
|
{
|
||||||
|
report_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
expect_character(module, ';');
|
||||||
|
}
|
||||||
},
|
},
|
||||||
.typealias =>
|
.typealias =>
|
||||||
{
|
{
|
||||||
@ -8840,7 +8937,69 @@ analyze_type = fn (module: &Module, value: &Value, expected_type: &Type, analysi
|
|||||||
{
|
{
|
||||||
.struct =>
|
.struct =>
|
||||||
{
|
{
|
||||||
#trap();
|
>fields = aggregate_type.content.struct.fields;
|
||||||
|
assert(fields.length <= 64);
|
||||||
|
>is_ordered: u1 = 1;
|
||||||
|
|
||||||
|
>same_values_as_field = fields.length == elements.length;
|
||||||
|
>is_properly_initialized = same_values_as_field or zero;
|
||||||
|
|
||||||
|
if (zero and same_values_as_field)
|
||||||
|
{
|
||||||
|
report_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_properly_initialized)
|
||||||
|
{
|
||||||
|
report_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(elements.length <= fields.length);
|
||||||
|
|
||||||
|
for (initialization_index: 0..elements.length)
|
||||||
|
{
|
||||||
|
>element = &elements[initialization_index];
|
||||||
|
>name = element.name;
|
||||||
|
>value = element.value;
|
||||||
|
|
||||||
|
>declaration_index: u64 = 0;
|
||||||
|
|
||||||
|
while (declaration_index < fields.length)
|
||||||
|
{
|
||||||
|
>field = &fields[declaration_index];
|
||||||
|
|
||||||
|
if (string_equal(name, field.name))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
declaration_index += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (declaration_index == fields.length)
|
||||||
|
{
|
||||||
|
report_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
>mask = 1 << declaration_index;
|
||||||
|
>current_mask = field_mask;
|
||||||
|
if (current_mask & mask)
|
||||||
|
{
|
||||||
|
// Repeated field
|
||||||
|
report_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
field_mask = current_mask | mask;
|
||||||
|
|
||||||
|
is_ordered = is_ordered and declaration_index == initialization_index;
|
||||||
|
>field = &fields[declaration_index];
|
||||||
|
>declaration_type = field.type;
|
||||||
|
|
||||||
|
analyze_type(module, value, declaration_type, { .must_be_constant = analysis.must_be_constant, zero });
|
||||||
|
is_constant = is_constant and value_is_constant(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
value.content.aggregate_initialization.is_constant = is_constant and is_ordered;
|
||||||
},
|
},
|
||||||
.bits =>
|
.bits =>
|
||||||
{
|
{
|
||||||
@ -10526,7 +10685,39 @@ emit_value = fn (module: &Module, value: &Value, type_kind: TypeKind, expect_con
|
|||||||
{
|
{
|
||||||
.struct =>
|
.struct =>
|
||||||
{
|
{
|
||||||
#trap();
|
>fields = resolved_value_type.content.struct.fields;
|
||||||
|
assert(fields.length <= 64);
|
||||||
|
assert(elements.length <= 64);
|
||||||
|
|
||||||
|
if (is_constant)
|
||||||
|
{
|
||||||
|
>constant_buffer: [64]&LLVMValue = undefined;
|
||||||
|
for (i: 0..elements.length)
|
||||||
|
{
|
||||||
|
>value = elements[i].value;
|
||||||
|
emit_value(module, value, .memory, must_be_constant);
|
||||||
|
>llvm_value = value.llvm;
|
||||||
|
assert(llvm_value != zero);
|
||||||
|
assert(LLVMIsAConstant(llvm_value) != 0);
|
||||||
|
constant_buffer[i] = llvm_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
>constant_count = elements.length;
|
||||||
|
|
||||||
|
if (is_zero)
|
||||||
|
{
|
||||||
|
#trap();
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(constant_count == fields.length);
|
||||||
|
|
||||||
|
llvm_value = LLVMConstNamedStruct(get_llvm_type(resolved_value_type, type_kind), &constant_buffer[0], #truncate(constant_count));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// TODO: shouldn't this be a left value?
|
||||||
|
report_error();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
.union =>
|
.union =>
|
||||||
{
|
{
|
||||||
@ -12469,6 +12660,8 @@ names: [_][]u8 = [
|
|||||||
"bits_no_backing_type",
|
"bits_no_backing_type",
|
||||||
"bits_return_u1",
|
"bits_return_u1",
|
||||||
"bits_zero",
|
"bits_zero",
|
||||||
|
"comparison",
|
||||||
|
"global_struct",
|
||||||
];
|
];
|
||||||
|
|
||||||
[export] main = fn [cc(c)] (argument_count: u32, argv: &&u8, envp: &&u8) s32
|
[export] main = fn [cc(c)] (argument_count: u32, argv: &&u8, envp: &&u8) s32
|
||||||
|
@ -853,6 +853,7 @@ struct ValueConstantInteger
|
|||||||
|
|
||||||
struct FunctionLLVM
|
struct FunctionLLVM
|
||||||
{
|
{
|
||||||
|
LLVMValueRef alloca_insertion_point;
|
||||||
LLVMBasicBlockRef return_block;
|
LLVMBasicBlockRef return_block;
|
||||||
LLVMValueRef return_alloca;
|
LLVMValueRef return_alloca;
|
||||||
};
|
};
|
||||||
|
@ -1949,6 +1949,25 @@ struct AllocaOptions
|
|||||||
u32 alignment;
|
u32 alignment;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
fn Global* get_current_function(Module* module)
|
||||||
|
{
|
||||||
|
Global* parent_function_global;
|
||||||
|
if (module->current_function)
|
||||||
|
{
|
||||||
|
parent_function_global = module->current_function;
|
||||||
|
}
|
||||||
|
else if (module->current_macro_instantiation)
|
||||||
|
{
|
||||||
|
parent_function_global = module->current_macro_instantiation->instantiation_function;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
report_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent_function_global;
|
||||||
|
}
|
||||||
|
|
||||||
fn LLVMValueRef create_alloca(Module* module, AllocaOptions options)
|
fn LLVMValueRef create_alloca(Module* module, AllocaOptions options)
|
||||||
{
|
{
|
||||||
auto abi_type = options.type;
|
auto abi_type = options.type;
|
||||||
@ -1964,7 +1983,15 @@ fn LLVMValueRef create_alloca(Module* module, AllocaOptions options)
|
|||||||
alignment = get_byte_alignment(abi_type);
|
alignment = get_byte_alignment(abi_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto original_block = LLVMGetInsertBlock(module->llvm.builder);
|
||||||
|
auto function = get_current_function(module);
|
||||||
|
auto debug_location = LLVMGetCurrentDebugLocation2(module->llvm.builder);
|
||||||
|
LLVMPositionBuilderBefore(module->llvm.builder, function->variable.storage->function.llvm.alloca_insertion_point);
|
||||||
|
LLVMSetCurrentDebugLocation2(module->llvm.builder, 0);
|
||||||
|
|
||||||
auto alloca = llvm_builder_create_alloca(module->llvm.builder, abi_type->llvm.memory, alignment, options.name);
|
auto alloca = llvm_builder_create_alloca(module->llvm.builder, abi_type->llvm.memory, alignment, options.name);
|
||||||
|
LLVMPositionBuilderAtEnd(module->llvm.builder, original_block);
|
||||||
|
LLVMSetCurrentDebugLocation2(module->llvm.builder, debug_location);
|
||||||
return alloca;
|
return alloca;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3070,6 +3097,12 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, TypeAnal
|
|||||||
auto* entry_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "entry");
|
auto* entry_block = LLVMAppendBasicBlockInContext(module->llvm.context, llvm_function, "entry");
|
||||||
LLVMPositionBuilderAtEnd(module->llvm.builder, entry_block);
|
LLVMPositionBuilderAtEnd(module->llvm.builder, entry_block);
|
||||||
|
|
||||||
|
auto u32_type = uint32(module);
|
||||||
|
resolve_type_in_place(module, u32_type);
|
||||||
|
auto current_function = get_current_function(module);
|
||||||
|
auto old_alloca_insertion_point = current_function->variable.storage->function.llvm.alloca_insertion_point;
|
||||||
|
current_function->variable.storage->function.llvm.alloca_insertion_point = LLVMBuildAlloca(module->llvm.builder, u32_type->llvm.abi, "alloca_insert_point");
|
||||||
|
|
||||||
auto alloca = create_alloca(module, {
|
auto alloca = create_alloca(module, {
|
||||||
.type = string_type,
|
.type = string_type,
|
||||||
.name = string_literal("retval"),
|
.name = string_literal("retval"),
|
||||||
@ -3137,6 +3170,8 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, TypeAnal
|
|||||||
|
|
||||||
enum_to_string = llvm_function;
|
enum_to_string = llvm_function;
|
||||||
enum_type->enumerator.enum_to_string_function = enum_to_string;
|
enum_type->enumerator.enum_to_string_function = enum_to_string;
|
||||||
|
|
||||||
|
current_function->variable.storage->function.llvm.alloca_insertion_point = old_alloca_insertion_point;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(enum_to_string);
|
assert(enum_to_string);
|
||||||
@ -4260,6 +4295,12 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, TypeAnal
|
|||||||
|
|
||||||
LLVMPositionBuilderAtEnd(module->llvm.builder, entry_block);
|
LLVMPositionBuilderAtEnd(module->llvm.builder, entry_block);
|
||||||
|
|
||||||
|
auto current_function = get_current_function(module);
|
||||||
|
auto old_alloca_insertion_point = current_function->variable.storage->function.llvm.alloca_insertion_point;
|
||||||
|
auto u32_type = uint32(module);
|
||||||
|
resolve_type_in_place(module, u32_type);
|
||||||
|
current_function->variable.storage->function.llvm.alloca_insertion_point = LLVMBuildAlloca(module->llvm.builder, u32_type->llvm.abi, "alloca_insert_point");
|
||||||
|
|
||||||
LLVMValueRef arguments[2];
|
LLVMValueRef arguments[2];
|
||||||
LLVMGetParams(llvm_function, arguments);
|
LLVMGetParams(llvm_function, arguments);
|
||||||
|
|
||||||
@ -4468,6 +4509,8 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, TypeAnal
|
|||||||
|
|
||||||
enum_type->enumerator.string_to_enum_function = llvm_function;
|
enum_type->enumerator.string_to_enum_function = llvm_function;
|
||||||
enum_type->enumerator.string_to_enum_struct_type = struct_type;
|
enum_type->enumerator.string_to_enum_struct_type = struct_type;
|
||||||
|
|
||||||
|
current_function->variable.storage->function.llvm.alloca_insertion_point = old_alloca_insertion_point;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto struct_type = enum_type->enumerator.string_to_enum_struct_type;
|
auto struct_type = enum_type->enumerator.string_to_enum_struct_type;
|
||||||
@ -9507,6 +9550,10 @@ void emit(Module* module)
|
|||||||
LLVMPositionBuilderAtEnd(module->llvm.builder, entry_block);
|
LLVMPositionBuilderAtEnd(module->llvm.builder, entry_block);
|
||||||
LLVMSetCurrentDebugLocation2(module->llvm.builder, 0);
|
LLVMSetCurrentDebugLocation2(module->llvm.builder, 0);
|
||||||
|
|
||||||
|
auto u32_type = uint32(module);
|
||||||
|
resolve_type_in_place(module, u32_type);
|
||||||
|
global->variable.storage->function.llvm.alloca_insertion_point = LLVMBuildAlloca(module->llvm.builder, u32_type->llvm.abi, "alloca_insert_point");
|
||||||
|
|
||||||
auto return_abi_kind = function_type->abi.return_abi.flags.kind;
|
auto return_abi_kind = function_type->abi.return_abi.flags.kind;
|
||||||
switch (return_abi_kind)
|
switch (return_abi_kind)
|
||||||
{
|
{
|
||||||
@ -9893,6 +9940,8 @@ void emit(Module* module)
|
|||||||
LLVMBuildRet(module->llvm.builder, return_value);
|
LLVMBuildRet(module->llvm.builder, return_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LLVMInstructionEraseFromParent(global->variable.storage->function.llvm.alloca_insertion_point);
|
||||||
|
|
||||||
// END OF SCOPE
|
// END OF SCOPE
|
||||||
module->current_function = 0;
|
module->current_function = 0;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user