authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-04-25 23:48:03-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-04-25 23:48:03-07:00
log13101295b93fe8ec5467bbd6cdf758a2bf823945
tree18d88995a46b7b6d6d5fcb939463c27df1925eee
parent295b8ca467da36cd1066395e7f50b6245f456573
parenta1fcb516928d1ba1106ea715acd1f6feba95e977
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #15454 from jacobly0/cbe-extern

cbe: implement `@extern`

7 files changed, 84 insertions(+), 70 deletions(-)

lib/zig.h+8
...@@ -188,6 +188,14 @@ typedef char bool;...@@ -188,6 +188,14 @@ typedef char bool;
188#define zig_export(sig, symbol, name) __asm(name " = " symbol)188#define zig_export(sig, symbol, name) __asm(name " = " symbol)
189#endif189#endif
190190
191#if zig_has_attribute(weak) || defined(zig_gnuc)
192#define zig_weak_linkage __attribute__((weak))
193#elif _MSC_VER
194#define zig_weak_linkage __declspec(selectany)
195#else
196#define zig_weak_linkage zig_weak_linkage_unavailable
197#endif
198
191#if zig_has_builtin(trap)199#if zig_has_builtin(trap)
192#define zig_trap() __builtin_trap()200#define zig_trap() __builtin_trap()
193#elif _MSC_VER && (_M_IX86 || _M_X64)201#elif _MSC_VER && (_M_IX86 || _M_X64)
src/Compilation.zig+1-1
...@@ -5265,7 +5265,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: Allocator) Alloca...@@ -5265,7 +5265,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: Allocator) Alloca
52655265
5266 if (comp.bin_file.options.is_test) {5266 if (comp.bin_file.options.is_test) {
5267 try buffer.appendSlice(5267 try buffer.appendSlice(
5268 \\pub var test_functions: []std.builtin.TestFn = undefined; // overwritten later5268 \\pub var test_functions: []const std.builtin.TestFn = undefined; // overwritten later
5269 \\5269 \\
5270 );5270 );
5271 if (comp.test_evented_io) {5271 if (comp.test_evented_io) {
src/Module.zig+18-12
...@@ -6439,19 +6439,25 @@ pub fn populateTestFunctions(...@@ -6439,19 +6439,25 @@ pub fn populateTestFunctions(
6439 errdefer new_decl_arena.deinit();6439 errdefer new_decl_arena.deinit();
6440 const arena = new_decl_arena.allocator();6440 const arena = new_decl_arena.allocator();
64416441
6442 // This copy accesses the old Decl Type/Value so it must be done before `clearValues`.6442 {
6443 const new_ty = try Type.Tag.const_slice.create(arena, try tmp_test_fn_ty.copy(arena));6443 // This copy accesses the old Decl Type/Value so it must be done before `clearValues`.
6444 const new_val = try Value.Tag.slice.create(arena, .{6444 const new_ty = try Type.Tag.const_slice.create(arena, try tmp_test_fn_ty.copy(arena));
6445 .ptr = try Value.Tag.decl_ref.create(arena, array_decl_index),6445 const new_var = try gpa.create(Var);
6446 .len = try Value.Tag.int_u64.create(arena, mod.test_functions.count()),6446 errdefer gpa.destroy(new_var);
6447 });6447 new_var.* = decl.val.castTag(.variable).?.data.*;
6448 new_var.init = try Value.Tag.slice.create(arena, .{
6449 .ptr = try Value.Tag.decl_ref.create(arena, array_decl_index),
6450 .len = try Value.Tag.int_u64.create(arena, mod.test_functions.count()),
6451 });
6452 const new_val = try Value.Tag.variable.create(arena, new_var);
64486453
6449 // Since we are replacing the Decl's value we must perform cleanup on the6454 // Since we are replacing the Decl's value we must perform cleanup on the
6450 // previous value.6455 // previous value.
6451 decl.clearValues(mod);6456 decl.clearValues(mod);
6452 decl.ty = new_ty;6457 decl.ty = new_ty;
6453 decl.val = new_val;6458 decl.val = new_val;
6454 decl.has_tv = true;6459 decl.has_tv = true;
6460 }
64556461
6456 try decl.finalizeNewArena(&new_decl_arena);6462 try decl.finalizeNewArena(&new_decl_arena);
6457 }6463 }
src/codegen/c.zig+55-45
...@@ -220,8 +220,8 @@ fn isReservedIdent(ident: []const u8) bool {...@@ -220,8 +220,8 @@ fn isReservedIdent(ident: []const u8) bool {
220 'A'...'Z', '_' => return true,220 'A'...'Z', '_' => return true,
221 else => return false,221 else => return false,
222 }222 }
223 } else if (std.mem.startsWith(u8, ident, "DUMMYSTRUCTNAME") or223 } else if (mem.startsWith(u8, ident, "DUMMYSTRUCTNAME") or
224 std.mem.startsWith(u8, ident, "DUMMYUNIONNAME"))224 mem.startsWith(u8, ident, "DUMMYUNIONNAME"))
225 { // windows.h225 { // windows.h
226 return true;226 return true;
227 } else return reserved_idents.has(ident);227 } else return reserved_idents.has(ident);
...@@ -279,8 +279,6 @@ pub const Function = struct {...@@ -279,8 +279,6 @@ pub const Function = struct {
279 /// by type alignment.279 /// by type alignment.
280 /// The value is whether the alloc needs to be emitted in the header.280 /// The value is whether the alloc needs to be emitted in the header.
281 allocs: std.AutoArrayHashMapUnmanaged(LocalIndex, bool) = .{},281 allocs: std.AutoArrayHashMapUnmanaged(LocalIndex, bool) = .{},
282 /// Needed for memory used by the keys of free_locals_map entries.
283 arena: std.heap.ArenaAllocator,
284282
285 fn resolveInst(f: *Function, ref: Air.Inst.Ref) !CValue {283 fn resolveInst(f: *Function, ref: Air.Inst.Ref) !CValue {
286 if (Air.refToIndex(ref)) |inst| {284 if (Air.refToIndex(ref)) |inst| {
...@@ -481,7 +479,6 @@ pub const Function = struct {...@@ -481,7 +479,6 @@ pub const Function = struct {
481 f.object.code.deinit();479 f.object.code.deinit();
482 f.object.dg.ctypes.deinit(gpa);480 f.object.dg.ctypes.deinit(gpa);
483 f.object.dg.fwd_decl.deinit();481 f.object.dg.fwd_decl.deinit();
484 f.arena.deinit();
485 }482 }
486};483};
487484
...@@ -501,7 +498,7 @@ pub const Object = struct {...@@ -501,7 +498,7 @@ pub const Object = struct {
501498
502/// This data is available both when outputting .c code and when outputting an .h file.499/// This data is available both when outputting .c code and when outputting an .h file.
503pub const DeclGen = struct {500pub const DeclGen = struct {
504 gpa: std.mem.Allocator,501 gpa: mem.Allocator,
505 module: *Module,502 module: *Module,
506 decl: ?*Decl,503 decl: ?*Decl,
507 decl_index: Decl.OptionalIndex,504 decl_index: Decl.OptionalIndex,
...@@ -539,6 +536,9 @@ pub const DeclGen = struct {...@@ -539,6 +536,9 @@ pub const DeclGen = struct {
539 if (func.data.owner_decl != decl_index)536 if (func.data.owner_decl != decl_index)
540 return dg.renderDeclValue(writer, ty, val, func.data.owner_decl, location);537 return dg.renderDeclValue(writer, ty, val, func.data.owner_decl, location);
541538
539 if (decl.val.castTag(.variable)) |var_payload|
540 try dg.renderFwdDecl(decl_index, var_payload.data);
541
542 if (ty.isSlice()) {542 if (ty.isSlice()) {
543 if (location == .StaticInitializer) {543 if (location == .StaticInitializer) {
544 try writer.writeByte('{');544 try writer.writeByte('{');
...@@ -1819,8 +1819,23 @@ pub const DeclGen = struct {...@@ -1819,8 +1819,23 @@ pub const DeclGen = struct {
1819 try dg.writeCValue(writer, member);1819 try dg.writeCValue(writer, member);
1820 }1820 }
18211821
1822 const IdentHasher = std.crypto.auth.siphash.SipHash128(1, 3);1822 fn renderFwdDecl(dg: *DeclGen, decl_index: Decl.Index, variable: *Module.Var) !void {
1823 const ident_hasher_init: IdentHasher = IdentHasher.init(&[_]u8{0} ** IdentHasher.key_length);1823 const decl = dg.module.declPtr(decl_index);
1824 const fwd_decl_writer = dg.fwd_decl.writer();
1825 const is_global = dg.declIsGlobal(.{ .ty = decl.ty, .val = decl.val }) or variable.is_extern;
1826 try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static ");
1827 if (variable.is_threadlocal) try fwd_decl_writer.writeAll("zig_threadlocal ");
1828 if (variable.is_weak_linkage) try fwd_decl_writer.writeAll("zig_weak_linkage ");
1829 try dg.renderTypeAndName(
1830 fwd_decl_writer,
1831 decl.ty,
1832 .{ .decl = decl_index },
1833 CQualifiers.init(.{ .@"const" = !variable.is_mutable }),
1834 decl.@"align",
1835 .complete,
1836 );
1837 try fwd_decl_writer.writeAll(";\n");
1838 }
18241839
1825 fn renderDeclName(dg: *DeclGen, writer: anytype, decl_index: Decl.Index, export_index: u32) !void {1840 fn renderDeclName(dg: *DeclGen, writer: anytype, decl_index: Decl.Index, export_index: u32) !void {
1826 const decl = dg.module.declPtr(decl_index);1841 const decl = dg.module.declPtr(decl_index);
...@@ -1829,7 +1844,7 @@ pub const DeclGen = struct {...@@ -1829,7 +1844,7 @@ pub const DeclGen = struct {
1829 if (dg.module.decl_exports.get(decl_index)) |exports| {1844 if (dg.module.decl_exports.get(decl_index)) |exports| {
1830 try writer.writeAll(exports.items[export_index].options.name);1845 try writer.writeAll(exports.items[export_index].options.name);
1831 } else if (decl.isExtern()) {1846 } else if (decl.isExtern()) {
1832 try writer.writeAll(mem.sliceTo(decl.name, 0));1847 try writer.writeAll(mem.span(decl.name));
1833 } else {1848 } else {
1834 // MSVC has a limit of 4095 character token length limit, and fmtIdent can (worst case),1849 // MSVC has a limit of 4095 character token length limit, and fmtIdent can (worst case),
1835 // expand to 3x the length of its input, but let's cut it off at a much shorter limit.1850 // expand to 3x the length of its input, but let's cut it off at a much shorter limit.
...@@ -2396,9 +2411,9 @@ pub fn genErrDecls(o: *Object) !void {...@@ -2396,9 +2411,9 @@ pub fn genErrDecls(o: *Object) !void {
2396 const name_buf = try o.dg.gpa.alloc(u8, name_prefix.len + max_name_len);2411 const name_buf = try o.dg.gpa.alloc(u8, name_prefix.len + max_name_len);
2397 defer o.dg.gpa.free(name_buf);2412 defer o.dg.gpa.free(name_buf);
23982413
2399 std.mem.copy(u8, name_buf, name_prefix);2414 mem.copy(u8, name_buf, name_prefix);
2400 for (o.dg.module.error_name_list.items) |name| {2415 for (o.dg.module.error_name_list.items) |name| {
2401 std.mem.copy(u8, name_buf[name_prefix.len..], name);2416 mem.copy(u8, name_buf[name_prefix.len..], name);
2402 const identifier = name_buf[0 .. name_prefix.len + name.len];2417 const identifier = name_buf[0 .. name_prefix.len + name.len];
24032418
2404 var name_ty_pl = Type.Payload.Len{ .base = .{ .tag = .array_u8_sentinel_0 }, .data = name.len };2419 var name_ty_pl = Type.Payload.Len{ .base = .{ .tag = .array_u8_sentinel_0 }, .data = name.len };
...@@ -2644,21 +2659,16 @@ pub fn genDecl(o: *Object) !void {...@@ -2644,21 +2659,16 @@ pub fn genDecl(o: *Object) !void {
2644 try genExports(o);2659 try genExports(o);
2645 } else if (tv.val.castTag(.variable)) |var_payload| {2660 } else if (tv.val.castTag(.variable)) |var_payload| {
2646 const variable: *Module.Var = var_payload.data;2661 const variable: *Module.Var = var_payload.data;
26472662 try o.dg.renderFwdDecl(decl_c_value.decl, variable);
2648 const is_global = o.dg.declIsGlobal(tv) or variable.is_extern;
2649 const fwd_decl_writer = o.dg.fwd_decl.writer();
2650
2651 try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static ");
2652 if (variable.is_threadlocal) try fwd_decl_writer.writeAll("zig_threadlocal ");
2653 try o.dg.renderTypeAndName(fwd_decl_writer, decl.ty, decl_c_value, .{}, decl.@"align", .complete);
2654 try fwd_decl_writer.writeAll(";\n");
2655 try genExports(o);2663 try genExports(o);
26562664
2657 if (variable.is_extern) return;2665 if (variable.is_extern) return;
26582666
2667 const is_global = o.dg.declIsGlobal(tv) or variable.is_extern;
2659 const w = o.writer();2668 const w = o.writer();
2660 if (!is_global) try w.writeAll("static ");2669 if (!is_global) try w.writeAll("static ");
2661 if (variable.is_threadlocal) try w.writeAll("zig_threadlocal ");2670 if (variable.is_threadlocal) try w.writeAll("zig_threadlocal ");
2671 if (variable.is_weak_linkage) try w.writeAll("zig_weak_linkage ");
2662 if (decl.@"linksection") |section| try w.print("zig_linksection(\"{s}\", ", .{section});2672 if (decl.@"linksection") |section| try w.print("zig_linksection(\"{s}\", ", .{section});
2663 try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, .{}, decl.@"align", .complete);2673 try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, .{}, decl.@"align", .complete);
2664 if (decl.@"linksection" != null) try w.writeAll(", read, write)");2674 if (decl.@"linksection" != null) try w.writeAll(", read, write)");
...@@ -3396,7 +3406,7 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue {...@@ -3396,7 +3406,7 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue {
3396 var deref = is_ptr;3406 var deref = is_ptr;
3397 const is_array = lowersToArray(ret_ty, target);3407 const is_array = lowersToArray(ret_ty, target);
3398 const ret_val = if (is_array) ret_val: {3408 const ret_val = if (is_array) ret_val: {
3399 const array_local = try f.allocLocal(inst, try lowered_ret_ty.copy(f.arena.allocator()));3409 const array_local = try f.allocLocal(inst, lowered_ret_ty);
3400 try writer.writeAll("memcpy(");3410 try writer.writeAll("memcpy(");
3401 try f.writeCValueMember(writer, array_local, .{ .identifier = "array" });3411 try f.writeCValueMember(writer, array_local, .{ .identifier = "array" });
3402 try writer.writeAll(", ");3412 try writer.writeAll(", ");
...@@ -4113,7 +4123,7 @@ fn airCall(...@@ -4113,7 +4123,7 @@ fn airCall(
4113 var lowered_arg_buf: LowerFnRetTyBuffer = undefined;4123 var lowered_arg_buf: LowerFnRetTyBuffer = undefined;
4114 const lowered_arg_ty = lowerFnRetTy(arg_ty, &lowered_arg_buf, target);4124 const lowered_arg_ty = lowerFnRetTy(arg_ty, &lowered_arg_buf, target);
41154125
4116 const array_local = try f.allocLocal(inst, try lowered_arg_ty.copy(f.arena.allocator()));4126 const array_local = try f.allocLocal(inst, lowered_arg_ty);
4117 try writer.writeAll("memcpy(");4127 try writer.writeAll("memcpy(");
4118 try f.writeCValueMember(writer, array_local, .{ .identifier = "array" });4128 try f.writeCValueMember(writer, array_local, .{ .identifier = "array" });
4119 try writer.writeAll(", ");4129 try writer.writeAll(", ");
...@@ -4156,7 +4166,7 @@ fn airCall(...@@ -4156,7 +4166,7 @@ fn airCall(
4156 try writer.writeByte(')');4166 try writer.writeByte(')');
4157 break :result .none;4167 break :result .none;
4158 } else {4168 } else {
4159 const local = try f.allocLocal(inst, try lowered_ret_ty.copy(f.arena.allocator()));4169 const local = try f.allocLocal(inst, lowered_ret_ty);
4160 try f.writeCValue(writer, local, .Other);4170 try f.writeCValue(writer, local, .Other);
4161 try writer.writeAll(" = ");4171 try writer.writeAll(" = ");
4162 break :result local;4172 break :result local;
...@@ -4732,9 +4742,9 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4732,9 +4742,9 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
4732 const locals_begin = @intCast(LocalIndex, f.locals.items.len);4742 const locals_begin = @intCast(LocalIndex, f.locals.items.len);
4733 const constraints_extra_begin = extra_i;4743 const constraints_extra_begin = extra_i;
4734 for (outputs) |output| {4744 for (outputs) |output| {
4735 const extra_bytes = std.mem.sliceAsBytes(f.air.extra[extra_i..]);4745 const extra_bytes = mem.sliceAsBytes(f.air.extra[extra_i..]);
4736 const constraint = std.mem.sliceTo(extra_bytes, 0);4746 const constraint = mem.sliceTo(extra_bytes, 0);
4737 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);4747 const name = mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
4738 // This equation accounts for the fact that even if we have exactly 4 bytes4748 // This equation accounts for the fact that even if we have exactly 4 bytes
4739 // for the string, we still use the next u32 for the null terminator.4749 // for the string, we still use the next u32 for the null terminator.
4740 extra_i += (constraint.len + name.len + (2 + 3)) / 4;4750 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
...@@ -4764,14 +4774,14 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4764,14 +4774,14 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
4764 }4774 }
4765 }4775 }
4766 for (inputs) |input| {4776 for (inputs) |input| {
4767 const extra_bytes = std.mem.sliceAsBytes(f.air.extra[extra_i..]);4777 const extra_bytes = mem.sliceAsBytes(f.air.extra[extra_i..]);
4768 const constraint = std.mem.sliceTo(extra_bytes, 0);4778 const constraint = mem.sliceTo(extra_bytes, 0);
4769 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);4779 const name = mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
4770 // This equation accounts for the fact that even if we have exactly 4 bytes4780 // This equation accounts for the fact that even if we have exactly 4 bytes
4771 // for the string, we still use the next u32 for the null terminator.4781 // for the string, we still use the next u32 for the null terminator.
4772 extra_i += (constraint.len + name.len + (2 + 3)) / 4;4782 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
47734783
4774 if (constraint.len < 1 or std.mem.indexOfScalar(u8, "=+&%", constraint[0]) != null or4784 if (constraint.len < 1 or mem.indexOfScalar(u8, "=+&%", constraint[0]) != null or
4775 (constraint[0] == '{' and constraint[constraint.len - 1] != '}'))4785 (constraint[0] == '{' and constraint[constraint.len - 1] != '}'))
4776 {4786 {
4777 return f.fail("CBE: constraint not supported: '{s}'", .{constraint});4787 return f.fail("CBE: constraint not supported: '{s}'", .{constraint});
...@@ -4797,7 +4807,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4797,7 +4807,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
4797 }4807 }
4798 }4808 }
4799 for (0..clobbers_len) |_| {4809 for (0..clobbers_len) |_| {
4800 const clobber = std.mem.sliceTo(std.mem.sliceAsBytes(f.air.extra[extra_i..]), 0);4810 const clobber = mem.sliceTo(mem.sliceAsBytes(f.air.extra[extra_i..]), 0);
4801 // This equation accounts for the fact that even if we have exactly 4 bytes4811 // This equation accounts for the fact that even if we have exactly 4 bytes
4802 // for the string, we still use the next u32 for the null terminator.4812 // for the string, we still use the next u32 for the null terminator.
4803 extra_i += clobber.len / 4 + 1;4813 extra_i += clobber.len / 4 + 1;
...@@ -4862,16 +4872,16 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4862,16 +4872,16 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
4862 var locals_index = locals_begin;4872 var locals_index = locals_begin;
4863 try writer.writeByte(':');4873 try writer.writeByte(':');
4864 for (outputs, 0..) |output, index| {4874 for (outputs, 0..) |output, index| {
4865 const extra_bytes = std.mem.sliceAsBytes(f.air.extra[extra_i..]);4875 const extra_bytes = mem.sliceAsBytes(f.air.extra[extra_i..]);
4866 const constraint = std.mem.sliceTo(extra_bytes, 0);4876 const constraint = mem.sliceTo(extra_bytes, 0);
4867 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);4877 const name = mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
4868 // This equation accounts for the fact that even if we have exactly 4 bytes4878 // This equation accounts for the fact that even if we have exactly 4 bytes
4869 // for the string, we still use the next u32 for the null terminator.4879 // for the string, we still use the next u32 for the null terminator.
4870 extra_i += (constraint.len + name.len + (2 + 3)) / 4;4880 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
48714881
4872 if (index > 0) try writer.writeByte(',');4882 if (index > 0) try writer.writeByte(',');
4873 try writer.writeByte(' ');4883 try writer.writeByte(' ');
4874 if (!std.mem.eql(u8, name, "_")) try writer.print("[{s}]", .{name});4884 if (!mem.eql(u8, name, "_")) try writer.print("[{s}]", .{name});
4875 const is_reg = constraint[1] == '{';4885 const is_reg = constraint[1] == '{';
4876 try writer.print("{s}(", .{fmtStringLiteral(if (is_reg) "=r" else constraint, null)});4886 try writer.print("{s}(", .{fmtStringLiteral(if (is_reg) "=r" else constraint, null)});
4877 if (is_reg) {4887 if (is_reg) {
...@@ -4886,16 +4896,16 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4886,16 +4896,16 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
4886 }4896 }
4887 try writer.writeByte(':');4897 try writer.writeByte(':');
4888 for (inputs, 0..) |input, index| {4898 for (inputs, 0..) |input, index| {
4889 const extra_bytes = std.mem.sliceAsBytes(f.air.extra[extra_i..]);4899 const extra_bytes = mem.sliceAsBytes(f.air.extra[extra_i..]);
4890 const constraint = std.mem.sliceTo(extra_bytes, 0);4900 const constraint = mem.sliceTo(extra_bytes, 0);
4891 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);4901 const name = mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
4892 // This equation accounts for the fact that even if we have exactly 4 bytes4902 // This equation accounts for the fact that even if we have exactly 4 bytes
4893 // for the string, we still use the next u32 for the null terminator.4903 // for the string, we still use the next u32 for the null terminator.
4894 extra_i += (constraint.len + name.len + (2 + 3)) / 4;4904 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
48954905
4896 if (index > 0) try writer.writeByte(',');4906 if (index > 0) try writer.writeByte(',');
4897 try writer.writeByte(' ');4907 try writer.writeByte(' ');
4898 if (!std.mem.eql(u8, name, "_")) try writer.print("[{s}]", .{name});4908 if (!mem.eql(u8, name, "_")) try writer.print("[{s}]", .{name});
48994909
4900 const is_reg = constraint[0] == '{';4910 const is_reg = constraint[0] == '{';
4901 const input_val = try f.resolveInst(input);4911 const input_val = try f.resolveInst(input);
...@@ -4909,7 +4919,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4909,7 +4919,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
4909 }4919 }
4910 try writer.writeByte(':');4920 try writer.writeByte(':');
4911 for (0..clobbers_len) |clobber_i| {4921 for (0..clobbers_len) |clobber_i| {
4912 const clobber = std.mem.sliceTo(std.mem.sliceAsBytes(f.air.extra[extra_i..]), 0);4922 const clobber = mem.sliceTo(mem.sliceAsBytes(f.air.extra[extra_i..]), 0);
4913 // This equation accounts for the fact that even if we have exactly 4 bytes4923 // This equation accounts for the fact that even if we have exactly 4 bytes
4914 // for the string, we still use the next u32 for the null terminator.4924 // for the string, we still use the next u32 for the null terminator.
4915 extra_i += clobber.len / 4 + 1;4925 extra_i += clobber.len / 4 + 1;
...@@ -4924,9 +4934,9 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4924,9 +4934,9 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
4924 extra_i = constraints_extra_begin;4934 extra_i = constraints_extra_begin;
4925 locals_index = locals_begin;4935 locals_index = locals_begin;
4926 for (outputs) |output| {4936 for (outputs) |output| {
4927 const extra_bytes = std.mem.sliceAsBytes(f.air.extra[extra_i..]);4937 const extra_bytes = mem.sliceAsBytes(f.air.extra[extra_i..]);
4928 const constraint = std.mem.sliceTo(extra_bytes, 0);4938 const constraint = mem.sliceTo(extra_bytes, 0);
4929 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);4939 const name = mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
4930 // This equation accounts for the fact that even if we have exactly 4 bytes4940 // This equation accounts for the fact that even if we have exactly 4 bytes
4931 // for the string, we still use the next u32 for the null terminator.4941 // for the string, we still use the next u32 for the null terminator.
4932 extra_i += (constraint.len + name.len + (2 + 3)) / 4;4942 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
...@@ -5363,7 +5373,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5363,7 +5373,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
5363 };5373 };
5364 const field_int_ty = Type.initPayload(&field_int_pl.base);5374 const field_int_ty = Type.initPayload(&field_int_pl.base);
53655375
5366 const temp_local = try f.allocLocal(inst, try field_int_ty.copy(f.arena.allocator()));5376 const temp_local = try f.allocLocal(inst, field_int_ty);
5367 try f.writeCValue(writer, temp_local, .Other);5377 try f.writeCValue(writer, temp_local, .Other);
5368 try writer.writeAll(" = zig_wrap_");5378 try writer.writeAll(" = zig_wrap_");
5369 try f.object.dg.renderTypeForBuiltinFnName(writer, field_int_ty);5379 try f.object.dg.renderTypeForBuiltinFnName(writer, field_int_ty);
...@@ -7277,7 +7287,7 @@ fn formatIntLiteral(...@@ -7277,7 +7287,7 @@ fn formatIntLiteral(
7277 var int_buf: Value.BigIntSpace = undefined;7287 var int_buf: Value.BigIntSpace = undefined;
7278 const int = if (data.val.isUndefDeep()) blk: {7288 const int = if (data.val.isUndefDeep()) blk: {
7279 undef_limbs = try allocator.alloc(BigIntLimb, BigInt.calcTwosCompLimbCount(data.int_info.bits));7289 undef_limbs = try allocator.alloc(BigIntLimb, BigInt.calcTwosCompLimbCount(data.int_info.bits));
7280 std.mem.set(BigIntLimb, undef_limbs, undefPattern(BigIntLimb));7290 mem.set(BigIntLimb, undef_limbs, undefPattern(BigIntLimb));
72817291
7282 var undef_int = BigInt.Mutable{7292 var undef_int = BigInt.Mutable{
7283 .limbs = undef_limbs,7293 .limbs = undef_limbs,
...@@ -7372,7 +7382,7 @@ fn formatIntLiteral(...@@ -7372,7 +7382,7 @@ fn formatIntLiteral(
7372 } else {7382 } else {
7373 try data.cty.renderLiteralPrefix(writer, data.kind);7383 try data.cty.renderLiteralPrefix(writer, data.kind);
7374 wrap.convertToTwosComplement(int, data.int_info.signedness, c_bits);7384 wrap.convertToTwosComplement(int, data.int_info.signedness, c_bits);
7375 std.mem.set(BigIntLimb, wrap.limbs[wrap.len..], 0);7385 mem.set(BigIntLimb, wrap.limbs[wrap.len..], 0);
7376 wrap.len = wrap.limbs.len;7386 wrap.len = wrap.limbs.len;
7377 const limbs_per_c_limb = @divExact(wrap.len, c_limb_info.count);7387 const limbs_per_c_limb = @divExact(wrap.len, c_limb_info.count);
73787388
src/codegen/c/type.zig+1-11
...@@ -1720,17 +1720,7 @@ pub const CType = extern union {...@@ -1720,17 +1720,7 @@ pub const CType = extern union {
1720 } else self.init(.anon_struct);1720 } else self.init(.anon_struct);
1721 },1721 },
17221722
1723 .Opaque => switch (ty.tag()) {1723 .Opaque => self.init(.void),
1724 .anyopaque => self.init(.void),
1725 .@"opaque" => {
1726 self.storage = .{ .fwd = .{
1727 .base = .{ .tag = .fwd_struct },
1728 .data = ty.getOwnerDecl(),
1729 } };
1730 self.value = .{ .cty = initPayload(&self.storage.fwd) };
1731 },
1732 else => unreachable,
1733 },
17341724
1735 .Fn => {1725 .Fn => {
1736 const info = ty.fnInfo();1726 const info = ty.fnInfo();
src/link/C.zig-1
...@@ -126,7 +126,6 @@ pub fn updateFunc(self: *C, module: *Module, func: *Module.Fn, air: Air, livenes...@@ -126,7 +126,6 @@ pub fn updateFunc(self: *C, module: *Module, func: *Module.Fn, air: Air, livenes
126 .indent_writer = undefined, // set later so we can get a pointer to object.code126 .indent_writer = undefined, // set later so we can get a pointer to object.code
127 },127 },
128 .lazy_fns = lazy_fns.*,128 .lazy_fns = lazy_fns.*,
129 .arena = std.heap.ArenaAllocator.init(gpa),
130 };129 };
131130
132 function.object.indent_writer = .{ .underlying_writer = function.object.code.writer() };131 function.object.indent_writer = .{ .underlying_writer = function.object.code.writer() };
test/behavior/basic.zig+1
...@@ -774,6 +774,7 @@ test "extern variable with non-pointer opaque type" {...@@ -774,6 +774,7 @@ test "extern variable with non-pointer opaque type" {
774 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO774 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
775 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO775 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
776 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO776 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
777 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
777778
778 @export(var_to_export, .{ .name = "opaque_extern_var" });779 @export(var_to_export, .{ .name = "opaque_extern_var" });
779 try expect(@ptrCast(*align(1) u32, &opaque_extern_var).* == 42);780 try expect(@ptrCast(*align(1) u32, &opaque_extern_var).* == 42);