wip
This commit is contained in:
parent
9b1c5ce7b0
commit
bdc41f303b
153
src/compiler.bbb
153
src/compiler.bbb
@ -808,6 +808,7 @@ ValueId = enum
|
|||||||
external_function,
|
external_function,
|
||||||
function,
|
function,
|
||||||
constant_integer,
|
constant_integer,
|
||||||
|
global,
|
||||||
}
|
}
|
||||||
|
|
||||||
ValueConstantInteger = struct
|
ValueConstantInteger = struct
|
||||||
@ -2784,6 +2785,85 @@ parse = fn (module: &Module) void
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resolve_alias = fn (module: &Module, type: &Type) &Type
|
||||||
|
{
|
||||||
|
>result: &Type = zero;
|
||||||
|
|
||||||
|
switch (type.id)
|
||||||
|
{
|
||||||
|
.void,
|
||||||
|
.integer,
|
||||||
|
=>
|
||||||
|
{
|
||||||
|
result = type;
|
||||||
|
},
|
||||||
|
else =>
|
||||||
|
{
|
||||||
|
#trap();
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(result != zero);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
AbiSystemVClass = enum
|
||||||
|
{
|
||||||
|
none,
|
||||||
|
integer,
|
||||||
|
sse,
|
||||||
|
sse_up,
|
||||||
|
x87,
|
||||||
|
x87_up,
|
||||||
|
complex_x87,
|
||||||
|
memory,
|
||||||
|
}
|
||||||
|
|
||||||
|
AbiSystemVClassifyArgument = struct
|
||||||
|
{
|
||||||
|
base_offset: u64,
|
||||||
|
is_variable_argument: u1,
|
||||||
|
is_register_call: u1,
|
||||||
|
}
|
||||||
|
|
||||||
|
abi_system_v_classify_type = fn (type: &Type, options: AbiSystemVClassifyArgument) [2]AbiSystemVClass
|
||||||
|
{
|
||||||
|
>result: [2]AbiSystemVClass = zero;
|
||||||
|
|
||||||
|
>is_memory = options.base_offset >= 8;
|
||||||
|
>current_index: u64 = #extend(is_memory);
|
||||||
|
>not_current_index: u64 = #extend(!is_memory);
|
||||||
|
assert(current_index != not_current_index);
|
||||||
|
result[current_index] = .memory;
|
||||||
|
|
||||||
|
switch (type.id)
|
||||||
|
{
|
||||||
|
.void, .noreturn =>
|
||||||
|
{
|
||||||
|
result[current_index] = .none;
|
||||||
|
},
|
||||||
|
else =>
|
||||||
|
{
|
||||||
|
#trap();
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
abi_system_v_classify_return_type = fn (module: &Module, semantic_return_type: &Type) AbiInformation
|
||||||
|
{
|
||||||
|
>type_classes = abi_system_v_classify_type(semantic_return_type, zero);
|
||||||
|
#trap();
|
||||||
|
}
|
||||||
|
|
||||||
|
ResolvedCallingConvention = enum
|
||||||
|
{
|
||||||
|
system_v,
|
||||||
|
win64,
|
||||||
|
}
|
||||||
|
|
||||||
emit = fn (module: &Module) void
|
emit = fn (module: &Module) void
|
||||||
{
|
{
|
||||||
assert(!module.current_function);
|
assert(!module.current_function);
|
||||||
@ -2889,6 +2969,79 @@ emit = fn (module: &Module) void
|
|||||||
>name = #enum_name(e);
|
>name = #enum_name(e);
|
||||||
module.llvm.intrinsic_table[i] = LLVMLookupIntrinsicID(name.pointer, name.length);
|
module.llvm.intrinsic_table[i] = LLVMLookupIntrinsicID(name.pointer, name.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
>global = module.first_global;
|
||||||
|
|
||||||
|
while (global)
|
||||||
|
{
|
||||||
|
assert(!module.current_function);
|
||||||
|
assert(!module.current_macro_instantiation);
|
||||||
|
assert(!module.current_macro_declaration);
|
||||||
|
|
||||||
|
if (global.emitted)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
>global_pointer_type = global.variable.storage.type;
|
||||||
|
assert(global_pointer_type.id == .pointer);
|
||||||
|
>global_value_type = global_pointer_type.content.pointer.element_type;
|
||||||
|
|
||||||
|
switch (global.variable.storage.id)
|
||||||
|
{
|
||||||
|
.function, .external_function =>
|
||||||
|
{
|
||||||
|
>function_type = &global_value_type.content.function;
|
||||||
|
>semantic_argument_types = function_type.semantic_argument_types;
|
||||||
|
>semantic_return_type = function_type.semantic_return_type;
|
||||||
|
function_type.argument_abis = arena_allocate_slice[AbiInformation](module.arena, semantic_argument_types.length);
|
||||||
|
>llvm_abi_argument_type_buffer: [64]&LLVMType = undefined;
|
||||||
|
|
||||||
|
>resolved_calling_convention: ResolvedCallingConvention = undefined;
|
||||||
|
switch (function_type.calling_convention)
|
||||||
|
{
|
||||||
|
.c =>
|
||||||
|
{
|
||||||
|
// TODO: switch on platform
|
||||||
|
resolved_calling_convention = .system_v;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
>is_reg_call = resolved_calling_convention == .system_v and 0; // TODO: regcall calling convention
|
||||||
|
|
||||||
|
switch (resolved_calling_convention)
|
||||||
|
{
|
||||||
|
.system_v =>
|
||||||
|
{
|
||||||
|
function_type.available_registers = {
|
||||||
|
.system_v = {
|
||||||
|
.gpr = #select(is_reg_call, 11, 6),
|
||||||
|
.sse = #select(is_reg_call, 16, 8),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
function_type.return_abi = abi_system_v_classify_return_type(module, resolve_alias(module, semantic_return_type));
|
||||||
|
#trap();
|
||||||
|
},
|
||||||
|
.win64 =>
|
||||||
|
{
|
||||||
|
#trap();
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.global =>
|
||||||
|
{
|
||||||
|
#trap();
|
||||||
|
},
|
||||||
|
else =>
|
||||||
|
{
|
||||||
|
report_error();
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
global = global.next;
|
||||||
|
}
|
||||||
|
|
||||||
|
#trap();
|
||||||
}
|
}
|
||||||
|
|
||||||
compile = fn (arena: &Arena, options: CompileOptions) void
|
compile = fn (arena: &Arena, options: CompileOptions) void
|
||||||
|
@ -435,6 +435,9 @@ global_variable String names[] =
|
|||||||
string_literal("opaque"),
|
string_literal("opaque"),
|
||||||
string_literal("basic_struct_passing"),
|
string_literal("basic_struct_passing"),
|
||||||
string_literal("enum_arbitrary_abi"),
|
string_literal("enum_arbitrary_abi"),
|
||||||
|
string_literal("enum_debug_info"),
|
||||||
|
string_literal("return_array"),
|
||||||
|
string_literal("bool_pair"),
|
||||||
};
|
};
|
||||||
|
|
||||||
void entry_point(Slice<char* const> arguments, Slice<char* const> envp)
|
void entry_point(Slice<char* const> arguments, Slice<char* const> envp)
|
||||||
|
@ -629,6 +629,11 @@ fn u64 get_bit_size(Type* type)
|
|||||||
case TypeId::integer: return type->integer.bit_count;
|
case TypeId::integer: return type->integer.bit_count;
|
||||||
case TypeId::enumerator: return get_bit_size(type->enumerator.backing_type);
|
case TypeId::enumerator: return get_bit_size(type->enumerator.backing_type);
|
||||||
case TypeId::alias: return get_bit_size(type->alias.type);
|
case TypeId::alias: return get_bit_size(type->alias.type);
|
||||||
|
case TypeId::array: return get_byte_size(type->array.element_type) * type->array.element_count * 8;
|
||||||
|
case TypeId::pointer: return 64;
|
||||||
|
case TypeId::structure: return type->structure.byte_size * 8;
|
||||||
|
case TypeId::union_type: return type->union_type.byte_size * 8;
|
||||||
|
case TypeId::enum_array: return get_byte_size(type->enum_array.element_type) * type->enum_array.enum_type->enumerator.fields.length * 8;
|
||||||
default: trap();
|
default: trap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
155
src/emitter.cpp
155
src/emitter.cpp
@ -153,6 +153,7 @@ fn bool is_integral_or_enumeration_type(Type* type)
|
|||||||
case TypeId::bits:
|
case TypeId::bits:
|
||||||
case TypeId::enumerator:
|
case TypeId::enumerator:
|
||||||
return true;
|
return true;
|
||||||
|
case TypeId::array:
|
||||||
case TypeId::structure:
|
case TypeId::structure:
|
||||||
return false;
|
return false;
|
||||||
default: unreachable();
|
default: unreachable();
|
||||||
@ -667,31 +668,25 @@ fn Type* abi_system_v_get_integer_type_at_offset(Module* module, Type* type, u32
|
|||||||
{
|
{
|
||||||
case TypeId::integer:
|
case TypeId::integer:
|
||||||
{
|
{
|
||||||
auto bit_count = type->integer.bit_count;
|
if (offset == 0)
|
||||||
switch (bit_count)
|
|
||||||
{
|
{
|
||||||
case 64: return type;
|
auto bit_count = type->integer.bit_count;
|
||||||
case 32: case 16: case 8:
|
auto start = source_offset + get_byte_size(type);
|
||||||
{
|
auto end = source_offset + 8;
|
||||||
assert(offset == 0);
|
|
||||||
auto start = source_offset + get_byte_size(type);
|
|
||||||
auto end = source_offset + 8;
|
|
||||||
|
|
||||||
if (contains_no_user_data(source_type, start, end))
|
bool type_contains_no_user_data = contains_no_user_data(source_type, start, end);
|
||||||
{
|
switch (bit_count)
|
||||||
return type;
|
{
|
||||||
}
|
case 64: return type;
|
||||||
} break;
|
case 32: case 16: case 8:
|
||||||
default:
|
{
|
||||||
{
|
if (type_contains_no_user_data)
|
||||||
auto original_byte_count = get_byte_size(type);
|
{
|
||||||
assert(original_byte_count != source_offset);
|
return type;
|
||||||
auto byte_count = MIN(original_byte_count - source_offset, 8);
|
}
|
||||||
auto bit_count = byte_count * 8;
|
} break;
|
||||||
|
default: break;
|
||||||
auto result_type = integer_type(module, { .bit_count = (u32)bit_count, .is_signed = false });
|
}
|
||||||
return result_type;
|
|
||||||
} break;
|
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case TypeId::pointer:
|
case TypeId::pointer:
|
||||||
@ -738,10 +733,18 @@ fn Type* abi_system_v_get_integer_type_at_offset(Module* module, Type* type, u32
|
|||||||
auto backing_type = type->enumerator.backing_type;
|
auto backing_type = type->enumerator.backing_type;
|
||||||
return abi_system_v_get_integer_type_at_offset(module, backing_type, offset, source_type == type ? backing_type : source_type, source_offset);
|
return abi_system_v_get_integer_type_at_offset(module, backing_type, offset, source_type == type ? backing_type : source_type, source_offset);
|
||||||
} break;
|
} break;
|
||||||
|
case TypeId::array:
|
||||||
|
{
|
||||||
|
auto element_type = type->array.element_type;
|
||||||
|
auto element_size = get_byte_size(element_type);
|
||||||
|
auto element_offset = (offset / element_size) * element_size;
|
||||||
|
return abi_system_v_get_integer_type_at_offset(module, element_type, offset - element_offset, source_type, source_offset);
|
||||||
|
} break;
|
||||||
default: unreachable();
|
default: unreachable();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto source_size = get_byte_size(source_type);
|
auto source_size = get_byte_size(source_type);
|
||||||
|
assert(source_size != source_offset);
|
||||||
auto byte_count = source_size - source_offset;
|
auto byte_count = source_size - source_offset;
|
||||||
u32 bit_count = byte_count > 8 ? 64 : byte_count * 8;
|
u32 bit_count = byte_count > 8 ? 64 : byte_count * 8;
|
||||||
auto result = integer_type(module, { .bit_count = bit_count, .is_signed = false });
|
auto result = integer_type(module, { .bit_count = bit_count, .is_signed = false });
|
||||||
@ -1103,7 +1106,7 @@ fn void resolve_type_in_place_debug(Module* module, Type* type)
|
|||||||
assert(array_element_count);
|
assert(array_element_count);
|
||||||
resolve_type_in_place_debug(module, array_element_type);
|
resolve_type_in_place_debug(module, array_element_type);
|
||||||
auto bit_alignment = get_byte_alignment(type) * 8;
|
auto bit_alignment = get_byte_alignment(type) * 8;
|
||||||
auto array_type = LLVMDIBuilderCreateArrayType(module->llvm.di_builder, array_element_count, bit_alignment, array_element_type->llvm.debug, 0, 0);
|
auto array_type = LLVMDIBuilderCreateArrayType(module->llvm.di_builder, get_bit_size(type), bit_alignment, array_element_type->llvm.debug, 0, 0);
|
||||||
result = array_type;
|
result = array_type;
|
||||||
} break;
|
} break;
|
||||||
case TypeId::enumerator:
|
case TypeId::enumerator:
|
||||||
@ -1119,7 +1122,10 @@ fn void resolve_type_in_place_debug(Module* module, Type* type)
|
|||||||
field_buffer[i] = enum_field;
|
field_buffer[i] = enum_field;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = LLVMDIBuilderCreateEnumerationType(module->llvm.di_builder, module->scope.llvm, (char*)type->name.pointer, type->name.length, module->llvm.file, type->enumerator.line, get_bit_size(type), get_byte_alignment(type) * 8, field_buffer, type->enumerator.fields.length, backing_type->llvm.debug);
|
auto debug_aligned_type = align_integer_type(module, backing_type);
|
||||||
|
resolve_type_in_place_debug(module, debug_aligned_type);
|
||||||
|
|
||||||
|
result = LLVMDIBuilderCreateEnumerationType(module->llvm.di_builder, module->scope.llvm, (char*)type->name.pointer, type->name.length, module->llvm.file, type->enumerator.line, get_bit_size(type), get_byte_alignment(type) * 8, field_buffer, type->enumerator.fields.length, debug_aligned_type->llvm.debug);
|
||||||
} break;
|
} break;
|
||||||
case TypeId::structure:
|
case TypeId::structure:
|
||||||
{
|
{
|
||||||
@ -1136,7 +1142,7 @@ fn void resolve_type_in_place_debug(Module* module, Type* type)
|
|||||||
auto& field = fields[i];
|
auto& field = fields[i];
|
||||||
auto field_type = field.type;
|
auto field_type = field.type;
|
||||||
resolve_type_in_place_debug(module, field_type);
|
resolve_type_in_place_debug(module, field_type);
|
||||||
auto member_type = LLVMDIBuilderCreateMemberType(module->llvm.di_builder, module->scope.llvm, (char*)field.name.pointer, field.name.length, module->llvm.file, field.line, get_byte_size(field_type) * 8, get_byte_alignment(field_type) * 8, field.offset * 8, flags, field_type->llvm.debug);
|
auto member_type = LLVMDIBuilderCreateMemberType(module->llvm.di_builder, module->scope.llvm, (char*)field.name.pointer, field.name.length, module->llvm.file, field.line, get_bit_size(field_type), get_byte_alignment(field_type) * 8, field.offset * 8, flags, field_type->llvm.debug);
|
||||||
llvm_type_buffer[i] = member_type;
|
llvm_type_buffer[i] = member_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1762,7 +1768,7 @@ fn AbiInformation abi_system_v_get_indirect_return_result(Type* type)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn AbiInformation abi_system_classify_return_type(Module* module, Type* semantic_return_type)
|
fn AbiInformation abi_system_v_classify_return_type(Module* module, Type* semantic_return_type)
|
||||||
{
|
{
|
||||||
auto type_classes = abi_system_v_classify_type(semantic_return_type, {});
|
auto type_classes = abi_system_v_classify_type(semantic_return_type, {});
|
||||||
auto low_class = type_classes.r[0];
|
auto low_class = type_classes.r[0];
|
||||||
@ -2278,8 +2284,8 @@ enum class IndexType
|
|||||||
|
|
||||||
struct TypeAnalysis
|
struct TypeAnalysis
|
||||||
{
|
{
|
||||||
|
Type* indexing_type;
|
||||||
bool must_be_constant;
|
bool must_be_constant;
|
||||||
bool is_index;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
fn void analyze_type(Module* module, Value* value, Type* expected_type, TypeAnalysis analysis);
|
fn void analyze_type(Module* module, Value* value, Type* expected_type, TypeAnalysis analysis);
|
||||||
@ -2692,7 +2698,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, TypeAnal
|
|||||||
{
|
{
|
||||||
if (!expected_type)
|
if (!expected_type)
|
||||||
{
|
{
|
||||||
if (analysis.is_index)
|
if (analysis.indexing_type)
|
||||||
{
|
{
|
||||||
expected_type = uint64(module);
|
expected_type = uint64(module);
|
||||||
}
|
}
|
||||||
@ -3268,7 +3274,9 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, TypeAnal
|
|||||||
}
|
}
|
||||||
auto pointer_element_type = array_like_type->pointer.element_type;
|
auto pointer_element_type = array_like_type->pointer.element_type;
|
||||||
|
|
||||||
analyze_type(module, value->array_expression.index, 0, { .must_be_constant = analysis.must_be_constant, .is_index = true });
|
auto indexing_type = pointer_element_type->id == TypeId::enum_array ? pointer_element_type->enum_array.enum_type : uint64(module);
|
||||||
|
|
||||||
|
analyze_type(module, value->array_expression.index, 0, { .indexing_type = indexing_type, .must_be_constant = analysis.must_be_constant });
|
||||||
|
|
||||||
Type* element_type = 0;
|
Type* element_type = 0;
|
||||||
switch (pointer_element_type->id)
|
switch (pointer_element_type->id)
|
||||||
@ -3311,6 +3319,11 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, TypeAnal
|
|||||||
} break;
|
} break;
|
||||||
case ValueId::enum_literal:
|
case ValueId::enum_literal:
|
||||||
{
|
{
|
||||||
|
if (!expected_type)
|
||||||
|
{
|
||||||
|
expected_type = analysis.indexing_type;
|
||||||
|
}
|
||||||
|
|
||||||
if (!expected_type)
|
if (!expected_type)
|
||||||
{
|
{
|
||||||
report_error();
|
report_error();
|
||||||
@ -4379,10 +4392,20 @@ fn ValueTypePair enter_struct_pointer_for_coerced_access(Module* module, LLVMVal
|
|||||||
|
|
||||||
if (!(first_field_size < destination_size && first_field_size < source_size))
|
if (!(first_field_size < destination_size && first_field_size < source_size))
|
||||||
{
|
{
|
||||||
trap();
|
auto gep = LLVMBuildStructGEP2(module->llvm.builder, source_type->llvm.abi, source_value, 0, "coerce.dive");
|
||||||
|
if (first_field_type->id == TypeId::structure)
|
||||||
|
{
|
||||||
|
trap();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return { gep, first_field_type };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return { source_value, source_type };
|
||||||
}
|
}
|
||||||
|
|
||||||
return { source_value, source_type };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn LLVMValueRef coerce_integer_or_pointer_to_integer_or_pointer(Module* module, LLVMValueRef source, Type* source_type, Type* destination_type)
|
fn LLVMValueRef coerce_integer_or_pointer_to_integer_or_pointer(Module* module, LLVMValueRef source, Type* source_type, Type* destination_type)
|
||||||
@ -4418,7 +4441,12 @@ fn LLVMValueRef create_coerced_load(Module* module, LLVMValueRef source, Type* s
|
|||||||
|
|
||||||
if (type_is_integer_backing(source_type) && type_is_integer_backing(destination_type))
|
if (type_is_integer_backing(source_type) && type_is_integer_backing(destination_type))
|
||||||
{
|
{
|
||||||
trap();
|
auto load = create_load(module, {
|
||||||
|
.type = source_type,
|
||||||
|
.pointer = source,
|
||||||
|
});
|
||||||
|
auto result = coerce_integer_or_pointer_to_integer_or_pointer(module, load, source_type, destination_type);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -5083,6 +5111,16 @@ fn LLVMValueRef emit_call(Module* module, Value* value, LLVMValueRef left_llvm,
|
|||||||
trap();
|
trap();
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
case ValueId::zero:
|
||||||
|
{
|
||||||
|
for (u32 i = 0; i < coerce_fields.length; i += 1)
|
||||||
|
{
|
||||||
|
auto& field = coerce_fields[i];
|
||||||
|
auto field_type = field.type;
|
||||||
|
llvm_abi_argument_value_buffer[abi_argument_count] = LLVMConstNull(field_type->llvm.abi);
|
||||||
|
abi_argument_count += 1;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
default: trap();
|
default: trap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -5342,19 +5380,42 @@ fn LLVMValueRef emit_call(Module* module, Value* value, LLVMValueRef left_llvm,
|
|||||||
|
|
||||||
auto destination_type = return_abi.semantic_type;
|
auto destination_type = return_abi.semantic_type;
|
||||||
|
|
||||||
assert(return_abi.semantic_type->id == TypeId::structure);
|
|
||||||
if (return_abi.semantic_type->structure.fields.length > 0)
|
auto source_value = llvm_call;
|
||||||
|
auto source_type = raw_function_type->function.abi_return_type;
|
||||||
|
auto destination_size = get_byte_size(destination_type);
|
||||||
|
auto left_destination_size = destination_size - return_abi.attributes.direct.offset;
|
||||||
|
auto is_destination_volatile = false;
|
||||||
|
|
||||||
|
switch (return_abi.semantic_type->id)
|
||||||
{
|
{
|
||||||
auto source_value = llvm_call;
|
case TypeId::structure:
|
||||||
auto source_type = raw_function_type->function.abi_return_type;
|
{
|
||||||
auto destination_size = get_byte_size(destination_type);
|
if (return_abi.semantic_type->structure.fields.length > 0)
|
||||||
auto left_destination_size = destination_size - return_abi.attributes.direct.offset;
|
{
|
||||||
auto is_destination_volatile = false;
|
create_coerced_store(module, source_value, source_type, destination_pointer, destination_type, left_destination_size, is_destination_volatile);
|
||||||
create_coerced_store(module, source_value, source_type, destination_pointer, destination_type, left_destination_size, is_destination_volatile);
|
}
|
||||||
}
|
else
|
||||||
else
|
{
|
||||||
{
|
trap();
|
||||||
trap();
|
}
|
||||||
|
} break;
|
||||||
|
case TypeId::array:
|
||||||
|
{
|
||||||
|
if (get_byte_size(return_abi.semantic_type) <= 8)
|
||||||
|
{
|
||||||
|
create_store(module, {
|
||||||
|
.source = source_value,
|
||||||
|
.destination = destination_pointer,
|
||||||
|
.type = source_type,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
trap();
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
default: unreachable();
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(coerce_alloca);
|
assert(coerce_alloca);
|
||||||
@ -8586,7 +8647,7 @@ void emit(Module* module)
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
auto semantic_return_type = function_type->semantic_return_type;
|
auto semantic_return_type = function_type->semantic_return_type;
|
||||||
function_type->return_abi = abi_system_classify_return_type(module, resolve_alias(module, semantic_return_type));
|
function_type->return_abi = abi_system_v_classify_return_type(module, resolve_alias(module, semantic_return_type));
|
||||||
auto return_abi_kind = function_type->return_abi.flags.kind;
|
auto return_abi_kind = function_type->return_abi.flags.kind;
|
||||||
|
|
||||||
Type* abi_argument_type_buffer[64];
|
Type* abi_argument_type_buffer[64];
|
||||||
|
@ -1241,6 +1241,7 @@ fn Value* parse_aggregate_initialization(Module* module, Scope* scope, ValueBuil
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto field_index = field_count;
|
auto field_index = field_count;
|
||||||
|
auto checkpoint = get_checkpoint(module);
|
||||||
if (consume_character_if_match(module, '.'))
|
if (consume_character_if_match(module, '.'))
|
||||||
{
|
{
|
||||||
auto name = parse_identifier(module);
|
auto name = parse_identifier(module);
|
||||||
@ -1540,7 +1541,26 @@ fn Value* parse_left(Module* module, Scope* scope, ValueBuilder builder)
|
|||||||
|
|
||||||
skip_space(module);
|
skip_space(module);
|
||||||
|
|
||||||
if (module->content[module->offset] == '.')
|
auto checkpoint = get_checkpoint(module);
|
||||||
|
bool is_aggregate_initialization = false;
|
||||||
|
if (consume_character_if_match(module, '.'))
|
||||||
|
{
|
||||||
|
auto identifier = parse_identifier(module);
|
||||||
|
|
||||||
|
skip_space(module);
|
||||||
|
is_aggregate_initialization = consume_character_if_match(module, '=');
|
||||||
|
if (!is_aggregate_initialization)
|
||||||
|
{
|
||||||
|
if (!consume_character_if_match(module, ','))
|
||||||
|
{
|
||||||
|
report_error();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
set_checkpoint(module, checkpoint);
|
||||||
|
|
||||||
|
if (is_aggregate_initialization)
|
||||||
{
|
{
|
||||||
result = parse_aggregate_initialization(module, scope, builder, right_bracket);
|
result = parse_aggregate_initialization(module, scope, builder, right_bracket);
|
||||||
}
|
}
|
||||||
|
18
tests/bool_pair.bbb
Normal file
18
tests/bool_pair.bbb
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
BoolPair = struct
|
||||||
|
{
|
||||||
|
a: u1,
|
||||||
|
b: u1,
|
||||||
|
}
|
||||||
|
|
||||||
|
bool_pair = fn () BoolPair
|
||||||
|
{
|
||||||
|
return { .a = 0, .b = 1 };
|
||||||
|
}
|
||||||
|
|
||||||
|
[export] main = fn [cc(c)] () s32
|
||||||
|
{
|
||||||
|
>result = bool_pair();
|
||||||
|
if (result.a) #trap();
|
||||||
|
if (!result.b) #trap();
|
||||||
|
return 0;
|
||||||
|
}
|
38
tests/enum_debug_info.bbb
Normal file
38
tests/enum_debug_info.bbb
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
TypeId = enum
|
||||||
|
{
|
||||||
|
void,
|
||||||
|
noreturn,
|
||||||
|
forward_declaration,
|
||||||
|
integer,
|
||||||
|
function,
|
||||||
|
pointer,
|
||||||
|
array,
|
||||||
|
enum,
|
||||||
|
struct,
|
||||||
|
bits,
|
||||||
|
alias,
|
||||||
|
union,
|
||||||
|
unresolved,
|
||||||
|
vector,
|
||||||
|
floating_point,
|
||||||
|
enum_array,
|
||||||
|
opaque,
|
||||||
|
}
|
||||||
|
|
||||||
|
Type = struct
|
||||||
|
{
|
||||||
|
arr: [5]u32,
|
||||||
|
id: TypeId,
|
||||||
|
a: [2]u64,
|
||||||
|
b: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
[export] main = fn [cc(c)] () s32
|
||||||
|
{
|
||||||
|
>t: Type = {
|
||||||
|
.id = .integer,
|
||||||
|
zero,
|
||||||
|
};
|
||||||
|
t.arr[0] = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
22
tests/return_array.bbb
Normal file
22
tests/return_array.bbb
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
SomeEnum = enum
|
||||||
|
{
|
||||||
|
a,
|
||||||
|
b,
|
||||||
|
c,
|
||||||
|
d,
|
||||||
|
e,
|
||||||
|
f,
|
||||||
|
}
|
||||||
|
|
||||||
|
foo = fn () [2]SomeEnum
|
||||||
|
{
|
||||||
|
return [ .f, .e ];
|
||||||
|
}
|
||||||
|
|
||||||
|
[export] main = fn [cc(c)] () s32
|
||||||
|
{
|
||||||
|
>result = foo();
|
||||||
|
if (result[0] != .f) #trap();
|
||||||
|
if (result[1] != .e) #trap();
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user