commit 4d6d6977b05571e6d164dbf5f26c7a48ee3541a3 (tree)
parent 82ec56e47e004176cc380cc69764602c4a8d0768
Author: Andrew Kelley <andrew@ziglang.org>
Date: Sat, 16 Oct 2021 12:26:06 -0700
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`
Diffstat:
3 files changed, 63 insertions(+), 22 deletions(-)
diff --git 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
@@ -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
@@ -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;
+
+ 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;
+ }
- return self.todo("implement llvm codegen for 'airWrapErrUnionPayload'", .{});
+ 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 {