advance llvm well enough
This commit is contained in:
parent
745e74cc3d
commit
589677fa5b
135
build.zig
135
build.zig
@ -1,4 +1,5 @@
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
|
||||
fn run_process_and_capture_stdout(b: *std.Build, argv: []const []const u8) ![]const u8 {
|
||||
const result = std.process.Child.run(.{
|
||||
@ -17,11 +18,115 @@ fn run_process_and_capture_stdout(b: *std.Build, argv: []const []const u8) ![]co
|
||||
return result.stdout;
|
||||
}
|
||||
|
||||
fn file_find_in_path(allocator: std.mem.Allocator, file_name: []const u8, path_env: []const u8, extension: []const u8) ?[]const u8 {
|
||||
const path_env_separator = switch (builtin.os.tag) {
|
||||
.windows => ';',
|
||||
else => ':',
|
||||
};
|
||||
const path_separator = switch (builtin.os.tag) {
|
||||
.windows => '\\',
|
||||
else => '/',
|
||||
};
|
||||
var env_it = std.mem.splitScalar(u8, path_env, path_env_separator);
|
||||
const result: ?[]const u8 = while (env_it.next()) |dir_path| {
|
||||
const full_path = std.mem.concatWithSentinel(allocator, u8, &.{ dir_path, &[1]u8{path_separator}, file_name, extension }, 0) catch unreachable;
|
||||
const file = std.fs.cwd().openFile(full_path, .{}) catch continue;
|
||||
file.close();
|
||||
break full_path;
|
||||
} else null;
|
||||
return result;
|
||||
}
|
||||
|
||||
fn executable_find_in_path(allocator: std.mem.Allocator, file_name: []const u8, path_env: []const u8) ?[]const u8 {
|
||||
const extension = switch (builtin.os.tag) {
|
||||
.windows => ".exe",
|
||||
else => "",
|
||||
};
|
||||
return file_find_in_path(allocator, file_name, path_env, extension);
|
||||
}
|
||||
|
||||
const LLVM = struct {
|
||||
module: *std.Build.Module,
|
||||
|
||||
fn setup(b: *std.Build, path: []const u8, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode) !LLVM {
|
||||
var llvm_libs = std.ArrayList([]const u8).init(b.allocator);
|
||||
var flags = std.ArrayList([]const u8).init(b.allocator);
|
||||
const llvm_config_path = if (b.option([]const u8, "llvm_prefix", "LLVM prefix")) |llvm_prefix| blk: {
|
||||
const full_path = try std.mem.concat(b.allocator, u8, &.{ llvm_prefix, "/bin/llvm-config" });
|
||||
const f = std.fs.cwd().openFile(full_path, .{}) catch return error.llvm_not_found;
|
||||
f.close();
|
||||
break :blk full_path;
|
||||
} else executable_find_in_path(b.allocator, "llvm-config", path) orelse return error.llvm_not_found;
|
||||
const llvm_components_result = try run_process_and_capture_stdout(b, &.{ llvm_config_path, "--components" });
|
||||
var it = std.mem.splitScalar(u8, llvm_components_result, ' ');
|
||||
var args = std.ArrayList([]const u8).init(b.allocator);
|
||||
try args.append(llvm_config_path);
|
||||
try args.append("--libs");
|
||||
while (it.next()) |component| {
|
||||
try args.append(std.mem.trimRight(u8, component, "\n"));
|
||||
}
|
||||
const llvm_libs_result = try run_process_and_capture_stdout(b, args.items);
|
||||
it = std.mem.splitScalar(u8, llvm_libs_result, ' ');
|
||||
|
||||
while (it.next()) |lib| {
|
||||
const llvm_lib = std.mem.trimLeft(u8, std.mem.trimRight(u8, lib, "\n"), "-l");
|
||||
try llvm_libs.append(llvm_lib);
|
||||
}
|
||||
|
||||
const llvm_cxx_flags_result = try run_process_and_capture_stdout(b, &.{ llvm_config_path, "--cxxflags" });
|
||||
it = std.mem.splitScalar(u8, llvm_cxx_flags_result, ' ');
|
||||
while (it.next()) |flag| {
|
||||
const llvm_cxx_flag = std.mem.trimRight(u8, flag, "\n");
|
||||
try flags.append(llvm_cxx_flag);
|
||||
}
|
||||
|
||||
const llvm_lib_dir = std.mem.trimRight(u8, try run_process_and_capture_stdout(b, &.{ llvm_config_path, "--libdir" }), "\n");
|
||||
|
||||
if (optimize != .ReleaseSmall) {
|
||||
try flags.append("-g");
|
||||
}
|
||||
|
||||
try flags.append("-fno-rtti");
|
||||
|
||||
const llvm = b.createModule(.{
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
|
||||
llvm.addLibraryPath(.{ .cwd_relative = llvm_lib_dir });
|
||||
|
||||
llvm.addCSourceFiles(.{
|
||||
.files = &.{"src/llvm.cpp"},
|
||||
.flags = flags.items,
|
||||
});
|
||||
llvm.addIncludePath(.{ .cwd_relative = "/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/14.2.1/../../../../include/c++/14.2.1" });
|
||||
llvm.addIncludePath(.{ .cwd_relative = "/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/14.2.1/../../../../include/c++/14.2.1/x86_64-pc-linux-gnu" });
|
||||
|
||||
llvm.addObjectFile(.{ .cwd_relative = "/usr/lib/libstdc++.so.6" });
|
||||
llvm.linkSystemLibrary("unwind", .{});
|
||||
llvm.linkSystemLibrary("z", .{});
|
||||
|
||||
for (llvm_libs.items) |llvm_lib| {
|
||||
llvm.linkSystemLibrary(llvm_lib, .{});
|
||||
}
|
||||
|
||||
return LLVM{
|
||||
.module = llvm,
|
||||
};
|
||||
}
|
||||
|
||||
fn link(llvm: LLVM, target: *std.Build.Step.Compile) void {
|
||||
if (target.root_module != llvm.module) {
|
||||
target.root_module.addImport("llvm", llvm.module);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
pub fn build(b: *std.Build) !void {
|
||||
const ci = b.option(bool, "ci", "");
|
||||
_ = &ci;
|
||||
const target = b.standardTargetOptions(.{});
|
||||
const optimize = b.standardOptimizeOption(.{});
|
||||
const env = try std.process.getEnvMap(b.allocator);
|
||||
const path = env.get("PATH") orelse unreachable;
|
||||
|
||||
const exe_mod = b.createModule(.{
|
||||
.root_source_file = b.path("src/main.zig"),
|
||||
@ -29,33 +134,14 @@ pub fn build(b: *std.Build) !void {
|
||||
.optimize = optimize,
|
||||
});
|
||||
|
||||
var llvm_libs = std.ArrayList([]const u8).init(b.allocator);
|
||||
{
|
||||
const llvm_components_result = try run_process_and_capture_stdout(b, &.{ "llvm-config", "--components" });
|
||||
var it = std.mem.splitScalar(u8, llvm_components_result, ' ');
|
||||
var args = std.ArrayList([]const u8).init(b.allocator);
|
||||
try args.append("llvm-config");
|
||||
try args.append("--libs");
|
||||
while (it.next()) |component| {
|
||||
try args.append(std.mem.trim(u8, component, "\n"));
|
||||
}
|
||||
const llvm_libs_result = try run_process_and_capture_stdout(b, args.items);
|
||||
it = std.mem.splitScalar(u8, llvm_libs_result, ' ');
|
||||
|
||||
while (it.next()) |component| {
|
||||
const llvm_lib = std.mem.trim(u8, std.mem.trim(u8, component, "\n"), "-l");
|
||||
try llvm_libs.append(llvm_lib);
|
||||
}
|
||||
}
|
||||
const llvm = try LLVM.setup(b, path, target, optimize);
|
||||
|
||||
const exe = b.addExecutable(.{
|
||||
.name = "bloat-buster",
|
||||
.root_module = exe_mod,
|
||||
});
|
||||
exe.linkLibC();
|
||||
for (llvm_libs.items) |llvm_lib| {
|
||||
exe.linkSystemLibrary(llvm_lib);
|
||||
}
|
||||
|
||||
llvm.link(exe);
|
||||
|
||||
b.installArtifact(exe);
|
||||
|
||||
@ -70,6 +156,7 @@ pub fn build(b: *std.Build) !void {
|
||||
const exe_unit_tests = b.addTest(.{
|
||||
.root_module = exe_mod,
|
||||
});
|
||||
llvm.link(exe_unit_tests);
|
||||
const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests);
|
||||
|
||||
const test_step = b.step("test", "Run unit tests");
|
||||
|
280
src/LLVM.zig
Normal file
280
src/LLVM.zig
Normal file
@ -0,0 +1,280 @@
|
||||
const lib = @import("lib.zig");
|
||||
const Arena = lib.Arena;
|
||||
const api = @import("llvm_api.zig");
|
||||
pub const Architecture = enum {
|
||||
X86,
|
||||
};
|
||||
|
||||
pub const TargetInitializerOptions = struct {
|
||||
asm_parser: bool = true,
|
||||
asm_printer: bool = true,
|
||||
disassembler: bool = false,
|
||||
};
|
||||
|
||||
const targets = [@typeInfo(Architecture).@"enum".fields.len]type{
|
||||
api.get_initializer(.X86),
|
||||
};
|
||||
|
||||
pub const Context = opaque {
|
||||
pub const create = api.LLVMContextCreate;
|
||||
pub fn create_module(context: *Context, name: [:0]const u8) *Module {
|
||||
return api.llvm_context_create_module(context, name.ptr, name.len);
|
||||
}
|
||||
pub const create_builder = api.LLVMCreateBuilderInContext;
|
||||
pub fn create_basic_block(context: *Context, name: []const u8, parent: *Function) *BasicBlock {
|
||||
return api.llvm_context_create_basic_block(context, name.ptr, name.len, parent);
|
||||
}
|
||||
};
|
||||
|
||||
pub const BasicBlock = opaque {};
|
||||
|
||||
pub const Module = opaque {
|
||||
pub const create_di_builder = api.LLVMCreateDIBuilder;
|
||||
|
||||
pub fn to_string(module: *Module) []const u8 {
|
||||
var result: []const u8 = undefined;
|
||||
api.llvm_module_to_string(module, &result.ptr, &result.len);
|
||||
return result;
|
||||
}
|
||||
|
||||
const FunctionCreate = struct {
|
||||
type: *Type.Function,
|
||||
linkage: LinkageType,
|
||||
address_space: c_uint = 0,
|
||||
name: []const u8,
|
||||
};
|
||||
|
||||
pub fn create_function(module: *Module, create: FunctionCreate) *Function {
|
||||
return api.llvm_module_create_function(module, create.type, create.linkage, create.address_space, create.name.ptr, create.name.len);
|
||||
}
|
||||
|
||||
pub fn verify(module: *Module) VerifyResult {
|
||||
var result: VerifyResult = undefined;
|
||||
result.success = api.llvm_module_verify(module, &result.error_message.ptr, &result.error_message.len);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
pub const VerifyResult = struct {
|
||||
error_message: []const u8,
|
||||
success: bool,
|
||||
};
|
||||
|
||||
pub const Builder = opaque {
|
||||
pub const position_at_end = api.LLVMPositionBuilderAtEnd;
|
||||
|
||||
pub const create_ret = api.LLVMBuildRet;
|
||||
|
||||
pub fn create_ret_void(builder: *Builder) void {
|
||||
builder.create_ret(null);
|
||||
}
|
||||
};
|
||||
|
||||
pub const Function = opaque {
|
||||
pub fn verify(function: *Function) VerifyResult {
|
||||
var result: VerifyResult = undefined;
|
||||
result.success = api.llvm_function_verify(function, &result.error_message.ptr, &result.error_message.len);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
pub const Constant = opaque {
|
||||
pub fn to_value(constant: *Constant) *Value {
|
||||
return @ptrCast(constant);
|
||||
}
|
||||
|
||||
pub const Integer = opaque {
|
||||
pub fn to_value(constant: *Constant.Integer) *Value {
|
||||
return @ptrCast(constant);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
pub const Value = opaque {};
|
||||
|
||||
pub const DI = struct {
|
||||
pub const Builder = opaque {
|
||||
pub fn create_file(builder: *DI.Builder, file_name: []const u8, directory_name: []const u8) *File {
|
||||
return api.LLVMCreateDIBuilder(builder, file_name.ptr, file_name.len, directory_name.ptr, directory_name.len);
|
||||
}
|
||||
};
|
||||
pub const File = opaque {};
|
||||
|
||||
const Flags = enum(c_int) {
|
||||
_,
|
||||
const Zero = 0;
|
||||
const Private = 1;
|
||||
const Protected = 2;
|
||||
const Public = 3;
|
||||
const FwdDecl = 1 << 2;
|
||||
const AppleBlock = 1 << 3;
|
||||
const ReservedBit4 = 1 << 4;
|
||||
const Virtual = 1 << 5;
|
||||
const Artificial = 1 << 6;
|
||||
const Explicit = 1 << 7;
|
||||
const Prototyped = 1 << 8;
|
||||
const ObjcClassComplete = 1 << 9;
|
||||
const ObjectPointer = 1 << 10;
|
||||
const Vector = 1 << 11;
|
||||
const StaticMember = 1 << 12;
|
||||
const LValueReference = 1 << 13;
|
||||
const RValueReference = 1 << 14;
|
||||
const Reserved = 1 << 15;
|
||||
const SingleInheritance = 1 << 16;
|
||||
const MultipleInheritance = 2 << 16;
|
||||
const VirtualInheritance = 3 << 16;
|
||||
const IntroducedVirtual = 1 << 18;
|
||||
const BitField = 1 << 19;
|
||||
const NoReturn = 1 << 20;
|
||||
const TypePassByValue = 1 << 22;
|
||||
const TypePassByReference = 1 << 23;
|
||||
const EnumClass = 1 << 24;
|
||||
const Thunk = 1 << 25;
|
||||
const NonTrivial = 1 << 26;
|
||||
const BigEndian = 1 << 27;
|
||||
const LittleEndian = 1 << 28;
|
||||
const IndirectVirtualBase = (1 << 2) | (1 << 5);
|
||||
const Accessibility = Private | Protected | Public;
|
||||
const PtrToMemberRep = SingleInheritance | MultipleInheritance | VirtualInheritance;
|
||||
};
|
||||
};
|
||||
|
||||
pub const Type = opaque {
|
||||
pub const Function = opaque {
|
||||
pub fn get(return_type: *Type, parameter_types: []const *Type, is_var_args: c_int) *Type.Function {
|
||||
return api.LLVMFunctionType(return_type, parameter_types.ptr, @intCast(parameter_types.len), is_var_args);
|
||||
}
|
||||
};
|
||||
|
||||
pub const Integer = opaque {
|
||||
pub const get_constant = api.LLVMConstInt;
|
||||
pub fn to_type(integer: *Type.Integer) *Type {
|
||||
return @ptrCast(integer);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
pub const LinkageType = enum(c_int) {
|
||||
ExternalLinkage,
|
||||
AvailableExternallyLinkage,
|
||||
LinkOnceAnyLinkage,
|
||||
LinkOnceODRLinkage,
|
||||
WeakAnyLinkage,
|
||||
WeakODRLinkage,
|
||||
AppendingLinkage,
|
||||
InternalLinkage,
|
||||
PrivateLinkage,
|
||||
ExternalWeakLinkage,
|
||||
CommonLinkage,
|
||||
};
|
||||
|
||||
pub const DwarfSourceLanguage = enum(c_int) {
|
||||
c17 = 0x2c,
|
||||
};
|
||||
pub const DwarfEmissionKind = enum(c_int) {
|
||||
none,
|
||||
full,
|
||||
line_tables_only,
|
||||
};
|
||||
|
||||
pub const Thread = struct {
|
||||
context: *Context,
|
||||
i1: Integer,
|
||||
i8: Integer,
|
||||
i16: Integer,
|
||||
i32: Integer,
|
||||
i64: Integer,
|
||||
i128: Integer,
|
||||
|
||||
pub const Integer = struct {
|
||||
type: *Type.Integer,
|
||||
zero: *Constant.Integer,
|
||||
};
|
||||
|
||||
pub fn initialize(thread: *Thread) void {
|
||||
const context = Context.create();
|
||||
const type_i1 = api.LLVMInt1TypeInContext(context);
|
||||
const type_i8 = api.LLVMInt8TypeInContext(context);
|
||||
const type_i16 = api.LLVMInt16TypeInContext(context);
|
||||
const type_i32 = api.LLVMInt32TypeInContext(context);
|
||||
const type_i64 = api.LLVMInt64TypeInContext(context);
|
||||
const type_i128 = api.LLVMInt128TypeInContext(context);
|
||||
const zero_i1 = type_i1.get_constant(0, 0);
|
||||
const zero_i8 = type_i8.get_constant(0, 0);
|
||||
const zero_i16 = type_i16.get_constant(0, 0);
|
||||
const zero_i32 = type_i32.get_constant(0, 0);
|
||||
const zero_i64 = type_i64.get_constant(0, 0);
|
||||
const zero_i128 = type_i128.get_constant(0, 0);
|
||||
|
||||
thread.* = .{
|
||||
.context = context,
|
||||
.i1 = .{
|
||||
.type = type_i1,
|
||||
.zero = zero_i1,
|
||||
},
|
||||
.i8 = .{
|
||||
.type = type_i8,
|
||||
.zero = zero_i8,
|
||||
},
|
||||
.i16 = .{
|
||||
.type = type_i16,
|
||||
.zero = zero_i16,
|
||||
},
|
||||
.i32 = .{
|
||||
.type = type_i32,
|
||||
.zero = zero_i32,
|
||||
},
|
||||
.i64 = .{
|
||||
.type = type_i64,
|
||||
.zero = zero_i64,
|
||||
},
|
||||
.i128 = .{
|
||||
.type = type_i128,
|
||||
.zero = zero_i128,
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
pub var threads: []Thread = undefined;
|
||||
|
||||
// This is meant to call globally, only once per execution
|
||||
pub fn initialize_all() void {
|
||||
threads = lib.global.arena.allocate(Thread, lib.global.thread_count);
|
||||
inline for (targets) |target| {
|
||||
target.initialize(.{});
|
||||
}
|
||||
}
|
||||
|
||||
pub fn experiment() void {
|
||||
const thread = &threads[0];
|
||||
thread.initialize();
|
||||
const module = thread.context.create_module("first_module");
|
||||
const builder = thread.context.create_builder();
|
||||
// const di_builder = module.create_di_builder();
|
||||
const return_type = thread.i32.type;
|
||||
const return_value = thread.i32.zero;
|
||||
// const return_value = thread.
|
||||
const function_type = Type.Function.get(return_type.to_type(), &.{}, 0);
|
||||
const function = module.create_function(.{
|
||||
.type = function_type,
|
||||
.linkage = .ExternalLinkage,
|
||||
.name = "main",
|
||||
});
|
||||
const entry_basic_block = thread.context.create_basic_block("entry", function);
|
||||
builder.position_at_end(entry_basic_block);
|
||||
builder.create_ret(return_value.to_value());
|
||||
const function_verify = function.verify();
|
||||
if (!function_verify.success) {
|
||||
unreachable;
|
||||
}
|
||||
const module_verify = module.verify();
|
||||
if (!module_verify.success) {
|
||||
unreachable;
|
||||
}
|
||||
|
||||
const module_z = api.LLVMPrintModuleToString(module);
|
||||
_ = module_z;
|
||||
const module_string = module.to_string();
|
||||
lib.print_string(module_string);
|
||||
}
|
130
src/lib.zig
130
src/lib.zig
@ -3,6 +3,10 @@ const VariableArguments = @import("std").builtin.VaList;
|
||||
extern "c" fn IsDebuggerPresent() bool;
|
||||
extern "c" fn __errno_location() *c_int;
|
||||
|
||||
test {
|
||||
_ = @import("lib_test.zig");
|
||||
}
|
||||
|
||||
pub const KB = 1024;
|
||||
pub const MB = 1024 * 1024;
|
||||
pub const GB = 1024 * 1024 * 1024;
|
||||
@ -59,48 +63,6 @@ pub fn value_from_flag(value: anytype, flag: anytype) @TypeOf(value) {
|
||||
return result;
|
||||
}
|
||||
|
||||
test "value_from_flag" {
|
||||
const std = @import("std");
|
||||
const expect = std.testing.expect;
|
||||
|
||||
try expect(value_from_flag(1, 1) == 1);
|
||||
try expect(value_from_flag(2, true) == 2);
|
||||
try expect(value_from_flag(3, false) == 0);
|
||||
try expect(value_from_flag(3, true) == 3);
|
||||
try expect(value_from_flag(3, 1) == 3);
|
||||
|
||||
try expect(value_from_flag(0xffff, 1) == 0xffff);
|
||||
try expect(value_from_flag(0xffff, 0) == 0);
|
||||
try expect(value_from_flag(0xffff, true) == 0xffff);
|
||||
try expect(value_from_flag(0xffff, false) == 0);
|
||||
|
||||
try expect(value_from_flag(0xffffffff, 1) == 0xffffffff);
|
||||
try expect(value_from_flag(0xffffffff, 0) == 0);
|
||||
try expect(value_from_flag(0xffffffff, true) == 0xffffffff);
|
||||
try expect(value_from_flag(0xffffffff, false) == 0);
|
||||
|
||||
try expect(value_from_flag(0xffffffffffffffff, 1) == 0xffffffffffffffff);
|
||||
try expect(value_from_flag(0xffffffffffffffff, 0) == 0);
|
||||
try expect(value_from_flag(0xffffffffffffffff, true) == 0xffffffffffffffff);
|
||||
try expect(value_from_flag(0xffffffffffffffff, false) == 0);
|
||||
|
||||
const a: u32 = 1235;
|
||||
const b_true: bool = true;
|
||||
const b_false: bool = false;
|
||||
const u_true: u1 = 1;
|
||||
const u_false: u1 = 0;
|
||||
try expect(value_from_flag(a, b_true) == a);
|
||||
try expect(value_from_flag(a, b_false) == 0);
|
||||
try expect(value_from_flag(a, u_true) == a);
|
||||
try expect(value_from_flag(a, u_false) == 0);
|
||||
|
||||
const b: u64 = 0xffffffffffffffff;
|
||||
try expect(value_from_flag(b, b_true) == b);
|
||||
try expect(value_from_flag(b, b_false) == 0);
|
||||
try expect(value_from_flag(b, u_true) == b);
|
||||
try expect(value_from_flag(b, u_false) == 0);
|
||||
}
|
||||
|
||||
pub const Error = enum(c_int) {
|
||||
SUCCESS = 0,
|
||||
PERM = 1,
|
||||
@ -302,7 +264,37 @@ pub const os = struct {
|
||||
return result;
|
||||
}
|
||||
|
||||
pub fn get_cpu_count() usize {
|
||||
switch (builtin.os.tag) {
|
||||
.windows => @compileError("TODO"),
|
||||
else => {
|
||||
var cpu_set: posix.cpu_set_t = undefined;
|
||||
const result = posix.sched_getaffinity(0, @sizeOf(posix.cpu_set_t), &cpu_set);
|
||||
assert(result == 0);
|
||||
const cpu_count = posix.CPU_COUNT(cpu_set);
|
||||
return cpu_count;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const linux = struct {
|
||||
pub const CPU_SETSIZE = 128;
|
||||
pub const cpu_set_t = [CPU_SETSIZE / @sizeOf(usize)]usize;
|
||||
pub const cpu_count_t = @Type(.{
|
||||
.int = .{
|
||||
.signedness = .unsigned,
|
||||
.bits = log2_int(@as(u64, CPU_SETSIZE * 8)),
|
||||
},
|
||||
});
|
||||
|
||||
pub fn CPU_COUNT(set: cpu_set_t) cpu_count_t {
|
||||
var sum: cpu_count_t = 0;
|
||||
for (set) |x| {
|
||||
sum += @popCount(x);
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
const FileDescriptor = c_int;
|
||||
|
||||
fn fd_is_valid(fd: FileDescriptor) bool {
|
||||
@ -414,6 +406,7 @@ pub const os = struct {
|
||||
extern "c" fn fstat(fd: system.FileDescriptor, stat: *Stat) c_int;
|
||||
extern "c" fn read(fd: system.FileDescriptor, pointer: [*]u8, byte_count: usize) isize;
|
||||
extern "c" fn write(fd: system.FileDescriptor, pointer: [*]const u8, byte_count: usize) isize;
|
||||
extern "c" fn sched_getaffinity(pid: c_int, size: usize, set: *cpu_set_t) c_int;
|
||||
|
||||
const mode_t = usize;
|
||||
|
||||
@ -490,6 +483,17 @@ pub const os = struct {
|
||||
libc.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_stdout() File {
|
||||
return switch (builtin.os.tag) {
|
||||
.windows => @compileError("TODO"),
|
||||
else => {
|
||||
return File{
|
||||
.fd = 1,
|
||||
};
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
pub const libc = struct {
|
||||
@ -586,6 +590,18 @@ pub const Arena = struct {
|
||||
return result;
|
||||
}
|
||||
|
||||
pub fn allocate(arena: *Arena, T: type, count: usize) []T {
|
||||
const result = arena.allocate_bytes(@sizeOf(T) * count, @alignOf(T));
|
||||
const t_ptr: [*]T = @alignCast(@ptrCast(result));
|
||||
const t_len = count;
|
||||
return t_ptr[0..t_len];
|
||||
}
|
||||
|
||||
pub fn allocate_one(arena: *Arena, T: type) *T {
|
||||
const result = arena.allocate(T, 1);
|
||||
return &result[0];
|
||||
}
|
||||
|
||||
pub fn join_string(arena: *Arena, pieces: []const []const u8) [:0]u8 {
|
||||
var size: u64 = 0;
|
||||
for (pieces) |piece| {
|
||||
@ -2424,6 +2440,20 @@ pub fn format(buffer_pointer: [*]u8, buffer_length: usize, format_string: [*:0]c
|
||||
return byte_count;
|
||||
}
|
||||
|
||||
pub const GlobalState = struct {
|
||||
arena: *Arena,
|
||||
thread_count: usize,
|
||||
|
||||
pub fn initialize() void {
|
||||
const thread_count = os.get_cpu_count();
|
||||
global = .{
|
||||
.arena = Arena.initialize_default(2 * MB),
|
||||
.thread_count = thread_count,
|
||||
};
|
||||
}
|
||||
};
|
||||
pub var global: GlobalState = undefined;
|
||||
|
||||
pub const parse = struct {
|
||||
fn integer_decimal(str: []const u8) u64 {
|
||||
var value: u64 = 0;
|
||||
@ -2436,3 +2466,19 @@ pub const parse = struct {
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
fn vprint(format_string: [*:0]const u8, args: *VariableArguments) void {
|
||||
var buffer: [16 * 1024]u8 = undefined;
|
||||
const slice = format_va(&buffer, format_string, args);
|
||||
print_string(slice);
|
||||
}
|
||||
|
||||
pub fn print(format_string: [*:0]const u8, ...) callconv(.C) void {
|
||||
const args = @cVaStart();
|
||||
vprint(format_string, &args);
|
||||
@cVaEnd(&args);
|
||||
}
|
||||
|
||||
pub fn print_string(str: []const u8) void {
|
||||
os.get_stdout().write(str);
|
||||
}
|
||||
|
44
src/lib_test.zig
Normal file
44
src/lib_test.zig
Normal file
@ -0,0 +1,44 @@
|
||||
const lib = @import("lib.zig");
|
||||
|
||||
test "value_from_flag" {
|
||||
const std = @import("std");
|
||||
const expect = std.testing.expect;
|
||||
const value_from_flag = lib.value_from_flag;
|
||||
|
||||
try expect(value_from_flag(1, 1) == 1);
|
||||
try expect(value_from_flag(2, true) == 2);
|
||||
try expect(value_from_flag(3, false) == 0);
|
||||
try expect(value_from_flag(3, true) == 3);
|
||||
try expect(value_from_flag(3, 1) == 3);
|
||||
|
||||
try expect(value_from_flag(0xffff, 1) == 0xffff);
|
||||
try expect(value_from_flag(0xffff, 0) == 0);
|
||||
try expect(value_from_flag(0xffff, true) == 0xffff);
|
||||
try expect(value_from_flag(0xffff, false) == 0);
|
||||
|
||||
try expect(value_from_flag(0xffffffff, 1) == 0xffffffff);
|
||||
try expect(value_from_flag(0xffffffff, 0) == 0);
|
||||
try expect(value_from_flag(0xffffffff, true) == 0xffffffff);
|
||||
try expect(value_from_flag(0xffffffff, false) == 0);
|
||||
|
||||
try expect(value_from_flag(0xffffffffffffffff, 1) == 0xffffffffffffffff);
|
||||
try expect(value_from_flag(0xffffffffffffffff, 0) == 0);
|
||||
try expect(value_from_flag(0xffffffffffffffff, true) == 0xffffffffffffffff);
|
||||
try expect(value_from_flag(0xffffffffffffffff, false) == 0);
|
||||
|
||||
const a: u32 = 1235;
|
||||
const b_true: bool = true;
|
||||
const b_false: bool = false;
|
||||
const u_true: u1 = 1;
|
||||
const u_false: u1 = 0;
|
||||
try expect(value_from_flag(a, b_true) == a);
|
||||
try expect(value_from_flag(a, b_false) == 0);
|
||||
try expect(value_from_flag(a, u_true) == a);
|
||||
try expect(value_from_flag(a, u_false) == 0);
|
||||
|
||||
const b: u64 = 0xffffffffffffffff;
|
||||
try expect(value_from_flag(b, b_true) == b);
|
||||
try expect(value_from_flag(b, b_false) == 0);
|
||||
try expect(value_from_flag(b, u_true) == b);
|
||||
try expect(value_from_flag(b, u_false) == 0);
|
||||
}
|
104
src/llvm.cpp
Normal file
104
src/llvm.cpp
Normal file
@ -0,0 +1,104 @@
|
||||
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/IR/Verifier.h"
|
||||
|
||||
#define EXPORT extern "C"
|
||||
#define fn static
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
EXPORT Module* llvm_context_create_module(LLVMContext& context, const char* name_pointer, size_t name_length)
|
||||
{
|
||||
auto name = StringRef(name_pointer, name_length);
|
||||
return new Module(name, context);
|
||||
}
|
||||
|
||||
EXPORT Value* llvm_builder_create_add(IRBuilder<>& builder, Value* left, Value* right, bool nuw, bool nsw)
|
||||
{
|
||||
auto* result = builder.CreateAdd(left, right, "", nuw, nsw);
|
||||
return result;
|
||||
}
|
||||
|
||||
EXPORT Function* llvm_module_create_function(Module* module, FunctionType* function_type, GlobalValue::LinkageTypes linkage_type, unsigned address_space, const char* name_pointer, size_t name_length)
|
||||
{
|
||||
auto name = StringRef(name_pointer, name_length);
|
||||
auto* function = Function::Create(function_type, linkage_type, address_space, name, module);
|
||||
return function;
|
||||
}
|
||||
|
||||
EXPORT StructType* llvm_context_create_struct_type(LLVMContext& context, Type** type_pointer, size_t type_count, const char* name_pointer, size_t name_length, bool is_packed)
|
||||
{
|
||||
auto types = ArrayRef<Type*>(type_pointer, type_count);
|
||||
auto name = StringRef(name_pointer, name_length);
|
||||
auto* struct_type = StructType::create(context, types, name, is_packed);
|
||||
return struct_type;
|
||||
}
|
||||
|
||||
EXPORT StructType* llvm_context_get_struct_type(LLVMContext& context, Type** type_pointer, size_t type_count, bool is_packed)
|
||||
{
|
||||
auto types = ArrayRef<Type*>(type_pointer, type_count);
|
||||
auto* struct_type = StructType::get(context, types, is_packed);
|
||||
return struct_type;
|
||||
}
|
||||
|
||||
EXPORT BasicBlock* llvm_context_create_basic_block(LLVMContext& context, const char* name_pointer, size_t name_length, Function* parent)
|
||||
{
|
||||
auto name = StringRef(name_pointer, name_length);
|
||||
auto* basic_block = BasicBlock::Create(context, name, parent);
|
||||
return basic_block;
|
||||
}
|
||||
|
||||
fn void stream_to_string(raw_string_ostream& stream, const char** message_pointer, size_t* message_length)
|
||||
{
|
||||
// No need to call stream.flush(); because it's string-based
|
||||
stream.flush();
|
||||
|
||||
auto string = stream.str();
|
||||
auto length = string.length();
|
||||
|
||||
char* result = 0;
|
||||
if (length)
|
||||
{
|
||||
result = new char[length];
|
||||
memcpy(result, string.c_str(), length);
|
||||
}
|
||||
|
||||
*message_pointer = result;
|
||||
*message_length = length;
|
||||
}
|
||||
|
||||
EXPORT bool llvm_function_verify(Function& function, const char** message_pointer, size_t* message_length)
|
||||
{
|
||||
std::string message_buffer;
|
||||
raw_string_ostream message_stream(message_buffer);
|
||||
|
||||
bool result = verifyFunction(function, &message_stream);
|
||||
auto size = message_stream.str().size();
|
||||
stream_to_string(message_stream, message_pointer, message_length);
|
||||
|
||||
// We invert the condition because LLVM conventions are just stupid
|
||||
return !result;
|
||||
}
|
||||
|
||||
EXPORT bool llvm_module_verify(const Module& module, const char** message_pointer, size_t* message_length)
|
||||
{
|
||||
std::string message_buffer;
|
||||
raw_string_ostream message_stream(message_buffer);
|
||||
|
||||
bool result = verifyModule(module, &message_stream);
|
||||
stream_to_string(message_stream, message_pointer, message_length);
|
||||
|
||||
// We invert the condition because LLVM conventions are just stupid
|
||||
return !result;
|
||||
}
|
||||
|
||||
EXPORT void llvm_module_to_string(Module* module, const char** module_pointer, size_t* module_length)
|
||||
{
|
||||
std::string buffer;
|
||||
raw_string_ostream stream(buffer);
|
||||
module->print(stream, nullptr);
|
||||
|
||||
stream_to_string(stream, module_pointer, module_length);
|
||||
}
|
||||
|
110
src/llvm_api.zig
Normal file
110
src/llvm_api.zig
Normal file
@ -0,0 +1,110 @@
|
||||
const llvm = @import("LLVM.zig");
|
||||
|
||||
const Bool = c_int;
|
||||
|
||||
pub extern fn llvm_context_create_module(context: *llvm.Context, name_pointer: [*]const u8, name_length: usize) *llvm.Module;
|
||||
pub extern fn LLVMContextCreate() *llvm.Context;
|
||||
pub extern fn LLVMCreateBuilderInContext(context: *llvm.Context) *llvm.Builder;
|
||||
|
||||
// Module
|
||||
pub extern fn llvm_module_create_function(module: *llvm.Module, function_type: *llvm.Type.Function, linkage_type: llvm.LinkageType, address_space: c_uint, name_pointer: [*]const u8, name_length: usize) *llvm.Function;
|
||||
pub extern fn llvm_context_create_basic_block(context: *llvm.Context, name_pointer: [*]const u8, name_length: usize, parent: *llvm.Function) *llvm.BasicBlock;
|
||||
|
||||
pub extern fn llvm_function_verify(function: *llvm.Function, message_pointer: *[*]const u8, message_length: *usize) bool;
|
||||
pub extern fn llvm_module_verify(module: *llvm.Module, message_pointer: *[*]const u8, message_length: *usize) bool;
|
||||
|
||||
pub extern fn llvm_module_to_string(module: *llvm.Module, module_pointer: *[*]const u8, module_length: *usize) void;
|
||||
pub extern fn LLVMPrintModuleToString(module: *llvm.Module) [*:0]const u8;
|
||||
|
||||
// Builder API
|
||||
pub extern fn LLVMPositionBuilderAtEnd(builder: *llvm.Builder, basic_block: *llvm.BasicBlock) void;
|
||||
pub extern fn LLVMBuildRet(builder: *llvm.Builder, value: ?*llvm.Value) void;
|
||||
|
||||
// TYPES
|
||||
// Types: integers
|
||||
pub extern fn LLVMInt1TypeInContext(context: *llvm.Context) *llvm.Type.Integer;
|
||||
pub extern fn LLVMInt8TypeInContext(context: *llvm.Context) *llvm.Type.Integer;
|
||||
pub extern fn LLVMInt16TypeInContext(context: *llvm.Context) *llvm.Type.Integer;
|
||||
pub extern fn LLVMInt32TypeInContext(context: *llvm.Context) *llvm.Type.Integer;
|
||||
pub extern fn LLVMInt64TypeInContext(context: *llvm.Context) *llvm.Type.Integer;
|
||||
pub extern fn LLVMInt128TypeInContext(context: *llvm.Context) *llvm.Type.Integer;
|
||||
pub extern fn LLVMIntTypeInContext(context: *llvm.Context, bit_count: c_uint) *llvm.Type.Integer;
|
||||
|
||||
// Types: floating point
|
||||
pub extern fn LLVMHalfTypeInContext(context: *llvm.Context) *llvm.Type;
|
||||
pub extern fn LLVMBFloatTypeInContext(context: *llvm.Context) *llvm.Type;
|
||||
pub extern fn LLVMFloatTypeInContext(context: *llvm.Context) *llvm.Type;
|
||||
pub extern fn LLVMDoubleTypeInContext(context: *llvm.Context) *llvm.Type;
|
||||
pub extern fn LLVMFP128TypeInContext(context: *llvm.Context) *llvm.Type;
|
||||
|
||||
// Types: functions
|
||||
pub extern fn LLVMFunctionType(return_type: *llvm.Type, parameter_type_pointer: [*]const *llvm.Type, parameter_type_count: c_uint, is_var_arg: Bool) *llvm.Type.Function;
|
||||
pub extern fn LLVMIsFunctionVarArg(function_type: *llvm.Type.Function) Bool;
|
||||
pub extern fn LLVMGetReturnType(function_type: *llvm.Type.Function) *llvm.Type;
|
||||
pub extern fn LLVMCountParamTypes(function_type: *llvm.Type.Function) c_uint;
|
||||
pub extern fn LLVMGetParamTypes(function_type: *llvm.Type.Function, types: [*]*llvm.Type) void;
|
||||
|
||||
// Types: struct
|
||||
pub extern fn llvm_context_create_struct_type(context: *llvm.Context, element_types_pointer: [*]const *llvm.Type, element_type_count: usize, name_pointer: [*]const u8, name_length: usize, is_packed: bool) *llvm.Type.Struct;
|
||||
pub extern fn llvm_context_get_struct_type(context: *llvm.Context, element_types_pointer: [*]const *llvm.Type, element_type_count: usize, is_packed: bool) *llvm.Type.Struct;
|
||||
|
||||
// Types: arrays
|
||||
pub extern fn LLVMArrayType2(element_type: *llvm.Type, element_count: u64) *llvm.Type.Array;
|
||||
|
||||
// Types: pointers
|
||||
pub extern fn LLVMPointerTypeInContext(context: *llvm.Context, address_space: c_uint) *llvm.Type.Pointer;
|
||||
|
||||
// Types: vectors
|
||||
pub extern fn LLVMVectorType(element_type: *llvm.Type, element_count: c_uint) *llvm.Type.FixedVector;
|
||||
pub extern fn LLVMScalableVectorType(element_type: *llvm.Type, element_count: c_uint) *llvm.Type.ScalableVector;
|
||||
|
||||
// VALUES
|
||||
pub extern fn LLVMConstInt(type: *llvm.Type.Integer, value: c_ulonglong, sign_extend: Bool) *llvm.Constant.Integer;
|
||||
|
||||
// Debug info API
|
||||
pub extern fn LLVMCreateDIBuilder(module: *llvm.Module) *llvm.DI.Builder;
|
||||
pub extern fn LLVMDIBuilderCreateFile(builder: *llvm.DI.Builder, file_name_pointer: [*]const u8, file_name_length: usize, directory_name_pointer: [*]const u8, directory_name_length: usize) *llvm.DI.File;
|
||||
pub extern fn LLVMDIBuilderCreateCompileUnit(builder: *llvm.DI.Builder, language: llvm.DwarfSourceLanguage, file: *llvm.DI.File, producer_name_pointer: [*]const u8, producer_name_length: usize, optimized: Bool, flags_pointer: [*]const u8, flags_length: usize, runtime_version: c_uint, split_name_pointer: [*]const u8, split_name_length: usize, dwarf_emission_kind: llvm.DwarfEmissionKind, debug_with_offset_id: c_uint, split_debug_inlining: Bool, debug_info_for_profiling: Bool, sysroot_pointer: [*]const u8, sysroot_length: usize, sdk_pointer: [*]const u8, sdk_length: usize) *llvm.DI.CompileUnit;
|
||||
pub extern fn LLVMDIBuilderCreateFunction(builder: *llvm.DI.Builder, scope: *llvm.DI.Scope, name_pointer: [*]const u8, name_length: usize, linkage_name_pointer: [*]const u8, linkage_name_length: usize, file: *llvm.DI.File, line_number: c_uint, type: *llvm.DI.Type.Subroutine, local_to_unit: Bool, is_definition: Bool, scope_line: c_uint, flags: llvm.DI.Flags, is_optimized: Bool) *llvm.DI.Subprogram;
|
||||
|
||||
pub fn get_initializer(comptime llvm_arch: llvm.Architecture) type {
|
||||
const arch_name = @tagName(llvm_arch);
|
||||
return struct {
|
||||
pub const initialize_target_info = @extern(*const fn () callconv(.C) void, .{
|
||||
.name = "LLVMInitialize" ++ arch_name ++ "TargetInfo",
|
||||
});
|
||||
pub const initialize_target = @extern(*const fn () callconv(.C) void, .{
|
||||
.name = "LLVMInitialize" ++ arch_name ++ "Target",
|
||||
});
|
||||
pub const initialize_target_mc = @extern(*const fn () callconv(.C) void, .{
|
||||
.name = "LLVMInitialize" ++ arch_name ++ "TargetMC",
|
||||
});
|
||||
pub const initialize_asm_printer = @extern(*const fn () callconv(.C) void, .{
|
||||
.name = "LLVMInitialize" ++ arch_name ++ "AsmPrinter",
|
||||
});
|
||||
pub const initialize_asm_parser = @extern(*const fn () callconv(.C) void, .{
|
||||
.name = "LLVMInitialize" ++ arch_name ++ "AsmParser",
|
||||
});
|
||||
pub const initialize_disassembler = @extern(*const fn () callconv(.C) void, .{
|
||||
.name = "LLVMInitialize" ++ arch_name ++ "Disassembler",
|
||||
});
|
||||
|
||||
pub fn initialize(options: llvm.TargetInitializerOptions) void {
|
||||
initialize_target_info();
|
||||
initialize_target();
|
||||
initialize_target_mc();
|
||||
|
||||
if (options.asm_printer) {
|
||||
initialize_asm_printer();
|
||||
}
|
||||
|
||||
if (options.asm_parser) {
|
||||
initialize_asm_parser();
|
||||
}
|
||||
|
||||
if (options.disassembler) {
|
||||
initialize_disassembler();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
21
src/main.zig
21
src/main.zig
@ -1,4 +1,6 @@
|
||||
const lib = @import("lib.zig");
|
||||
const llvm = @import("LLVM.zig");
|
||||
const Arena = lib.Arena;
|
||||
|
||||
pub const panic = struct {
|
||||
const abort = lib.os.abort;
|
||||
@ -133,19 +135,13 @@ pub const panic = struct {
|
||||
}
|
||||
};
|
||||
|
||||
pub fn main() callconv(.C) c_int {
|
||||
const arena = lib.Arena.initialize_default(2 * lib.MB);
|
||||
_ = arena.allocate_bytes(1024, 1);
|
||||
_ = arena.join_string(&.{ "foo", "fa" });
|
||||
arena.reset();
|
||||
lib.file.write(".zig-cache/foo", "fafu", .{});
|
||||
const a = lib.file.read(arena, ".zig-cache/foo");
|
||||
lib.assert(lib.string.equal(a, "fafu"));
|
||||
var global_persistent_arena: *Arena = undefined;
|
||||
|
||||
var buffer: [100]u8 = undefined;
|
||||
const written_character_count = lib.format(&buffer, buffer.len, "fjaksdjkasd {u64}\n", @as(u64, 123123));
|
||||
const result_str = buffer[0..written_character_count];
|
||||
lib.assert(lib.string.equal(result_str, "fjaksdjkasd 123123\n"));
|
||||
pub fn main() callconv(.C) c_int {
|
||||
lib.GlobalState.initialize();
|
||||
|
||||
llvm.initialize_all();
|
||||
llvm.experiment();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -159,4 +155,5 @@ comptime {
|
||||
|
||||
test {
|
||||
_ = lib;
|
||||
_ = llvm;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user