diff --git a/CMakeLists.txt b/CMakeLists.txt index ebb4f74ffa..3ddbec11c6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -541,6 +541,8 @@ set(ZIG_STAGE2_SOURCES "${CMAKE_SOURCE_DIR}/src/codegen/aarch64.zig" "${CMAKE_SOURCE_DIR}/src/codegen/arm.zig" "${CMAKE_SOURCE_DIR}/src/codegen/c.zig" + "${CMAKE_SOURCE_DIR}/src/codegen/llvm.zig" + "${CMAKE_SOURCE_DIR}/src/codegen/llvm/bindings.zig" "${CMAKE_SOURCE_DIR}/src/codegen/riscv64.zig" "${CMAKE_SOURCE_DIR}/src/codegen/spu-mk2.zig" "${CMAKE_SOURCE_DIR}/src/codegen/wasm.zig" @@ -562,8 +564,6 @@ set(ZIG_STAGE2_SOURCES "${CMAKE_SOURCE_DIR}/src/link/C/zig.h" "${CMAKE_SOURCE_DIR}/src/link/msdos-stub.bin" "${CMAKE_SOURCE_DIR}/src/liveness.zig" - "${CMAKE_SOURCE_DIR}/src/llvm_backend.zig" - "${CMAKE_SOURCE_DIR}/src/llvm_bindings.zig" "${CMAKE_SOURCE_DIR}/src/main.zig" "${CMAKE_SOURCE_DIR}/src/mingw.zig" "${CMAKE_SOURCE_DIR}/src/musl.zig" diff --git a/src/Compilation.zig b/src/Compilation.zig index 8e2da5aec4..a2f4d07c98 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -2150,7 +2150,7 @@ pub fn addCCArgs( try argv.append("-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS"); } - const llvm_triple = try @import("llvm_backend.zig").targetTriple(arena, target); + const llvm_triple = try @import("codegen/llvm.zig").targetTriple(arena, target); try argv.appendSlice(&[_][]const u8{ "-target", llvm_triple }); switch (ext) { diff --git a/src/llvm_backend.zig b/src/codegen/llvm.zig similarity index 64% rename from src/llvm_backend.zig rename to src/codegen/llvm.zig index b0e59e3ffa..df97f7e0ef 100644 --- a/src/llvm_backend.zig +++ b/src/codegen/llvm.zig @@ -1,17 +1,18 @@ const std = @import("std"); const assert = std.debug.assert; const Allocator = std.mem.Allocator; -const Compilation = @import("Compilation.zig"); -const llvm = @import("llvm_bindings.zig"); -const link = @import("link.zig"); +const Compilation = @import("../Compilation.zig"); +const llvm = @import("llvm/bindings.zig"); +const link = @import("../link.zig"); +const log = std.log.scoped(.codegen); -const Module = @import("Module.zig"); -const TypedValue = @import("TypedValue.zig"); -const ir = @import("ir.zig"); +const Module = @import("../Module.zig"); +const TypedValue = @import("../TypedValue.zig"); +const ir = @import("../ir.zig"); const Inst = ir.Inst; -const Value = @import("value.zig").Value; -const Type = @import("type.zig").Type; +const Value = @import("../value.zig").Value; +const Type = @import("../type.zig").Type; pub fn targetTriple(allocator: *Allocator, target: std.Target) ![:0]u8 { const llvm_arch = switch (target.cpu.arch) { @@ -138,23 +139,32 @@ pub fn targetTriple(allocator: *Allocator, target: std.Target) ![:0]u8 { pub const LLVMIRModule = struct { module: *Module, - llvm_module: *const llvm.ModuleRef, - target_machine: *const llvm.TargetMachineRef, - builder: *const llvm.BuilderRef, + llvm_module: *const llvm.Module, + context: *const llvm.Context, + target_machine: *const llvm.TargetMachine, + builder: *const llvm.Builder, object_path: []const u8, gpa: *Allocator, err_msg: ?*Compilation.ErrorMsg = null, + // TODO: The fields below should really move into a different struct, + // because they are only valid when generating a function + /// This stores the LLVM values used in a function, such that they can be /// referred to in other instructions. This table is cleared before every function is generated. - func_inst_table: std.AutoHashMapUnmanaged(*Inst, *const llvm.ValueRef) = .{}, + func_inst_table: std.AutoHashMapUnmanaged(*Inst, *const llvm.Value) = .{}, /// These fields are used to refer to the LLVM value of the function paramaters in an Arg instruction. - args: []*const llvm.ValueRef = &[_]*const llvm.ValueRef{}, + args: []*const llvm.Value = &[_]*const llvm.Value{}, arg_index: usize = 0, + entry_block: *const llvm.BasicBlock = undefined, + /// This fields stores the last alloca instruction, such that we can append more alloca instructions + /// to the top of the function. + latest_alloca_inst: ?*const llvm.Value = null, + pub fn create(allocator: *Allocator, sub_path: []const u8, options: link.Options) !*LLVMIRModule { const self = try allocator.create(LLVMIRModule); errdefer allocator.destroy(self); @@ -172,19 +182,22 @@ pub const LLVMIRModule = struct { const object_path = try o_directory.join(gpa, &[_][]const u8{obj_basename}); errdefer gpa.free(object_path); + const context = llvm.Context.create(); + errdefer context.dispose(); + initializeLLVMTargets(); const root_nameZ = try gpa.dupeZ(u8, options.root_name); defer gpa.free(root_nameZ); - const llvm_module = llvm.ModuleRef.createWithName(root_nameZ.ptr); - errdefer llvm_module.disposeModule(); + const llvm_module = llvm.Module.createWithName(root_nameZ.ptr, context); + errdefer llvm_module.dispose(); const llvm_target_triple = try targetTriple(gpa, options.target); defer gpa.free(llvm_target_triple); var error_message: [*:0]const u8 = undefined; - var target_ref: *const llvm.TargetRef = undefined; - if (llvm.TargetRef.getTargetFromTriple(llvm_target_triple.ptr, &target_ref, &error_message)) { + var target: *const llvm.Target = undefined; + if (llvm.Target.getFromTriple(llvm_target_triple.ptr, &target, &error_message)) { defer llvm.disposeMessage(error_message); const stderr = std.io.getStdErr().outStream(); @@ -204,8 +217,8 @@ pub const LLVMIRModule = struct { } const opt_level: llvm.CodeGenOptLevel = if (options.optimize_mode == .Debug) .None else .Aggressive; - const target_machine = llvm.TargetMachineRef.createTargetMachine( - target_ref, + const target_machine = llvm.TargetMachine.create( + target, llvm_target_triple.ptr, "", "", @@ -213,14 +226,15 @@ pub const LLVMIRModule = struct { .Static, .Default, ); - errdefer target_machine.disposeTargetMachine(); + errdefer target_machine.dispose(); - const builder = llvm.BuilderRef.createBuilder(); - errdefer builder.disposeBuilder(); + const builder = context.createBuilder(); + errdefer builder.dispose(); self.* = .{ .module = options.module.?, .llvm_module = llvm_module, + .context = context, .target_machine = target_machine, .builder = builder, .object_path = object_path, @@ -230,9 +244,10 @@ pub const LLVMIRModule = struct { } pub fn deinit(self: *LLVMIRModule, allocator: *Allocator) void { - self.builder.disposeBuilder(); - self.target_machine.disposeTargetMachine(); - self.llvm_module.disposeModule(); + self.builder.dispose(); + self.target_machine.dispose(); + self.llvm_module.dispose(); + self.context.dispose(); self.func_inst_table.deinit(self.gpa); self.gpa.free(self.object_path); @@ -262,7 +277,7 @@ pub const LLVMIRModule = struct { // verifyModule always allocs the error_message even if there is no error defer llvm.disposeMessage(error_message); - if (self.llvm_module.verifyModule(.ReturnStatus, &error_message)) { + if (self.llvm_module.verify(.ReturnStatus, &error_message)) { const stderr = std.io.getStdErr().outStream(); try stderr.print("broken LLVM module found: {s}\nThis is a bug in the Zig compiler.", .{error_message}); return error.BrokenLLVMModule; @@ -288,8 +303,7 @@ pub const LLVMIRModule = struct { } pub fn updateDecl(self: *LLVMIRModule, module: *Module, decl: *Module.Decl) !void { - const typed_value = decl.typed_value.most_recent.typed_value; - self.gen(module, typed_value, decl.src()) catch |err| switch (err) { + self.gen(module, decl) catch |err| switch (err) { error.CodegenFail => { decl.analysis = .codegen_failure; try module.failed_decls.put(module.gpa, decl, self.err_msg.?); @@ -300,15 +314,20 @@ pub const LLVMIRModule = struct { }; } - fn gen(self: *LLVMIRModule, module: *Module, typed_value: TypedValue, src: usize) !void { - if (typed_value.val.castTag(.function)) |func_inst| { - const func = func_inst.data; + fn gen(self: *LLVMIRModule, module: *Module, decl: *Module.Decl) !void { + const typed_value = decl.typed_value.most_recent.typed_value; + const src = decl.src(); - const llvm_func = try self.resolveLLVMFunction(func, src); + log.debug("gen: {s} type: {}, value: {}", .{ decl.name, typed_value.ty, typed_value.val }); + + if (typed_value.val.castTag(.function)) |func_payload| { + const func = func_payload.data; + + const llvm_func = try self.resolveLLVMFunction(func.owner_decl, src); // This gets the LLVM values from the function and stores them in `self.args`. const fn_param_len = func.owner_decl.typed_value.most_recent.typed_value.ty.fnParamLen(); - var args = try self.gpa.alloc(*const llvm.ValueRef, fn_param_len); + var args = try self.gpa.alloc(*const llvm.Value, fn_param_len); defer self.gpa.free(args); for (args) |*arg, i| { @@ -327,12 +346,13 @@ pub const LLVMIRModule = struct { bb.deleteBasicBlock(); } - const entry_block = llvm_func.appendBasicBlock("Entry"); - self.builder.positionBuilderAtEnd(entry_block); + self.entry_block = self.context.appendBasicBlock(llvm_func, "Entry"); + self.builder.positionBuilderAtEnd(self.entry_block); + self.latest_alloca_inst = null; const instructions = func.body.instructions; for (instructions) |inst| { - const opt_llvm_val: ?*const llvm.ValueRef = switch (inst.tag) { + const opt_llvm_val: ?*const llvm.Value = switch (inst.tag) { .add => try self.genAdd(inst.castTag(.add).?), .alloc => try self.genAlloc(inst.castTag(.alloc).?), .arg => try self.genArg(inst.castTag(.arg).?), @@ -355,70 +375,77 @@ pub const LLVMIRModule = struct { }; if (opt_llvm_val) |llvm_val| try self.func_inst_table.putNoClobber(self.gpa, inst, llvm_val); } + } else if (typed_value.val.castTag(.extern_fn)) |extern_fn| { + _ = try self.resolveLLVMFunction(extern_fn.data, src); } else { - return self.fail(src, "TODO implement LLVM codegen for top-level decl type: {}", .{typed_value.ty}); + _ = try self.resolveGlobalDecl(decl, src); } } - fn genCall(self: *LLVMIRModule, inst: *Inst.Call) !?*const llvm.ValueRef { + fn genCall(self: *LLVMIRModule, inst: *Inst.Call) !?*const llvm.Value { if (inst.func.value()) |func_value| { - if (func_value.castTag(.function)) |func_payload| { - const func = func_payload.data; - const zig_fn_type = func.owner_decl.typed_value.most_recent.typed_value.ty; - const llvm_fn = try self.resolveLLVMFunction(func, inst.base.src); + const fn_decl = if (func_value.castTag(.extern_fn)) |extern_fn| + extern_fn.data + else if (func_value.castTag(.function)) |func_payload| + func_payload.data.owner_decl + else + unreachable; - const num_args = inst.args.len; + const zig_fn_type = fn_decl.typed_value.most_recent.typed_value.ty; + const llvm_fn = try self.resolveLLVMFunction(fn_decl, inst.base.src); - const llvm_param_vals = try self.gpa.alloc(*const llvm.ValueRef, num_args); - defer self.gpa.free(llvm_param_vals); + const num_args = inst.args.len; - for (inst.args) |arg, i| { - llvm_param_vals[i] = try self.resolveInst(arg); - } + const llvm_param_vals = try self.gpa.alloc(*const llvm.Value, num_args); + defer self.gpa.free(llvm_param_vals); - // TODO: LLVMBuildCall2 handles opaque function pointers, according to llvm docs - // Do we need that? - const call = self.builder.buildCall( - llvm_fn, - if (num_args == 0) null else llvm_param_vals.ptr, - @intCast(c_uint, num_args), - "", - ); - - const return_type = zig_fn_type.fnReturnType(); - if (return_type.tag() == .noreturn) { - _ = self.builder.buildUnreachable(); - } - - // No need to store the LLVM value if the return type is void or noreturn - if (!return_type.hasCodeGenBits()) return null; - - return call; + for (inst.args) |arg, i| { + llvm_param_vals[i] = try self.resolveInst(arg); } + + // TODO: LLVMBuildCall2 handles opaque function pointers, according to llvm docs + // Do we need that? + const call = self.builder.buildCall( + llvm_fn, + if (num_args == 0) null else llvm_param_vals.ptr, + @intCast(c_uint, num_args), + "", + ); + + const return_type = zig_fn_type.fnReturnType(); + if (return_type.tag() == .noreturn) { + _ = self.builder.buildUnreachable(); + } + + // No need to store the LLVM value if the return type is void or noreturn + if (!return_type.hasCodeGenBits()) return null; + + return call; + } else { + return self.fail(inst.base.src, "TODO implement calling runtime known function pointer LLVM backend", .{}); } - return self.fail(inst.base.src, "TODO implement calling runtime known function pointer LLVM backend", .{}); } - fn genRetVoid(self: *LLVMIRModule, inst: *Inst.NoOp) ?*const llvm.ValueRef { + fn genRetVoid(self: *LLVMIRModule, inst: *Inst.NoOp) ?*const llvm.Value { _ = self.builder.buildRetVoid(); return null; } - fn genRet(self: *LLVMIRModule, inst: *Inst.UnOp) !?*const llvm.ValueRef { + fn genRet(self: *LLVMIRModule, inst: *Inst.UnOp) !?*const llvm.Value { _ = self.builder.buildRet(try self.resolveInst(inst.operand)); return null; } - fn genNot(self: *LLVMIRModule, inst: *Inst.UnOp) !?*const llvm.ValueRef { + fn genNot(self: *LLVMIRModule, inst: *Inst.UnOp) !?*const llvm.Value { return self.builder.buildNot(try self.resolveInst(inst.operand), ""); } - fn genUnreach(self: *LLVMIRModule, inst: *Inst.NoOp) ?*const llvm.ValueRef { + fn genUnreach(self: *LLVMIRModule, inst: *Inst.NoOp) ?*const llvm.Value { _ = self.builder.buildUnreachable(); return null; } - fn genAdd(self: *LLVMIRModule, inst: *Inst.BinOp) !?*const llvm.ValueRef { + fn genAdd(self: *LLVMIRModule, inst: *Inst.BinOp) !?*const llvm.Value { const lhs = try self.resolveInst(inst.lhs); const rhs = try self.resolveInst(inst.rhs); @@ -431,7 +458,7 @@ pub const LLVMIRModule = struct { self.builder.buildNUWAdd(lhs, rhs, ""); } - fn genSub(self: *LLVMIRModule, inst: *Inst.BinOp) !?*const llvm.ValueRef { + fn genSub(self: *LLVMIRModule, inst: *Inst.BinOp) !?*const llvm.Value { const lhs = try self.resolveInst(inst.lhs); const rhs = try self.resolveInst(inst.rhs); @@ -444,7 +471,7 @@ pub const LLVMIRModule = struct { self.builder.buildNUWSub(lhs, rhs, ""); } - fn genIntCast(self: *LLVMIRModule, inst: *Inst.UnOp) !?*const llvm.ValueRef { + fn genIntCast(self: *LLVMIRModule, inst: *Inst.UnOp) !?*const llvm.Value { const val = try self.resolveInst(inst.operand); const signed = inst.base.ty.isSignedInt(); @@ -453,51 +480,73 @@ pub const LLVMIRModule = struct { return self.builder.buildIntCast2(val, try self.getLLVMType(inst.base.ty, inst.base.src), signed, ""); } - fn genBitCast(self: *LLVMIRModule, inst: *Inst.UnOp) !?*const llvm.ValueRef { + fn genBitCast(self: *LLVMIRModule, inst: *Inst.UnOp) !?*const llvm.Value { const val = try self.resolveInst(inst.operand); const dest_type = try self.getLLVMType(inst.base.ty, inst.base.src); return self.builder.buildBitCast(val, dest_type, ""); } - fn genArg(self: *LLVMIRModule, inst: *Inst.Arg) !?*const llvm.ValueRef { + fn genArg(self: *LLVMIRModule, inst: *Inst.Arg) !?*const llvm.Value { const arg_val = self.args[self.arg_index]; self.arg_index += 1; - const ptr_val = self.builder.buildAlloca(try self.getLLVMType(inst.base.ty, inst.base.src), ""); + const ptr_val = self.buildAlloca(try self.getLLVMType(inst.base.ty, inst.base.src)); _ = self.builder.buildStore(arg_val, ptr_val); return self.builder.buildLoad(ptr_val, ""); } - fn genAlloc(self: *LLVMIRModule, inst: *Inst.NoOp) !?*const llvm.ValueRef { + fn genAlloc(self: *LLVMIRModule, inst: *Inst.NoOp) !?*const llvm.Value { // buildAlloca expects the pointee type, not the pointer type, so assert that // a Payload.PointerSimple is passed to the alloc instruction. const pointee_type = inst.base.ty.castPointer().?.data; // TODO: figure out a way to get the name of the var decl. // TODO: set alignment and volatile - return self.builder.buildAlloca(try self.getLLVMType(pointee_type, inst.base.src), ""); + return self.buildAlloca(try self.getLLVMType(pointee_type, inst.base.src)); } - fn genStore(self: *LLVMIRModule, inst: *Inst.BinOp) !?*const llvm.ValueRef { + /// Use this instead of builder.buildAlloca, because this function makes sure to + /// put the alloca instruction at the top of the function! + fn buildAlloca(self: *LLVMIRModule, t: *const llvm.Type) *const llvm.Value { + if (self.latest_alloca_inst) |latest_alloc| { + // builder.positionBuilder adds it before the instruction, + // but we want to put it after the last alloca instruction. + self.builder.positionBuilder(self.entry_block, latest_alloc.getNextInstruction().?); + } else { + // There might have been other instructions emitted before the + // first alloca has been generated. However the alloca should still + // be first in the function. + if (self.entry_block.getFirstInstruction()) |first_inst| { + self.builder.positionBuilder(self.entry_block, first_inst); + } + } + defer self.builder.positionBuilderAtEnd(self.entry_block); + + const val = self.builder.buildAlloca(t, ""); + self.latest_alloca_inst = val; + return val; + } + + fn genStore(self: *LLVMIRModule, inst: *Inst.BinOp) !?*const llvm.Value { const val = try self.resolveInst(inst.rhs); const ptr = try self.resolveInst(inst.lhs); _ = self.builder.buildStore(val, ptr); return null; } - fn genLoad(self: *LLVMIRModule, inst: *Inst.UnOp) !?*const llvm.ValueRef { + fn genLoad(self: *LLVMIRModule, inst: *Inst.UnOp) !?*const llvm.Value { const ptr_val = try self.resolveInst(inst.operand); return self.builder.buildLoad(ptr_val, ""); } - fn genBreakpoint(self: *LLVMIRModule, inst: *Inst.NoOp) !?*const llvm.ValueRef { + fn genBreakpoint(self: *LLVMIRModule, inst: *Inst.NoOp) !?*const llvm.Value { const llvn_fn = self.getIntrinsic("llvm.debugtrap"); _ = self.builder.buildCall(llvn_fn, null, 0, ""); return null; } - fn getIntrinsic(self: *LLVMIRModule, name: []const u8) *const llvm.ValueRef { + fn getIntrinsic(self: *LLVMIRModule, name: []const u8) *const llvm.Value { const id = llvm.lookupIntrinsicID(name.ptr, name.len); assert(id != 0); // TODO: add support for overload intrinsics by passing the prefix of the intrinsic @@ -506,7 +555,7 @@ pub const LLVMIRModule = struct { return self.llvm_module.getIntrinsicDeclaration(id, null, 0); } - fn resolveInst(self: *LLVMIRModule, inst: *ir.Inst) !*const llvm.ValueRef { + fn resolveInst(self: *LLVMIRModule, inst: *ir.Inst) !*const llvm.Value { if (inst.value()) |val| { return self.genTypedValue(inst.src, .{ .ty = inst.ty, .val = val }); } @@ -515,7 +564,7 @@ pub const LLVMIRModule = struct { return self.fail(inst.src, "TODO implement global llvm values (or the value is not in the func_inst_table table)", .{}); } - fn genTypedValue(self: *LLVMIRModule, src: usize, tv: TypedValue) !*const llvm.ValueRef { + fn genTypedValue(self: *LLVMIRModule, src: usize, tv: TypedValue) error{ OutOfMemory, CodegenFail }!*const llvm.Value { const llvm_type = try self.getLLVMType(tv.ty, src); if (tv.val.isUndef()) @@ -538,16 +587,89 @@ pub const LLVMIRModule = struct { } return llvm_int; }, + .Pointer => switch (tv.val.tag()) { + .decl_ref => { + const decl = tv.val.castTag(.decl_ref).?.data; + const val = try self.resolveGlobalDecl(decl, src); + + const usize_type = try self.getLLVMType(Type.initTag(.usize), src); + + // TODO: second index should be the index into the memory! + var indices: [2]*const llvm.Value = .{ + usize_type.constNull(), + usize_type.constNull(), + }; + + // TODO: consider using buildInBoundsGEP2 for opaque pointers + return self.builder.buildInBoundsGEP(val, &indices, 2, ""); + }, + else => return self.fail(src, "TODO implement const of pointer type '{}'", .{tv.ty}), + }, + .Array => { + if (tv.val.castTag(.bytes)) |payload| { + const zero_sentinel = if (tv.ty.sentinel()) |sentinel| blk: { + if (sentinel.tag() == .zero) break :blk true; + return self.fail(src, "TODO handle other sentinel values", .{}); + } else false; + + return self.context.constString(payload.data.ptr, @intCast(c_uint, payload.data.len), !zero_sentinel); + } else { + return self.fail(src, "TODO handle more array values", .{}); + } + }, else => return self.fail(src, "TODO implement const of type '{}'", .{tv.ty}), } } - /// If the llvm function does not exist, create it - fn resolveLLVMFunction(self: *LLVMIRModule, func: *Module.Fn, src: usize) !*const llvm.ValueRef { - // TODO: do we want to store this in our own datastructure? - if (self.llvm_module.getNamedFunction(func.owner_decl.name)) |llvm_fn| return llvm_fn; + fn getLLVMType(self: *LLVMIRModule, t: Type, src: usize) error{ OutOfMemory, CodegenFail }!*const llvm.Type { + switch (t.zigTypeTag()) { + .Void => return self.context.voidType(), + .NoReturn => return self.context.voidType(), + .Int => { + const info = t.intInfo(self.module.getTarget()); + return self.context.intType(info.bits); + }, + .Bool => return self.context.intType(1), + .Pointer => { + if (t.isSlice()) { + return self.fail(src, "TODO: LLVM backend: implement slices", .{}); + } else { + const elem_type = try self.getLLVMType(t.elemType(), src); + return elem_type.pointerType(0); + } + }, + .Array => { + const elem_type = try self.getLLVMType(t.elemType(), src); + return elem_type.arrayType(@intCast(c_uint, t.abiSize(self.module.getTarget()))); + }, + else => return self.fail(src, "TODO implement getLLVMType for type '{}'", .{t}), + } + } - const zig_fn_type = func.owner_decl.typed_value.most_recent.typed_value.ty; + fn resolveGlobalDecl(self: *LLVMIRModule, decl: *Module.Decl, src: usize) error{ OutOfMemory, CodegenFail }!*const llvm.Value { + // TODO: do we want to store this in our own datastructure? + if (self.llvm_module.getNamedGlobal(decl.name)) |val| return val; + + const typed_value = decl.typed_value.most_recent.typed_value; + + // TODO: remove this redundant `getLLVMType`, it is also called in `genTypedValue`. + const llvm_type = try self.getLLVMType(typed_value.ty, src); + const val = try self.genTypedValue(src, typed_value); + const global = self.llvm_module.addGlobal(llvm_type, decl.name); + llvm.setInitializer(global, val); + + // TODO ask the Decl if it is const + // https://github.com/ziglang/zig/issues/7582 + + return global; + } + + /// If the llvm function does not exist, create it + fn resolveLLVMFunction(self: *LLVMIRModule, func: *Module.Decl, src: usize) !*const llvm.Value { + // TODO: do we want to store this in our own datastructure? + if (self.llvm_module.getNamedFunction(func.name)) |llvm_fn| return llvm_fn; + + const zig_fn_type = func.typed_value.most_recent.typed_value.ty; const return_type = zig_fn_type.fnReturnType(); const fn_param_len = zig_fn_type.fnParamLen(); @@ -556,44 +678,39 @@ pub const LLVMIRModule = struct { defer self.gpa.free(fn_param_types); zig_fn_type.fnParamTypes(fn_param_types); - const llvm_param = try self.gpa.alloc(*const llvm.TypeRef, fn_param_len); + const llvm_param = try self.gpa.alloc(*const llvm.Type, fn_param_len); defer self.gpa.free(llvm_param); for (fn_param_types) |fn_param, i| { llvm_param[i] = try self.getLLVMType(fn_param, src); } - const fn_type = llvm.TypeRef.functionType( + const fn_type = llvm.Type.functionType( try self.getLLVMType(return_type, src), if (fn_param_len == 0) null else llvm_param.ptr, @intCast(c_uint, fn_param_len), false, ); - const llvm_fn = self.llvm_module.addFunction(func.owner_decl.name, fn_type); + const llvm_fn = self.llvm_module.addFunction(func.name, fn_type); if (return_type.tag() == .noreturn) { - llvm_fn.addFnAttr("noreturn"); + self.addFnAttr(llvm_fn, "noreturn"); } return llvm_fn; } - fn getLLVMType(self: *LLVMIRModule, t: Type, src: usize) error{ OutOfMemory, CodegenFail }!*const llvm.TypeRef { - switch (t.zigTypeTag()) { - .Void => return llvm.voidType(), - .NoReturn => return llvm.voidType(), - .Int => { - const info = t.intInfo(self.module.getTarget()); - return llvm.intType(info.bits); - }, - .Bool => return llvm.intType(1), - .Pointer => { - const pointer = t.castPointer().?; - const elem_type = try self.getLLVMType(pointer.data, src); - return elem_type.pointerType(0); - }, - else => return self.fail(src, "TODO implement getLLVMType for type '{}'", .{t}), - } + // Helper functions + fn addAttr(self: LLVMIRModule, val: *const llvm.Value, index: llvm.AttributeIndex, name: []const u8) void { + const kind_id = llvm.getEnumAttributeKindForName(name.ptr, name.len); + assert(kind_id != 0); + const llvm_attr = self.context.createEnumAttribute(kind_id, 0); + val.addAttributeAtIndex(index, llvm_attr); + } + + fn addFnAttr(self: *LLVMIRModule, val: *const llvm.Value, attr_name: []const u8) void { + // TODO: improve this API, `addAttr(-1, attr_name)` + self.addAttr(val, std.math.maxInt(llvm.AttributeIndex), attr_name); } pub fn fail(self: *LLVMIRModule, src: usize, comptime format: []const u8, args: anytype) error{ OutOfMemory, CodegenFail } { diff --git a/src/llvm_bindings.zig b/src/codegen/llvm/bindings.zig similarity index 66% rename from src/llvm_bindings.zig rename to src/codegen/llvm/bindings.zig index aa95537328..cd928877b1 100644 --- a/src/llvm_bindings.zig +++ b/src/codegen/llvm/bindings.zig @@ -1,79 +1,100 @@ //! We do this instead of @cImport because the self-hosted compiler is easier //! to bootstrap if it does not depend on translate-c. -const std = @import("std"); -const assert = std.debug.assert; - const LLVMBool = bool; -pub const LLVMAttributeIndex = c_uint; +pub const AttributeIndex = c_uint; -pub const ValueRef = opaque { +/// Make sure to use the *InContext functions instead of the global ones. +pub const Context = opaque { + pub const create = LLVMContextCreate; + extern fn LLVMContextCreate() *const Context; + + pub const dispose = LLVMContextDispose; + extern fn LLVMContextDispose(C: *const Context) void; + + pub const createEnumAttribute = LLVMCreateEnumAttribute; + extern fn LLVMCreateEnumAttribute(*const Context, KindID: c_uint, Val: u64) *const Attribute; + + pub const intType = LLVMIntTypeInContext; + extern fn LLVMIntTypeInContext(C: *const Context, NumBits: c_uint) *const Type; + + pub const voidType = LLVMVoidTypeInContext; + extern fn LLVMVoidTypeInContext(C: *const Context) *const Type; + + pub const constString = LLVMConstStringInContext; + extern fn LLVMConstStringInContext(C: *const Context, Str: [*]const u8, Length: c_uint, DontNullTerminate: LLVMBool) *const Value; + + pub const appendBasicBlock = LLVMAppendBasicBlockInContext; + extern fn LLVMAppendBasicBlockInContext(C: *const Context, Fn: *const Value, Name: [*:0]const u8) *const BasicBlock; + + pub const createBuilder = LLVMCreateBuilderInContext; + extern fn LLVMCreateBuilderInContext(C: *const Context) *const Builder; +}; + +pub const Value = opaque { pub const addAttributeAtIndex = LLVMAddAttributeAtIndex; - extern fn LLVMAddAttributeAtIndex(*const ValueRef, Idx: LLVMAttributeIndex, A: *const AttributeRef) void; - - pub const appendBasicBlock = LLVMAppendBasicBlock; - extern fn LLVMAppendBasicBlock(Fn: *const ValueRef, Name: [*:0]const u8) *const BasicBlockRef; + extern fn LLVMAddAttributeAtIndex(*const Value, Idx: AttributeIndex, A: *const Attribute) void; pub const getFirstBasicBlock = LLVMGetFirstBasicBlock; - extern fn LLVMGetFirstBasicBlock(Fn: *const ValueRef) ?*const BasicBlockRef; + extern fn LLVMGetFirstBasicBlock(Fn: *const Value) ?*const BasicBlock; - // Helper functions - // TODO: Do we want to put these functions here? It allows for convienient function calls - // on ValueRef: llvm_fn.addFnAttr("noreturn") - fn addAttr(val: *const ValueRef, index: LLVMAttributeIndex, name: []const u8) void { - const kind_id = getEnumAttributeKindForName(name.ptr, name.len); - assert(kind_id != 0); - const llvm_attr = ContextRef.getGlobal().createEnumAttribute(kind_id, 0); - val.addAttributeAtIndex(index, llvm_attr); - } - - pub fn addFnAttr(val: *const ValueRef, attr_name: []const u8) void { - // TODO: improve this API, `addAttr(-1, attr_name)` - val.addAttr(std.math.maxInt(LLVMAttributeIndex), attr_name); - } + pub const getNextInstruction = LLVMGetNextInstruction; + extern fn LLVMGetNextInstruction(Inst: *const Value) ?*const Value; }; -pub const TypeRef = opaque { +pub const Type = opaque { pub const functionType = LLVMFunctionType; - extern fn LLVMFunctionType(ReturnType: *const TypeRef, ParamTypes: ?[*]*const TypeRef, ParamCount: c_uint, IsVarArg: LLVMBool) *const TypeRef; + extern fn LLVMFunctionType(ReturnType: *const Type, ParamTypes: ?[*]*const Type, ParamCount: c_uint, IsVarArg: LLVMBool) *const Type; pub const constNull = LLVMConstNull; - extern fn LLVMConstNull(Ty: *const TypeRef) *const ValueRef; + extern fn LLVMConstNull(Ty: *const Type) *const Value; pub const constAllOnes = LLVMConstAllOnes; - extern fn LLVMConstAllOnes(Ty: *const TypeRef) *const ValueRef; + extern fn LLVMConstAllOnes(Ty: *const Type) *const Value; pub const constInt = LLVMConstInt; - extern fn LLVMConstInt(IntTy: *const TypeRef, N: c_ulonglong, SignExtend: LLVMBool) *const ValueRef; + extern fn LLVMConstInt(IntTy: *const Type, N: c_ulonglong, SignExtend: LLVMBool) *const Value; + + pub const constArray = LLVMConstArray; + extern fn LLVMConstArray(ElementTy: *const Type, ConstantVals: ?[*]*const Value, Length: c_uint) *const Value; pub const getUndef = LLVMGetUndef; - extern fn LLVMGetUndef(Ty: *const TypeRef) *const ValueRef; + extern fn LLVMGetUndef(Ty: *const Type) *const Value; pub const pointerType = LLVMPointerType; - extern fn LLVMPointerType(ElementType: *const TypeRef, AddressSpace: c_uint) *const TypeRef; + extern fn LLVMPointerType(ElementType: *const Type, AddressSpace: c_uint) *const Type; + + pub const arrayType = LLVMArrayType; + extern fn LLVMArrayType(ElementType: *const Type, ElementCount: c_uint) *const Type; }; -pub const ModuleRef = opaque { - pub const createWithName = LLVMModuleCreateWithName; - extern fn LLVMModuleCreateWithName(ModuleID: [*:0]const u8) *const ModuleRef; +pub const Module = opaque { + pub const createWithName = LLVMModuleCreateWithNameInContext; + extern fn LLVMModuleCreateWithNameInContext(ModuleID: [*:0]const u8, C: *const Context) *const Module; - pub const disposeModule = LLVMDisposeModule; - extern fn LLVMDisposeModule(*const ModuleRef) void; + pub const dispose = LLVMDisposeModule; + extern fn LLVMDisposeModule(*const Module) void; - pub const verifyModule = LLVMVerifyModule; - extern fn LLVMVerifyModule(*const ModuleRef, Action: VerifierFailureAction, OutMessage: *[*:0]const u8) LLVMBool; + pub const verify = LLVMVerifyModule; + extern fn LLVMVerifyModule(*const Module, Action: VerifierFailureAction, OutMessage: *[*:0]const u8) LLVMBool; pub const addFunction = LLVMAddFunction; - extern fn LLVMAddFunction(*const ModuleRef, Name: [*:0]const u8, FunctionTy: *const TypeRef) *const ValueRef; + extern fn LLVMAddFunction(*const Module, Name: [*:0]const u8, FunctionTy: *const Type) *const Value; pub const getNamedFunction = LLVMGetNamedFunction; - extern fn LLVMGetNamedFunction(*const ModuleRef, Name: [*:0]const u8) ?*const ValueRef; + extern fn LLVMGetNamedFunction(*const Module, Name: [*:0]const u8) ?*const Value; pub const getIntrinsicDeclaration = LLVMGetIntrinsicDeclaration; - extern fn LLVMGetIntrinsicDeclaration(Mod: *const ModuleRef, ID: c_uint, ParamTypes: ?[*]*const TypeRef, ParamCount: usize) *const ValueRef; + extern fn LLVMGetIntrinsicDeclaration(Mod: *const Module, ID: c_uint, ParamTypes: ?[*]*const Type, ParamCount: usize) *const Value; pub const printToString = LLVMPrintModuleToString; - extern fn LLVMPrintModuleToString(*const ModuleRef) [*:0]const u8; + extern fn LLVMPrintModuleToString(*const Module) [*:0]const u8; + + pub const addGlobal = LLVMAddGlobal; + extern fn LLVMAddGlobal(M: *const Module, Ty: *const Type, Name: [*:0]const u8) *const Value; + + pub const getNamedGlobal = LLVMGetNamedGlobal; + extern fn LLVMGetNamedGlobal(M: *const Module, Name: [*:0]const u8) ?*const Value; }; pub const lookupIntrinsicID = LLVMLookupIntrinsicID; @@ -89,111 +110,106 @@ pub const VerifierFailureAction = extern enum { }; pub const constNeg = LLVMConstNeg; -extern fn LLVMConstNeg(ConstantVal: *const ValueRef) *const ValueRef; +extern fn LLVMConstNeg(ConstantVal: *const Value) *const Value; -pub const voidType = LLVMVoidType; -extern fn LLVMVoidType() *const TypeRef; +pub const setInitializer = LLVMSetInitializer; +extern fn LLVMSetInitializer(GlobalVar: *const Value, ConstantVal: *const Value) void; pub const getParam = LLVMGetParam; -extern fn LLVMGetParam(Fn: *const ValueRef, Index: c_uint) *const ValueRef; +extern fn LLVMGetParam(Fn: *const Value, Index: c_uint) *const Value; pub const getEnumAttributeKindForName = LLVMGetEnumAttributeKindForName; extern fn LLVMGetEnumAttributeKindForName(Name: [*]const u8, SLen: usize) c_uint; -pub const AttributeRef = opaque {}; +pub const Attribute = opaque {}; -pub const ContextRef = opaque { - pub const createEnumAttribute = LLVMCreateEnumAttribute; - extern fn LLVMCreateEnumAttribute(*const ContextRef, KindID: c_uint, Val: u64) *const AttributeRef; +pub const Builder = opaque { + pub const dispose = LLVMDisposeBuilder; + extern fn LLVMDisposeBuilder(Builder: *const Builder) void; - pub const getGlobal = LLVMGetGlobalContext; - extern fn LLVMGetGlobalContext() *const ContextRef; -}; - -pub const intType = LLVMIntType; -extern fn LLVMIntType(NumBits: c_uint) *const TypeRef; - -pub const BuilderRef = opaque { - pub const createBuilder = LLVMCreateBuilder; - extern fn LLVMCreateBuilder() *const BuilderRef; - - pub const disposeBuilder = LLVMDisposeBuilder; - extern fn LLVMDisposeBuilder(Builder: *const BuilderRef) void; + pub const positionBuilder = LLVMPositionBuilder; + extern fn LLVMPositionBuilder(Builder: *const Builder, Block: *const BasicBlock, Instr: *const Value) void; pub const positionBuilderAtEnd = LLVMPositionBuilderAtEnd; - extern fn LLVMPositionBuilderAtEnd(Builder: *const BuilderRef, Block: *const BasicBlockRef) void; + extern fn LLVMPositionBuilderAtEnd(Builder: *const Builder, Block: *const BasicBlock) void; pub const getInsertBlock = LLVMGetInsertBlock; - extern fn LLVMGetInsertBlock(Builder: *const BuilderRef) *const BasicBlockRef; + extern fn LLVMGetInsertBlock(Builder: *const Builder) *const BasicBlock; pub const buildCall = LLVMBuildCall; - extern fn LLVMBuildCall(*const BuilderRef, Fn: *const ValueRef, Args: ?[*]*const ValueRef, NumArgs: c_uint, Name: [*:0]const u8) *const ValueRef; + extern fn LLVMBuildCall(*const Builder, Fn: *const Value, Args: ?[*]*const Value, NumArgs: c_uint, Name: [*:0]const u8) *const Value; pub const buildCall2 = LLVMBuildCall2; - extern fn LLVMBuildCall2(*const BuilderRef, *const TypeRef, Fn: *const ValueRef, Args: [*]*const ValueRef, NumArgs: c_uint, Name: [*:0]const u8) *const ValueRef; + extern fn LLVMBuildCall2(*const Builder, *const Type, Fn: *const Value, Args: [*]*const Value, NumArgs: c_uint, Name: [*:0]const u8) *const Value; pub const buildRetVoid = LLVMBuildRetVoid; - extern fn LLVMBuildRetVoid(*const BuilderRef) *const ValueRef; + extern fn LLVMBuildRetVoid(*const Builder) *const Value; pub const buildRet = LLVMBuildRet; - extern fn LLVMBuildRet(*const BuilderRef, V: *const ValueRef) *const ValueRef; + extern fn LLVMBuildRet(*const Builder, V: *const Value) *const Value; pub const buildUnreachable = LLVMBuildUnreachable; - extern fn LLVMBuildUnreachable(*const BuilderRef) *const ValueRef; + extern fn LLVMBuildUnreachable(*const Builder) *const Value; pub const buildAlloca = LLVMBuildAlloca; - extern fn LLVMBuildAlloca(*const BuilderRef, Ty: *const TypeRef, Name: [*:0]const u8) *const ValueRef; + extern fn LLVMBuildAlloca(*const Builder, Ty: *const Type, Name: [*:0]const u8) *const Value; pub const buildStore = LLVMBuildStore; - extern fn LLVMBuildStore(*const BuilderRef, Val: *const ValueRef, Ptr: *const ValueRef) *const ValueRef; + extern fn LLVMBuildStore(*const Builder, Val: *const Value, Ptr: *const Value) *const Value; pub const buildLoad = LLVMBuildLoad; - extern fn LLVMBuildLoad(*const BuilderRef, PointerVal: *const ValueRef, Name: [*:0]const u8) *const ValueRef; + extern fn LLVMBuildLoad(*const Builder, PointerVal: *const Value, Name: [*:0]const u8) *const Value; pub const buildNot = LLVMBuildNot; - extern fn LLVMBuildNot(*const BuilderRef, V: *const ValueRef, Name: [*:0]const u8) *const ValueRef; + extern fn LLVMBuildNot(*const Builder, V: *const Value, Name: [*:0]const u8) *const Value; pub const buildNSWAdd = LLVMBuildNSWAdd; - extern fn LLVMBuildNSWAdd(*const BuilderRef, LHS: *const ValueRef, RHS: *const ValueRef, Name: [*:0]const u8) *const ValueRef; + extern fn LLVMBuildNSWAdd(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value; pub const buildNUWAdd = LLVMBuildNUWAdd; - extern fn LLVMBuildNUWAdd(*const BuilderRef, LHS: *const ValueRef, RHS: *const ValueRef, Name: [*:0]const u8) *const ValueRef; + extern fn LLVMBuildNUWAdd(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value; pub const buildNSWSub = LLVMBuildNSWSub; - extern fn LLVMBuildNSWSub(*const BuilderRef, LHS: *const ValueRef, RHS: *const ValueRef, Name: [*:0]const u8) *const ValueRef; + extern fn LLVMBuildNSWSub(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value; pub const buildNUWSub = LLVMBuildNUWSub; - extern fn LLVMBuildNUWSub(*const BuilderRef, LHS: *const ValueRef, RHS: *const ValueRef, Name: [*:0]const u8) *const ValueRef; + extern fn LLVMBuildNUWSub(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value; pub const buildIntCast2 = LLVMBuildIntCast2; - extern fn LLVMBuildIntCast2(*const BuilderRef, Val: *const ValueRef, DestTy: *const TypeRef, IsSigned: LLVMBool, Name: [*:0]const u8) *const ValueRef; + extern fn LLVMBuildIntCast2(*const Builder, Val: *const Value, DestTy: *const Type, IsSigned: LLVMBool, Name: [*:0]const u8) *const Value; pub const buildBitCast = LLVMBuildBitCast; - extern fn LLVMBuildBitCast(*const BuilderRef, Val: *const ValueRef, DestTy: *const TypeRef, Name: [*:0]const u8) *const ValueRef; + extern fn LLVMBuildBitCast(*const Builder, Val: *const Value, DestTy: *const Type, Name: [*:0]const u8) *const Value; + + pub const buildInBoundsGEP = LLVMBuildInBoundsGEP; + extern fn LLVMBuildInBoundsGEP(B: *const Builder, Pointer: *const Value, Indices: [*]*const Value, NumIndices: c_uint, Name: [*:0]const u8) *const Value; }; -pub const BasicBlockRef = opaque { +pub const BasicBlock = opaque { pub const deleteBasicBlock = LLVMDeleteBasicBlock; - extern fn LLVMDeleteBasicBlock(BB: *const BasicBlockRef) void; + extern fn LLVMDeleteBasicBlock(BB: *const BasicBlock) void; + + pub const getFirstInstruction = LLVMGetFirstInstruction; + extern fn LLVMGetFirstInstruction(BB: *const BasicBlock) ?*const Value; }; -pub const TargetMachineRef = opaque { - pub const createTargetMachine = LLVMCreateTargetMachine; +pub const TargetMachine = opaque { + pub const create = LLVMCreateTargetMachine; extern fn LLVMCreateTargetMachine( - T: *const TargetRef, + T: *const Target, Triple: [*:0]const u8, CPU: [*:0]const u8, Features: [*:0]const u8, Level: CodeGenOptLevel, Reloc: RelocMode, CodeModel: CodeMode, - ) *const TargetMachineRef; + ) *const TargetMachine; - pub const disposeTargetMachine = LLVMDisposeTargetMachine; - extern fn LLVMDisposeTargetMachine(T: *const TargetMachineRef) void; + pub const dispose = LLVMDisposeTargetMachine; + extern fn LLVMDisposeTargetMachine(T: *const TargetMachine) void; pub const emitToFile = LLVMTargetMachineEmitToFile; - extern fn LLVMTargetMachineEmitToFile(*const TargetMachineRef, M: *const ModuleRef, Filename: [*:0]const u8, codegen: CodeGenFileType, ErrorMessage: *[*:0]const u8) LLVMBool; + extern fn LLVMTargetMachineEmitToFile(*const TargetMachine, M: *const Module, Filename: [*:0]const u8, codegen: CodeGenFileType, ErrorMessage: *[*:0]const u8) LLVMBool; }; pub const CodeMode = extern enum { @@ -228,9 +244,9 @@ pub const CodeGenFileType = extern enum { ObjectFile, }; -pub const TargetRef = opaque { - pub const getTargetFromTriple = LLVMGetTargetFromTriple; - extern fn LLVMGetTargetFromTriple(Triple: [*:0]const u8, T: **const TargetRef, ErrorMessage: *[*:0]const u8) LLVMBool; +pub const Target = opaque { + pub const getFromTriple = LLVMGetTargetFromTriple; + extern fn LLVMGetTargetFromTriple(Triple: [*:0]const u8, T: **const Target, ErrorMessage: *[*:0]const u8) LLVMBool; }; extern fn LLVMInitializeAArch64TargetInfo() void; diff --git a/src/link.zig b/src/link.zig index 18b093a07a..ffb69adee9 100644 --- a/src/link.zig +++ b/src/link.zig @@ -570,7 +570,7 @@ pub const File = struct { std.debug.print("\n", .{}); } - const llvm = @import("llvm_bindings.zig"); + const llvm = @import("codegen/llvm/bindings.zig"); const os_type = @import("target.zig").osToLLVM(base.options.target.os.tag); const bad = llvm.WriteArchive(full_out_path_z, object_files.items.ptr, object_files.items.len, os_type); if (bad) return error.UnableToWriteArchive; diff --git a/src/link/Coff.zig b/src/link/Coff.zig index 117bdef4a7..f7d646356c 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -16,7 +16,7 @@ const link = @import("../link.zig"); const build_options = @import("build_options"); const Cache = @import("../Cache.zig"); const mingw = @import("../mingw.zig"); -const llvm_backend = @import("../llvm_backend.zig"); +const llvm_backend = @import("../codegen/llvm.zig"); const allocation_padding = 4 / 3; const minimum_text_block_size = 64 * allocation_padding; diff --git a/src/link/Elf.zig b/src/link/Elf.zig index b6b8fd7750..f3073824a5 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -24,7 +24,7 @@ const build_options = @import("build_options"); const target_util = @import("../target.zig"); const glibc = @import("../glibc.zig"); const Cache = @import("../Cache.zig"); -const llvm_backend = @import("../llvm_backend.zig"); +const llvm_backend = @import("../codegen/llvm.zig"); const default_entry_addr = 0x8000000; diff --git a/src/main.zig b/src/main.zig index f026b6b4b4..ac31437f85 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1703,7 +1703,7 @@ fn buildOutputType( if (build_options.have_llvm and emit_asm != .no) { // LLVM has no way to set this non-globally. const argv = [_][*:0]const u8{ "zig (LLVM option parsing)", "--x86-asm-syntax=intel" }; - @import("llvm_bindings.zig").ParseCommandLineOptions(argv.len, &argv); + @import("codegen/llvm/bindings.zig").ParseCommandLineOptions(argv.len, &argv); } gimmeMoreOfThoseSweetSweetFileDescriptors(); @@ -2890,7 +2890,7 @@ pub fn punt_to_lld(arena: *Allocator, args: []const []const u8) error{OutOfMemor argv[i] = try arena.dupeZ(u8, arg); // TODO If there was an argsAllocZ we could avoid this allocation. } const exit_code = rc: { - const llvm = @import("llvm_bindings.zig"); + const llvm = @import("codegen/llvm/bindings.zig"); const argc = @intCast(c_int, argv.len); if (mem.eql(u8, args[1], "ld.lld")) { break :rc llvm.LinkELF(argc, argv.ptr, true); @@ -3275,7 +3275,7 @@ fn detectNativeTargetInfo(gpa: *Allocator, cross_target: std.zig.CrossTarget) !s if (!build_options.have_llvm) fatal("CPU features detection is not yet available for {s} without LLVM extensions", .{@tagName(arch)}); - const llvm = @import("llvm_bindings.zig"); + const llvm = @import("codegen/llvm/bindings.zig"); const llvm_cpu_name = llvm.GetHostCPUName(); const llvm_cpu_features = llvm.GetNativeFeatures(); info.target.cpu = try detectNativeCpuWithLLVM(arch, llvm_cpu_name, llvm_cpu_features); diff --git a/src/mingw.zig b/src/mingw.zig index d55cc28b2b..0a7669f995 100644 --- a/src/mingw.zig +++ b/src/mingw.zig @@ -405,7 +405,7 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void { }); errdefer comp.gpa.free(lib_final_path); - const llvm = @import("llvm_bindings.zig"); + const llvm = @import("codegen/llvm/bindings.zig"); const arch_type = @import("target.zig").archToLLVM(target.cpu.arch); const def_final_path_z = try arena.dupeZ(u8, def_final_path); const lib_final_path_z = try arena.dupeZ(u8, lib_final_path); diff --git a/src/target.zig b/src/target.zig index d33e8d06b0..daac577c7b 100644 --- a/src/target.zig +++ b/src/target.zig @@ -1,5 +1,5 @@ const std = @import("std"); -const llvm = @import("llvm_bindings.zig"); +const llvm = @import("codegen/llvm/bindings.zig"); pub const ArchOsAbi = struct { arch: std.Target.Cpu.Arch, diff --git a/test/stage2/llvm_backend.zig b/test/stage2/llvm.zig similarity index 71% rename from test/stage2/llvm_backend.zig rename to test/stage2/llvm.zig index 1b753621ea..ebb5fc390f 100644 --- a/test/stage2/llvm_backend.zig +++ b/test/stage2/llvm.zig @@ -27,4 +27,17 @@ pub fn addCases(ctx: *TestContext) !void { \\} , ""); } + + { + var case = ctx.exeUsingLlvmBackend("hello world", linux_x64); + + case.addCompareOutput( + \\extern fn puts(s: [*:0]const u8) c_int; + \\ + \\export fn main() c_int { + \\ _ = puts("hello world!"); + \\ return 0; + \\} + , "hello world!" ++ std.cstr.line_sep); + } } diff --git a/test/stage2/test.zig b/test/stage2/test.zig index 829ab421ea..cd1d6c259d 100644 --- a/test/stage2/test.zig +++ b/test/stage2/test.zig @@ -31,7 +31,7 @@ pub fn addCases(ctx: *TestContext) !void { try @import("spu-ii.zig").addCases(ctx); try @import("arm.zig").addCases(ctx); try @import("aarch64.zig").addCases(ctx); - try @import("llvm_backend.zig").addCases(ctx); + try @import("llvm.zig").addCases(ctx); { var case = ctx.exe("hello world with updates", linux_x64);