wip
This commit is contained in:
parent
04ca049e6c
commit
b31b1915ad
590
src/compiler.bbb
590
src/compiler.bbb
@ -847,7 +847,8 @@ LLVMAttributeIndex = enum u32
|
||||
|
||||
LLVMLinkage = enum u32
|
||||
{
|
||||
external, // Externally visible function available_externally,
|
||||
external, // Externally visible function
|
||||
available_externally,
|
||||
link_once_any, // Keep one copy of function when linking (inline)*/
|
||||
link_once_odr, // Same, but only replaced by something
|
||||
|
||||
@ -1417,6 +1418,10 @@ get_byte_size = fn (type: &Type) u64
|
||||
assert(byte_count == 1 or byte_count == 2 or byte_count == 4 or byte_count == 8 or byte_count == 16);
|
||||
return byte_count;
|
||||
},
|
||||
.pointer =>
|
||||
{
|
||||
return 8;
|
||||
},
|
||||
else =>
|
||||
{
|
||||
#trap();
|
||||
@ -1449,6 +1454,7 @@ get_byte_alignment = fn (type: &Type) u32
|
||||
assert(aligned_byte_count == 1 or aligned_byte_count == 2 or aligned_byte_count == 4 or aligned_byte_count == 8 or aligned_byte_count == 16);
|
||||
return aligned_byte_count;
|
||||
},
|
||||
.pointer => { return 8; },
|
||||
else =>
|
||||
{
|
||||
#trap();
|
||||
@ -1514,6 +1520,8 @@ ValueId = enum
|
||||
variable,
|
||||
local,
|
||||
unary_type,
|
||||
macro_reference,
|
||||
call,
|
||||
}
|
||||
|
||||
ValueConstantInteger = struct
|
||||
@ -1673,6 +1681,13 @@ ValueBinary = struct
|
||||
id: BinaryId,
|
||||
}
|
||||
|
||||
ValueCall = struct
|
||||
{
|
||||
callable: &Value,
|
||||
arguments: []&Value,
|
||||
function_type: &Type,
|
||||
}
|
||||
|
||||
ValueContent = union
|
||||
{
|
||||
constant_integer: ValueConstantInteger,
|
||||
@ -1681,6 +1696,7 @@ ValueContent = union
|
||||
binary: ValueBinary,
|
||||
variable: &Variable,
|
||||
unary_type: ValueUnaryType,
|
||||
call: ValueCall,
|
||||
}
|
||||
|
||||
ValueKind = enum
|
||||
@ -2055,6 +2071,7 @@ LLVMICmpPredicate = enum u32
|
||||
[extern] LLVMCreateTypeAttribute = fn [cc(c)] (context: &LLVMContext, attribute_id: LLVMAttributeId, type: &LLVMType) &LLVMAttribute;
|
||||
[extern] LLVMCreateStringAttribute = fn [cc(c)] (context: &LLVMContext, attribute_key_pointer: &u8, attribute_key_length: u64, attribute_value_pointer: &u8, attribute_value_length: u64) &LLVMAttribute;
|
||||
[extern] LLVMAddAttributeAtIndex = fn [cc(c)] (value: &LLVMValue, index: u32, attribute: &LLVMAttribute) void;
|
||||
[extern] LLVMAddCallSiteAttribute = fn [cc(c)] (value: &LLVMValue, index: u32, attribute: &LLVMAttribute) void;
|
||||
|
||||
[extern] LLVMGetParams = fn [cc(c)] (function: &LLVMValue, parameter_pointer: &&LLVMValue) void;
|
||||
|
||||
@ -2094,6 +2111,8 @@ LLVMICmpPredicate = enum u32
|
||||
[extern] LLVMBuildSRem = fn [cc(c)] (builder: &LLVMBuilder, left: &LLVMValue, right: &LLVMValue, name: &u8) &LLVMValue;
|
||||
[extern] LLVMBuildURem = fn [cc(c)] (builder: &LLVMBuilder, left: &LLVMValue, right: &LLVMValue, name: &u8) &LLVMValue;
|
||||
|
||||
[extern] LLVMBuildCall2 = fn [cc(c)] (builder: &LLVMBuilder, function_type: &LLVMType, function_value: &LLVMValue, argument_pointer: &&LLVMValue, argument_count: u32, name: &u8) &LLVMValue;
|
||||
|
||||
[extern] LLVMGetInsertBlock = fn [cc(c)] (builder: &LLVMBuilder) &LLVMBasicBlock;
|
||||
[extern] LLVMGetBasicBlockTerminator = fn [cc(c)] (basic_block: &LLVMBasicBlock) &LLVMValue;
|
||||
[extern] LLVMGetBasicBlockParent = fn [cc(c)] (basic_block: &LLVMBasicBlock) &LLVMValue;
|
||||
@ -2129,6 +2148,7 @@ LLVMICmpPredicate = enum u32
|
||||
|
||||
[extern] llvm_module_create_function = fn [cc(c)] (module: &LLVMModule, function_type: &LLVMType, linkage_type: LLVMLinkage, address_space: u32, name: []u8) &LLVMValue;
|
||||
[extern] LLVMSetFunctionCallConv = fn [cc(c)] (function: &LLVMValue, calling_convention: LLVMCallingConvention) void;
|
||||
[extern] LLVMSetInstructionCallConv = fn [cc(c)] (call: &LLVMValue, calling_convention: LLVMCallingConvention) void;
|
||||
|
||||
[extern] llvm_module_run_optimization_pipeline = fn [cc(c)] (module: &LLVMModule, target_machine: &LLVMTargetMachine, options: &LLVMOptimizationOptions) void;
|
||||
[extern] llvm_module_run_code_generation_pipeline = fn [cc(c)] (module: &LLVMModule, target_machine: &LLVMTargetMachine, options: &LLVMCodeGenerationOptions) LLVMCodeGenerationResult;
|
||||
@ -2321,8 +2341,19 @@ Statement = struct
|
||||
scope_to_block = fn (scope: &Scope) &Block
|
||||
{
|
||||
assert(scope.kind == .local);
|
||||
>result: &Block = #field_parent_pointer(scope, "scope");
|
||||
return result;
|
||||
return #field_parent_pointer(scope, "scope");
|
||||
}
|
||||
|
||||
scope_to_function = fn (scope: &Scope) &ValueFunction
|
||||
{
|
||||
assert(scope.kind == .function);
|
||||
return #field_parent_pointer(scope, "scope");
|
||||
}
|
||||
|
||||
scope_to_module = fn (scope: &Scope) &Module
|
||||
{
|
||||
assert(scope.kind == .global);
|
||||
return #field_parent_pointer(scope, "scope");
|
||||
}
|
||||
|
||||
new_local = fn (module: &Module, scope: &Scope) &Local
|
||||
@ -3233,7 +3264,38 @@ tokenize = fn (module: &Module) Token
|
||||
},
|
||||
'.' =>
|
||||
{
|
||||
#trap();
|
||||
>id: TokenId = undefined;
|
||||
>next_ch = module.content[start_index + 1];
|
||||
switch (next_ch)
|
||||
{
|
||||
else => { id = .dot; },
|
||||
'&' => { id = .pointer_dereference; },
|
||||
'.' =>
|
||||
{
|
||||
switch (module.content[start_index + 2])
|
||||
{
|
||||
'.' => { id = .triple_dot; },
|
||||
else => { id = .double_dot; },
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
>add: u64 = undefined;
|
||||
|
||||
switch (id)
|
||||
{
|
||||
.dot => { add = 1; },
|
||||
.double_dot, .pointer_dereference => { add = 2; },
|
||||
.triple_dot => { add = 3; },
|
||||
else => { unreachable; },
|
||||
}
|
||||
|
||||
module.offset += add;
|
||||
|
||||
token = {
|
||||
.id = id,
|
||||
zero,
|
||||
};
|
||||
},
|
||||
'"' =>
|
||||
{
|
||||
@ -3437,11 +3499,41 @@ reference_identifier = fn (module: &Module, current_scope: &Scope, identifier: [
|
||||
{
|
||||
.global =>
|
||||
{
|
||||
#trap();
|
||||
assert(module == scope_to_module(scope));
|
||||
|
||||
>global = module.first_global;
|
||||
|
||||
while (global != zero)
|
||||
{
|
||||
if (string_equal(identifier, global.variable.name))
|
||||
{
|
||||
variable = &global.variable;
|
||||
break;
|
||||
}
|
||||
|
||||
global = global.next;
|
||||
}
|
||||
|
||||
>macro_declaration = module.first_macro_declaration;
|
||||
|
||||
while (macro_declaration != zero)
|
||||
{
|
||||
#trap();
|
||||
}
|
||||
},
|
||||
.function =>
|
||||
{
|
||||
#trap();
|
||||
assert(scope.parent != zero);
|
||||
>function = scope_to_function(scope);
|
||||
|
||||
for (&argument: function.arguments)
|
||||
{
|
||||
if (string_equal(identifier, argument.variable.name))
|
||||
{
|
||||
variable = &argument.variable;
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
.local =>
|
||||
{
|
||||
@ -3804,6 +3896,41 @@ get_token_precedence = fn (token: Token) Precedence
|
||||
}
|
||||
}
|
||||
|
||||
parse_call_arguments = fn (module: &Module, scope: &Scope) []&Value
|
||||
{
|
||||
>arguments: []&Value = zero;
|
||||
|
||||
>argument_count: u64 = 0;
|
||||
>argument_buffer: [64]&Value = undefined;
|
||||
|
||||
while (1)
|
||||
{
|
||||
skip_space(module);
|
||||
|
||||
if (consume_character_if_match(module, right_parenthesis))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
>argument = parse_value(module, scope, zero);
|
||||
>argument_index = argument_count;
|
||||
argument_buffer[argument_index] = argument;
|
||||
|
||||
skip_space(module);
|
||||
|
||||
consume_character_if_match(module, ',');
|
||||
|
||||
argument_count += 1;
|
||||
}
|
||||
|
||||
if (argument_count != 0)
|
||||
{
|
||||
#trap();
|
||||
}
|
||||
|
||||
return arguments;
|
||||
}
|
||||
|
||||
parse_right = fn (module: &Module, scope: &Scope, builder: ValueBuilder) &Value
|
||||
{
|
||||
>left = builder.left;
|
||||
@ -3887,11 +4014,46 @@ parse_right = fn (module: &Module, scope: &Scope, builder: ValueBuilder) &Value
|
||||
},
|
||||
.pointer_dereference =>
|
||||
{
|
||||
#trap();
|
||||
result = new_value(module);
|
||||
result.& = {
|
||||
.content = {
|
||||
.unary = {
|
||||
.value = left,
|
||||
.id = .dereference,
|
||||
},
|
||||
},
|
||||
.id = .unary,
|
||||
.kind = .right,
|
||||
zero,
|
||||
};
|
||||
},
|
||||
.left_parenthesis =>
|
||||
{
|
||||
#trap();
|
||||
result = new_value(module);
|
||||
|
||||
switch (left.id)
|
||||
{
|
||||
.macro_reference =>
|
||||
{
|
||||
#trap();
|
||||
},
|
||||
else =>
|
||||
{
|
||||
>arguments = parse_call_arguments(module, scope);
|
||||
result.& = {
|
||||
.content = {
|
||||
.call = {
|
||||
.callable = left,
|
||||
.arguments = arguments,
|
||||
zero,
|
||||
},
|
||||
},
|
||||
.id = .call,
|
||||
.kind = .right,
|
||||
zero,
|
||||
};
|
||||
},
|
||||
}
|
||||
},
|
||||
.left_bracket =>
|
||||
{
|
||||
@ -5023,7 +5185,7 @@ add_value_attribute = fn (module: &Module, value: &LLVMValue, index: u32, add_ca
|
||||
|
||||
AttributeBuildOptions = struct
|
||||
{
|
||||
return_abi: AbiInformation,
|
||||
return_abi: &AbiInformation,
|
||||
argument_abis: []AbiInformation,
|
||||
abi_argument_types: []&Type,
|
||||
abi_return_type: &Type,
|
||||
@ -5032,7 +5194,7 @@ AttributeBuildOptions = struct
|
||||
|
||||
emit_attributes = fn (module: &Module, value: &LLVMValue, add_callback: &LLVMAttributeCallback, options: AttributeBuildOptions) void
|
||||
{
|
||||
>return_abi = &options.return_abi;
|
||||
>return_abi = options.return_abi;
|
||||
>semantic_return_type = return_abi.semantic_type;
|
||||
resolve_type_in_place(module, semantic_return_type);
|
||||
>abi_return_type = options.abi_return_type;
|
||||
@ -5488,7 +5650,17 @@ analyze_type = fn (module: &Module, value: &Value, expected_type: &Type, analysi
|
||||
},
|
||||
.dereference =>
|
||||
{
|
||||
#trap();
|
||||
analyze_type(module, unary_value, zero, { .must_be_constant = analysis.must_be_constant, zero });
|
||||
if (value.kind == .left)
|
||||
{
|
||||
report_error();
|
||||
}
|
||||
>pointer_type = unary_value.type;
|
||||
assert(pointer_type.id == .pointer);
|
||||
>dereference_type = pointer_type.content.pointer.element_type;
|
||||
|
||||
typecheck(module, expected_type, dereference_type);
|
||||
value_type = dereference_type;
|
||||
},
|
||||
.int_from_enum =>
|
||||
{
|
||||
@ -5533,6 +5705,24 @@ analyze_type = fn (module: &Module, value: &Value, expected_type: &Type, analysi
|
||||
|
||||
typecheck(module, expected_type, value_type);
|
||||
},
|
||||
// TODO: this is the default case
|
||||
.ampersand
|
||||
=>
|
||||
{
|
||||
>is_boolean = unary_is_boolean(unary_id);
|
||||
if (is_boolean)
|
||||
{
|
||||
analyze_type(module, unary_value, zero, { .must_be_constant = analysis.must_be_constant, zero });
|
||||
value_type = uint1(module);
|
||||
}
|
||||
else
|
||||
{
|
||||
analyze_type(module, unary_value, expected_type, { .must_be_constant = analysis.must_be_constant, zero });
|
||||
value_type = unary_value.type;
|
||||
}
|
||||
|
||||
typecheck(module, expected_type, value_type);
|
||||
},
|
||||
else =>
|
||||
{
|
||||
// TODO
|
||||
@ -5607,6 +5797,93 @@ analyze_type = fn (module: &Module, value: &Value, expected_type: &Type, analysi
|
||||
|
||||
typecheck(module, expected_type, value_type);
|
||||
},
|
||||
.call =>
|
||||
{
|
||||
>call = &value.content.call;
|
||||
>callable = call.callable;
|
||||
analyze_type(module, callable, zero, { .must_be_constant = analysis.must_be_constant, zero });
|
||||
|
||||
>function_type: &Type = zero;
|
||||
|
||||
switch (callable.id)
|
||||
{
|
||||
.variable =>
|
||||
{
|
||||
>variable = callable.content.variable;
|
||||
>variable_type = variable.type;
|
||||
|
||||
switch (variable_type.id)
|
||||
{
|
||||
.function =>
|
||||
{
|
||||
function_type = variable_type;
|
||||
},
|
||||
.pointer =>
|
||||
{
|
||||
>element_type = resolve_alias(module, variable_type.content.pointer.element_type);
|
||||
|
||||
switch (element_type.id)
|
||||
{
|
||||
.function =>
|
||||
{
|
||||
function_type = element_type;
|
||||
},
|
||||
else => { report_error(); },
|
||||
}
|
||||
},
|
||||
else =>
|
||||
{
|
||||
report_error();
|
||||
},
|
||||
}
|
||||
},
|
||||
else =>
|
||||
{
|
||||
report_error();
|
||||
},
|
||||
}
|
||||
|
||||
assert(function_type != zero);
|
||||
assert(function_type.id == .function);
|
||||
call.function_type = function_type;
|
||||
|
||||
>semantic_argument_types = function_type.content.function.base.semantic_argument_types;
|
||||
>call_arguments = call.arguments;
|
||||
|
||||
if (function_type.content.function.base.is_variable_argument)
|
||||
{
|
||||
if (call_arguments.length < semantic_argument_types.length)
|
||||
{
|
||||
report_error();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (call_arguments.length != semantic_argument_types.length)
|
||||
{
|
||||
report_error();
|
||||
}
|
||||
}
|
||||
|
||||
for (i: 0..semantic_argument_types.length)
|
||||
{
|
||||
>argument_type = semantic_argument_types[i];
|
||||
>call_argument = call_arguments[i];
|
||||
analyze_type(module, call_argument, argument_type, { .must_be_constant = analysis.must_be_constant, zero });
|
||||
check_types(module, argument_type, call_argument.type);
|
||||
}
|
||||
|
||||
for (i: semantic_argument_types.length..call_arguments.length)
|
||||
{
|
||||
>call_argument = call_arguments[i];
|
||||
analyze_type(module, call_argument, zero, { .must_be_constant = analysis.must_be_constant, zero });
|
||||
}
|
||||
|
||||
>semantic_return_type = function_type.content.function.base.semantic_return_type;
|
||||
|
||||
typecheck(module, expected_type, semantic_return_type);
|
||||
value_type = semantic_return_type;
|
||||
},
|
||||
else =>
|
||||
{
|
||||
#trap();
|
||||
@ -5728,6 +6005,239 @@ emit_binary = fn (module: &Module, left: &LLVMValue, left_type: &Type, right: &L
|
||||
}
|
||||
}
|
||||
|
||||
type_is_abi_equal = fn (module: &Module, a: &Type, b: &Type) u1
|
||||
{
|
||||
resolve_type_in_place(module, a);
|
||||
resolve_type_in_place(module, b);
|
||||
|
||||
>result = a == b;
|
||||
if (!result)
|
||||
{
|
||||
result = a.llvm.abi == b.llvm.abi;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
emit_call = fn (module: &Module, value: &Value, left_llvm: &LLVMValue, left_type: &Type) &LLVMValue
|
||||
{
|
||||
assert(value.id == .call);
|
||||
|
||||
>call = &value.content.call;
|
||||
|
||||
>raw_function_type = call.function_type;
|
||||
>callable = call.callable;
|
||||
>call_arguments = call.arguments;
|
||||
|
||||
>llvm_callable: &LLVMValue = zero;
|
||||
|
||||
switch (callable.id)
|
||||
{
|
||||
.variable =>
|
||||
{
|
||||
>variable = callable.content.variable;
|
||||
>variable_type = variable.type;
|
||||
>llvm_value = variable.storage.llvm;
|
||||
|
||||
switch (variable_type.id)
|
||||
{
|
||||
.pointer =>
|
||||
{
|
||||
>element_type = resolve_alias(module, variable_type.content.pointer.element_type);
|
||||
|
||||
switch (element_type.id)
|
||||
{
|
||||
.function =>
|
||||
{
|
||||
llvm_callable = create_load(module, {
|
||||
.type = get_pointer_type(module, raw_function_type),
|
||||
.pointer = llvm_value,
|
||||
zero,
|
||||
});
|
||||
},
|
||||
else => { report_error(); },
|
||||
}
|
||||
},
|
||||
.function => { llvm_callable = llvm_value; },
|
||||
}
|
||||
},
|
||||
else => { report_error(); },
|
||||
}
|
||||
|
||||
assert(llvm_callable != zero);
|
||||
|
||||
>llvm_abi_argument_value_buffer: [64]&LLVMValue = undefined;
|
||||
>llvm_abi_argument_type_buffer: [64]&LLVMType = undefined;
|
||||
>abi_argument_type_buffer: [64]&Type = undefined;
|
||||
>argument_abi_buffer: [64]AbiInformation = undefined;
|
||||
>llvm_abi_argument_type_buffer_slice = llvm_abi_argument_type_buffer[..];
|
||||
>abi_argument_type_buffer_slice = abi_argument_type_buffer[..];
|
||||
|
||||
>abi_argument_count: u16 = 0;
|
||||
|
||||
>uses_in_alloca: u1 = 0;
|
||||
if (uses_in_alloca)
|
||||
{
|
||||
#trap();
|
||||
}
|
||||
|
||||
>llvm_indirect_return_value: &LLVMValue = zero;
|
||||
|
||||
>return_abi = &raw_function_type.content.function.abi.return_abi;
|
||||
>return_abi_kind = return_abi.flags.kind;
|
||||
|
||||
switch (return_abi_kind)
|
||||
{
|
||||
.indirect,
|
||||
.in_alloca,
|
||||
.coerce_and_expand,
|
||||
=>
|
||||
{
|
||||
#trap();
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
|
||||
>available_registers = raw_function_type.content.function.abi.available_registers;
|
||||
>declaration_semantic_argument_types = raw_function_type.content.function.base.semantic_argument_types;
|
||||
|
||||
for (call_argument_index: 0..call_arguments.length)
|
||||
{
|
||||
>is_named_argument = call_argument_index < declaration_semantic_argument_types.length;
|
||||
>semantic_call_argument_value = call_arguments[call_argument_index];
|
||||
|
||||
>semantic_argument_type: &Type = undefined;
|
||||
>argument_abi: AbiInformation = undefined;
|
||||
|
||||
if (is_named_argument)
|
||||
{
|
||||
argument_abi = raw_function_type.content.function.abi.argument_abis[call_argument_index];
|
||||
semantic_argument_type = argument_abi.semantic_type;
|
||||
}
|
||||
else
|
||||
{
|
||||
#trap();
|
||||
}
|
||||
|
||||
assert(semantic_argument_type != zero);
|
||||
|
||||
resolve_type_in_place(module, semantic_argument_type);
|
||||
|
||||
if (is_named_argument)
|
||||
{
|
||||
// TODO: better slice single statement
|
||||
>llvm_abi_argument_types = llvm_abi_argument_type_buffer_slice[#extend(argument_abi.abi_start)..#extend(argument_abi.abi_start + argument_abi.abi_count)];
|
||||
>destination_abi_argument_types = abi_argument_type_buffer_slice[#extend(argument_abi.abi_start)..#extend(argument_abi.abi_start + argument_abi.abi_count)];
|
||||
>source_abi_argument_types = raw_function_type.content.function.abi.abi_argument_types[#extend(argument_abi.abi_start)..#extend(argument_abi.abi_start + argument_abi.abi_count)];
|
||||
|
||||
for (i: 0..argument_abi.abi_count)
|
||||
{
|
||||
llvm_abi_argument_types[i] = source_abi_argument_types[i].llvm.abi;
|
||||
destination_abi_argument_types[i] = source_abi_argument_types[i];
|
||||
}
|
||||
}
|
||||
|
||||
argument_abi_buffer[call_argument_index] = argument_abi;
|
||||
|
||||
if (argument_abi.padding.type != zero)
|
||||
{
|
||||
#trap();
|
||||
}
|
||||
|
||||
assert(abi_argument_count == argument_abi.abi_start);
|
||||
|
||||
switch (argument_abi.flags.kind)
|
||||
{
|
||||
.direct,
|
||||
.extend,
|
||||
=>
|
||||
{
|
||||
#trap();
|
||||
},
|
||||
.indirect,
|
||||
.indirect_aliased,
|
||||
=>
|
||||
{
|
||||
#trap();
|
||||
},
|
||||
.ignore => { unreachable; },
|
||||
else => { #trap(); }, // TODO
|
||||
}
|
||||
|
||||
// TODO: uncomment this
|
||||
//assert(abi_argument_count == #extend(argument_abi.abi_start + argument_abi.abi_count));
|
||||
}
|
||||
|
||||
>declaration_abi_argument_types = raw_function_type.content.function.abi.abi_argument_types;
|
||||
|
||||
if (raw_function_type.content.function.base.is_variable_argument)
|
||||
{
|
||||
assert(declaration_abi_argument_types.length <= #extend(abi_argument_count));
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(declaration_abi_argument_types.length == #extend(abi_argument_count));
|
||||
}
|
||||
|
||||
assert(raw_function_type.llvm.abi != zero);
|
||||
|
||||
>llvm_call = LLVMBuildCall2(module.llvm.builder, raw_function_type.llvm.abi, llvm_callable, &llvm_abi_argument_value_buffer[0], #extend(abi_argument_count), "");
|
||||
>llvm_calling_convention: LLVMCallingConvention = undefined;
|
||||
switch (raw_function_type.content.function.base.calling_convention)
|
||||
{
|
||||
.c => { llvm_calling_convention = .c; },
|
||||
}
|
||||
|
||||
LLVMSetInstructionCallConv(llvm_call, llvm_calling_convention);
|
||||
|
||||
>argument_abis = argument_abi_buffer[..call_arguments.length];
|
||||
|
||||
emit_attributes(module, llvm_call, &LLVMAddCallSiteAttribute, {
|
||||
.return_abi = return_abi,
|
||||
.argument_abis = argument_abis,
|
||||
.abi_argument_types = abi_argument_type_buffer[..#extend(abi_argument_count)],
|
||||
.abi_return_type = raw_function_type.content.function.abi.abi_return_type,
|
||||
.attributes = zero,
|
||||
});
|
||||
|
||||
switch (return_abi_kind)
|
||||
{
|
||||
.ignore =>
|
||||
{
|
||||
assert(return_abi.semantic_type == noreturn_type(module) or return_abi.semantic_type == void_type(module));
|
||||
return llvm_call;
|
||||
},
|
||||
.direct,
|
||||
.extend,
|
||||
=>
|
||||
{
|
||||
>coerce_to_type = abi_get_coerce_to_type(return_abi);
|
||||
|
||||
if (return_abi.attributes.direct.offset == 0 and type_is_abi_equal(module, return_abi.semantic_type, coerce_to_type))
|
||||
{
|
||||
>evaluation_kind = get_evaluation_kind(coerce_to_type);
|
||||
|
||||
switch (evaluation_kind)
|
||||
{
|
||||
.scalar => { return llvm_call; },
|
||||
.aggregate => {},
|
||||
.complex => { unreachable; },
|
||||
}
|
||||
|
||||
#trap();
|
||||
}
|
||||
|
||||
#trap();
|
||||
},
|
||||
.indirect =>
|
||||
{
|
||||
assert(llvm_indirect_return_value != zero);
|
||||
return llvm_indirect_return_value;
|
||||
},
|
||||
else => { unreachable; },
|
||||
}
|
||||
}
|
||||
|
||||
emit_value = fn (module: &Module, value: &Value, type_kind: TypeKind, expect_constant: u1) void
|
||||
{
|
||||
assert(value.type != zero);
|
||||
@ -5826,6 +6336,35 @@ emit_value = fn (module: &Module, value: &Value, type_kind: TypeKind, expect_con
|
||||
|
||||
llvm_value = LLVMBuildTrunc(module.llvm.builder, llvm_unary_value, destination_type, "");
|
||||
},
|
||||
.ampersand =>
|
||||
{
|
||||
assert(resolved_value_type == resolved_unary_type);
|
||||
llvm_value = llvm_unary_value;
|
||||
},
|
||||
.dereference =>
|
||||
{
|
||||
switch (value.kind)
|
||||
{
|
||||
.right =>
|
||||
{
|
||||
>pointer_type = unary_value.type;
|
||||
assert(pointer_type.id == .pointer);
|
||||
>child_type = resolve_alias(module, pointer_type.content.pointer.element_type);
|
||||
assert(child_type == resolved_value_type);
|
||||
>load = create_load(module, {
|
||||
.type = child_type,
|
||||
.pointer = unary_value.llvm,
|
||||
.kind = type_kind,
|
||||
zero,
|
||||
});
|
||||
llvm_value = load;
|
||||
},
|
||||
.left =>
|
||||
{
|
||||
#trap();
|
||||
}
|
||||
}
|
||||
},
|
||||
else => { #trap(); },
|
||||
}
|
||||
},
|
||||
@ -5921,6 +6460,10 @@ emit_value = fn (module: &Module, value: &Value, type_kind: TypeKind, expect_con
|
||||
},
|
||||
}
|
||||
},
|
||||
.call =>
|
||||
{
|
||||
llvm_value = emit_call(module, value, zero, zero);
|
||||
},
|
||||
else =>
|
||||
{
|
||||
#trap();
|
||||
@ -6179,20 +6722,6 @@ emit_block = fn (module: &Module, basic_block: &LLVMBasicBlock) void
|
||||
LLVMPositionBuilderAtEnd(module.llvm.builder, basic_block);
|
||||
}
|
||||
|
||||
type_is_abi_equal = fn (module: &Module, a: &Type, b: &Type) u1
|
||||
{
|
||||
resolve_type_in_place(module, a);
|
||||
resolve_type_in_place(module, b);
|
||||
|
||||
>result = a == b;
|
||||
if (!result)
|
||||
{
|
||||
result = a.llvm.abi == b.llvm.abi;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
LLVMObjectGenerate = struct
|
||||
{
|
||||
path: []u8,
|
||||
@ -6624,7 +7153,7 @@ emit = fn (module: &Module) void
|
||||
LLVMSetFunctionCallConv(llvm_function, llvm_calling_convention);
|
||||
|
||||
emit_attributes(module, llvm_function, &LLVMAddAttributeAtIndex, {
|
||||
.return_abi = function_type.abi.return_abi,
|
||||
.return_abi = &function_type.abi.return_abi,
|
||||
.argument_abis = function_type.abi.argument_abis,
|
||||
.abi_argument_types = function_type.abi.abi_argument_types,
|
||||
.abi_return_type = function_type.abi.abi_return_type,
|
||||
@ -7184,6 +7713,15 @@ names: [_][]u8 = [
|
||||
"extend",
|
||||
"integer_max",
|
||||
"integer_hex",
|
||||
"basic_pointer",
|
||||
"basic_call",
|
||||
"basic_branch",
|
||||
"basic_array",
|
||||
"basic_enum",
|
||||
"basic_slice",
|
||||
"basic_string",
|
||||
"basic_varargs",
|
||||
"basic_while",
|
||||
];
|
||||
|
||||
[export] main = fn [cc(c)] (argument_count: u32, argv: &&u8, envp: &&u8) s32
|
||||
|
@ -5081,11 +5081,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);
|
||||
|
||||
if (is_named_argument)
|
||||
@ -8621,8 +8616,10 @@ fn void analyze_statement(Module* module, Scope* scope, Statement* statement, u3
|
||||
LLVMValueRef indices[] = {
|
||||
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, {
|
||||
.type = aggregate_type->structure.fields[0].type->pointer.element_type->llvm.memory,
|
||||
.type = gep_type->llvm.memory,
|
||||
.pointer = extract_pointer,
|
||||
.indices = array_to_slice(indices),
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user