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 {
bb: union(enum) {
function: Function,
@ -495,6 +500,7 @@ pub const Value = struct {
local,
intrinsic: Intrinsic,
dereference: *Value,
call: Call,
},
type: ?*Type = null,
llvm: ?*llvm.Value = null,
@ -652,7 +658,7 @@ pub const Scope = struct {
column: u32,
llvm: ?*llvm.DI.Scope = null,
kind: Kind,
parent: ?*Scope = null,
parent: ?*Scope,
pub const Kind = enum {
global,
@ -668,7 +674,7 @@ pub const LexicalBlock = struct {
};
pub const Function = struct {
arguments: Local.Buffer,
arguments: []*Local,
attributes: Attributes,
main_block: *LexicalBlock,
scope: Scope,
@ -1707,10 +1713,24 @@ pub const Module = struct {
const variable = blk: while (scope_it) |scope| : (scope_it = scope.parent) {
switch (scope.kind) {
.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 => {
@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 => {
const block: *LexicalBlock = @fieldParentPtr("scope", scope);
@ -1719,6 +1739,7 @@ pub const Module = struct {
break :blk &local.variable;
}
}
assert(scope.parent != null);
},
}
} else {
@ -1886,9 +1907,41 @@ pub const Module = struct {
}
fn rule_after_call(noalias module: *Module, value_builder: Value.Builder) *Value {
_ = module;
_ = value_builder;
@trap();
const may_be_callable = value_builder.left orelse module.report_error();
assert(value_builder.token == .@"(");
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 {
@ -2070,12 +2123,13 @@ pub const Module = struct {
storage.bb = .{
.function = .{
.main_block = undefined,
.arguments = .initialize(),
.arguments = &.{},
.attributes = .{},
.scope = .{
.kind = .function,
.line = global_line,
.column = global_column,
.parent = &module.scope,
},
},
};
@ -2157,7 +2211,7 @@ pub const Module = struct {
switch (global.variable.storage.?.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);
const resolved_calling_convention = function_type.calling_convention.resolve(module.target);
@ -2323,7 +2377,7 @@ pub const Module = struct {
//semantic_arguments,
function_type.argument_abis, argument_variables, 0..) |
//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];
assert(argument_abi.flags.kind == .ignore or argument_abi.abi_count != 0);
const argument_abi_kind = argument_abi.flags.kind;
@ -2796,6 +2850,19 @@ pub const Module = struct {
};
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(),
};
@ -2807,9 +2874,9 @@ pub const Module = struct {
assert(value.llvm == null);
// If a result type exists, then do the analysis against it
if (analysis.type) |expected_type| switch (expected_type.bb) {
.integer => |integer| switch (value.bb) {
.constant_integer => |constant_integer| switch (constant_integer.signed) {
if (analysis.type) |expected_type| switch (value.bb) {
.constant_integer => |constant_integer| switch (expected_type.bb) {
.integer => |integer| switch (constant_integer.signed) {
true => {
if (!integer.signed) {
module.report_error();
@ -2826,75 +2893,81 @@ pub const Module = struct {
}
},
},
.unary => |unary| {
switch (unary.id) {
.@"+" => @trap(),
.@"-" => {
module.analyze_value_type(function, unary.value, analysis);
if (!unary.value.type.?.is_signed()) {
module.report_error();
}
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()) {
else => @trap(),
},
.unary => |unary| {
switch (unary.id) {
.@"+" => @trap(),
.@"-" => {
module.analyze_value_type(function, unary.value, analysis);
if (!unary.value.type.?.is_signed()) {
module.report_error();
}
assert(expected_type == unary.value.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();
}
},
else => @trap(),
},
.dereference => |dereferenceable_value| {
module.analyze_value_type(function, dereferenceable_value, .{});
if (dereferenceable_value.type.?.bb != .pointer) {
.@"&" => @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();
}
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();
}
},
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(),
};
@ -4352,6 +4425,7 @@ pub fn compile(arena: *Arena, options: Options) void {
.kind = .global,
.column = 0,
.line = 0,
.parent = null,
},
.name = options.name,
.path = options.path,

View File

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