Pass 'global'
This commit is contained in:
parent
7f5d0834ae
commit
b9d7212169
749
src/compiler.bbb
749
src/compiler.bbb
@ -6238,7 +6238,30 @@ parse = fn (module: &Module) void
|
|||||||
|
|
||||||
if (!is_global_keyword)
|
if (!is_global_keyword)
|
||||||
{
|
{
|
||||||
#trap();
|
>initial_value = parse_value(module, scope, zero);
|
||||||
|
skip_space(module);
|
||||||
|
expect_character(module, ';');
|
||||||
|
|
||||||
|
>global_storage = new_value(module);
|
||||||
|
global_storage.& = {
|
||||||
|
.id = .global,
|
||||||
|
zero,
|
||||||
|
};
|
||||||
|
|
||||||
|
>global = new_global(module);
|
||||||
|
global.& = {
|
||||||
|
.variable = {
|
||||||
|
.storage = global_storage,
|
||||||
|
.type = global_type,
|
||||||
|
.scope = scope,
|
||||||
|
.name = global_name,
|
||||||
|
.line = global_line,
|
||||||
|
.column = global_column,
|
||||||
|
},
|
||||||
|
.initial_value = initial_value,
|
||||||
|
.linkage = .internal, // TODO: linkage
|
||||||
|
zero,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -10829,14 +10852,14 @@ emit = fn (module: &Module) void
|
|||||||
continue;
|
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)
|
switch (global.variable.storage.id)
|
||||||
{
|
{
|
||||||
.function, .forward_declared_function =>
|
.function, .forward_declared_function =>
|
||||||
{
|
{
|
||||||
|
>global_pointer_type = global.variable.storage.type;
|
||||||
|
assert(global_pointer_type.id == .pointer);
|
||||||
|
>global_value_type = global_pointer_type.content.pointer.element_type;
|
||||||
|
|
||||||
>function_type = &global_value_type.content.function;
|
>function_type = &global_value_type.content.function;
|
||||||
>semantic_argument_types = function_type.base.semantic_argument_types;
|
>semantic_argument_types = function_type.base.semantic_argument_types;
|
||||||
>semantic_return_type = function_type.base.semantic_return_type;
|
>semantic_return_type = function_type.base.semantic_return_type;
|
||||||
@ -11063,394 +11086,409 @@ emit = fn (module: &Module) void
|
|||||||
assert(!module.current_macro_instantiation);
|
assert(!module.current_macro_instantiation);
|
||||||
assert(!module.current_macro_declaration);
|
assert(!module.current_macro_declaration);
|
||||||
|
|
||||||
if (global.variable.storage.id == .function)
|
if (global.emitted)
|
||||||
{
|
{
|
||||||
module.current_function = global;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
>function = global.variable.storage;
|
switch (global.variable.storage.id)
|
||||||
assert(function.id == .function);
|
{
|
||||||
>pointer_type = function.type;
|
.function,
|
||||||
assert(pointer_type.id == .pointer);
|
.forward_declared_function,
|
||||||
>value_type = pointer_type.content.pointer.element_type;
|
=>
|
||||||
assert(value_type == global.variable.type);
|
|
||||||
assert(value_type.id == .function);
|
|
||||||
>function_type = &value_type.content.function;
|
|
||||||
>semantic_argument_types = function_type.base.semantic_argument_types;
|
|
||||||
>llvm_function = function.llvm;
|
|
||||||
assert(llvm_function != zero);
|
|
||||||
|
|
||||||
>llvm_abi_argument_buffer: [64]&LLVMValue = undefined;
|
|
||||||
>llvm_abi_arguments = llvm_abi_argument_buffer[..function_type.abi.abi_argument_types.length];
|
|
||||||
LLVMGetParams(llvm_function, &llvm_abi_argument_buffer[0]);
|
|
||||||
|
|
||||||
>entry_block = LLVMAppendBasicBlockInContext(module.llvm.context, llvm_function, "entry");
|
|
||||||
>return_block = LLVMAppendBasicBlockInContext(module.llvm.context, llvm_function, "return_block");
|
|
||||||
function.content.function.llvm.return_block = return_block;
|
|
||||||
|
|
||||||
LLVMPositionBuilderAtEnd(module.llvm.builder, entry_block);
|
|
||||||
LLVMSetCurrentDebugLocation2(module.llvm.builder, zero);
|
|
||||||
|
|
||||||
>return_abi = &function_type.abi.return_abi;
|
|
||||||
switch (return_abi.flags.kind)
|
|
||||||
{
|
{
|
||||||
.ignore => {},
|
module.current_function = global;
|
||||||
.indirect =>
|
|
||||||
{
|
|
||||||
#trap();
|
|
||||||
},
|
|
||||||
.in_alloca =>
|
|
||||||
{
|
|
||||||
#trap();
|
|
||||||
},
|
|
||||||
else =>
|
|
||||||
{
|
|
||||||
>alloca = create_alloca(module, {
|
|
||||||
.type = return_abi.semantic_type,
|
|
||||||
.name = "return_value",
|
|
||||||
zero,
|
|
||||||
});
|
|
||||||
function.content.function.llvm.return_alloca = alloca;
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
>arguments = function.content.function.arguments;
|
|
||||||
>argument_abis = function_type.abi.argument_abis;
|
|
||||||
assert(arguments.length == argument_abis.length);
|
|
||||||
|
|
||||||
for (i: 0..semantic_argument_types.length)
|
>function = global.variable.storage;
|
||||||
{
|
assert(function.id == .function);
|
||||||
>argument = &arguments[i];
|
>pointer_type = function.type;
|
||||||
>argument_abi = &argument_abis[i];
|
assert(pointer_type.id == .pointer);
|
||||||
// TODO: double slice
|
>value_type = pointer_type.content.pointer.element_type;
|
||||||
>argument_abi_arguments = llvm_abi_arguments[#extend(argument_abi.abi_start)..];
|
assert(value_type == global.variable.type);
|
||||||
argument_abi_arguments = argument_abi_arguments[..#extend(argument_abi.abi_count)];
|
assert(value_type.id == .function);
|
||||||
|
>function_type = &value_type.content.function;
|
||||||
|
>semantic_argument_types = function_type.base.semantic_argument_types;
|
||||||
|
>llvm_function = function.llvm;
|
||||||
|
assert(llvm_function != zero);
|
||||||
|
|
||||||
>semantic_argument_storage: &LLVMValue = zero;
|
>llvm_abi_argument_buffer: [64]&LLVMValue = undefined;
|
||||||
|
>llvm_abi_arguments = llvm_abi_argument_buffer[..function_type.abi.abi_argument_types.length];
|
||||||
|
LLVMGetParams(llvm_function, &llvm_abi_argument_buffer[0]);
|
||||||
|
|
||||||
switch (argument_abi.flags.kind)
|
>entry_block = LLVMAppendBasicBlockInContext(module.llvm.context, llvm_function, "entry");
|
||||||
|
>return_block = LLVMAppendBasicBlockInContext(module.llvm.context, llvm_function, "return_block");
|
||||||
|
function.content.function.llvm.return_block = return_block;
|
||||||
|
|
||||||
|
LLVMPositionBuilderAtEnd(module.llvm.builder, entry_block);
|
||||||
|
LLVMSetCurrentDebugLocation2(module.llvm.builder, zero);
|
||||||
|
|
||||||
|
>return_abi = &function_type.abi.return_abi;
|
||||||
|
switch (return_abi.flags.kind)
|
||||||
{
|
{
|
||||||
.direct, .extend =>
|
.ignore => {},
|
||||||
{
|
.indirect =>
|
||||||
>first_argument = argument_abi_arguments[0];
|
|
||||||
>coerce_to_type = abi_get_coerce_to_type(argument_abi);
|
|
||||||
|
|
||||||
if (coerce_to_type.id != .struct and argument_abi.attributes.direct.offset == 0 and type_is_abi_equal(module, coerce_to_type, argument_abi.semantic_type))
|
|
||||||
{
|
{
|
||||||
assert(argument_abi.abi_count == 1);
|
#trap();
|
||||||
>is_promoted: u1 = 0;
|
},
|
||||||
>v = first_argument;
|
.in_alloca =>
|
||||||
|
{
|
||||||
if (coerce_to_type.llvm.abi != LLVMTypeOf(v))
|
#trap();
|
||||||
{
|
},
|
||||||
#trap();
|
else =>
|
||||||
}
|
|
||||||
|
|
||||||
if (is_promoted)
|
|
||||||
{
|
|
||||||
#trap();
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: this we can get rid of because we handle all of this inside `create_alloca`, load, stores, etc
|
|
||||||
if (is_arbitrary_bit_integer(argument_abi.semantic_type))
|
|
||||||
{
|
|
||||||
>bit_count = get_bit_size(argument_abi.semantic_type);
|
|
||||||
>abi_bit_count = align_bit_count(bit_count);
|
|
||||||
>is_signed = type_is_signed(argument_abi.semantic_type);
|
|
||||||
>destination_type = integer_type(module, { .bit_count = abi_bit_count, .signed = is_signed });
|
|
||||||
>alloca = create_alloca(module, {
|
|
||||||
.type = destination_type,
|
|
||||||
.name = argument.variable.name,
|
|
||||||
zero,
|
|
||||||
});
|
|
||||||
|
|
||||||
>result: &LLVMValue = undefined;
|
|
||||||
|
|
||||||
if (bit_count < abi_bit_count)
|
|
||||||
{
|
|
||||||
>llvm_type = destination_type.llvm.memory;
|
|
||||||
if (is_signed)
|
|
||||||
{
|
|
||||||
result = LLVMBuildSExt(module.llvm.builder, first_argument, llvm_type, "");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
result = LLVMBuildZExt(module.llvm.builder, first_argument, llvm_type, "");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
#trap();
|
|
||||||
}
|
|
||||||
|
|
||||||
create_store(module, {
|
|
||||||
.source = result,
|
|
||||||
.destination = alloca,
|
|
||||||
.type = destination_type,
|
|
||||||
zero,
|
|
||||||
});
|
|
||||||
|
|
||||||
semantic_argument_storage = alloca;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
>alloca = create_alloca(module, {
|
|
||||||
.type = argument_abi.semantic_type,
|
|
||||||
.name = argument.variable.name,
|
|
||||||
zero,
|
|
||||||
});
|
|
||||||
|
|
||||||
create_store(module, {
|
|
||||||
.source = first_argument,
|
|
||||||
.destination = alloca,
|
|
||||||
.type = argument_abi.semantic_type,
|
|
||||||
zero,
|
|
||||||
});
|
|
||||||
|
|
||||||
semantic_argument_storage = alloca;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
>is_fixed_vector_type: u1 = 0;
|
|
||||||
if (is_fixed_vector_type)
|
|
||||||
{
|
|
||||||
#trap();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (coerce_to_type.id == .struct and coerce_to_type.content.struct.fields.length > 1 and argument_abi.flags.kind == .direct and !argument_abi.flags.can_be_flattened)
|
|
||||||
{
|
|
||||||
>contains_homogeneous_scalable_vector_types: u1 = 0;
|
|
||||||
if (contains_homogeneous_scalable_vector_types)
|
|
||||||
{
|
|
||||||
#trap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
>alloca = create_alloca(module, {
|
>alloca = create_alloca(module, {
|
||||||
.type = argument_abi.semantic_type,
|
.type = return_abi.semantic_type,
|
||||||
.name = argument.variable.name,
|
.name = "return_value",
|
||||||
zero,
|
zero,
|
||||||
});
|
});
|
||||||
|
function.content.function.llvm.return_alloca = alloca;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
>pointer: &LLVMValue = undefined;
|
>arguments = function.content.function.arguments;
|
||||||
>pointer_type: &Type = undefined;
|
>argument_abis = function_type.abi.argument_abis;
|
||||||
|
assert(arguments.length == argument_abis.length);
|
||||||
|
|
||||||
if (argument_abi.attributes.direct.offset > 0)
|
for (i: 0..semantic_argument_types.length)
|
||||||
{
|
{
|
||||||
#trap();
|
>argument = &arguments[i];
|
||||||
}
|
>argument_abi = &argument_abis[i];
|
||||||
else
|
// TODO: double slice
|
||||||
{
|
>argument_abi_arguments = llvm_abi_arguments[#extend(argument_abi.abi_start)..];
|
||||||
pointer = alloca;
|
argument_abi_arguments = argument_abi_arguments[..#extend(argument_abi.abi_count)];
|
||||||
pointer_type = argument_abi.semantic_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (coerce_to_type.id == .struct and coerce_to_type.content.struct.fields.length > 1 and argument_abi.flags.kind == .direct and argument_abi.flags.can_be_flattened)
|
>semantic_argument_storage: &LLVMValue = zero;
|
||||||
{
|
|
||||||
>struct_size = get_byte_size(coerce_to_type);
|
|
||||||
>pointer_element_size = get_byte_size(pointer_type);
|
|
||||||
>is_scalable: u1 = 0;
|
|
||||||
|
|
||||||
if (is_scalable)
|
switch (argument_abi.flags.kind)
|
||||||
{
|
{
|
||||||
#trap();
|
.direct, .extend =>
|
||||||
}
|
{
|
||||||
else
|
>first_argument = argument_abi_arguments[0];
|
||||||
{
|
>coerce_to_type = abi_get_coerce_to_type(argument_abi);
|
||||||
>source_size = struct_size;
|
|
||||||
>destination_size = pointer_element_size;
|
|
||||||
>address_alignment = get_byte_alignment(argument_abi.semantic_type);
|
|
||||||
|
|
||||||
>address: &LLVMValue = undefined;
|
if (coerce_to_type.id != .struct and argument_abi.attributes.direct.offset == 0 and type_is_abi_equal(module, coerce_to_type, argument_abi.semantic_type))
|
||||||
|
|
||||||
if (source_size <= destination_size)
|
|
||||||
{
|
|
||||||
address = alloca;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
address = create_alloca(module, {
|
|
||||||
.type = coerce_to_type,
|
|
||||||
.name = "coerce",
|
|
||||||
.alignment = address_alignment,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
>fields = coerce_to_type.content.struct.fields;
|
|
||||||
assert(fields.length == #extend(argument_abi.abi_count));
|
|
||||||
|
|
||||||
resolve_type_in_place(module, coerce_to_type);
|
|
||||||
|
|
||||||
for (i: 0..fields.length)
|
|
||||||
{
|
|
||||||
>field = &fields[i];
|
|
||||||
>gep = LLVMBuildStructGEP2(module.llvm.builder, coerce_to_type.llvm.abi, address, #truncate(i), "");
|
|
||||||
create_store(module, {
|
|
||||||
.source = argument_abi_arguments[i],
|
|
||||||
.destination = gep,
|
|
||||||
.type = fields[i].type,
|
|
||||||
zero,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (source_size > destination_size)
|
|
||||||
{
|
|
||||||
>u64_type = uint64(module);
|
|
||||||
resolve_type_in_place(module, u64_type);
|
|
||||||
|
|
||||||
>memcpy_size = LLVMConstInt(u64_type.llvm.abi, destination_size, 0);
|
|
||||||
LLVMBuildMemCpy(module.llvm.builder, pointer, address_alignment, address, address_alignment, memcpy_size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
assert(argument_abi.abi_count == 1);
|
assert(argument_abi.abi_count == 1);
|
||||||
>abi_argument_type = function_type.abi.abi_argument_types[argument_abi.abi_start];
|
>is_promoted: u1 = 0;
|
||||||
>destination_size: u64 = get_byte_size(pointer_type) - #extend(argument_abi.attributes.direct.offset);
|
>v = first_argument;
|
||||||
>is_volatile: u1 = 0;
|
|
||||||
create_coerced_store(module, argument_abi_arguments[0], abi_argument_type, pointer, pointer_type, destination_size, is_volatile);
|
if (coerce_to_type.llvm.abi != LLVMTypeOf(v))
|
||||||
|
{
|
||||||
|
#trap();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_promoted)
|
||||||
|
{
|
||||||
|
#trap();
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: this we can get rid of because we handle all of this inside `create_alloca`, load, stores, etc
|
||||||
|
if (is_arbitrary_bit_integer(argument_abi.semantic_type))
|
||||||
|
{
|
||||||
|
>bit_count = get_bit_size(argument_abi.semantic_type);
|
||||||
|
>abi_bit_count = align_bit_count(bit_count);
|
||||||
|
>is_signed = type_is_signed(argument_abi.semantic_type);
|
||||||
|
>destination_type = integer_type(module, { .bit_count = abi_bit_count, .signed = is_signed });
|
||||||
|
>alloca = create_alloca(module, {
|
||||||
|
.type = destination_type,
|
||||||
|
.name = argument.variable.name,
|
||||||
|
zero,
|
||||||
|
});
|
||||||
|
|
||||||
|
>result: &LLVMValue = undefined;
|
||||||
|
|
||||||
|
if (bit_count < abi_bit_count)
|
||||||
|
{
|
||||||
|
>llvm_type = destination_type.llvm.memory;
|
||||||
|
if (is_signed)
|
||||||
|
{
|
||||||
|
result = LLVMBuildSExt(module.llvm.builder, first_argument, llvm_type, "");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = LLVMBuildZExt(module.llvm.builder, first_argument, llvm_type, "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#trap();
|
||||||
|
}
|
||||||
|
|
||||||
|
create_store(module, {
|
||||||
|
.source = result,
|
||||||
|
.destination = alloca,
|
||||||
|
.type = destination_type,
|
||||||
|
zero,
|
||||||
|
});
|
||||||
|
|
||||||
|
semantic_argument_storage = alloca;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
>alloca = create_alloca(module, {
|
||||||
|
.type = argument_abi.semantic_type,
|
||||||
|
.name = argument.variable.name,
|
||||||
|
zero,
|
||||||
|
});
|
||||||
|
|
||||||
|
create_store(module, {
|
||||||
|
.source = first_argument,
|
||||||
|
.destination = alloca,
|
||||||
|
.type = argument_abi.semantic_type,
|
||||||
|
zero,
|
||||||
|
});
|
||||||
|
|
||||||
|
semantic_argument_storage = alloca;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
>is_fixed_vector_type: u1 = 0;
|
||||||
|
if (is_fixed_vector_type)
|
||||||
|
{
|
||||||
|
#trap();
|
||||||
|
}
|
||||||
|
|
||||||
semantic_argument_storage = alloca;
|
if (coerce_to_type.id == .struct and coerce_to_type.content.struct.fields.length > 1 and argument_abi.flags.kind == .direct and !argument_abi.flags.can_be_flattened)
|
||||||
}
|
{
|
||||||
},
|
>contains_homogeneous_scalable_vector_types: u1 = 0;
|
||||||
.indirect =>
|
if (contains_homogeneous_scalable_vector_types)
|
||||||
|
{
|
||||||
|
#trap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
>alloca = create_alloca(module, {
|
||||||
|
.type = argument_abi.semantic_type,
|
||||||
|
.name = argument.variable.name,
|
||||||
|
zero,
|
||||||
|
});
|
||||||
|
|
||||||
|
>pointer: &LLVMValue = undefined;
|
||||||
|
>pointer_type: &Type = undefined;
|
||||||
|
|
||||||
|
if (argument_abi.attributes.direct.offset > 0)
|
||||||
|
{
|
||||||
|
#trap();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pointer = alloca;
|
||||||
|
pointer_type = argument_abi.semantic_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (coerce_to_type.id == .struct and coerce_to_type.content.struct.fields.length > 1 and argument_abi.flags.kind == .direct and argument_abi.flags.can_be_flattened)
|
||||||
|
{
|
||||||
|
>struct_size = get_byte_size(coerce_to_type);
|
||||||
|
>pointer_element_size = get_byte_size(pointer_type);
|
||||||
|
>is_scalable: u1 = 0;
|
||||||
|
|
||||||
|
if (is_scalable)
|
||||||
|
{
|
||||||
|
#trap();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
>source_size = struct_size;
|
||||||
|
>destination_size = pointer_element_size;
|
||||||
|
>address_alignment = get_byte_alignment(argument_abi.semantic_type);
|
||||||
|
|
||||||
|
>address: &LLVMValue = undefined;
|
||||||
|
|
||||||
|
if (source_size <= destination_size)
|
||||||
|
{
|
||||||
|
address = alloca;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
address = create_alloca(module, {
|
||||||
|
.type = coerce_to_type,
|
||||||
|
.name = "coerce",
|
||||||
|
.alignment = address_alignment,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
>fields = coerce_to_type.content.struct.fields;
|
||||||
|
assert(fields.length == #extend(argument_abi.abi_count));
|
||||||
|
|
||||||
|
resolve_type_in_place(module, coerce_to_type);
|
||||||
|
|
||||||
|
for (i: 0..fields.length)
|
||||||
|
{
|
||||||
|
>field = &fields[i];
|
||||||
|
>gep = LLVMBuildStructGEP2(module.llvm.builder, coerce_to_type.llvm.abi, address, #truncate(i), "");
|
||||||
|
create_store(module, {
|
||||||
|
.source = argument_abi_arguments[i],
|
||||||
|
.destination = gep,
|
||||||
|
.type = fields[i].type,
|
||||||
|
zero,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (source_size > destination_size)
|
||||||
|
{
|
||||||
|
>u64_type = uint64(module);
|
||||||
|
resolve_type_in_place(module, u64_type);
|
||||||
|
|
||||||
|
>memcpy_size = LLVMConstInt(u64_type.llvm.abi, destination_size, 0);
|
||||||
|
LLVMBuildMemCpy(module.llvm.builder, pointer, address_alignment, address, address_alignment, memcpy_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert(argument_abi.abi_count == 1);
|
||||||
|
>abi_argument_type = function_type.abi.abi_argument_types[argument_abi.abi_start];
|
||||||
|
>destination_size: u64 = get_byte_size(pointer_type) - #extend(argument_abi.attributes.direct.offset);
|
||||||
|
>is_volatile: u1 = 0;
|
||||||
|
create_coerced_store(module, argument_abi_arguments[0], abi_argument_type, pointer, pointer_type, destination_size, is_volatile);
|
||||||
|
}
|
||||||
|
|
||||||
|
semantic_argument_storage = alloca;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.indirect =>
|
||||||
|
{
|
||||||
|
#trap();
|
||||||
|
},
|
||||||
|
else =>
|
||||||
|
{
|
||||||
|
unreachable;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(semantic_argument_storage != zero);
|
||||||
|
|
||||||
|
>storage = new_value(module);
|
||||||
|
>value_type = argument.variable.type;
|
||||||
|
storage.& = {
|
||||||
|
.type = get_pointer_type(module, value_type),
|
||||||
|
.id = .argument,
|
||||||
|
.llvm = semantic_argument_storage,
|
||||||
|
zero,
|
||||||
|
};
|
||||||
|
argument.variable.storage = storage;
|
||||||
|
|
||||||
|
if (module.has_debug_info)
|
||||||
{
|
{
|
||||||
#trap();
|
emit_debug_argument(module, argument, entry_block);
|
||||||
},
|
|
||||||
else =>
|
|
||||||
{
|
|
||||||
unreachable;
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(semantic_argument_storage != zero);
|
|
||||||
|
|
||||||
>storage = new_value(module);
|
|
||||||
>value_type = argument.variable.type;
|
|
||||||
storage.& = {
|
|
||||||
.type = get_pointer_type(module, value_type),
|
|
||||||
.id = .argument,
|
|
||||||
.llvm = semantic_argument_storage,
|
|
||||||
zero,
|
|
||||||
};
|
|
||||||
argument.variable.storage = storage;
|
|
||||||
|
|
||||||
if (module.has_debug_info)
|
|
||||||
{
|
|
||||||
emit_debug_argument(module, argument, entry_block);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
analyze_block(module, function.content.function.block);
|
|
||||||
|
|
||||||
>current_basic_block = LLVMGetInsertBlock(module.llvm.builder);
|
|
||||||
|
|
||||||
if (current_basic_block)
|
|
||||||
{
|
|
||||||
assert(!LLVMGetBasicBlockTerminator(current_basic_block));
|
|
||||||
if (!LLVMGetFirstInstruction(current_basic_block) or !LLVMGetFirstUse(#pointer_cast(current_basic_block)))
|
|
||||||
{
|
|
||||||
LLVMReplaceAllUsesWith(#pointer_cast(return_block), #pointer_cast(current_basic_block));
|
|
||||||
LLVMDeleteBasicBlock(return_block);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
#trap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
>has_single_jump_to_return_block: u1 = 0;
|
|
||||||
|
|
||||||
>first_use = LLVMGetFirstUse(#pointer_cast(return_block));
|
|
||||||
>user: &LLVMValue = zero;
|
|
||||||
|
|
||||||
if (first_use)
|
|
||||||
{
|
|
||||||
>second_use = LLVMGetNextUse(first_use);
|
|
||||||
>has_one_use = first_use != zero and first_use == zero;
|
|
||||||
|
|
||||||
if (has_one_use)
|
|
||||||
{
|
|
||||||
user = LLVMGetUser(first_use);
|
|
||||||
has_single_jump_to_return_block = LLVMIsABranchInst(user) != zero and? LLVMIsConditional(user) != 0 and? LLVMGetSuccessor(user, 0) == return_block;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has_single_jump_to_return_block)
|
analyze_block(module, function.content.function.block);
|
||||||
|
|
||||||
|
>current_basic_block = LLVMGetInsertBlock(module.llvm.builder);
|
||||||
|
|
||||||
|
if (current_basic_block)
|
||||||
{
|
{
|
||||||
#trap();
|
assert(!LLVMGetBasicBlockTerminator(current_basic_block));
|
||||||
|
if (!LLVMGetFirstInstruction(current_basic_block) or !LLVMGetFirstUse(#pointer_cast(current_basic_block)))
|
||||||
|
{
|
||||||
|
LLVMReplaceAllUsesWith(#pointer_cast(return_block), #pointer_cast(current_basic_block));
|
||||||
|
LLVMDeleteBasicBlock(return_block);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#trap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
emit_block(module, return_block);
|
>has_single_jump_to_return_block: u1 = 0;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (module.has_debug_info)
|
>first_use = LLVMGetFirstUse(#pointer_cast(return_block));
|
||||||
{
|
>user: &LLVMValue = zero;
|
||||||
LLVMSetCurrentDebugLocation2(module.llvm.builder, zero);
|
|
||||||
>subprogram = LLVMGetSubprogram(llvm_function);
|
|
||||||
LLVMDIBuilderFinalizeSubprogram(module.llvm.di_builder, subprogram);
|
|
||||||
}
|
|
||||||
|
|
||||||
>semantic_return_type = return_abi.semantic_type;
|
if (first_use)
|
||||||
if (semantic_return_type == noreturn_type(module) or function.content.function.attributes.naked)
|
|
||||||
{
|
|
||||||
#trap();
|
|
||||||
}
|
|
||||||
else if (semantic_return_type == void_type(module))
|
|
||||||
{
|
|
||||||
LLVMBuildRetVoid(module.llvm.builder);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
>return_value: &LLVMValue = zero;
|
|
||||||
|
|
||||||
switch (return_abi.flags.kind)
|
|
||||||
{
|
|
||||||
.direct, .extend =>
|
|
||||||
{
|
{
|
||||||
>return_alloca = function.content.function.llvm.return_alloca;
|
>second_use = LLVMGetNextUse(first_use);
|
||||||
>coerce_to_type = abi_get_coerce_to_type(return_abi);
|
>has_one_use = first_use != zero and first_use == zero;
|
||||||
if (type_is_abi_equal(module, coerce_to_type, semantic_return_type) and? return_abi.attributes.direct.offset == 0)
|
|
||||||
|
if (has_one_use)
|
||||||
{
|
{
|
||||||
>store = llvm_find_return_value_dominating_store(module.llvm.builder, return_alloca, semantic_return_type.llvm.abi);
|
user = LLVMGetUser(first_use);
|
||||||
if (store)
|
has_single_jump_to_return_block = LLVMIsABranchInst(user) != zero and? LLVMIsConditional(user) != 0 and? LLVMGetSuccessor(user, 0) == return_block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (has_single_jump_to_return_block)
|
||||||
|
{
|
||||||
|
#trap();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
emit_block(module, return_block);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (module.has_debug_info)
|
||||||
|
{
|
||||||
|
LLVMSetCurrentDebugLocation2(module.llvm.builder, zero);
|
||||||
|
>subprogram = LLVMGetSubprogram(llvm_function);
|
||||||
|
LLVMDIBuilderFinalizeSubprogram(module.llvm.di_builder, subprogram);
|
||||||
|
}
|
||||||
|
|
||||||
|
>semantic_return_type = return_abi.semantic_type;
|
||||||
|
if (semantic_return_type == noreturn_type(module) or function.content.function.attributes.naked)
|
||||||
|
{
|
||||||
|
#trap();
|
||||||
|
}
|
||||||
|
else if (semantic_return_type == void_type(module))
|
||||||
|
{
|
||||||
|
LLVMBuildRetVoid(module.llvm.builder);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
>return_value: &LLVMValue = zero;
|
||||||
|
|
||||||
|
switch (return_abi.flags.kind)
|
||||||
|
{
|
||||||
|
.direct, .extend =>
|
||||||
|
{
|
||||||
|
>return_alloca = function.content.function.llvm.return_alloca;
|
||||||
|
>coerce_to_type = abi_get_coerce_to_type(return_abi);
|
||||||
|
if (type_is_abi_equal(module, coerce_to_type, semantic_return_type) and? return_abi.attributes.direct.offset == 0)
|
||||||
{
|
{
|
||||||
return_value = LLVMGetOperand(store, 0);
|
>store = llvm_find_return_value_dominating_store(module.llvm.builder, return_alloca, semantic_return_type.llvm.abi);
|
||||||
>alloca = LLVMGetOperand(store, 1);
|
if (store)
|
||||||
assert(alloca == return_alloca);
|
{
|
||||||
LLVMInstructionEraseFromParent(store);
|
return_value = LLVMGetOperand(store, 0);
|
||||||
LLVMInstructionEraseFromParent(alloca);
|
>alloca = LLVMGetOperand(store, 1);
|
||||||
|
assert(alloca == return_alloca);
|
||||||
|
LLVMInstructionEraseFromParent(store);
|
||||||
|
LLVMInstructionEraseFromParent(alloca);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return_value = create_load(module, {
|
||||||
|
.type = semantic_return_type,
|
||||||
|
.pointer = return_alloca,
|
||||||
|
zero,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return_value = create_load(module, {
|
#trap();
|
||||||
.type = semantic_return_type,
|
|
||||||
.pointer = return_alloca,
|
|
||||||
zero,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
else
|
.indirect =>
|
||||||
{
|
{
|
||||||
#trap();
|
#trap();
|
||||||
}
|
},
|
||||||
},
|
}
|
||||||
.indirect =>
|
|
||||||
{
|
LLVMBuildRet(module.llvm.builder, return_value);
|
||||||
#trap();
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LLVMBuildRet(module.llvm.builder, return_value);
|
// END OF SCOPE
|
||||||
}
|
module.current_function = zero;
|
||||||
|
},
|
||||||
// END OF SCOPE
|
.global =>
|
||||||
module.current_function = zero;
|
{
|
||||||
|
#trap();
|
||||||
|
},
|
||||||
|
else => { report_error(); },
|
||||||
}
|
}
|
||||||
|
|
||||||
global = global.next;
|
global = global.next;
|
||||||
@ -11783,6 +11821,7 @@ names: [_][]u8 = [
|
|||||||
"pointer_cast",
|
"pointer_cast",
|
||||||
"u1_return",
|
"u1_return",
|
||||||
"local_type_inference",
|
"local_type_inference",
|
||||||
|
"global",
|
||||||
];
|
];
|
||||||
|
|
||||||
[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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user