Basic call with no arguments
All checks were successful
CI / ci (ReleaseFast, ubuntu-latest) (pull_request) Successful in 36s
CI / ci (ReleaseSmall, ubuntu-latest) (pull_request) Successful in 37s
CI / ci (ReleaseSafe, ubuntu-latest) (pull_request) Successful in 44s
CI / ci (Debug, ubuntu-latest) (pull_request) Successful in 58s
CI / ci (ReleaseFast, ubuntu-latest) (push) Successful in 33s
CI / ci (ReleaseSmall, ubuntu-latest) (push) Successful in 34s
CI / ci (ReleaseSafe, ubuntu-latest) (push) Successful in 40s
CI / ci (Debug, ubuntu-latest) (push) Successful in 55s

This commit is contained in:
David Gonzalez Martin 2025-04-09 12:29:54 +02:00
parent 3309329911
commit 143fa2d03b
2 changed files with 149 additions and 73 deletions

View File

@ -485,6 +485,11 @@ const Binary = struct {
}; };
}; };
pub const Call = struct {
callable: *Value,
arguments: []const *Value,
};
pub const Value = struct { pub const Value = struct {
bb: union(enum) { bb: union(enum) {
function: Function, function: Function,
@ -495,6 +500,7 @@ pub const Value = struct {
local, local,
intrinsic: Intrinsic, intrinsic: Intrinsic,
dereference: *Value, dereference: *Value,
call: Call,
}, },
type: ?*Type = null, type: ?*Type = null,
llvm: ?*llvm.Value = null, llvm: ?*llvm.Value = null,
@ -652,7 +658,7 @@ pub const Scope = struct {
column: u32, column: u32,
llvm: ?*llvm.DI.Scope = null, llvm: ?*llvm.DI.Scope = null,
kind: Kind, kind: Kind,
parent: ?*Scope = null, parent: ?*Scope,
pub const Kind = enum { pub const Kind = enum {
global, global,
@ -668,7 +674,7 @@ pub const LexicalBlock = struct {
}; };
pub const Function = struct { pub const Function = struct {
arguments: Local.Buffer, arguments: []*Local,
attributes: Attributes, attributes: Attributes,
main_block: *LexicalBlock, main_block: *LexicalBlock,
scope: Scope, scope: Scope,
@ -1707,10 +1713,24 @@ pub const Module = struct {
const variable = blk: while (scope_it) |scope| : (scope_it = scope.parent) { const variable = blk: while (scope_it) |scope| : (scope_it = scope.parent) {
switch (scope.kind) { switch (scope.kind) {
.global => { .global => {
@trap(); const m: *Module = @fieldParentPtr("scope", scope);
assert(m == module);
for (module.globals.get_slice()) |*global| {
if (lib.string.equal(global.variable.name, identifier)) {
break :blk &global.variable;
}
}
assert(scope.parent == null);
}, },
.function => { .function => {
@trap(); const function: *Function = @fieldParentPtr("scope", scope);
for (function.arguments) |argument| {
if (lib.string.equal(argument.variable.name, identifier)) {
break :blk &argument.variable;
}
}
assert(scope.parent != null);
}, },
.local => { .local => {
const block: *LexicalBlock = @fieldParentPtr("scope", scope); const block: *LexicalBlock = @fieldParentPtr("scope", scope);
@ -1719,6 +1739,7 @@ pub const Module = struct {
break :blk &local.variable; break :blk &local.variable;
} }
} }
assert(scope.parent != null);
}, },
} }
} else { } else {
@ -1886,9 +1907,41 @@ pub const Module = struct {
} }
fn rule_after_call(noalias module: *Module, value_builder: Value.Builder) *Value { fn rule_after_call(noalias module: *Module, value_builder: Value.Builder) *Value {
_ = module; const may_be_callable = value_builder.left orelse module.report_error();
_ = value_builder; assert(value_builder.token == .@"(");
@trap(); var semantic_argument_count: u32 = 0;
_ = &semantic_argument_count;
var semantic_argument_buffer: [64]*Value = undefined;
_ = &semantic_argument_buffer;
while (true) {
module.skip_space();
if (module.consume_character_if_match(right_parenthesis)) {
break;
}
// const argument = module.parse_value(.{});
// const argument_index = semantic_argument_count;
// semantic_argument_buffer[argument_index] = argument;
// semantic_argument_count = argument_index + 1;
@trap();
}
const arguments: []const *Value = if (semantic_argument_count != 0) {
@trap();
} else &.{};
const call = module.values.add();
call.* = .{
.bb = .{
.call = .{
.arguments = arguments,
.callable = may_be_callable,
},
},
};
return call;
} }
pub fn get_anonymous_struct_pair(module: *Module, pair: [2]*Type) *Type { pub fn get_anonymous_struct_pair(module: *Module, pair: [2]*Type) *Type {
@ -2070,12 +2123,13 @@ pub const Module = struct {
storage.bb = .{ storage.bb = .{
.function = .{ .function = .{
.main_block = undefined, .main_block = undefined,
.arguments = .initialize(), .arguments = &.{},
.attributes = .{}, .attributes = .{},
.scope = .{ .scope = .{
.kind = .function, .kind = .function,
.line = global_line, .line = global_line,
.column = global_column, .column = global_column,
.parent = &module.scope,
}, },
}, },
}; };
@ -2157,7 +2211,7 @@ pub const Module = struct {
switch (global.variable.storage.?.bb) { switch (global.variable.storage.?.bb) {
.function => { .function => {
const function_type = &global.variable.storage.?.type.?.bb.pointer.type.bb.function; const function_type = &global.variable.storage.?.type.?.bb.pointer.type.bb.function;
const argument_variables = global.variable.storage.?.bb.function.arguments.get_slice(); const argument_variables = global.variable.storage.?.bb.function.arguments;
function_type.argument_abis = module.arena.allocate(Abi.Information, argument_variables.len); function_type.argument_abis = module.arena.allocate(Abi.Information, argument_variables.len);
const resolved_calling_convention = function_type.calling_convention.resolve(module.target); const resolved_calling_convention = function_type.calling_convention.resolve(module.target);
@ -2323,7 +2377,7 @@ pub const Module = struct {
//semantic_arguments, //semantic_arguments,
function_type.argument_abis, argument_variables, 0..) | function_type.argument_abis, argument_variables, 0..) |
//semantic_argument, //semantic_argument,
argument_abi, *argument_variable, argument_index| { argument_abi, argument_variable, argument_index| {
const abi_arguments = llvm_abi_arguments[argument_abi.abi_start..][0..argument_abi.abi_count]; const abi_arguments = llvm_abi_arguments[argument_abi.abi_start..][0..argument_abi.abi_count];
assert(argument_abi.flags.kind == .ignore or argument_abi.abi_count != 0); assert(argument_abi.flags.kind == .ignore or argument_abi.abi_count != 0);
const argument_abi_kind = argument_abi.flags.kind; const argument_abi_kind = argument_abi.flags.kind;
@ -2796,6 +2850,19 @@ pub const Module = struct {
}; };
break :blk result; break :blk result;
}, },
.call => |call| blk: {
const llvm_callable = switch (call.callable.bb) {
.variable_reference => |variable| variable.storage.?.llvm.?,
else => @trap(),
};
const function_type = switch (call.callable.bb) {
.variable_reference => |variable| variable.storage.?.type.?.bb.pointer.type,
else => @trap(),
};
const llvm_function_type = function_type.resolve(module).handle;
const llvm_call = module.llvm.builder.create_call(llvm_function_type.to_function(), llvm_callable, &.{});
break :blk llvm_call;
},
else => @trap(), else => @trap(),
}; };
@ -2807,9 +2874,9 @@ pub const Module = struct {
assert(value.llvm == null); assert(value.llvm == null);
// If a result type exists, then do the analysis against it // If a result type exists, then do the analysis against it
if (analysis.type) |expected_type| switch (expected_type.bb) { if (analysis.type) |expected_type| switch (value.bb) {
.integer => |integer| switch (value.bb) { .constant_integer => |constant_integer| switch (expected_type.bb) {
.constant_integer => |constant_integer| switch (constant_integer.signed) { .integer => |integer| switch (constant_integer.signed) {
true => { true => {
if (!integer.signed) { if (!integer.signed) {
module.report_error(); module.report_error();
@ -2826,75 +2893,81 @@ pub const Module = struct {
} }
}, },
}, },
.unary => |unary| { else => @trap(),
switch (unary.id) { },
.@"+" => @trap(), .unary => |unary| {
.@"-" => { switch (unary.id) {
module.analyze_value_type(function, unary.value, analysis); .@"+" => @trap(),
if (!unary.value.type.?.is_signed()) { .@"-" => {
module.report_error(); module.analyze_value_type(function, unary.value, analysis);
} if (!unary.value.type.?.is_signed()) {
assert(expected_type == unary.value.type);
},
.@"&" => @trap(),
}
},
.binary => |binary| {
const is_boolean = binary.id.is_boolean();
const boolean_type = module.integer_type(1, false);
if (is_boolean and expected_type != boolean_type) {
module.report_error();
}
module.analyze_value_type(function, binary.left, .{
.type = if (is_boolean) null else expected_type,
});
module.analyze_value_type(function, binary.right, .{
.type = binary.left.type,
});
},
.variable_reference => |variable| {
if (variable.type != expected_type) {
module.report_error();
}
},
.intrinsic => |intrinsic| switch (intrinsic) {
.extend => |extended_value| {
module.analyze_value_type(function, extended_value, .{});
assert(extended_value.type != null);
const destination_type = expected_type;
const source_type = extended_value.type.?;
if (source_type.get_bit_size() > destination_type.get_bit_size()) {
module.report_error();
} else if (source_type.get_bit_size() == destination_type.get_bit_size() and source_type.is_signed() == destination_type.is_signed()) {
module.report_error(); module.report_error();
} }
assert(expected_type == unary.value.type);
}, },
.truncate => |value_to_truncate| { .@"&" => @trap(),
module.analyze_value_type(function, value_to_truncate, .{}); }
if (expected_type.get_bit_size() >= value_to_truncate.type.?.get_bit_size()) { },
module.report_error(); .binary => |binary| {
} const is_boolean = binary.id.is_boolean();
},
else => @trap(), const boolean_type = module.integer_type(1, false);
},
.dereference => |dereferenceable_value| { if (is_boolean and expected_type != boolean_type) {
module.analyze_value_type(function, dereferenceable_value, .{}); module.report_error();
if (dereferenceable_value.type.?.bb != .pointer) { }
module.analyze_value_type(function, binary.left, .{
.type = if (is_boolean) null else expected_type,
});
module.analyze_value_type(function, binary.right, .{
.type = binary.left.type,
});
},
.variable_reference => |variable| {
if (variable.type != expected_type) {
module.report_error();
}
},
.intrinsic => |intrinsic| switch (intrinsic) {
.extend => |extended_value| {
module.analyze_value_type(function, extended_value, .{});
assert(extended_value.type != null);
const destination_type = expected_type;
const source_type = extended_value.type.?;
if (source_type.get_bit_size() > destination_type.get_bit_size()) {
module.report_error();
} else if (source_type.get_bit_size() == destination_type.get_bit_size() and source_type.is_signed() == destination_type.is_signed()) {
module.report_error(); module.report_error();
} }
},
if (dereferenceable_value.type.?.bb.pointer.type != expected_type) { .truncate => |value_to_truncate| {
module.analyze_value_type(function, value_to_truncate, .{});
if (expected_type.get_bit_size() >= value_to_truncate.type.?.get_bit_size()) {
module.report_error(); module.report_error();
} }
}, },
else => @trap(), else => @trap(),
}, },
.dereference => |dereferenceable_value| {
module.analyze_value_type(function, dereferenceable_value, .{});
if (dereferenceable_value.type.?.bb != .pointer) {
module.report_error();
}
if (dereferenceable_value.type.?.bb.pointer.type != expected_type) {
module.report_error();
}
},
.call => |call| {
module.analyze_value_type(function, call.callable, .{});
for (call.arguments) |argument| {
module.analyze_value_type(function, argument, .{});
}
},
else => @trap(), else => @trap(),
}; };
@ -4352,6 +4425,7 @@ pub fn compile(arena: *Arena, options: Options) void {
.kind = .global, .kind = .global,
.column = 0, .column = 0,
.line = 0, .line = 0,
.parent = null,
}, },
.name = options.name, .name = options.name,
.path = options.path, .path = options.path,

View File

@ -188,8 +188,10 @@ const names = &[_][]const u8{
"minimal_stack_arithmetic3", "minimal_stack_arithmetic3",
"extend", "extend",
"stack_negation", "stack_negation",
"basic_pointer", "stack_add",
"integer_max", "integer_max",
"integer_hex", "integer_hex",
"basic_pointer",
"basic_call",
// "pointer", // "pointer",
}; };