Basic call
This commit is contained in:
parent
e63649bdda
commit
27bd136487
30
src/LLVM.zig
30
src/LLVM.zig
@ -636,6 +636,10 @@ pub const Builder = opaque {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub const create_conditional_branch = api.LLVMBuildCondBr;
|
pub const create_conditional_branch = api.LLVMBuildCondBr;
|
||||||
|
|
||||||
|
pub fn create_call(builder: *Builder, function_type: *Type.Function, function_value: *Value, arguments: []const *Value) *Value {
|
||||||
|
return api.LLVMBuildCall2(builder, function_type, function_value, arguments.ptr, @intCast(arguments.len), "");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const GlobalValue = opaque {
|
pub const GlobalValue = opaque {
|
||||||
@ -699,10 +703,32 @@ pub const Value = opaque {
|
|||||||
return api.LLVMIsConstant(value) != 0;
|
return api.LLVMIsConstant(value) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const is_instruction = api.llvm_value_is_instruction;
|
||||||
|
|
||||||
pub fn to_constant(value: *Value) *Constant {
|
pub fn to_constant(value: *Value) *Constant {
|
||||||
assert(value.is_constant());
|
assert(value.is_constant());
|
||||||
return @ptrCast(value);
|
return @ptrCast(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn to_instruction(value: *Value) *Instruction {
|
||||||
|
assert(value.is_instruction());
|
||||||
|
return @ptrCast(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_calling_convention(value: *Value) CallingConvention {
|
||||||
|
if (value.is_instruction()) {
|
||||||
|
const instruction = value.to_instruction();
|
||||||
|
return instruction.get_calling_convention();
|
||||||
|
} else {
|
||||||
|
const function = @as(*Function, @ptrCast(value));
|
||||||
|
return function.get_calling_convention();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Instruction = opaque {
|
||||||
|
pub const set_calling_convention = api.LLVMSetInstructionCallConv;
|
||||||
|
pub const get_calling_convention = api.LLVMGetInstructionCallConv;
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const DI = struct {
|
pub const DI = struct {
|
||||||
@ -827,6 +853,7 @@ pub const DI = struct {
|
|||||||
pub const Type = opaque {
|
pub const Type = opaque {
|
||||||
pub const is_function = api.llvm_type_is_function;
|
pub const is_function = api.llvm_type_is_function;
|
||||||
pub const is_integer = api.llvm_type_is_integer;
|
pub const is_integer = api.llvm_type_is_integer;
|
||||||
|
|
||||||
pub fn to_function(t: *Type) *Type.Function {
|
pub fn to_function(t: *Type) *Type.Function {
|
||||||
assert(t.is_function());
|
assert(t.is_function());
|
||||||
return @ptrCast(t);
|
return @ptrCast(t);
|
||||||
@ -1260,8 +1287,7 @@ pub fn link(arena: *Arena, options: LinkOptions) lld.Result {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (link_libc) {
|
if (link_libc) {
|
||||||
const scrt1_path = arena.join_string(&.{ scrt1_object_directory_path, "/Scrt1.o" });
|
arg_builder.add(arena.join_string(&.{ scrt1_object_directory_path, "/", "Scrt1.o" }));
|
||||||
arg_builder.add(scrt1_path);
|
|
||||||
arg_builder.add("-lc");
|
arg_builder.add("-lc");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -474,7 +474,19 @@ const Converter = struct {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
converter.report_error();
|
converter.skip_space();
|
||||||
|
|
||||||
|
if (converter.consume_character_if_match(left_parenthesis)) {
|
||||||
|
// This is a call
|
||||||
|
const variable = if (function.locals.find(statement_start_identifier)) |local| local else if (module.globals.find(statement_start_identifier)) |global| global else {
|
||||||
|
converter.report_error();
|
||||||
|
};
|
||||||
|
const call = thread.builder.create_call(variable.type.get().to_function(), variable.storage, &.{});
|
||||||
|
_ = call;
|
||||||
|
@trap();
|
||||||
|
} else {
|
||||||
|
converter.report_error();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
converter.report_error();
|
converter.report_error();
|
||||||
@ -688,7 +700,20 @@ const Converter = struct {
|
|||||||
converter.report_error();
|
converter.report_error();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
break :b thread.builder.create_load(variable.type.get(), variable.storage);
|
|
||||||
|
converter.skip_space();
|
||||||
|
|
||||||
|
if (converter.consume_character_if_match(left_parenthesis)) {
|
||||||
|
// TODO: arguments
|
||||||
|
converter.skip_space();
|
||||||
|
converter.expect_character(right_parenthesis);
|
||||||
|
const call = thread.builder.create_call(variable.type.get().to_function(), variable.storage, &.{});
|
||||||
|
call.to_instruction().set_calling_convention(variable.storage.get_calling_convention());
|
||||||
|
break :b call;
|
||||||
|
} else {
|
||||||
|
const load = thread.builder.create_load(variable.type.get(), variable.storage);
|
||||||
|
break :b load;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
converter.report_error();
|
converter.report_error();
|
||||||
}
|
}
|
||||||
|
@ -20,35 +20,16 @@ fn invoke(name: []const u8) !void {
|
|||||||
defer tmp_dir.cleanup();
|
defer tmp_dir.cleanup();
|
||||||
const base_path = lib.global.arena.join_string(&.{ ".zig-cache/tmp/", &tmp_dir.sub_path, "/", name });
|
const base_path = lib.global.arena.join_string(&.{ ".zig-cache/tmp/", &tmp_dir.sub_path, "/", name });
|
||||||
const executable_path = base_path;
|
const executable_path = base_path;
|
||||||
invoke_wrapper(.{
|
const directory_path = lib.global.arena.join_string(&.{ ".zig-cache/tmp/", &tmp_dir.sub_path });
|
||||||
|
try unit_test(allocator, .{
|
||||||
.object_path = lib.global.arena.join_string(&.{ base_path, ".o" }),
|
.object_path = lib.global.arena.join_string(&.{ base_path, ".o" }),
|
||||||
.executable_path = executable_path,
|
.executable_path = executable_path,
|
||||||
.file_path = lib.global.arena.join_string(&.{ "tests/", name, ".bbb" }),
|
.file_path = lib.global.arena.join_string(&.{ "tests/", name, ".bbb" }),
|
||||||
.name = name,
|
.name = name,
|
||||||
}, build_mode, has_debug_info);
|
.directory_path = directory_path,
|
||||||
const run_result = std.process.Child.run(.{
|
.build_mode = build_mode,
|
||||||
.allocator = allocator,
|
.has_debug_info = has_debug_info,
|
||||||
.argv = &.{executable_path},
|
});
|
||||||
}) catch |err| {
|
|
||||||
std.debug.print("error: {}\n", .{err});
|
|
||||||
const path = lib.global.arena.join_string(&.{ ".zig-cache/tmp/", &tmp_dir.sub_path });
|
|
||||||
const r = try std.process.Child.run(.{
|
|
||||||
.allocator = allocator,
|
|
||||||
.argv = &.{ "/usr/bin/ls", "-lasR", path },
|
|
||||||
.max_output_bytes = std.math.maxInt(usize),
|
|
||||||
});
|
|
||||||
defer allocator.free(r.stdout);
|
|
||||||
defer allocator.free(r.stderr);
|
|
||||||
std.debug.print("ls {s} {s}\n", .{ path, r.stdout });
|
|
||||||
return err;
|
|
||||||
};
|
|
||||||
const success = switch (run_result.term) {
|
|
||||||
.Exited => |exit_code| exit_code == 0,
|
|
||||||
else => false,
|
|
||||||
};
|
|
||||||
if (!success) {
|
|
||||||
return error.executable_failed_to_run_successfully;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -58,14 +39,12 @@ const InvokeWrapper = struct {
|
|||||||
object_path: [:0]const u8,
|
object_path: [:0]const u8,
|
||||||
file_path: [:0]const u8,
|
file_path: [:0]const u8,
|
||||||
name: []const u8,
|
name: []const u8,
|
||||||
|
build_mode: BuildMode,
|
||||||
|
has_debug_info: bool,
|
||||||
|
directory_path: [:0]const u8,
|
||||||
};
|
};
|
||||||
|
|
||||||
// We invoke a function with comptime parameters so it's easily visible in CI stack traces
|
fn unit_test(allocator: std.mem.Allocator, options: InvokeWrapper) !void {
|
||||||
fn invoke_wrapper(options: InvokeWrapper, comptime build_mode: BuildMode, comptime has_debug_info: bool) void {
|
|
||||||
return invoke_single(options, build_mode, has_debug_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn invoke_single(options: InvokeWrapper, build_mode: BuildMode, has_debug_info: bool) void {
|
|
||||||
const file_content = lib.file.read(lib.global.arena, options.file_path);
|
const file_content = lib.file.read(lib.global.arena, options.file_path);
|
||||||
|
|
||||||
converter.convert(.{
|
converter.convert(.{
|
||||||
@ -73,10 +52,34 @@ fn invoke_single(options: InvokeWrapper, build_mode: BuildMode, has_debug_info:
|
|||||||
.content = file_content,
|
.content = file_content,
|
||||||
.object = options.object_path,
|
.object = options.object_path,
|
||||||
.executable = options.executable_path,
|
.executable = options.executable_path,
|
||||||
.build_mode = build_mode,
|
.build_mode = options.build_mode,
|
||||||
.name = options.name,
|
.name = options.name,
|
||||||
.has_debug_info = has_debug_info,
|
.has_debug_info = options.has_debug_info,
|
||||||
});
|
});
|
||||||
|
const run_result = std.process.Child.run(.{
|
||||||
|
.allocator = allocator,
|
||||||
|
.argv = &.{options.executable_path},
|
||||||
|
}) catch |err| {
|
||||||
|
std.debug.print("error: {}\n", .{err});
|
||||||
|
const r = try std.process.Child.run(.{
|
||||||
|
.allocator = allocator,
|
||||||
|
.argv = &.{ "/usr/bin/ls", "-lasR", options.directory_path },
|
||||||
|
.max_output_bytes = std.math.maxInt(usize),
|
||||||
|
});
|
||||||
|
defer allocator.free(r.stdout);
|
||||||
|
defer allocator.free(r.stderr);
|
||||||
|
std.debug.print("ls {s} {s}\n", .{ options.directory_path, r.stdout });
|
||||||
|
return err;
|
||||||
|
};
|
||||||
|
|
||||||
|
const success = switch (run_result.term) {
|
||||||
|
.Exited => |exit_code| exit_code == 0,
|
||||||
|
else => false,
|
||||||
|
};
|
||||||
|
if (!success) {
|
||||||
|
std.debug.print("{}\n{}\n", .{ run_result, options });
|
||||||
|
return error.executable_failed_to_run_successfully;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn invsrc(src: std.builtin.SourceLocation) !void {
|
fn invsrc(src: std.builtin.SourceLocation) !void {
|
||||||
@ -146,3 +149,7 @@ test "global" {
|
|||||||
test "simple_branch" {
|
test "simple_branch" {
|
||||||
try invsrc(@src());
|
try invsrc(@src());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "basic_call" {
|
||||||
|
try invsrc(@src());
|
||||||
|
}
|
||||||
|
@ -53,6 +53,12 @@ EXPORT Module* llvm_context_create_module(LLVMContext& context, BBLLVMString nam
|
|||||||
return new Module(name.string_ref(), context);
|
return new Module(name.string_ref(), context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EXPORT bool llvm_value_is_instruction(Value* value)
|
||||||
|
{
|
||||||
|
auto result = isa<Instruction>(value);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
EXPORT bool llvm_type_is_function(const Type& type)
|
EXPORT bool llvm_type_is_function(const Type& type)
|
||||||
{
|
{
|
||||||
auto result = type.isFunctionTy();
|
auto result = type.isFunctionTy();
|
||||||
|
@ -17,6 +17,9 @@ pub extern fn LLVMGetBasicBlockTerminator(basic_block: *llvm.BasicBlock) ?*llvm.
|
|||||||
pub extern fn LLVMSetFunctionCallConv(function: *llvm.Function, calling_convention: llvm.CallingConvention) void;
|
pub extern fn LLVMSetFunctionCallConv(function: *llvm.Function, calling_convention: llvm.CallingConvention) void;
|
||||||
pub extern fn LLVMGetFunctionCallConv(function: *llvm.Function) llvm.CallingConvention;
|
pub extern fn LLVMGetFunctionCallConv(function: *llvm.Function) llvm.CallingConvention;
|
||||||
|
|
||||||
|
pub extern fn LLVMSetInstructionCallConv(instruction: *llvm.Instruction, calling_convention: llvm.CallingConvention) void;
|
||||||
|
pub extern fn LLVMGetInstructionCallConv(instruction: *llvm.Instruction) llvm.CallingConvention;
|
||||||
|
|
||||||
pub extern fn llvm_function_to_string(function: *llvm.Function) *llvm.String;
|
pub extern fn llvm_function_to_string(function: *llvm.Function) *llvm.String;
|
||||||
pub extern fn llvm_function_verify(function: *llvm.Function, error_message: *llvm.String) bool;
|
pub extern fn llvm_function_verify(function: *llvm.Function, error_message: *llvm.String) bool;
|
||||||
pub extern fn llvm_module_verify(module: *llvm.Module, error_message: *llvm.String) bool;
|
pub extern fn llvm_module_verify(module: *llvm.Module, error_message: *llvm.String) bool;
|
||||||
@ -45,11 +48,13 @@ pub extern fn LLVMBuildCondBr(builder: *llvm.Builder, condition: *llvm.Value, ta
|
|||||||
pub extern fn llvm_builder_create_alloca(builder: *llvm.Builder, ty: *llvm.Type, address_space: c_uint, name: llvm.String) *llvm.Value;
|
pub extern fn llvm_builder_create_alloca(builder: *llvm.Builder, ty: *llvm.Type, address_space: c_uint, name: llvm.String) *llvm.Value;
|
||||||
pub extern fn LLVMBuildStore(builder: *llvm.Builder, value: *llvm.Value, pointer: *llvm.Value) *llvm.Value;
|
pub extern fn LLVMBuildStore(builder: *llvm.Builder, value: *llvm.Value, pointer: *llvm.Value) *llvm.Value;
|
||||||
pub extern fn LLVMBuildLoad2(builder: *llvm.Builder, ty: *llvm.Type, pointer: *llvm.Value, name: [*:0]const u8) *llvm.Value;
|
pub extern fn LLVMBuildLoad2(builder: *llvm.Builder, ty: *llvm.Type, pointer: *llvm.Value, name: [*:0]const u8) *llvm.Value;
|
||||||
|
pub extern fn LLVMBuildCall2(builder: *llvm.Builder, ty: *llvm.Type.Function, pointer: *llvm.Value, argument_pointer: [*]const *llvm.Value, argument_count: c_uint, name: [*:0]const u8) *llvm.Value;
|
||||||
|
|
||||||
pub extern fn LLVMSetCurrentDebugLocation2(builder: *llvm.Builder, location: ?*llvm.DI.Location) void;
|
pub extern fn LLVMSetCurrentDebugLocation2(builder: *llvm.Builder, location: ?*llvm.DI.Location) void;
|
||||||
|
|
||||||
pub extern fn LLVMTypeOf(value: *llvm.Value) *llvm.Type;
|
pub extern fn LLVMTypeOf(value: *llvm.Value) *llvm.Type;
|
||||||
pub extern fn LLVMGlobalGetValueType(value: *llvm.GlobalValue) *llvm.Type;
|
pub extern fn LLVMGlobalGetValueType(value: *llvm.GlobalValue) *llvm.Type;
|
||||||
|
pub extern fn llvm_value_is_instruction(value: *llvm.Value) bool;
|
||||||
|
|
||||||
// TYPES
|
// TYPES
|
||||||
// Types: integers
|
// Types: integers
|
||||||
|
9
tests/basic_call.bbb
Normal file
9
tests/basic_call.bbb
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
foo = fn() s32
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
[export] main = fn[cc(c)] () s32
|
||||||
|
{
|
||||||
|
return foo();
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user