From 4d6d6977b05571e6d164dbf5f26c7a48ee3541a3 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 16 Oct 2021 12:26:06 -0700 Subject: [PATCH] stage2: fixes to extern variables * Relax compile error for "unable to export type foo" to allow integers, structs, arrays, and floats. This will need to be further improved to do the same checks as we do for C ABI struct field types. * LLVM backend: fix extern variables * LLVM backend: implement AIR instruction `wrap_err_union_payload` --- src/Module.zig | 9 ++++++ src/Sema.zig | 3 +- src/codegen/llvm.zig | 73 +++++++++++++++++++++++++++++++------------- 3 files changed, 63 insertions(+), 22 deletions(-) diff --git a/src/Module.zig b/src/Module.zig index 43c0178863..a42ec3c2e1 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -754,6 +754,15 @@ pub const Decl = struct { fn removeDependency(decl: *Decl, other: *Decl) void { assert(decl.dependencies.swapRemove(other)); } + + pub fn isExtern(decl: Decl) bool { + assert(decl.has_tv); + return switch (decl.val.tag()) { + .extern_fn => true, + .variable => decl.val.castTag(.variable).?.data.init.tag() == .unreachable_value, + else => false, + }; + } }; /// This state is attached to every Decl when Module emit_h is non-null. diff --git a/src/Sema.zig b/src/Sema.zig index 4c3f20f28b..e1874c6e8b 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -3020,8 +3020,9 @@ pub fn analyzeExport( const mod = sema.mod; try mod.ensureDeclAnalyzed(exported_decl); + // TODO run the same checks as we do for C ABI struct fields switch (exported_decl.ty.zigTypeTag()) { - .Fn => {}, + .Fn, .Int, .Struct, .Array, .Float => {}, else => return sema.fail(block, src, "unable to export type '{}'", .{exported_decl.ty}), } diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index e0f30568a3..4349fce4d9 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -498,21 +498,21 @@ pub const Object = struct { ) !void { // If the module does not already have the function, we ignore this function call // because we call `updateDeclExports` at the end of `updateFunc` and `updateDecl`. - const llvm_fn = self.decl_map.get(decl) orelse return; - const is_extern = decl.val.tag() == .extern_fn; + const llvm_global = self.decl_map.get(decl) orelse return; + const is_extern = decl.isExtern(); if (is_extern) { - llvm_fn.setValueName(decl.name); - llvm_fn.setUnnamedAddr(.False); - llvm_fn.setLinkage(.External); + llvm_global.setValueName(decl.name); + llvm_global.setUnnamedAddr(.False); + llvm_global.setLinkage(.External); } else if (exports.len != 0) { const exp_name = exports[0].options.name; - llvm_fn.setValueName2(exp_name.ptr, exp_name.len); - llvm_fn.setUnnamedAddr(.False); + llvm_global.setValueName2(exp_name.ptr, exp_name.len); + llvm_global.setUnnamedAddr(.False); switch (exports[0].options.linkage) { .Internal => unreachable, - .Strong => llvm_fn.setLinkage(.External), - .Weak => llvm_fn.setLinkage(.WeakODR), - .LinkOnce => llvm_fn.setLinkage(.LinkOnceODR), + .Strong => llvm_global.setLinkage(.External), + .Weak => llvm_global.setLinkage(.WeakODR), + .LinkOnce => llvm_global.setLinkage(.LinkOnceODR), } // If a Decl is exported more than one time (which is rare), // we add aliases for all but the first export. @@ -525,9 +525,9 @@ pub const Object = struct { defer module.gpa.free(exp_name_z); if (self.llvm_module.getNamedGlobalAlias(exp_name_z.ptr, exp_name_z.len)) |alias| { - alias.setAliasee(llvm_fn); + alias.setAliasee(llvm_global); } else { - const alias = self.llvm_module.addAlias(llvm_fn.typeOf(), llvm_fn, exp_name_z); + const alias = self.llvm_module.addAlias(llvm_global.typeOf(), llvm_global, exp_name_z); switch (exp.options.linkage) { .Internal => alias.setLinkage(.Internal), .Strong => alias.setLinkage(.External), @@ -545,9 +545,9 @@ pub const Object = struct { } else { const fqn = try decl.getFullyQualifiedName(module.gpa); defer module.gpa.free(fqn); - llvm_fn.setValueName2(fqn.ptr, fqn.len); - llvm_fn.setLinkage(.Internal); - llvm_fn.setUnnamedAddr(.True); + llvm_global.setValueName2(fqn.ptr, fqn.len); + llvm_global.setLinkage(.Internal); + llvm_global.setUnnamedAddr(.True); } } @@ -598,9 +598,10 @@ pub const DeclGen = struct { global.setGlobalConstant(.True); break :init_val decl.val; }; - - const llvm_init = try self.genTypedValue(.{ .ty = decl.ty, .val = init_val }); - global.setInitializer(llvm_init); + if (init_val.tag() != .unreachable_value) { + const llvm_init = try self.genTypedValue(.{ .ty = decl.ty, .val = init_val }); + global.setInitializer(llvm_init); + } } } @@ -704,6 +705,13 @@ pub const DeclGen = struct { const llvm_addrspace = dg.llvmAddressSpace(decl.@"addrspace"); const llvm_global = dg.object.llvm_module.addGlobalInAddressSpace(llvm_type, fqn, llvm_addrspace); gop.value_ptr.* = llvm_global; + + const is_extern = decl.val.tag() == .unreachable_value; + if (!is_extern) { + llvm_global.setLinkage(.Internal); + llvm_global.setUnnamedAddr(.True); + } + return llvm_global; } @@ -2431,10 +2439,33 @@ pub const FuncGen = struct { } fn airWrapErrUnionPayload(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { - if (self.liveness.isUnused(inst)) - return null; + if (self.liveness.isUnused(inst)) return null; - return self.todo("implement llvm codegen for 'airWrapErrUnionPayload'", .{}); + const ty_op = self.air.instructions.items(.data)[inst].ty_op; + const payload_ty = self.air.typeOf(ty_op.operand); + const operand = try self.resolveInst(ty_op.operand); + if (!payload_ty.hasCodeGenBits()) { + return operand; + } + const inst_ty = self.air.typeOfIndex(inst); + const ok_err_code = self.context.intType(16).constNull(); + const err_un_llvm_ty = try self.dg.llvmType(inst_ty); + if (isByRef(inst_ty)) { + const result_ptr = self.buildAlloca(err_un_llvm_ty); + const err_ptr = self.builder.buildStructGEP(result_ptr, 0, ""); + _ = self.builder.buildStore(ok_err_code, err_ptr); + const payload_ptr = self.builder.buildStructGEP(result_ptr, 1, ""); + var ptr_ty_payload: Type.Payload.ElemType = .{ + .base = .{ .tag = .single_mut_pointer }, + .data = payload_ty, + }; + const payload_ptr_ty = Type.initPayload(&ptr_ty_payload.base); + self.store(payload_ptr, payload_ptr_ty, operand, .NotAtomic); + return result_ptr; + } + + const partial = self.builder.buildInsertValue(err_un_llvm_ty.getUndef(), ok_err_code, 0, ""); + return self.builder.buildInsertValue(partial, operand, 1, ""); } fn airWrapErrUnionErr(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {