authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-10-16 12:26:06-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-10-16 12:26:06-07:00
log4d6d6977b05571e6d164dbf5f26c7a48ee3541a3
treebeb25554dc6e6f9f238ee84d0096f89a557f4ea5
parent82ec56e47e004176cc380cc69764602c4a8d0768

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`

3 files changed, 63 insertions(+), 22 deletions(-)

src/Module.zig+9
...@@ -754,6 +754,15 @@ pub const Decl = struct {...@@ -754,6 +754,15 @@ pub const Decl = struct {
754 fn removeDependency(decl: *Decl, other: *Decl) void {754 fn removeDependency(decl: *Decl, other: *Decl) void {
755 assert(decl.dependencies.swapRemove(other));755 assert(decl.dependencies.swapRemove(other));
756 }756 }
757
758 pub fn isExtern(decl: Decl) bool {
759 assert(decl.has_tv);
760 return switch (decl.val.tag()) {
761 .extern_fn => true,
762 .variable => decl.val.castTag(.variable).?.data.init.tag() == .unreachable_value,
763 else => false,
764 };
765 }
757};766};
758767
759/// This state is attached to every Decl when Module emit_h is non-null.768/// This state is attached to every Decl when Module emit_h is non-null.
src/Sema.zig+2-1
...@@ -3020,8 +3020,9 @@ pub fn analyzeExport(...@@ -3020,8 +3020,9 @@ pub fn analyzeExport(
3020 const mod = sema.mod;3020 const mod = sema.mod;
30213021
3022 try mod.ensureDeclAnalyzed(exported_decl);3022 try mod.ensureDeclAnalyzed(exported_decl);
3023 // TODO run the same checks as we do for C ABI struct fields
3023 switch (exported_decl.ty.zigTypeTag()) {3024 switch (exported_decl.ty.zigTypeTag()) {
3024 .Fn => {},3025 .Fn, .Int, .Struct, .Array, .Float => {},
3025 else => return sema.fail(block, src, "unable to export type '{}'", .{exported_decl.ty}),3026 else => return sema.fail(block, src, "unable to export type '{}'", .{exported_decl.ty}),
3026 }3027 }
30273028
src/codegen/llvm.zig+52-21
...@@ -498,21 +498,21 @@ pub const Object = struct {...@@ -498,21 +498,21 @@ pub const Object = struct {
498 ) !void {498 ) !void {
499 // If the module does not already have the function, we ignore this function call499 // If the module does not already have the function, we ignore this function call
500 // because we call `updateDeclExports` at the end of `updateFunc` and `updateDecl`.500 // because we call `updateDeclExports` at the end of `updateFunc` and `updateDecl`.
501 const llvm_fn = self.decl_map.get(decl) orelse return;501 const llvm_global = self.decl_map.get(decl) orelse return;
502 const is_extern = decl.val.tag() == .extern_fn;502 const is_extern = decl.isExtern();
503 if (is_extern) {503 if (is_extern) {
504 llvm_fn.setValueName(decl.name);504 llvm_global.setValueName(decl.name);
505 llvm_fn.setUnnamedAddr(.False);505 llvm_global.setUnnamedAddr(.False);
506 llvm_fn.setLinkage(.External);506 llvm_global.setLinkage(.External);
507 } else if (exports.len != 0) {507 } else if (exports.len != 0) {
508 const exp_name = exports[0].options.name;508 const exp_name = exports[0].options.name;
509 llvm_fn.setValueName2(exp_name.ptr, exp_name.len);509 llvm_global.setValueName2(exp_name.ptr, exp_name.len);
510 llvm_fn.setUnnamedAddr(.False);510 llvm_global.setUnnamedAddr(.False);
511 switch (exports[0].options.linkage) {511 switch (exports[0].options.linkage) {
512 .Internal => unreachable,512 .Internal => unreachable,
513 .Strong => llvm_fn.setLinkage(.External),513 .Strong => llvm_global.setLinkage(.External),
514 .Weak => llvm_fn.setLinkage(.WeakODR),514 .Weak => llvm_global.setLinkage(.WeakODR),
515 .LinkOnce => llvm_fn.setLinkage(.LinkOnceODR),515 .LinkOnce => llvm_global.setLinkage(.LinkOnceODR),
516 }516 }
517 // If a Decl is exported more than one time (which is rare),517 // If a Decl is exported more than one time (which is rare),
518 // we add aliases for all but the first export.518 // we add aliases for all but the first export.
...@@ -525,9 +525,9 @@ pub const Object = struct {...@@ -525,9 +525,9 @@ pub const Object = struct {
525 defer module.gpa.free(exp_name_z);525 defer module.gpa.free(exp_name_z);
526526
527 if (self.llvm_module.getNamedGlobalAlias(exp_name_z.ptr, exp_name_z.len)) |alias| {527 if (self.llvm_module.getNamedGlobalAlias(exp_name_z.ptr, exp_name_z.len)) |alias| {
528 alias.setAliasee(llvm_fn);528 alias.setAliasee(llvm_global);
529 } else {529 } else {
530 const alias = self.llvm_module.addAlias(llvm_fn.typeOf(), llvm_fn, exp_name_z);530 const alias = self.llvm_module.addAlias(llvm_global.typeOf(), llvm_global, exp_name_z);
531 switch (exp.options.linkage) {531 switch (exp.options.linkage) {
532 .Internal => alias.setLinkage(.Internal),532 .Internal => alias.setLinkage(.Internal),
533 .Strong => alias.setLinkage(.External),533 .Strong => alias.setLinkage(.External),
...@@ -545,9 +545,9 @@ pub const Object = struct {...@@ -545,9 +545,9 @@ pub const Object = struct {
545 } else {545 } else {
546 const fqn = try decl.getFullyQualifiedName(module.gpa);546 const fqn = try decl.getFullyQualifiedName(module.gpa);
547 defer module.gpa.free(fqn);547 defer module.gpa.free(fqn);
548 llvm_fn.setValueName2(fqn.ptr, fqn.len);548 llvm_global.setValueName2(fqn.ptr, fqn.len);
549 llvm_fn.setLinkage(.Internal);549 llvm_global.setLinkage(.Internal);
550 llvm_fn.setUnnamedAddr(.True);550 llvm_global.setUnnamedAddr(.True);
551 }551 }
552 }552 }
553553
...@@ -598,9 +598,10 @@ pub const DeclGen = struct {...@@ -598,9 +598,10 @@ pub const DeclGen = struct {
598 global.setGlobalConstant(.True);598 global.setGlobalConstant(.True);
599 break :init_val decl.val;599 break :init_val decl.val;
600 };600 };
601601 if (init_val.tag() != .unreachable_value) {
602 const llvm_init = try self.genTypedValue(.{ .ty = decl.ty, .val = init_val });602 const llvm_init = try self.genTypedValue(.{ .ty = decl.ty, .val = init_val });
603 global.setInitializer(llvm_init);603 global.setInitializer(llvm_init);
604 }
604 }605 }
605 }606 }
606607
...@@ -704,6 +705,13 @@ pub const DeclGen = struct {...@@ -704,6 +705,13 @@ pub const DeclGen = struct {
704 const llvm_addrspace = dg.llvmAddressSpace(decl.@"addrspace");705 const llvm_addrspace = dg.llvmAddressSpace(decl.@"addrspace");
705 const llvm_global = dg.object.llvm_module.addGlobalInAddressSpace(llvm_type, fqn, llvm_addrspace);706 const llvm_global = dg.object.llvm_module.addGlobalInAddressSpace(llvm_type, fqn, llvm_addrspace);
706 gop.value_ptr.* = llvm_global;707 gop.value_ptr.* = llvm_global;
708
709 const is_extern = decl.val.tag() == .unreachable_value;
710 if (!is_extern) {
711 llvm_global.setLinkage(.Internal);
712 llvm_global.setUnnamedAddr(.True);
713 }
714
707 return llvm_global;715 return llvm_global;
708 }716 }
709717
...@@ -2431,10 +2439,33 @@ pub const FuncGen = struct {...@@ -2431,10 +2439,33 @@ pub const FuncGen = struct {
2431 }2439 }
24322440
2433 fn airWrapErrUnionPayload(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {2441 fn airWrapErrUnionPayload(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
2434 if (self.liveness.isUnused(inst))2442 if (self.liveness.isUnused(inst)) return null;
2435 return null;2443
2444 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2445 const payload_ty = self.air.typeOf(ty_op.operand);
2446 const operand = try self.resolveInst(ty_op.operand);
2447 if (!payload_ty.hasCodeGenBits()) {
2448 return operand;
2449 }
2450 const inst_ty = self.air.typeOfIndex(inst);
2451 const ok_err_code = self.context.intType(16).constNull();
2452 const err_un_llvm_ty = try self.dg.llvmType(inst_ty);
2453 if (isByRef(inst_ty)) {
2454 const result_ptr = self.buildAlloca(err_un_llvm_ty);
2455 const err_ptr = self.builder.buildStructGEP(result_ptr, 0, "");
2456 _ = self.builder.buildStore(ok_err_code, err_ptr);
2457 const payload_ptr = self.builder.buildStructGEP(result_ptr, 1, "");
2458 var ptr_ty_payload: Type.Payload.ElemType = .{
2459 .base = .{ .tag = .single_mut_pointer },
2460 .data = payload_ty,
2461 };
2462 const payload_ptr_ty = Type.initPayload(&ptr_ty_payload.base);
2463 self.store(payload_ptr, payload_ptr_ty, operand, .NotAtomic);
2464 return result_ptr;
2465 }
24362466
2437 return self.todo("implement llvm codegen for 'airWrapErrUnionPayload'", .{});2467 const partial = self.builder.buildInsertValue(err_un_llvm_ty.getUndef(), ok_err_code, 0, "");
2468 return self.builder.buildInsertValue(partial, operand, 1, "");
2438 }2469 }
24392470
2440 fn airWrapErrUnionErr(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {2471 fn airWrapErrUnionErr(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {