authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2024-04-11 23:40:15-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2024-04-13 01:35:20-04:00
logf1c0f42cddd344d6ac56569decb42eab2dfc07e5
treeef0f626df3ac7339da7ba6394aecbd5770474874
parent05d9755766e45e454a16440bfc9f98abef992247

cbe: fix optional codegen

Also reduce ctype pool string memory usage, remove self assignments, and enable more warnings.

17 files changed, 1118 insertions(+), 850 deletions(-)

lib/std/posix/test.zig+1-1
...@@ -839,7 +839,7 @@ test "sigaction" {...@@ -839,7 +839,7 @@ test "sigaction" {
839 const S = struct {839 const S = struct {
840 var handler_called_count: u32 = 0;840 var handler_called_count: u32 = 0;
841841
842 fn handler(sig: i32, info: *const posix.siginfo_t, ctx_ptr: ?*const anyopaque) callconv(.C) void {842 fn handler(sig: i32, info: *const posix.siginfo_t, ctx_ptr: ?*anyopaque) callconv(.C) void {
843 _ = ctx_ptr;843 _ = ctx_ptr;
844 // Check that we received the correct signal.844 // Check that we received the correct signal.
845 switch (native_os) {845 switch (native_os) {
src/codegen/c.zig+831-696
...@@ -43,10 +43,12 @@ pub const CValue = union(enum) {...@@ -43,10 +43,12 @@ pub const CValue = union(enum) {
43 decl_ref: InternPool.DeclIndex,43 decl_ref: InternPool.DeclIndex,
44 /// An undefined value (cannot be dereferenced)44 /// An undefined value (cannot be dereferenced)
45 undef: Type,45 undef: Type,
46 /// Render the slice as an identifier (using fmtIdent)46 /// Rendered as an identifier (using fmtIdent)
47 identifier: []const u8,47 identifier: []const u8,
48 /// Render the slice as an payload.identifier (using fmtIdent)48 /// Rendered as "payload." followed by as identifier (using fmtIdent)
49 payload_identifier: []const u8,49 payload_identifier: []const u8,
50 /// Rendered with fmtCTypePoolString
51 ctype_pool_string: CType.Pool.String,
50};52};
5153
52const BlockData = struct {54const BlockData = struct {
...@@ -62,10 +64,10 @@ pub const LazyFnKey = union(enum) {...@@ -62,10 +64,10 @@ pub const LazyFnKey = union(enum) {
62 never_inline: InternPool.DeclIndex,64 never_inline: InternPool.DeclIndex,
63};65};
64pub const LazyFnValue = struct {66pub const LazyFnValue = struct {
65 fn_name: CType.String,67 fn_name: CType.Pool.String,
66 data: Data,68 data: Data,
6769
68 pub const Data = union {70 const Data = union {
69 tag_name: Type,71 tag_name: Type,
70 never_tail: void,72 never_tail: void,
71 never_inline: void,73 never_inline: void,
...@@ -80,7 +82,7 @@ const Local = struct {...@@ -80,7 +82,7 @@ const Local = struct {
80 _: u20 = undefined,82 _: u20 = undefined,
81 },83 },
8284
83 pub fn getType(local: Local) LocalType {85 fn getType(local: Local) LocalType {
84 return .{ .ctype = local.ctype, .alignas = local.flags.alignas };86 return .{ .ctype = local.ctype, .alignas = local.flags.alignas };
85 }87 }
86};88};
...@@ -96,12 +98,20 @@ const ValueRenderLocation = enum {...@@ -96,12 +98,20 @@ const ValueRenderLocation = enum {
96 StaticInitializer,98 StaticInitializer,
97 Other,99 Other,
98100
99 pub fn isInitializer(self: ValueRenderLocation) bool {101 fn isInitializer(loc: ValueRenderLocation) bool {
100 return switch (self) {102 return switch (loc) {
101 .Initializer, .StaticInitializer => true,103 .Initializer, .StaticInitializer => true,
102 else => false,104 else => false,
103 };105 };
104 }106 }
107
108 fn toCTypeKind(loc: ValueRenderLocation) CType.Kind {
109 return switch (loc) {
110 .FunctionArgument => .parameter,
111 .Initializer, .Other => .complete,
112 .StaticInitializer => .global,
113 };
114 }
105};115};
106116
107const BuiltinInfo = enum { none, bits };117const BuiltinInfo = enum { none, bits };
...@@ -234,12 +244,11 @@ fn isReservedIdent(ident: []const u8) bool {...@@ -234,12 +244,11 @@ fn isReservedIdent(ident: []const u8) bool {
234244
235fn formatIdent(245fn formatIdent(
236 ident: []const u8,246 ident: []const u8,
237 comptime fmt: []const u8,247 comptime fmt_str: []const u8,
238 options: std.fmt.FormatOptions,248 _: std.fmt.FormatOptions,
239 writer: anytype,249 writer: anytype,
240) !void {250) @TypeOf(writer).Error!void {
241 _ = options;251 const solo = fmt_str.len != 0 and fmt_str[0] == ' '; // space means solo; not part of a bigger ident.
242 const solo = fmt.len != 0 and fmt[0] == ' '; // space means solo; not part of a bigger ident.
243 if (solo and isReservedIdent(ident)) {252 if (solo and isReservedIdent(ident)) {
244 try writer.writeAll("zig_e_");253 try writer.writeAll("zig_e_");
245 }254 }
...@@ -256,11 +265,32 @@ fn formatIdent(...@@ -256,11 +265,32 @@ fn formatIdent(
256 }265 }
257 }266 }
258}267}
259
260pub fn fmtIdent(ident: []const u8) std.fmt.Formatter(formatIdent) {268pub fn fmtIdent(ident: []const u8) std.fmt.Formatter(formatIdent) {
261 return .{ .data = ident };269 return .{ .data = ident };
262}270}
263271
272const CTypePoolStringFormatData = struct {
273 ctype_pool_string: CType.Pool.String,
274 ctype_pool: *const CType.Pool,
275};
276fn formatCTypePoolString(
277 data: CTypePoolStringFormatData,
278 comptime fmt_str: []const u8,
279 fmt_opts: std.fmt.FormatOptions,
280 writer: anytype,
281) @TypeOf(writer).Error!void {
282 if (data.ctype_pool_string.toSlice(data.ctype_pool)) |slice|
283 try formatIdent(slice, fmt_str, fmt_opts, writer)
284 else
285 try writer.print("{}", .{data.ctype_pool_string.fmt(data.ctype_pool)});
286}
287pub fn fmtCTypePoolString(
288 ctype_pool_string: CType.Pool.String,
289 ctype_pool: *const CType.Pool,
290) std.fmt.Formatter(formatCTypePoolString) {
291 return .{ .data = .{ .ctype_pool_string = ctype_pool_string, .ctype_pool = ctype_pool } };
292}
293
264// Returns true if `formatIdent` would make any edits to ident.294// Returns true if `formatIdent` would make any edits to ident.
265// This must be kept in sync with `formatIdent`.295// This must be kept in sync with `formatIdent`.
266pub fn isMangledIdent(ident: []const u8, solo: bool) bool {296pub fn isMangledIdent(ident: []const u8, solo: bool) bool {
...@@ -321,7 +351,7 @@ pub const Function = struct {...@@ -321,7 +351,7 @@ pub const Function = struct {
321 try writer.writeAll(" = ");351 try writer.writeAll(" = ");
322 try f.object.dg.renderValue(writer, val, .StaticInitializer);352 try f.object.dg.renderValue(writer, val, .StaticInitializer);
323 try writer.writeAll(";\n ");353 try writer.writeAll(";\n ");
324 break :result decl_c_value;354 break :result .{ .local = decl_c_value.new_local };
325 } else .{ .constant = val };355 } else .{ .constant = val };
326356
327 gop.value_ptr.* = result;357 gop.value_ptr.* = result;
...@@ -377,27 +407,7 @@ pub const Function = struct {...@@ -377,27 +407,7 @@ pub const Function = struct {
377 switch (c_value) {407 switch (c_value) {
378 .none => unreachable,408 .none => unreachable,
379 .new_local, .local => |i| try w.print("t{d}", .{i}),409 .new_local, .local => |i| try w.print("t{d}", .{i}),
380 .local_ref => |i| {410 .local_ref => |i| try w.print("&t{d}", .{i}),
381 const local = &f.locals.items[i];
382 if (local.flags.alignas.abiOrder().compare(.lt)) {
383 const gpa = f.object.dg.gpa;
384 const mod = f.object.dg.mod;
385 const ctype_pool = &f.object.dg.ctype_pool;
386
387 try w.writeByte('(');
388 try f.renderCType(w, try ctype_pool.getPointer(gpa, .{
389 .elem_ctype = try ctype_pool.fromIntInfo(gpa, .{
390 .signedness = .unsigned,
391 .bits = @min(
392 local.flags.alignas.toByteUnits(),
393 mod.resolved_target.result.maxIntAlignment(),
394 ) * 8,
395 }, mod, .forward),
396 }));
397 try w.writeByte(')');
398 }
399 try w.print("&t{d}", .{i});
400 },
401 .constant => |val| try f.object.dg.renderValue(w, val, location),411 .constant => |val| try f.object.dg.renderValue(w, val, location),
402 .arg => |i| try w.print("a{d}", .{i}),412 .arg => |i| try w.print("a{d}", .{i}),
403 .arg_array => |i| try f.writeCValueMember(w, .{ .arg = i }, .{ .identifier = "array" }),413 .arg_array => |i| try f.writeCValueMember(w, .{ .arg = i }, .{ .identifier = "array" }),
...@@ -516,7 +526,7 @@ pub const Function = struct {...@@ -516,7 +526,7 @@ pub const Function = struct {
516 },526 },
517 };527 };
518 }528 }
519 return gop.value_ptr.fn_name.slice(ctype_pool);529 return gop.value_ptr.fn_name.toSlice(ctype_pool).?;
520 }530 }
521531
522 pub fn deinit(f: *Function) void {532 pub fn deinit(f: *Function) void {
...@@ -538,6 +548,43 @@ pub const Function = struct {...@@ -538,6 +548,43 @@ pub const Function = struct {
538 const zcu = f.object.dg.zcu;548 const zcu = f.object.dg.zcu;
539 return f.air.typeOfIndex(inst, &zcu.intern_pool);549 return f.air.typeOfIndex(inst, &zcu.intern_pool);
540 }550 }
551
552 fn copyCValue(f: *Function, ctype: CType, dst: CValue, src: CValue) !void {
553 switch (dst) {
554 .new_local, .local => |dst_local_index| switch (src) {
555 .new_local, .local => |src_local_index| if (dst_local_index == src_local_index) return,
556 else => {},
557 },
558 else => {},
559 }
560 const writer = f.object.writer();
561 const a = try Assignment.start(f, writer, ctype);
562 try f.writeCValue(writer, dst, .Other);
563 try a.assign(f, writer);
564 try f.writeCValue(writer, src, .Initializer);
565 try a.end(f, writer);
566 }
567
568 fn moveCValue(f: *Function, inst: Air.Inst.Index, ty: Type, src: CValue) !CValue {
569 switch (src) {
570 // Move the freshly allocated local to be owned by this instruction,
571 // by returning it here instead of freeing it.
572 .new_local => return src,
573 else => {
574 try freeCValue(f, inst, src);
575 const dst = try f.allocLocal(inst, ty);
576 try f.copyCValue(try f.ctypeFromType(ty, .complete), dst, src);
577 return dst;
578 },
579 }
580 }
581
582 fn freeCValue(f: *Function, inst: ?Air.Inst.Index, val: CValue) !void {
583 switch (val) {
584 .new_local => |local_index| try freeLocal(f, inst, local_index, null),
585 else => {},
586 }
587 }
541};588};
542589
543/// This data is available when outputting .c code for a `Zcu`.590/// This data is available when outputting .c code for a `Zcu`.
...@@ -627,13 +674,14 @@ pub const DeclGen = struct {...@@ -627,13 +674,14 @@ pub const DeclGen = struct {
627 // them). The analysis until now should ensure that the C function674 // them). The analysis until now should ensure that the C function
628 // pointers are compatible. If they are not, then there is a bug675 // pointers are compatible. If they are not, then there is a bug
629 // somewhere and we should let the C compiler tell us about it.676 // somewhere and we should let the C compiler tell us about it.
630 const elem_ctype = (try dg.ctypeFromType(ptr_ty, .complete)).info(ctype_pool).pointer.elem_ctype;677 const ptr_ctype = try dg.ctypeFromType(ptr_ty, .complete);
678 const elem_ctype = ptr_ctype.info(ctype_pool).pointer.elem_ctype;
631 const decl_ctype = try dg.ctypeFromType(decl_ty, .complete);679 const decl_ctype = try dg.ctypeFromType(decl_ty, .complete);
632 const need_cast = !elem_ctype.eql(decl_ctype) and680 const need_cast = !elem_ctype.eql(decl_ctype) and
633 (elem_ctype.info(ctype_pool) != .function or decl_ctype.info(ctype_pool) != .function);681 (elem_ctype.info(ctype_pool) != .function or decl_ctype.info(ctype_pool) != .function);
634 if (need_cast) {682 if (need_cast) {
635 try writer.writeAll("((");683 try writer.writeAll("((");
636 try dg.renderType(writer, ptr_ty);684 try dg.renderCType(writer, ptr_ctype);
637 try writer.writeByte(')');685 try writer.writeByte(')');
638 }686 }
639 try writer.writeByte('&');687 try writer.writeByte('&');
...@@ -692,13 +740,14 @@ pub const DeclGen = struct {...@@ -692,13 +740,14 @@ pub const DeclGen = struct {
692 // them). The analysis until now should ensure that the C function740 // them). The analysis until now should ensure that the C function
693 // pointers are compatible. If they are not, then there is a bug741 // pointers are compatible. If they are not, then there is a bug
694 // somewhere and we should let the C compiler tell us about it.742 // somewhere and we should let the C compiler tell us about it.
695 const elem_ctype = (try dg.ctypeFromType(ty, .complete)).info(ctype_pool).pointer.elem_ctype;743 const ctype = try dg.ctypeFromType(ty, .complete);
744 const elem_ctype = ctype.info(ctype_pool).pointer.elem_ctype;
696 const decl_ctype = try dg.ctypeFromType(decl_ty, .complete);745 const decl_ctype = try dg.ctypeFromType(decl_ty, .complete);
697 const need_cast = !elem_ctype.eql(decl_ctype) and746 const need_cast = !elem_ctype.eql(decl_ctype) and
698 (elem_ctype.info(ctype_pool) != .function or decl_ctype.info(ctype_pool) != .function);747 (elem_ctype.info(ctype_pool) != .function or decl_ctype.info(ctype_pool) != .function);
699 if (need_cast) {748 if (need_cast) {
700 try writer.writeAll("((");749 try writer.writeAll("((");
701 try dg.renderType(writer, ty);750 try dg.renderCType(writer, ctype);
702 try writer.writeByte(')');751 try writer.writeByte(')');
703 }752 }
704 try writer.writeByte('&');753 try writer.writeByte('&');
...@@ -828,6 +877,12 @@ pub const DeclGen = struct {...@@ -828,6 +877,12 @@ pub const DeclGen = struct {
828 }877 }
829 }878 }
830879
880 fn renderErrorName(dg: *DeclGen, writer: anytype, err_name: InternPool.NullTerminatedString) !void {
881 const zcu = dg.zcu;
882 const ip = &zcu.intern_pool;
883 try writer.print("zig_error_{}", .{fmtIdent(err_name.toSlice(ip))});
884 }
885
831 fn renderValue(886 fn renderValue(
832 dg: *DeclGen,887 dg: *DeclGen,
833 writer: anytype,888 writer: anytype,
...@@ -837,6 +892,7 @@ pub const DeclGen = struct {...@@ -837,6 +892,7 @@ pub const DeclGen = struct {
837 const zcu = dg.zcu;892 const zcu = dg.zcu;
838 const ip = &zcu.intern_pool;893 const ip = &zcu.intern_pool;
839 const target = &dg.mod.resolved_target.result;894 const target = &dg.mod.resolved_target.result;
895 const ctype_pool = &dg.ctype_pool;
840896
841 const initializer_type: ValueRenderLocation = switch (location) {897 const initializer_type: ValueRenderLocation = switch (location) {
842 .StaticInitializer => .StaticInitializer,898 .StaticInitializer => .StaticInitializer,
...@@ -845,6 +901,7 @@ pub const DeclGen = struct {...@@ -845,6 +901,7 @@ pub const DeclGen = struct {
845901
846 const ty = val.typeOf(zcu);902 const ty = val.typeOf(zcu);
847 if (val.isUndefDeep(zcu)) return dg.renderUndefValue(writer, ty, location);903 if (val.isUndefDeep(zcu)) return dg.renderUndefValue(writer, ty, location);
904 const ctype = try dg.ctypeFromType(ty, location.toCTypeKind());
848 switch (ip.indexToKey(val.toIntern())) {905 switch (ip.indexToKey(val.toIntern())) {
849 // types, not values906 // types, not values
850 .int_type,907 .int_type,
...@@ -890,76 +947,53 @@ pub const DeclGen = struct {...@@ -890,76 +947,53 @@ pub const DeclGen = struct {
890 .u64, .i64, .big_int => try writer.print("{}", .{try dg.fmtIntLiteral(val, location)}),947 .u64, .i64, .big_int => try writer.print("{}", .{try dg.fmtIntLiteral(val, location)}),
891 .lazy_align, .lazy_size => {948 .lazy_align, .lazy_size => {
892 try writer.writeAll("((");949 try writer.writeAll("((");
893 try dg.renderType(writer, ty);950 try dg.renderCType(writer, ctype);
894 try writer.print("){x})", .{try dg.fmtIntLiteral(951 try writer.print("){x})", .{try dg.fmtIntLiteral(
895 try zcu.intValue(Type.usize, val.toUnsignedInt(zcu)),952 try zcu.intValue(Type.usize, val.toUnsignedInt(zcu)),
896 .Other,953 .Other,
897 )});954 )});
898 },955 },
899 },956 },
900 .err => |err| try writer.print("zig_error_{}", .{957 .err => |err| try dg.renderErrorName(writer, err.name),
901 fmtIdent(err.name.toSlice(ip)),958 .error_union => |error_union| switch (ctype.info(ctype_pool)) {
902 }),959 .basic => switch (error_union.val) {
903 .error_union => |error_union| {960 .err_name => |err_name| try dg.renderErrorName(writer, err_name),
904 const payload_ty = ty.errorUnionPayload(zcu);961 .payload => try writer.writeAll("0"),
905 const error_ty = ty.errorUnionSet(zcu);962 },
906 const err_int_ty = try zcu.errorIntType();963 .pointer, .aligned, .array, .vector, .fwd_decl, .function => unreachable,
907 if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {964 .aggregate => |aggregate| {
908 switch (error_union.val) {965 if (!location.isInitializer()) {
909 .err_name => |err_name| return dg.renderValue(966 try writer.writeByte('(');
910 writer,967 try dg.renderCType(writer, ctype);
911 Value.fromInterned((try zcu.intern(.{ .err = .{968 try writer.writeByte(')');
912 .ty = error_ty.toIntern(),
913 .name = err_name,
914 } }))),
915 location,
916 ),
917 .payload => return dg.renderValue(
918 writer,
919 try zcu.intValue(err_int_ty, 0),
920 location,
921 ),
922 }969 }
923 }970 try writer.writeByte('{');
924971 for (0..aggregate.fields.len) |field_index| {
925 if (!location.isInitializer()) {972 if (field_index > 0) try writer.writeByte(',');
926 try writer.writeByte('(');973 switch (aggregate.fields.at(field_index, ctype_pool).name.index) {
927 try dg.renderType(writer, ty);974 .@"error" => switch (error_union.val) {
928 try writer.writeByte(')');975 .err_name => |err_name| try dg.renderErrorName(writer, err_name),
929 }976 .payload => try writer.writeByte('0'),
930977 },
931 try writer.writeAll("{ .payload = ");978 .payload => switch (error_union.val) {
932 try dg.renderValue(979 .err_name => try dg.renderUndefValue(
933 writer,980 writer,
934 Value.fromInterned(switch (error_union.val) {981 ty.errorUnionPayload(zcu),
935 .err_name => (try zcu.undefValue(payload_ty)).toIntern(),982 initializer_type,
936 .payload => |payload| payload,983 ),
937 }),984 .payload => |payload| try dg.renderValue(
938 initializer_type,985 writer,
939 );986 Value.fromInterned(payload),
940 try writer.writeAll(", .error = ");987 initializer_type,
941 switch (error_union.val) {988 ),
942 .err_name => |err_name| try dg.renderValue(989 },
943 writer,990 else => unreachable,
944 Value.fromInterned((try zcu.intern(.{ .err = .{991 }
945 .ty = error_ty.toIntern(),992 }
946 .name = err_name,993 try writer.writeByte('}');
947 } }))),994 },
948 location,
949 ),
950 .payload => try dg.renderValue(
951 writer,
952 try zcu.intValue(err_int_ty, 0),
953 location,
954 ),
955 }
956 try writer.writeAll(" }");
957 },995 },
958 .enum_tag => |enum_tag| try dg.renderValue(996 .enum_tag => |enum_tag| try dg.renderValue(writer, Value.fromInterned(enum_tag.int), location),
959 writer,
960 Value.fromInterned(enum_tag.int),
961 location,
962 ),
963 .float => {997 .float => {
964 const bits = ty.floatBits(target.*);998 const bits = ty.floatBits(target.*);
965 const f128_val = val.toFloat(f128, zcu);999 const f128_val = val.toFloat(f128, zcu);
...@@ -1050,15 +1084,23 @@ pub const DeclGen = struct {...@@ -1050,15 +1084,23 @@ pub const DeclGen = struct {
1050 if (!empty) try writer.writeByte(')');1084 if (!empty) try writer.writeByte(')');
1051 },1085 },
1052 .slice => |slice| {1086 .slice => |slice| {
1087 const aggregate = ctype.info(ctype_pool).aggregate;
1053 if (!location.isInitializer()) {1088 if (!location.isInitializer()) {
1054 try writer.writeByte('(');1089 try writer.writeByte('(');
1055 try dg.renderType(writer, ty);1090 try dg.renderCType(writer, ctype);
1056 try writer.writeByte(')');1091 try writer.writeByte(')');
1057 }1092 }
1058 try writer.writeByte('{');1093 try writer.writeByte('{');
1059 try dg.renderValue(writer, Value.fromInterned(slice.ptr), initializer_type);1094 for (0..aggregate.fields.len) |field_index| {
1060 try writer.writeAll(", ");1095 if (field_index > 0) try writer.writeByte(',');
1061 try dg.renderValue(writer, Value.fromInterned(slice.len), initializer_type);1096 try dg.renderValue(writer, Value.fromInterned(
1097 switch (aggregate.fields.at(field_index, ctype_pool).name.index) {
1098 .ptr => slice.ptr,
1099 .len => slice.len,
1100 else => unreachable,
1101 },
1102 ), initializer_type);
1103 }
1062 try writer.writeByte('}');1104 try writer.writeByte('}');
1063 },1105 },
1064 .ptr => |ptr| switch (ptr.addr) {1106 .ptr => |ptr| switch (ptr.addr) {
...@@ -1066,7 +1108,7 @@ pub const DeclGen = struct {...@@ -1066,7 +1108,7 @@ pub const DeclGen = struct {
1066 .anon_decl => |decl_val| try dg.renderAnonDeclValue(writer, val, decl_val, location),1108 .anon_decl => |decl_val| try dg.renderAnonDeclValue(writer, val, decl_val, location),
1067 .int => |int| {1109 .int => |int| {
1068 try writer.writeAll("((");1110 try writer.writeAll("((");
1069 try dg.renderType(writer, ty);1111 try dg.renderCType(writer, ctype);
1070 try writer.print("){x})", .{try dg.fmtIntLiteral(Value.fromInterned(int), location)});1112 try writer.print("){x})", .{try dg.fmtIntLiteral(Value.fromInterned(int), location)});
1071 },1113 },
1072 .eu_payload,1114 .eu_payload,
...@@ -1076,54 +1118,80 @@ pub const DeclGen = struct {...@@ -1076,54 +1118,80 @@ pub const DeclGen = struct {
1076 => try dg.renderParentPtr(writer, val.toIntern(), location),1118 => try dg.renderParentPtr(writer, val.toIntern(), location),
1077 .comptime_field, .comptime_alloc => unreachable,1119 .comptime_field, .comptime_alloc => unreachable,
1078 },1120 },
1079 .opt => |opt| {1121 .opt => |opt| switch (ctype.info(ctype_pool)) {
1080 const payload_ty = ty.optionalChild(zcu);1122 .basic => if (ctype.isBool()) try writer.writeAll(switch (opt.val) {
10811123 .none => "true",
1082 const is_null_val = Value.makeBool(opt.val == .none);1124 else => "false",
1083 if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu))1125 }) else switch (opt.val) {
1084 return dg.renderValue(writer, is_null_val, location);1126 .none => try writer.writeAll("0"),
10851127 else => |payload| switch (ip.indexToKey(payload)) {
1086 if (ty.optionalReprIsPayload(zcu)) return dg.renderValue(1128 .undef => |err_ty| try dg.renderUndefValue(
1087 writer,1129 writer,
1130 Type.fromInterned(err_ty),
1131 location,
1132 ),
1133 .err => |err| try dg.renderErrorName(writer, err.name),
1134 else => unreachable,
1135 },
1136 },
1137 .pointer => switch (opt.val) {
1138 .none => try writer.writeAll("NULL"),
1139 else => |payload| try dg.renderValue(writer, Value.fromInterned(payload), location),
1140 },
1141 .aligned, .array, .vector, .fwd_decl, .function => unreachable,
1142 .aggregate => |aggregate| {
1088 switch (opt.val) {1143 switch (opt.val) {
1089 .none => switch (payload_ty.zigTypeTag(zcu)) {1144 .none => {},
1090 .ErrorSet => try zcu.intValue(try zcu.errorIntType(), 0),1145 else => |payload| switch (aggregate.fields.at(0, ctype_pool).name.index) {
1091 .Pointer => try zcu.getCoerced(val, payload_ty),1146 .is_null, .payload => {},
1147 .ptr, .len => return dg.renderValue(
1148 writer,
1149 Value.fromInterned(payload),
1150 location,
1151 ),
1092 else => unreachable,1152 else => unreachable,
1093 },1153 },
1094 else => |payload| Value.fromInterned(payload),1154 }
1095 },1155 if (!location.isInitializer()) {
1096 location,1156 try writer.writeByte('(');
1097 );1157 try dg.renderCType(writer, ctype);
10981158 try writer.writeByte(')');
1099 if (!location.isInitializer()) {1159 }
1100 try writer.writeByte('(');1160 try writer.writeByte('{');
1101 try dg.renderType(writer, ty);1161 for (0..aggregate.fields.len) |field_index| {
1102 try writer.writeByte(')');1162 if (field_index > 0) try writer.writeByte(',');
1103 }1163 switch (aggregate.fields.at(field_index, ctype_pool).name.index) {
11041164 .is_null => try writer.writeAll(switch (opt.val) {
1105 try writer.writeAll("{ .payload = ");1165 .none => "true",
1106 switch (opt.val) {1166 else => "false",
1107 .none => try dg.renderUndefValue(writer, payload_ty, initializer_type),1167 }),
1108 else => |payload| try dg.renderValue(1168 .payload => switch (opt.val) {
1109 writer,1169 .none => try dg.renderUndefValue(
1110 Value.fromInterned(payload),1170 writer,
1111 initializer_type,1171 ty.optionalChild(zcu),
1112 ),1172 initializer_type,
1113 }1173 ),
1114 try writer.writeAll(", .is_null = ");1174 else => |payload| try dg.renderValue(
1115 try dg.renderValue(writer, is_null_val, initializer_type);1175 writer,
1116 try writer.writeAll(" }");1176 Value.fromInterned(payload),
1177 initializer_type,
1178 ),
1179 },
1180 .ptr => try writer.writeAll("NULL"),
1181 .len => try dg.renderUndefValue(writer, Type.usize, initializer_type),
1182 else => unreachable,
1183 }
1184 }
1185 try writer.writeByte('}');
1186 },
1117 },1187 },
1118 .aggregate => switch (ip.indexToKey(ty.toIntern())) {1188 .aggregate => switch (ip.indexToKey(ty.toIntern())) {
1119 .array_type, .vector_type => {1189 .array_type, .vector_type => {
1120 if (location == .FunctionArgument) {1190 if (location == .FunctionArgument) {
1121 try writer.writeByte('(');1191 try writer.writeByte('(');
1122 try dg.renderType(writer, ty);1192 try dg.renderCType(writer, ctype);
1123 try writer.writeByte(')');1193 try writer.writeByte(')');
1124 }1194 }
1125 // Fall back to generic implementation.
1126
1127 const ai = ty.arrayInfo(zcu);1195 const ai = ty.arrayInfo(zcu);
1128 if (ai.elem_type.eql(Type.u8, zcu)) {1196 if (ai.elem_type.eql(Type.u8, zcu)) {
1129 var literal = stringLiteral(writer, ty.arrayLenIncludingSentinel(zcu));1197 var literal = stringLiteral(writer, ty.arrayLenIncludingSentinel(zcu));
...@@ -1160,7 +1228,7 @@ pub const DeclGen = struct {...@@ -1160,7 +1228,7 @@ pub const DeclGen = struct {
1160 .anon_struct_type => |tuple| {1228 .anon_struct_type => |tuple| {
1161 if (!location.isInitializer()) {1229 if (!location.isInitializer()) {
1162 try writer.writeByte('(');1230 try writer.writeByte('(');
1163 try dg.renderType(writer, ty);1231 try dg.renderCType(writer, ctype);
1164 try writer.writeByte(')');1232 try writer.writeByte(')');
1165 }1233 }
11661234
...@@ -1196,7 +1264,7 @@ pub const DeclGen = struct {...@@ -1196,7 +1264,7 @@ pub const DeclGen = struct {
1196 .auto, .@"extern" => {1264 .auto, .@"extern" => {
1197 if (!location.isInitializer()) {1265 if (!location.isInitializer()) {
1198 try writer.writeByte('(');1266 try writer.writeByte('(');
1199 try dg.renderType(writer, ty);1267 try dg.renderCType(writer, ctype);
1200 try writer.writeByte(')');1268 try writer.writeByte(')');
1201 }1269 }
12021270
...@@ -1238,7 +1306,7 @@ pub const DeclGen = struct {...@@ -1238,7 +1306,7 @@ pub const DeclGen = struct {
12381306
1239 if (eff_num_fields == 0) {1307 if (eff_num_fields == 0) {
1240 try writer.writeByte('(');1308 try writer.writeByte('(');
1241 try dg.renderUndefValue(writer, ty, initializer_type);1309 try dg.renderUndefValue(writer, ty, location);
1242 try writer.writeByte(')');1310 try writer.writeByte(')');
1243 } else if (ty.bitSize(zcu) > 64) {1311 } else if (ty.bitSize(zcu) > 64) {
1244 // zig_or_u128(zig_or_u128(zig_shl_u128(a, a_off), zig_shl_u128(b, b_off)), zig_shl_u128(c, c_off))1312 // zig_or_u128(zig_or_u128(zig_shl_u128(a, a_off), zig_shl_u128(b, b_off)), zig_shl_u128(c, c_off))
...@@ -1293,7 +1361,7 @@ pub const DeclGen = struct {...@@ -1293,7 +1361,7 @@ pub const DeclGen = struct {
12931361
1294 if (!empty) try writer.writeAll(" | ");1362 if (!empty) try writer.writeAll(" | ");
1295 try writer.writeByte('(');1363 try writer.writeByte('(');
1296 try dg.renderType(writer, ty);1364 try dg.renderCType(writer, ctype);
1297 try writer.writeByte(')');1365 try writer.writeByte(')');
12981366
1299 const field_val = switch (ip.indexToKey(val.toIntern()).aggregate.storage) {1367 const field_val = switch (ip.indexToKey(val.toIntern()).aggregate.storage) {
...@@ -1334,7 +1402,7 @@ pub const DeclGen = struct {...@@ -1334,7 +1402,7 @@ pub const DeclGen = struct {
1334 try dg.renderType(writer, backing_ty);1402 try dg.renderType(writer, backing_ty);
1335 try writer.writeByte(')');1403 try writer.writeByte(')');
1336 }1404 }
1337 try dg.renderValue(writer, Value.fromInterned(un.val), initializer_type);1405 try dg.renderValue(writer, Value.fromInterned(un.val), location);
1338 },1406 },
1339 .@"extern" => {1407 .@"extern" => {
1340 if (location == .StaticInitializer) {1408 if (location == .StaticInitializer) {
...@@ -1347,7 +1415,7 @@ pub const DeclGen = struct {...@@ -1347,7 +1415,7 @@ pub const DeclGen = struct {
1347 try writer.writeAll(")(");1415 try writer.writeAll(")(");
1348 try dg.renderType(writer, backing_ty);1416 try dg.renderType(writer, backing_ty);
1349 try writer.writeAll("){");1417 try writer.writeAll("){");
1350 try dg.renderValue(writer, Value.fromInterned(un.val), initializer_type);1418 try dg.renderValue(writer, Value.fromInterned(un.val), location);
1351 try writer.writeAll("})");1419 try writer.writeAll("})");
1352 },1420 },
1353 else => unreachable,1421 else => unreachable,
...@@ -1355,7 +1423,7 @@ pub const DeclGen = struct {...@@ -1355,7 +1423,7 @@ pub const DeclGen = struct {
1355 } else {1423 } else {
1356 if (!location.isInitializer()) {1424 if (!location.isInitializer()) {
1357 try writer.writeByte('(');1425 try writer.writeByte('(');
1358 try dg.renderType(writer, ty);1426 try dg.renderCType(writer, ctype);
1359 try writer.writeByte(')');1427 try writer.writeByte(')');
1360 }1428 }
13611429
...@@ -1366,43 +1434,56 @@ pub const DeclGen = struct {...@@ -1366,43 +1434,56 @@ pub const DeclGen = struct {
1366 if (field_ty.hasRuntimeBits(zcu)) {1434 if (field_ty.hasRuntimeBits(zcu)) {
1367 if (field_ty.isPtrAtRuntime(zcu)) {1435 if (field_ty.isPtrAtRuntime(zcu)) {
1368 try writer.writeByte('(');1436 try writer.writeByte('(');
1369 try dg.renderType(writer, ty);1437 try dg.renderCType(writer, ctype);
1370 try writer.writeByte(')');1438 try writer.writeByte(')');
1371 } else if (field_ty.zigTypeTag(zcu) == .Float) {1439 } else if (field_ty.zigTypeTag(zcu) == .Float) {
1372 try writer.writeByte('(');1440 try writer.writeByte('(');
1373 try dg.renderType(writer, ty);1441 try dg.renderCType(writer, ctype);
1374 try writer.writeByte(')');1442 try writer.writeByte(')');
1375 }1443 }
1376 try dg.renderValue(writer, Value.fromInterned(un.val), initializer_type);1444 try dg.renderValue(writer, Value.fromInterned(un.val), location);
1377 } else {1445 } else try writer.writeAll("0");
1378 try writer.writeAll("0");
1379 }
1380 return;1446 return;
1381 }1447 }
13821448
1383 try writer.writeByte('{');1449 const has_tag = loaded_union.hasTag(ip);
1384 if (ty.unionTagTypeSafety(zcu)) |_| {1450 if (has_tag) try writer.writeByte('{');
1385 const layout = zcu.getUnionLayout(loaded_union);1451 const aggregate = ctype.info(ctype_pool).aggregate;
1386 if (layout.tag_size != 0) {1452 for (0..if (has_tag) aggregate.fields.len else 1) |outer_field_index| {
1387 try writer.writeAll(" .tag = ");1453 if (outer_field_index > 0) try writer.writeByte(',');
1388 try dg.renderValue(writer, Value.fromInterned(un.tag), initializer_type);1454 switch (if (has_tag)
1455 aggregate.fields.at(outer_field_index, ctype_pool).name.index
1456 else
1457 .payload) {
1458 .tag => try dg.renderValue(
1459 writer,
1460 Value.fromInterned(un.tag),
1461 initializer_type,
1462 ),
1463 .payload => {
1464 try writer.writeByte('{');
1465 if (field_ty.hasRuntimeBits(zcu)) {
1466 try writer.print(" .{ } = ", .{fmtIdent(field_name.toSlice(ip))});
1467 try dg.renderValue(
1468 writer,
1469 Value.fromInterned(un.val),
1470 initializer_type,
1471 );
1472 try writer.writeByte(' ');
1473 } else for (0..loaded_union.field_types.len) |inner_field_index| {
1474 const inner_field_ty = Type.fromInterned(
1475 loaded_union.field_types.get(ip)[inner_field_index],
1476 );
1477 if (!inner_field_ty.hasRuntimeBits(zcu)) continue;
1478 try dg.renderUndefValue(writer, inner_field_ty, initializer_type);
1479 break;
1480 }
1481 try writer.writeByte('}');
1482 },
1483 else => unreachable,
1389 }1484 }
1390 if (ty.unionHasAllZeroBitFieldTypes(zcu)) return try writer.writeByte('}');
1391 if (layout.tag_size != 0) try writer.writeByte(',');
1392 try writer.writeAll(" .payload = {");
1393 }
1394 if (field_ty.hasRuntimeBits(zcu)) {
1395 try writer.print(" .{ } = ", .{fmtIdent(field_name.toSlice(ip))});
1396 try dg.renderValue(writer, Value.fromInterned(un.val), initializer_type);
1397 try writer.writeByte(' ');
1398 } else for (0..loaded_union.field_types.len) |this_field_index| {
1399 const this_field_ty = Type.fromInterned(loaded_union.field_types.get(ip)[this_field_index]);
1400 if (!this_field_ty.hasRuntimeBits(zcu)) continue;
1401 try dg.renderUndefValue(writer, this_field_ty, initializer_type);
1402 break;
1403 }1485 }
1404 if (ty.unionTagTypeSafety(zcu)) |_| try writer.writeByte('}');1486 if (has_tag) try writer.writeByte('}');
1405 try writer.writeByte('}');
1406 }1487 }
1407 },1488 },
1408 }1489 }
...@@ -1417,6 +1498,7 @@ pub const DeclGen = struct {...@@ -1417,6 +1498,7 @@ pub const DeclGen = struct {
1417 const zcu = dg.zcu;1498 const zcu = dg.zcu;
1418 const ip = &zcu.intern_pool;1499 const ip = &zcu.intern_pool;
1419 const target = &dg.mod.resolved_target.result;1500 const target = &dg.mod.resolved_target.result;
1501 const ctype_pool = &dg.ctype_pool;
14201502
1421 const initializer_type: ValueRenderLocation = switch (location) {1503 const initializer_type: ValueRenderLocation = switch (location) {
1422 .StaticInitializer => .StaticInitializer,1504 .StaticInitializer => .StaticInitializer,
...@@ -1428,6 +1510,7 @@ pub const DeclGen = struct {...@@ -1428,6 +1510,7 @@ pub const DeclGen = struct {
1428 .ReleaseFast, .ReleaseSmall => false,1510 .ReleaseFast, .ReleaseSmall => false,
1429 };1511 };
14301512
1513 const ctype = try dg.ctypeFromType(ty, location.toCTypeKind());
1431 switch (ty.toIntern()) {1514 switch (ty.toIntern()) {
1432 .c_longdouble_type,1515 .c_longdouble_type,
1433 .f16_type,1516 .f16_type,
...@@ -1465,48 +1548,64 @@ pub const DeclGen = struct {...@@ -1465,48 +1548,64 @@ pub const DeclGen = struct {
1465 => return writer.print("{x}", .{1548 => return writer.print("{x}", .{
1466 try dg.fmtIntLiteral(try zcu.undefValue(ty), location),1549 try dg.fmtIntLiteral(try zcu.undefValue(ty), location),
1467 }),1550 }),
1468 .ptr_type => if (ty.isSlice(zcu)) {1551 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
1469 if (!location.isInitializer()) {1552 .One, .Many, .C => {
1470 try writer.writeByte('(');1553 try writer.writeAll("((");
1471 try dg.renderType(writer, ty);1554 try dg.renderCType(writer, ctype);
1472 try writer.writeByte(')');1555 return writer.print("){x})", .{
1473 }1556 try dg.fmtIntLiteral(try zcu.undefValue(Type.usize), .Other),
1557 });
1558 },
1559 .Slice => {
1560 if (!location.isInitializer()) {
1561 try writer.writeByte('(');
1562 try dg.renderCType(writer, ctype);
1563 try writer.writeByte(')');
1564 }
14741565
1475 try writer.writeAll("{(");1566 try writer.writeAll("{(");
1476 const ptr_ty = ty.slicePtrFieldType(zcu);1567 const ptr_ty = ty.slicePtrFieldType(zcu);
1477 try dg.renderType(writer, ptr_ty);1568 try dg.renderType(writer, ptr_ty);
1478 return writer.print("){x}, {0x}}}", .{1569 return writer.print("){x}, {0x}}}", .{
1479 try dg.fmtIntLiteral(try zcu.undefValue(Type.usize), .Other),1570 try dg.fmtIntLiteral(try zcu.undefValue(Type.usize), .Other),
1480 });1571 });
1481 } else {1572 },
1482 try writer.writeAll("((");
1483 try dg.renderType(writer, ty);
1484 return writer.print("){x})", .{
1485 try dg.fmtIntLiteral(try zcu.undefValue(Type.usize), .Other),
1486 });
1487 },1573 },
1488 .opt_type => {1574 .opt_type => |child_type| switch (ctype.info(ctype_pool)) {
1489 const payload_ty = ty.optionalChild(zcu);1575 .basic, .pointer => try dg.renderUndefValue(
14901576 writer,
1491 if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {1577 Type.fromInterned(if (ctype.isBool()) .bool_type else child_type),
1492 return dg.renderUndefValue(writer, Type.bool, location);1578 location,
1493 }1579 ),
14941580 .aligned, .array, .vector, .fwd_decl, .function => unreachable,
1495 if (ty.optionalReprIsPayload(zcu)) {1581 .aggregate => |aggregate| {
1496 return dg.renderUndefValue(writer, payload_ty, location);1582 switch (aggregate.fields.at(0, ctype_pool).name.index) {
1497 }1583 .is_null, .payload => {},
14981584 .ptr, .len => return dg.renderUndefValue(
1499 if (!location.isInitializer()) {1585 writer,
1500 try writer.writeByte('(');1586 Type.fromInterned(child_type),
1501 try dg.renderType(writer, ty);1587 location,
1502 try writer.writeByte(')');1588 ),
1503 }1589 else => unreachable,
15041590 }
1505 try writer.writeAll("{ .payload = ");1591 if (!location.isInitializer()) {
1506 try dg.renderUndefValue(writer, payload_ty, initializer_type);1592 try writer.writeByte('(');
1507 try writer.writeAll(", .is_null = ");1593 try dg.renderCType(writer, ctype);
1508 try dg.renderUndefValue(writer, Type.bool, initializer_type);1594 try writer.writeByte(')');
1509 return writer.writeAll(" }");1595 }
1596 try writer.writeByte('{');
1597 for (0..aggregate.fields.len) |field_index| {
1598 if (field_index > 0) try writer.writeByte(',');
1599 try dg.renderUndefValue(writer, Type.fromInterned(
1600 switch (aggregate.fields.at(field_index, ctype_pool).name.index) {
1601 .is_null => .bool_type,
1602 .payload => child_type,
1603 else => unreachable,
1604 },
1605 ), initializer_type);
1606 }
1607 try writer.writeByte('}');
1608 },
1510 },1609 },
1511 .struct_type => {1610 .struct_type => {
1512 const loaded_struct = ip.loadStructType(ty.toIntern());1611 const loaded_struct = ip.loadStructType(ty.toIntern());
...@@ -1514,7 +1613,7 @@ pub const DeclGen = struct {...@@ -1514,7 +1613,7 @@ pub const DeclGen = struct {
1514 .auto, .@"extern" => {1613 .auto, .@"extern" => {
1515 if (!location.isInitializer()) {1614 if (!location.isInitializer()) {
1516 try writer.writeByte('(');1615 try writer.writeByte('(');
1517 try dg.renderType(writer, ty);1616 try dg.renderCType(writer, ctype);
1518 try writer.writeByte(')');1617 try writer.writeByte(')');
1519 }1618 }
15201619
...@@ -1539,7 +1638,7 @@ pub const DeclGen = struct {...@@ -1539,7 +1638,7 @@ pub const DeclGen = struct {
1539 .anon_struct_type => |anon_struct_info| {1638 .anon_struct_type => |anon_struct_info| {
1540 if (!location.isInitializer()) {1639 if (!location.isInitializer()) {
1541 try writer.writeByte('(');1640 try writer.writeByte('(');
1542 try dg.renderType(writer, ty);1641 try dg.renderCType(writer, ctype);
1543 try writer.writeByte(')');1642 try writer.writeByte(')');
1544 }1643 }
15451644
...@@ -1562,54 +1661,80 @@ pub const DeclGen = struct {...@@ -1562,54 +1661,80 @@ pub const DeclGen = struct {
1562 .auto, .@"extern" => {1661 .auto, .@"extern" => {
1563 if (!location.isInitializer()) {1662 if (!location.isInitializer()) {
1564 try writer.writeByte('(');1663 try writer.writeByte('(');
1565 try dg.renderType(writer, ty);1664 try dg.renderCType(writer, ctype);
1566 try writer.writeByte(')');1665 try writer.writeByte(')');
1567 }1666 }
15681667
1569 try writer.writeByte('{');1668 const has_tag = loaded_union.hasTag(ip);
1570 if (ty.unionTagTypeSafety(zcu)) |tag_ty| {1669 if (has_tag) try writer.writeByte('{');
1571 const layout = ty.unionGetLayout(zcu);1670 const aggregate = ctype.info(ctype_pool).aggregate;
1572 if (layout.tag_size != 0) {1671 for (0..if (has_tag) aggregate.fields.len else 1) |outer_field_index| {
1573 try writer.writeAll(" .tag = ");1672 if (outer_field_index > 0) try writer.writeByte(',');
1574 try dg.renderUndefValue(writer, tag_ty, initializer_type);1673 switch (if (has_tag)
1674 aggregate.fields.at(outer_field_index, ctype_pool).name.index
1675 else
1676 .payload) {
1677 .tag => try dg.renderUndefValue(
1678 writer,
1679 Type.fromInterned(loaded_union.enum_tag_ty),
1680 initializer_type,
1681 ),
1682 .payload => {
1683 try writer.writeByte('{');
1684 for (0..loaded_union.field_types.len) |inner_field_index| {
1685 const inner_field_ty = Type.fromInterned(
1686 loaded_union.field_types.get(ip)[inner_field_index],
1687 );
1688 if (!inner_field_ty.hasRuntimeBits(zcu)) continue;
1689 try dg.renderUndefValue(
1690 writer,
1691 inner_field_ty,
1692 initializer_type,
1693 );
1694 break;
1695 }
1696 try writer.writeByte('}');
1697 },
1698 else => unreachable,
1575 }1699 }
1576 if (ty.unionHasAllZeroBitFieldTypes(zcu)) return try writer.writeByte('}');
1577 if (layout.tag_size != 0) try writer.writeByte(',');
1578 try writer.writeAll(" .payload = {");
1579 }
1580 for (0..loaded_union.field_types.len) |field_index| {
1581 const field_ty = Type.fromInterned(loaded_union.field_types.get(ip)[field_index]);
1582 if (!field_ty.hasRuntimeBits(zcu)) continue;
1583 try dg.renderUndefValue(writer, field_ty, initializer_type);
1584 break;
1585 }1700 }
1586 if (ty.unionTagTypeSafety(zcu)) |_| try writer.writeByte('}');1701 if (has_tag) try writer.writeByte('}');
1587 return writer.writeByte('}');
1588 },1702 },
1589 .@"packed" => return writer.print("{x}", .{1703 .@"packed" => return writer.print("{x}", .{
1590 try dg.fmtIntLiteral(try zcu.undefValue(ty), .Other),1704 try dg.fmtIntLiteral(try zcu.undefValue(ty), .Other),
1591 }),1705 }),
1592 }1706 }
1593 },1707 },
1594 .error_union_type => {1708 .error_union_type => |error_union_type| switch (ctype.info(ctype_pool)) {
1595 const payload_ty = ty.errorUnionPayload(zcu);1709 .basic => try dg.renderUndefValue(
1596 const error_ty = ty.errorUnionSet(zcu);1710 writer,
15971711 Type.fromInterned(error_union_type.error_set_type),
1598 if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {1712 location,
1599 return dg.renderUndefValue(writer, error_ty, location);1713 ),
1600 }1714 .pointer, .aligned, .array, .vector, .fwd_decl, .function => unreachable,
16011715 .aggregate => |aggregate| {
1602 if (!location.isInitializer()) {1716 if (!location.isInitializer()) {
1603 try writer.writeByte('(');1717 try writer.writeByte('(');
1604 try dg.renderType(writer, ty);1718 try dg.renderCType(writer, ctype);
1605 try writer.writeByte(')');1719 try writer.writeByte(')');
1606 }1720 }
16071721 try writer.writeByte('{');
1608 try writer.writeAll("{ .payload = ");1722 for (0..aggregate.fields.len) |field_index| {
1609 try dg.renderUndefValue(writer, payload_ty, initializer_type);1723 if (field_index > 0) try writer.writeByte(',');
1610 try writer.writeAll(", .error = ");1724 try dg.renderUndefValue(
1611 try dg.renderUndefValue(writer, error_ty, initializer_type);1725 writer,
1612 return writer.writeAll(" }");1726 Type.fromInterned(
1727 switch (aggregate.fields.at(field_index, ctype_pool).name.index) {
1728 .@"error" => error_union_type.error_set_type,
1729 .payload => error_union_type.payload_type,
1730 else => unreachable,
1731 },
1732 ),
1733 initializer_type,
1734 );
1735 }
1736 try writer.writeByte('}');
1737 },
1613 },1738 },
1614 .array_type, .vector_type => {1739 .array_type, .vector_type => {
1615 const ai = ty.arrayInfo(zcu);1740 const ai = ty.arrayInfo(zcu);
...@@ -1624,7 +1749,7 @@ pub const DeclGen = struct {...@@ -1624,7 +1749,7 @@ pub const DeclGen = struct {
1624 } else {1749 } else {
1625 if (!location.isInitializer()) {1750 if (!location.isInitializer()) {
1626 try writer.writeByte('(');1751 try writer.writeByte('(');
1627 try dg.renderType(writer, ty);1752 try dg.renderCType(writer, ctype);
1628 try writer.writeByte(')');1753 try writer.writeByte(')');
1629 }1754 }
16301755
...@@ -1674,6 +1799,7 @@ pub const DeclGen = struct {...@@ -1674,6 +1799,7 @@ pub const DeclGen = struct {
1674 name: union(enum) {1799 name: union(enum) {
1675 export_index: u32,1800 export_index: u32,
1676 ident: []const u8,1801 ident: []const u8,
1802 fmt_ctype_pool_string: std.fmt.Formatter(formatCTypePoolString),
1677 },1803 },
1678 ) !void {1804 ) !void {
1679 const zcu = dg.zcu;1805 const zcu = dg.zcu;
...@@ -1717,6 +1843,7 @@ pub const DeclGen = struct {...@@ -1717,6 +1843,7 @@ pub const DeclGen = struct {
1717 try dg.renderDeclName(w, fn_decl_index, export_index);1843 try dg.renderDeclName(w, fn_decl_index, export_index);
1718 },1844 },
1719 .ident => |ident| try w.print("{}{ }", .{ trailing, fmtIdent(ident) }),1845 .ident => |ident| try w.print("{}{ }", .{ trailing, fmtIdent(ident) }),
1846 .fmt_ctype_pool_string => |fmt| try w.print("{}{ }", .{ trailing, fmt }),
1720 }1847 }
17211848
1722 try renderTypeSuffix(1849 try renderTypeSuffix(
...@@ -1772,7 +1899,7 @@ pub const DeclGen = struct {...@@ -1772,7 +1899,7 @@ pub const DeclGen = struct {
1772 });1899 });
1773 }1900 }
1774 },1901 },
1775 .ident => {},1902 .ident, .fmt_ctype_pool_string => {},
1776 }1903 }
1777 },1904 },
1778 .complete => {},1905 .complete => {},
...@@ -1800,11 +1927,11 @@ pub const DeclGen = struct {...@@ -1800,11 +1927,11 @@ pub const DeclGen = struct {
1800 /// | `renderTypeAndName` | "uint8_t *name" | "uint8_t *name[10]" |1927 /// | `renderTypeAndName` | "uint8_t *name" | "uint8_t *name[10]" |
1801 /// | `renderType` | "uint8_t *" | "uint8_t *[10]" |1928 /// | `renderType` | "uint8_t *" | "uint8_t *[10]" |
1802 ///1929 ///
1803 fn renderType(dg: *DeclGen, w: anytype, t: Type) error{ OutOfMemory, AnalysisFail }!void {1930 fn renderType(dg: *DeclGen, w: anytype, t: Type) error{OutOfMemory}!void {
1804 try dg.renderCType(w, try dg.ctypeFromType(t, .complete));1931 try dg.renderCType(w, try dg.ctypeFromType(t, .complete));
1805 }1932 }
18061933
1807 fn renderCType(dg: *DeclGen, w: anytype, ctype: CType) error{ OutOfMemory, AnalysisFail }!void {1934 fn renderCType(dg: *DeclGen, w: anytype, ctype: CType) error{OutOfMemory}!void {
1808 _ = try renderTypePrefix(dg.pass, &dg.ctype_pool, dg.zcu, w, ctype, .suffix, .{});1935 _ = try renderTypePrefix(dg.pass, &dg.ctype_pool, dg.zcu, w, ctype, .suffix, .{});
1809 try renderTypeSuffix(dg.pass, &dg.ctype_pool, dg.zcu, w, ctype, .suffix, .{});1936 try renderTypeSuffix(dg.pass, &dg.ctype_pool, dg.zcu, w, ctype, .suffix, .{});
1810 }1937 }
...@@ -1829,7 +1956,26 @@ pub const DeclGen = struct {...@@ -1829,7 +1956,26 @@ pub const DeclGen = struct {
1829 }1956 }
1830 }1957 }
1831 };1958 };
1959 fn intCastIsNoop(dg: *DeclGen, dest_ty: Type, src_ty: Type) bool {
1960 const zcu = dg.zcu;
1961 const dest_bits = dest_ty.bitSize(zcu);
1962 const dest_int_info = dest_ty.intInfo(zcu);
1963
1964 const src_is_ptr = src_ty.isPtrAtRuntime(zcu);
1965 const src_eff_ty: Type = if (src_is_ptr) switch (dest_int_info.signedness) {
1966 .unsigned => Type.usize,
1967 .signed => Type.isize,
1968 } else src_ty;
18321969
1970 const src_bits = src_eff_ty.bitSize(zcu);
1971 const src_int_info = if (src_eff_ty.isAbiInt(zcu)) src_eff_ty.intInfo(zcu) else null;
1972 if (dest_bits <= 64 and src_bits <= 64) {
1973 const needs_cast = src_int_info == null or
1974 (toCIntBits(dest_int_info.bits) != toCIntBits(src_int_info.?.bits) or
1975 dest_int_info.signedness != src_int_info.?.signedness);
1976 return !needs_cast and !src_is_ptr;
1977 } else return false;
1978 }
1833 /// Renders a cast to an int type, from either an int or a pointer.1979 /// Renders a cast to an int type, from either an int or a pointer.
1834 ///1980 ///
1835 /// Some platforms don't have 128 bit integers, so we need to use1981 /// Some platforms don't have 128 bit integers, so we need to use
...@@ -1843,7 +1989,14 @@ pub const DeclGen = struct {...@@ -1843,7 +1989,14 @@ pub const DeclGen = struct {
1843 /// | > 64 bit integer | pointer | zig_make_<dest_ty>(0, (zig_<u|i>size)src)1989 /// | > 64 bit integer | pointer | zig_make_<dest_ty>(0, (zig_<u|i>size)src)
1844 /// | > 64 bit integer | < 64 bit integer | zig_make_<dest_ty>(0, src)1990 /// | > 64 bit integer | < 64 bit integer | zig_make_<dest_ty>(0, src)
1845 /// | > 64 bit integer | > 64 bit integer | zig_make_<dest_ty>(zig_hi_<src_ty>(src), zig_lo_<src_ty>(src))1991 /// | > 64 bit integer | > 64 bit integer | zig_make_<dest_ty>(zig_hi_<src_ty>(src), zig_lo_<src_ty>(src))
1846 fn renderIntCast(dg: *DeclGen, w: anytype, dest_ty: Type, context: IntCastContext, src_ty: Type, location: ValueRenderLocation) !void {1992 fn renderIntCast(
1993 dg: *DeclGen,
1994 w: anytype,
1995 dest_ty: Type,
1996 context: IntCastContext,
1997 src_ty: Type,
1998 location: ValueRenderLocation,
1999 ) !void {
1847 const zcu = dg.zcu;2000 const zcu = dg.zcu;
1848 const dest_bits = dest_ty.bitSize(zcu);2001 const dest_bits = dest_ty.bitSize(zcu);
1849 const dest_int_info = dest_ty.intInfo(zcu);2002 const dest_int_info = dest_ty.intInfo(zcu);
...@@ -1998,12 +2151,23 @@ pub const DeclGen = struct {...@@ -1998,12 +2151,23 @@ pub const DeclGen = struct {
1998 fmtIdent("payload"),2151 fmtIdent("payload"),
1999 fmtIdent(ident),2152 fmtIdent(ident),
2000 }),2153 }),
2154 .ctype_pool_string => |string| try w.print("{ }", .{
2155 fmtCTypePoolString(string, &dg.ctype_pool),
2156 }),
2001 }2157 }
2002 }2158 }
20032159
2004 fn writeCValueDeref(dg: *DeclGen, w: anytype, c_value: CValue) !void {2160 fn writeCValueDeref(dg: *DeclGen, w: anytype, c_value: CValue) !void {
2005 switch (c_value) {2161 switch (c_value) {
2006 .none, .new_local, .local, .local_ref, .constant, .arg, .arg_array => unreachable,2162 .none,
2163 .new_local,
2164 .local,
2165 .local_ref,
2166 .constant,
2167 .arg,
2168 .arg_array,
2169 .ctype_pool_string,
2170 => unreachable,
2007 .field => |i| try w.print("f{d}", .{i}),2171 .field => |i| try w.print("f{d}", .{i}),
2008 .decl => |decl| {2172 .decl => |decl| {
2009 try w.writeAll("(*");2173 try w.writeAll("(*");
...@@ -2033,7 +2197,17 @@ pub const DeclGen = struct {...@@ -2033,7 +2197,17 @@ pub const DeclGen = struct {
20332197
2034 fn writeCValueDerefMember(dg: *DeclGen, writer: anytype, c_value: CValue, member: CValue) !void {2198 fn writeCValueDerefMember(dg: *DeclGen, writer: anytype, c_value: CValue, member: CValue) !void {
2035 switch (c_value) {2199 switch (c_value) {
2036 .none, .new_local, .local, .local_ref, .constant, .field, .undef, .arg, .arg_array => unreachable,2200 .none,
2201 .new_local,
2202 .local,
2203 .local_ref,
2204 .constant,
2205 .field,
2206 .undef,
2207 .arg,
2208 .arg_array,
2209 .ctype_pool_string,
2210 => unreachable,
2037 .decl, .identifier, .payload_identifier => {2211 .decl, .identifier, .payload_identifier => {
2038 try dg.writeCValue(writer, c_value);2212 try dg.writeCValue(writer, c_value);
2039 try writer.writeAll("->");2213 try writer.writeAll("->");
...@@ -2172,11 +2346,7 @@ pub const DeclGen = struct {...@@ -2172,11 +2346,7 @@ pub const DeclGen = struct {
2172 loc: ValueRenderLocation,2346 loc: ValueRenderLocation,
2173 ) !std.fmt.Formatter(formatIntLiteral) {2347 ) !std.fmt.Formatter(formatIntLiteral) {
2174 const zcu = dg.zcu;2348 const zcu = dg.zcu;
2175 const kind: CType.Kind = switch (loc) {2349 const kind = loc.toCTypeKind();
2176 .FunctionArgument => .parameter,
2177 .Initializer, .Other => .complete,
2178 .StaticInitializer => .global,
2179 };
2180 const ty = val.typeOf(zcu);2350 const ty = val.typeOf(zcu);
2181 return std.fmt.Formatter(formatIntLiteral){ .data = .{2351 return std.fmt.Formatter(formatIntLiteral){ .data = .{
2182 .dg = dg,2352 .dg = dg,
...@@ -2439,7 +2609,7 @@ fn renderFields(...@@ -2439,7 +2609,7 @@ fn renderFields(
2439 .suffix,2609 .suffix,
2440 .{},2610 .{},
2441 );2611 );
2442 try writer.print("{}{ }", .{ trailing, fmtIdent(field_info.name.slice(ctype_pool)) });2612 try writer.print("{}{ }", .{ trailing, fmtCTypePoolString(field_info.name, ctype_pool) });
2443 try renderTypeSuffix(.flush, ctype_pool, zcu, writer, field_info.ctype, .suffix, .{});2613 try renderTypeSuffix(.flush, ctype_pool, zcu, writer, field_info.ctype, .suffix, .{});
2444 try writer.writeAll(";\n");2614 try writer.writeAll(";\n");
2445 }2615 }
...@@ -2698,9 +2868,7 @@ pub fn genLazyFn(o: *Object, lazy_ctype_pool: *const CType.Pool, lazy_fn: LazyFn...@@ -2698,9 +2868,7 @@ pub fn genLazyFn(o: *Object, lazy_ctype_pool: *const CType.Pool, lazy_fn: LazyFn
26982868
2699 try w.writeAll("static ");2869 try w.writeAll("static ");
2700 try o.dg.renderType(w, name_slice_ty);2870 try o.dg.renderType(w, name_slice_ty);
2701 try w.writeByte(' ');2871 try w.print(" {}(", .{val.fn_name.fmt(lazy_ctype_pool)});
2702 try w.writeAll(val.fn_name.slice(lazy_ctype_pool));
2703 try w.writeByte('(');
2704 try o.dg.renderTypeAndName(w, enum_ty, .{ .identifier = "tag" }, Const, .none, .complete);2872 try o.dg.renderTypeAndName(w, enum_ty, .{ .identifier = "tag" }, Const, .none, .complete);
2705 try w.writeAll(") {\n switch (tag) {\n");2873 try w.writeAll(") {\n switch (tag) {\n");
2706 const tag_names = enum_ty.enumFields(zcu);2874 const tag_names = enum_ty.enumFields(zcu);
...@@ -2744,21 +2912,18 @@ pub fn genLazyFn(o: *Object, lazy_ctype_pool: *const CType.Pool, lazy_fn: LazyFn...@@ -2744,21 +2912,18 @@ pub fn genLazyFn(o: *Object, lazy_ctype_pool: *const CType.Pool, lazy_fn: LazyFn
2744 const fn_decl = zcu.declPtr(fn_decl_index);2912 const fn_decl = zcu.declPtr(fn_decl_index);
2745 const fn_ctype = try o.dg.ctypeFromType(fn_decl.typeOf(zcu), .complete);2913 const fn_ctype = try o.dg.ctypeFromType(fn_decl.typeOf(zcu), .complete);
2746 const fn_info = fn_ctype.info(ctype_pool).function;2914 const fn_info = fn_ctype.info(ctype_pool).function;
2747 const fn_name = val.fn_name.slice(lazy_ctype_pool);2915 const fn_name = fmtCTypePoolString(val.fn_name, lazy_ctype_pool);
27482916
2749 const fwd_decl_writer = o.dg.fwdDeclWriter();2917 const fwd_decl_writer = o.dg.fwdDeclWriter();
2750 try fwd_decl_writer.print("static zig_{s} ", .{@tagName(key)});2918 try fwd_decl_writer.print("static zig_{s} ", .{@tagName(key)});
2751 try o.dg.renderFunctionSignature(2919 try o.dg.renderFunctionSignature(fwd_decl_writer, fn_decl_index, .forward, .{
2752 fwd_decl_writer,2920 .fmt_ctype_pool_string = fn_name,
2753 fn_decl_index,2921 });
2754 .forward,
2755 .{ .ident = fn_name },
2756 );
2757 try fwd_decl_writer.writeAll(";\n");2922 try fwd_decl_writer.writeAll(";\n");
27582923
2759 try w.print("static zig_{s} ", .{@tagName(key)});2924 try w.print("static zig_{s} ", .{@tagName(key)});
2760 try o.dg.renderFunctionSignature(w, fn_decl_index, .complete, .{2925 try o.dg.renderFunctionSignature(w, fn_decl_index, .complete, .{
2761 .ident = fn_name,2926 .fmt_ctype_pool_string = fn_name,
2762 });2927 });
2763 try w.writeAll(" {\n return ");2928 try w.writeAll(" {\n return ");
2764 try o.dg.renderDeclName(w, fn_decl_index, 0);2929 try o.dg.renderDeclName(w, fn_decl_index, 0);
...@@ -3143,8 +3308,8 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,...@@ -3143,8 +3308,8 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
3143 .shl_exact => try airBinOp(f, inst, "<<", "shl", .none),3308 .shl_exact => try airBinOp(f, inst, "<<", "shl", .none),
3144 .not => try airNot (f, inst),3309 .not => try airNot (f, inst),
31453310
3146 .optional_payload => try airOptionalPayload(f, inst),3311 .optional_payload => try airOptionalPayload(f, inst, false),
3147 .optional_payload_ptr => try airOptionalPayloadPtr(f, inst),3312 .optional_payload_ptr => try airOptionalPayload(f, inst, true),
3148 .optional_payload_ptr_set => try airOptionalPayloadPtrSet(f, inst),3313 .optional_payload_ptr_set => try airOptionalPayloadPtrSet(f, inst),
3149 .wrap_optional => try airWrapOptional(f, inst),3314 .wrap_optional => try airWrapOptional(f, inst),
31503315
...@@ -3153,10 +3318,10 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,...@@ -3153,10 +3318,10 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
3153 .is_err_ptr => try airIsErr(f, inst, true, "!="),3318 .is_err_ptr => try airIsErr(f, inst, true, "!="),
3154 .is_non_err_ptr => try airIsErr(f, inst, true, "=="),3319 .is_non_err_ptr => try airIsErr(f, inst, true, "=="),
31553320
3156 .is_null => try airIsNull(f, inst, "==", false),3321 .is_null => try airIsNull(f, inst, .eq, false),
3157 .is_non_null => try airIsNull(f, inst, "!=", false),3322 .is_non_null => try airIsNull(f, inst, .neq, false),
3158 .is_null_ptr => try airIsNull(f, inst, "==", true),3323 .is_null_ptr => try airIsNull(f, inst, .eq, true),
3159 .is_non_null_ptr => try airIsNull(f, inst, "!=", true),3324 .is_non_null_ptr => try airIsNull(f, inst, .neq, true),
31603325
3161 .alloc => try airAlloc(f, inst),3326 .alloc => try airAlloc(f, inst),
3162 .ret_ptr => try airRetPtr(f, inst),3327 .ret_ptr => try airRetPtr(f, inst),
...@@ -3239,8 +3404,8 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,...@@ -3239,8 +3404,8 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
3239 .slice_ptr => try airSliceField(f, inst, false, "ptr"),3404 .slice_ptr => try airSliceField(f, inst, false, "ptr"),
3240 .slice_len => try airSliceField(f, inst, false, "len"),3405 .slice_len => try airSliceField(f, inst, false, "len"),
32413406
3242 .ptr_slice_len_ptr => try airSliceField(f, inst, true, "len"),
3243 .ptr_slice_ptr_ptr => try airSliceField(f, inst, true, "ptr"),3407 .ptr_slice_ptr_ptr => try airSliceField(f, inst, true, "ptr"),
3408 .ptr_slice_len_ptr => try airSliceField(f, inst, true, "len"),
32443409
3245 .ptr_elem_val => try airPtrElemVal(f, inst),3410 .ptr_elem_val => try airPtrElemVal(f, inst),
3246 .ptr_elem_ptr => try airPtrElemPtr(f, inst),3411 .ptr_elem_ptr => try airPtrElemPtr(f, inst),
...@@ -3308,7 +3473,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,...@@ -3308,7 +3473,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
3308 }3473 }
3309 try f.value_map.putNoClobber(inst.toRef(), switch (result_value) {3474 try f.value_map.putNoClobber(inst.toRef(), switch (result_value) {
3310 .none => continue,3475 .none => continue,
3311 .new_local => |i| .{ .local = i },3476 .new_local => |local_index| .{ .local = local_index },
3312 else => result_value,3477 else => result_value,
3313 });3478 });
3314 }3479 }
...@@ -3323,7 +3488,7 @@ fn airSliceField(f: *Function, inst: Air.Inst.Index, is_ptr: bool, field_name: [...@@ -3323,7 +3488,7 @@ fn airSliceField(f: *Function, inst: Air.Inst.Index, is_ptr: bool, field_name: [
33233488
3324 const writer = f.object.writer();3489 const writer = f.object.writer();
3325 const local = try f.allocLocal(inst, inst_ty);3490 const local = try f.allocLocal(inst, inst_ty);
3326 const a = try Assignment.start(f, writer, inst_ty);3491 const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete));
3327 try f.writeCValue(writer, local, .Other);3492 try f.writeCValue(writer, local, .Other);
3328 try a.assign(f, writer);3493 try a.assign(f, writer);
3329 if (is_ptr) {3494 if (is_ptr) {
...@@ -3349,7 +3514,7 @@ fn airPtrElemVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3349,7 +3514,7 @@ fn airPtrElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
33493514
3350 const writer = f.object.writer();3515 const writer = f.object.writer();
3351 const local = try f.allocLocal(inst, inst_ty);3516 const local = try f.allocLocal(inst, inst_ty);
3352 const a = try Assignment.start(f, writer, inst_ty);3517 const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete));
3353 try f.writeCValue(writer, local, .Other);3518 try f.writeCValue(writer, local, .Other);
3354 try a.assign(f, writer);3519 try a.assign(f, writer);
3355 try f.writeCValue(writer, ptr, .Other);3520 try f.writeCValue(writer, ptr, .Other);
...@@ -3375,7 +3540,7 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3375,7 +3540,7 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
33753540
3376 const writer = f.object.writer();3541 const writer = f.object.writer();
3377 const local = try f.allocLocal(inst, inst_ty);3542 const local = try f.allocLocal(inst, inst_ty);
3378 const a = try Assignment.start(f, writer, inst_ty);3543 const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete));
3379 try f.writeCValue(writer, local, .Other);3544 try f.writeCValue(writer, local, .Other);
3380 try a.assign(f, writer);3545 try a.assign(f, writer);
3381 try writer.writeByte('(');3546 try writer.writeByte('(');
...@@ -3410,7 +3575,7 @@ fn airSliceElemVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3410,7 +3575,7 @@ fn airSliceElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
34103575
3411 const writer = f.object.writer();3576 const writer = f.object.writer();
3412 const local = try f.allocLocal(inst, inst_ty);3577 const local = try f.allocLocal(inst, inst_ty);
3413 const a = try Assignment.start(f, writer, inst_ty);3578 const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete));
3414 try f.writeCValue(writer, local, .Other);3579 try f.writeCValue(writer, local, .Other);
3415 try a.assign(f, writer);3580 try a.assign(f, writer);
3416 try f.writeCValueMember(writer, slice, .{ .identifier = "ptr" });3581 try f.writeCValueMember(writer, slice, .{ .identifier = "ptr" });
...@@ -3437,7 +3602,7 @@ fn airSliceElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3437,7 +3602,7 @@ fn airSliceElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
34373602
3438 const writer = f.object.writer();3603 const writer = f.object.writer();
3439 const local = try f.allocLocal(inst, inst_ty);3604 const local = try f.allocLocal(inst, inst_ty);
3440 const a = try Assignment.start(f, writer, inst_ty);3605 const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete));
3441 try f.writeCValue(writer, local, .Other);3606 try f.writeCValue(writer, local, .Other);
3442 try a.assign(f, writer);3607 try a.assign(f, writer);
3443 if (elem_has_bits) try writer.writeByte('&');3608 if (elem_has_bits) try writer.writeByte('&');
...@@ -3466,7 +3631,7 @@ fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3466,7 +3631,7 @@ fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
34663631
3467 const writer = f.object.writer();3632 const writer = f.object.writer();
3468 const local = try f.allocLocal(inst, inst_ty);3633 const local = try f.allocLocal(inst, inst_ty);
3469 const a = try Assignment.start(f, writer, inst_ty);3634 const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete));
3470 try f.writeCValue(writer, local, .Other);3635 try f.writeCValue(writer, local, .Other);
3471 try a.assign(f, writer);3636 try a.assign(f, writer);
3472 try f.writeCValue(writer, array, .Other);3637 try f.writeCValue(writer, array, .Other);
...@@ -3691,17 +3856,18 @@ fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3691,17 +3856,18 @@ fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue {
3691 const operand_ty = f.typeOf(ty_op.operand);3856 const operand_ty = f.typeOf(ty_op.operand);
3692 const scalar_ty = operand_ty.scalarType(zcu);3857 const scalar_ty = operand_ty.scalarType(zcu);
36933858
3859 if (f.object.dg.intCastIsNoop(inst_scalar_ty, scalar_ty)) return f.moveCValue(inst, inst_ty, operand);
3860
3694 const writer = f.object.writer();3861 const writer = f.object.writer();
3695 const local = try f.allocLocal(inst, inst_ty);3862 const local = try f.allocLocal(inst, inst_ty);
3696 const v = try Vectorize.start(f, inst, writer, operand_ty);3863 const v = try Vectorize.start(f, inst, writer, operand_ty);
3697 const a = try Assignment.start(f, writer, scalar_ty);3864 const a = try Assignment.start(f, writer, try f.ctypeFromType(scalar_ty, .complete));
3698 try f.writeCValue(writer, local, .Other);3865 try f.writeCValue(writer, local, .Other);
3699 try v.elem(f, writer);3866 try v.elem(f, writer);
3700 try a.assign(f, writer);3867 try a.assign(f, writer);
3701 try f.renderIntCast(writer, inst_scalar_ty, operand, v, scalar_ty, .Other);3868 try f.renderIntCast(writer, inst_scalar_ty, operand, v, scalar_ty, .Other);
3702 try a.end(f, writer);3869 try a.end(f, writer);
3703 try v.end(f, inst, writer);3870 try v.end(f, inst, writer);
3704
3705 return local;3871 return local;
3706}3872}
37073873
...@@ -3711,38 +3877,40 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3711,38 +3877,40 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {
37113877
3712 const operand = try f.resolveInst(ty_op.operand);3878 const operand = try f.resolveInst(ty_op.operand);
3713 try reap(f, inst, &.{ty_op.operand});3879 try reap(f, inst, &.{ty_op.operand});
3880
3714 const inst_ty = f.typeOfIndex(inst);3881 const inst_ty = f.typeOfIndex(inst);
3715 const inst_scalar_ty = inst_ty.scalarType(zcu);3882 const inst_scalar_ty = inst_ty.scalarType(zcu);
3716 const dest_int_info = inst_scalar_ty.intInfo(zcu);3883 const dest_int_info = inst_scalar_ty.intInfo(zcu);
3717 const dest_bits = dest_int_info.bits;3884 const dest_bits = dest_int_info.bits;
3718 const dest_c_bits = toCIntBits(dest_int_info.bits) orelse3885 const dest_c_bits = toCIntBits(dest_bits) orelse
3719 return f.fail("TODO: C backend: implement integer types larger than 128 bits", .{});3886 return f.fail("TODO: C backend: implement integer types larger than 128 bits", .{});
3720 const operand_ty = f.typeOf(ty_op.operand);3887 const operand_ty = f.typeOf(ty_op.operand);
3721 const scalar_ty = operand_ty.scalarType(zcu);3888 const scalar_ty = operand_ty.scalarType(zcu);
3722 const scalar_int_info = scalar_ty.intInfo(zcu);3889 const scalar_int_info = scalar_ty.intInfo(zcu);
37233890
3891 const need_cast = dest_c_bits < 64;
3892 const need_lo = scalar_int_info.bits > 64 and dest_bits <= 64;
3893 const need_mask = dest_bits < 8 or !std.math.isPowerOfTwo(dest_bits);
3894 if (!need_cast and !need_lo and !need_mask) return f.moveCValue(inst, inst_ty, operand);
3895
3724 const writer = f.object.writer();3896 const writer = f.object.writer();
3725 const local = try f.allocLocal(inst, inst_ty);3897 const local = try f.allocLocal(inst, inst_ty);
3726 const v = try Vectorize.start(f, inst, writer, operand_ty);3898 const v = try Vectorize.start(f, inst, writer, operand_ty);
37273899 const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_scalar_ty, .complete));
3728 try f.writeCValue(writer, local, .Other);3900 try f.writeCValue(writer, local, .Other);
3729 try v.elem(f, writer);3901 try v.elem(f, writer);
3730 try writer.writeAll(" = ");3902 try a.assign(f, writer);
37313903 if (need_cast) {
3732 if (dest_c_bits < 64) {
3733 try writer.writeByte('(');3904 try writer.writeByte('(');
3734 try f.renderType(writer, inst_scalar_ty);3905 try f.renderType(writer, inst_scalar_ty);
3735 try writer.writeByte(')');3906 try writer.writeByte(')');
3736 }3907 }
37373908 if (need_lo) {
3738 const needs_lo = scalar_int_info.bits > 64 and dest_bits <= 64;
3739 if (needs_lo) {
3740 try writer.writeAll("zig_lo_");3909 try writer.writeAll("zig_lo_");
3741 try f.object.dg.renderTypeForBuiltinFnName(writer, scalar_ty);3910 try f.object.dg.renderTypeForBuiltinFnName(writer, scalar_ty);
3742 try writer.writeByte('(');3911 try writer.writeByte('(');
3743 }3912 }
37443913 if (!need_mask) {
3745 if (dest_bits >= 8 and std.math.isPowerOfTwo(dest_bits)) {
3746 try f.writeCValue(writer, operand, .Other);3914 try f.writeCValue(writer, operand, .Other);
3747 try v.elem(f, writer);3915 try v.elem(f, writer);
3748 } else switch (dest_int_info.signedness) {3916 } else switch (dest_int_info.signedness) {
...@@ -3782,11 +3950,9 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3782,11 +3950,9 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {
3782 try writer.print(", {})", .{try f.fmtIntLiteral(shift_val)});3950 try writer.print(", {})", .{try f.fmtIntLiteral(shift_val)});
3783 },3951 },
3784 }3952 }
37853953 if (need_lo) try writer.writeByte(')');
3786 if (needs_lo) try writer.writeByte(')');3954 try a.end(f, writer);
3787 try writer.writeAll(";\n");
3788 try v.end(f, inst, writer);3955 try v.end(f, inst, writer);
3789
3790 return local;3956 return local;
3791}3957}
37923958
...@@ -3797,7 +3963,7 @@ fn airIntFromBool(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3797,7 +3963,7 @@ fn airIntFromBool(f: *Function, inst: Air.Inst.Index) !CValue {
3797 const writer = f.object.writer();3963 const writer = f.object.writer();
3798 const inst_ty = f.typeOfIndex(inst);3964 const inst_ty = f.typeOfIndex(inst);
3799 const local = try f.allocLocal(inst, inst_ty);3965 const local = try f.allocLocal(inst, inst_ty);
3800 const a = try Assignment.start(f, writer, inst_ty);3966 const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete));
3801 try f.writeCValue(writer, local, .Other);3967 try f.writeCValue(writer, local, .Other);
3802 try a.assign(f, writer);3968 try a.assign(f, writer);
3803 try f.writeCValue(writer, operand, .Other);3969 try f.writeCValue(writer, operand, .Other);
...@@ -3842,9 +4008,8 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {...@@ -3842,9 +4008,8 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
3842 const src_val = try f.resolveInst(bin_op.rhs);4008 const src_val = try f.resolveInst(bin_op.rhs);
3843 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });4009 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
38444010
4011 const src_scalar_ctype = try f.ctypeFromType(src_ty.scalarType(zcu), .complete);
3845 const writer = f.object.writer();4012 const writer = f.object.writer();
3846 const v = try Vectorize.start(f, inst, writer, ptr_ty);
3847
3848 if (need_memcpy) {4013 if (need_memcpy) {
3849 // For this memcpy to safely work we need the rhs to have the same4014 // For this memcpy to safely work we need the rhs to have the same
3850 // underlying type as the lhs (i.e. they must both be arrays of the same underlying type).4015 // underlying type as the lhs (i.e. they must both be arrays of the same underlying type).
...@@ -3863,6 +4028,7 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {...@@ -3863,6 +4028,7 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
3863 break :blk new_local;4028 break :blk new_local;
3864 } else src_val;4029 } else src_val;
38654030
4031 const v = try Vectorize.start(f, inst, writer, ptr_ty);
3866 try writer.writeAll("memcpy((char *)");4032 try writer.writeAll("memcpy((char *)");
3867 try f.writeCValue(writer, ptr_val, .FunctionArgument);4033 try f.writeCValue(writer, ptr_val, .FunctionArgument);
3868 try v.elem(f, writer);4034 try v.elem(f, writer);
...@@ -3873,9 +4039,9 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {...@@ -3873,9 +4039,9 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
3873 try writer.writeAll(", sizeof(");4039 try writer.writeAll(", sizeof(");
3874 try f.renderType(writer, src_ty);4040 try f.renderType(writer, src_ty);
3875 try writer.writeAll("))");4041 try writer.writeAll("))");
3876 if (src_val == .constant) {4042 try f.freeCValue(inst, array_src);
3877 try freeLocal(f, inst, array_src.new_local, null);4043 try writer.writeAll(";\n");
3878 }4044 try v.end(f, inst, writer);
3879 } else if (ptr_info.packed_offset.host_size > 0 and ptr_info.flags.vector_index == .none) {4045 } else if (ptr_info.packed_offset.host_size > 0 and ptr_info.flags.vector_index == .none) {
3880 const host_bits = ptr_info.packed_offset.host_size * 8;4046 const host_bits = ptr_info.packed_offset.host_size * 8;
3881 const host_ty = try zcu.intType(.unsigned, host_bits);4047 const host_ty = try zcu.intType(.unsigned, host_bits);
...@@ -3898,9 +4064,12 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {...@@ -3898,9 +4064,12 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
38984064
3899 const mask_val = try zcu.intValue_big(host_ty, mask.toConst());4065 const mask_val = try zcu.intValue_big(host_ty, mask.toConst());
39004066
4067 const v = try Vectorize.start(f, inst, writer, ptr_ty);
4068 const a = try Assignment.start(f, writer, src_scalar_ctype);
3901 try f.writeCValueDeref(writer, ptr_val);4069 try f.writeCValueDeref(writer, ptr_val);
3902 try v.elem(f, writer);4070 try v.elem(f, writer);
3903 try writer.writeAll(" = zig_or_");4071 try a.assign(f, writer);
4072 try writer.writeAll("zig_or_");
3904 try f.object.dg.renderTypeForBuiltinFnName(writer, host_ty);4073 try f.object.dg.renderTypeForBuiltinFnName(writer, host_ty);
3905 try writer.writeAll("(zig_and_");4074 try writer.writeAll("(zig_and_");
3906 try f.object.dg.renderTypeForBuiltinFnName(writer, host_ty);4075 try f.object.dg.renderTypeForBuiltinFnName(writer, host_ty);
...@@ -3931,16 +4100,27 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {...@@ -3931,16 +4100,27 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
3931 try v.elem(f, writer);4100 try v.elem(f, writer);
3932 if (cant_cast) try writer.writeByte(')');4101 if (cant_cast) try writer.writeByte(')');
3933 try writer.print(", {}))", .{try f.fmtIntLiteral(bit_offset_val)});4102 try writer.print(", {}))", .{try f.fmtIntLiteral(bit_offset_val)});
4103 try a.end(f, writer);
4104 try v.end(f, inst, writer);
3934 } else {4105 } else {
4106 switch (ptr_val) {
4107 .local_ref => |ptr_local_index| switch (src_val) {
4108 .new_local, .local => |src_local_index| if (ptr_local_index == src_local_index)
4109 return .none,
4110 else => {},
4111 },
4112 else => {},
4113 }
4114 const v = try Vectorize.start(f, inst, writer, ptr_ty);
4115 const a = try Assignment.start(f, writer, src_scalar_ctype);
3935 try f.writeCValueDeref(writer, ptr_val);4116 try f.writeCValueDeref(writer, ptr_val);
3936 try v.elem(f, writer);4117 try v.elem(f, writer);
3937 try writer.writeAll(" = ");4118 try a.assign(f, writer);
3938 try f.writeCValue(writer, src_val, .Other);4119 try f.writeCValue(writer, src_val, .Other);
3939 try v.elem(f, writer);4120 try v.elem(f, writer);
4121 try a.end(f, writer);
4122 try v.end(f, inst, writer);
3940 }4123 }
3941 try writer.writeAll(";\n");
3942 try v.end(f, inst, writer);
3943
3944 return .none;4124 return .none;
3945}4125}
39464126
...@@ -4103,6 +4283,7 @@ fn airEquality(...@@ -4103,6 +4283,7 @@ fn airEquality(
4103 operator: std.math.CompareOperator,4283 operator: std.math.CompareOperator,
4104) !CValue {4284) !CValue {
4105 const zcu = f.object.dg.zcu;4285 const zcu = f.object.dg.zcu;
4286 const ctype_pool = &f.object.dg.ctype_pool;
4106 const bin_op = f.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;4287 const bin_op = f.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
41074288
4108 const operand_ty = f.typeOf(bin_op.lhs);4289 const operand_ty = f.typeOf(bin_op.lhs);
...@@ -4124,28 +4305,47 @@ fn airEquality(...@@ -4124,28 +4305,47 @@ fn airEquality(
4124 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });4305 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
41254306
4126 const writer = f.object.writer();4307 const writer = f.object.writer();
4127 const inst_ty = f.typeOfIndex(inst);4308 const local = try f.allocLocal(inst, Type.bool);
4128 const local = try f.allocLocal(inst, inst_ty);4309 const a = try Assignment.start(f, writer, CType.bool);
4129 const a = try Assignment.start(f, writer, inst_ty);
4130 try f.writeCValue(writer, local, .Other);4310 try f.writeCValue(writer, local, .Other);
4131 try a.assign(f, writer);4311 try a.assign(f, writer);
41324312
4133 if (operand_ty.zigTypeTag(zcu) == .Optional and !operand_ty.optionalReprIsPayload(zcu)) {4313 const operand_ctype = try f.ctypeFromType(operand_ty, .complete);
4134 try f.writeCValueMember(writer, lhs, .{ .identifier = "is_null" });4314 switch (operand_ctype.info(ctype_pool)) {
4135 try writer.writeAll(" || ");4315 .basic, .pointer => {
4136 try f.writeCValueMember(writer, rhs, .{ .identifier = "is_null" });4316 try f.writeCValue(writer, lhs, .Other);
4137 try writer.writeAll(" ? ");4317 try writer.writeAll(compareOperatorC(operator));
4138 try f.writeCValueMember(writer, lhs, .{ .identifier = "is_null" });4318 try f.writeCValue(writer, rhs, .Other);
4139 try writer.writeAll(compareOperatorC(operator));4319 },
4140 try f.writeCValueMember(writer, rhs, .{ .identifier = "is_null" });4320 .aligned, .array, .vector, .fwd_decl, .function => unreachable,
4141 try writer.writeAll(" : ");4321 .aggregate => |aggregate| if (aggregate.fields.len == 2 and
4142 try f.writeCValueMember(writer, lhs, .{ .identifier = "payload" });4322 (aggregate.fields.at(0, ctype_pool).name.index == .is_null or
4143 try writer.writeAll(compareOperatorC(operator));4323 aggregate.fields.at(1, ctype_pool).name.index == .is_null))
4144 try f.writeCValueMember(writer, rhs, .{ .identifier = "payload" });4324 {
4145 } else {4325 try f.writeCValueMember(writer, lhs, .{ .identifier = "is_null" });
4146 try f.writeCValue(writer, lhs, .Other);4326 try writer.writeAll(" || ");
4147 try writer.writeAll(compareOperatorC(operator));4327 try f.writeCValueMember(writer, rhs, .{ .identifier = "is_null" });
4148 try f.writeCValue(writer, rhs, .Other);4328 try writer.writeAll(" ? ");
4329 try f.writeCValueMember(writer, lhs, .{ .identifier = "is_null" });
4330 try writer.writeAll(compareOperatorC(operator));
4331 try f.writeCValueMember(writer, rhs, .{ .identifier = "is_null" });
4332 try writer.writeAll(" : ");
4333 try f.writeCValueMember(writer, lhs, .{ .identifier = "payload" });
4334 try writer.writeAll(compareOperatorC(operator));
4335 try f.writeCValueMember(writer, rhs, .{ .identifier = "payload" });
4336 } else for (0..aggregate.fields.len) |field_index| {
4337 if (field_index > 0) try writer.writeAll(switch (operator) {
4338 .lt, .lte, .gte, .gt => unreachable,
4339 .eq => " && ",
4340 .neq => " || ",
4341 });
4342 const field_name: CValue = .{
4343 .ctype_pool_string = aggregate.fields.at(field_index, ctype_pool).name,
4344 };
4345 try f.writeCValueMember(writer, lhs, field_name);
4346 try writer.writeAll(compareOperatorC(operator));
4347 try f.writeCValueMember(writer, rhs, field_name);
4348 },
4149 }4349 }
4150 try a.end(f, writer);4350 try a.end(f, writer);
41514351
...@@ -4155,12 +4355,11 @@ fn airEquality(...@@ -4155,12 +4355,11 @@ fn airEquality(
4155fn airCmpLtErrorsLen(f: *Function, inst: Air.Inst.Index) !CValue {4355fn airCmpLtErrorsLen(f: *Function, inst: Air.Inst.Index) !CValue {
4156 const un_op = f.air.instructions.items(.data)[@intFromEnum(inst)].un_op;4356 const un_op = f.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
41574357
4158 const inst_ty = f.typeOfIndex(inst);
4159 const operand = try f.resolveInst(un_op);4358 const operand = try f.resolveInst(un_op);
4160 try reap(f, inst, &.{un_op});4359 try reap(f, inst, &.{un_op});
41614360
4162 const writer = f.object.writer();4361 const writer = f.object.writer();
4163 const local = try f.allocLocal(inst, inst_ty);4362 const local = try f.allocLocal(inst, Type.bool);
4164 try f.writeCValue(writer, local, .Other);4363 try f.writeCValue(writer, local, .Other);
4165 try writer.writeAll(" = ");4364 try writer.writeAll(" = ");
4166 try f.writeCValue(writer, operand, .Other);4365 try f.writeCValue(writer, operand, .Other);
...@@ -4180,39 +4379,34 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue {...@@ -4180,39 +4379,34 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue {
4180 const inst_ty = f.typeOfIndex(inst);4379 const inst_ty = f.typeOfIndex(inst);
4181 const inst_scalar_ty = inst_ty.scalarType(zcu);4380 const inst_scalar_ty = inst_ty.scalarType(zcu);
4182 const elem_ty = inst_scalar_ty.elemType2(zcu);4381 const elem_ty = inst_scalar_ty.elemType2(zcu);
4382 if (!elem_ty.hasRuntimeBitsIgnoreComptime(zcu)) return f.moveCValue(inst, inst_ty, lhs);
4383 const inst_scalar_ctype = try f.ctypeFromType(inst_scalar_ty, .complete);
41834384
4184 const local = try f.allocLocal(inst, inst_ty);4385 const local = try f.allocLocal(inst, inst_ty);
4185 const writer = f.object.writer();4386 const writer = f.object.writer();
4186 const v = try Vectorize.start(f, inst, writer, inst_ty);4387 const v = try Vectorize.start(f, inst, writer, inst_ty);
4388 const a = try Assignment.start(f, writer, inst_scalar_ctype);
4187 try f.writeCValue(writer, local, .Other);4389 try f.writeCValue(writer, local, .Other);
4188 try v.elem(f, writer);4390 try v.elem(f, writer);
4189 try writer.writeAll(" = ");4391 try a.assign(f, writer);
41904392 // We must convert to and from integer types to prevent UB if the operation
4191 if (elem_ty.hasRuntimeBitsIgnoreComptime(zcu)) {4393 // results in a NULL pointer, or if LHS is NULL. The operation is only UB
4192 // We must convert to and from integer types to prevent UB if the operation4394 // if the result is NULL and then dereferenced.
4193 // results in a NULL pointer, or if LHS is NULL. The operation is only UB4395 try writer.writeByte('(');
4194 // if the result is NULL and then dereferenced.4396 try f.renderCType(writer, inst_scalar_ctype);
4195 try writer.writeByte('(');4397 try writer.writeAll(")(((uintptr_t)");
4196 try f.renderType(writer, inst_scalar_ty);4398 try f.writeCValue(writer, lhs, .Other);
4197 try writer.writeAll(")(((uintptr_t)");4399 try v.elem(f, writer);
4198 try f.writeCValue(writer, lhs, .Other);4400 try writer.writeAll(") ");
4199 try v.elem(f, writer);4401 try writer.writeByte(operator);
4200 try writer.writeAll(") ");4402 try writer.writeAll(" (");
4201 try writer.writeByte(operator);4403 try f.writeCValue(writer, rhs, .Other);
4202 try writer.writeAll(" (");4404 try v.elem(f, writer);
4203 try f.writeCValue(writer, rhs, .Other);4405 try writer.writeAll("*sizeof(");
4204 try v.elem(f, writer);4406 try f.renderType(writer, elem_ty);
4205 try writer.writeAll("*sizeof(");4407 try writer.writeAll(")))");
4206 try f.renderType(writer, elem_ty);4408 try a.end(f, writer);
4207 try writer.writeAll(")))");
4208 } else {
4209 try f.writeCValue(writer, lhs, .Other);
4210 try v.elem(f, writer);
4211 }
4212
4213 try writer.writeAll(";\n");
4214 try v.end(f, inst, writer);4409 try v.end(f, inst, writer);
4215
4216 return local;4410 return local;
4217}4411}
42184412
...@@ -4273,14 +4467,14 @@ fn airSlice(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4273,14 +4467,14 @@ fn airSlice(f: *Function, inst: Air.Inst.Index) !CValue {
4273 const writer = f.object.writer();4467 const writer = f.object.writer();
4274 const local = try f.allocLocal(inst, inst_ty);4468 const local = try f.allocLocal(inst, inst_ty);
4275 {4469 {
4276 const a = try Assignment.start(f, writer, ptr_ty);4470 const a = try Assignment.start(f, writer, try f.ctypeFromType(ptr_ty, .complete));
4277 try f.writeCValueMember(writer, local, .{ .identifier = "ptr" });4471 try f.writeCValueMember(writer, local, .{ .identifier = "ptr" });
4278 try a.assign(f, writer);4472 try a.assign(f, writer);
4279 try f.writeCValue(writer, ptr, .Other);4473 try f.writeCValue(writer, ptr, .Other);
4280 try a.end(f, writer);4474 try a.end(f, writer);
4281 }4475 }
4282 {4476 {
4283 const a = try Assignment.start(f, writer, Type.usize);4477 const a = try Assignment.start(f, writer, CType.usize);
4284 try f.writeCValueMember(writer, local, .{ .identifier = "len" });4478 try f.writeCValueMember(writer, local, .{ .identifier = "len" });
4285 try a.assign(f, writer);4479 try a.assign(f, writer);
4286 try f.writeCValue(writer, len, .Initializer);4480 try f.writeCValue(writer, len, .Initializer);
...@@ -4347,7 +4541,7 @@ fn airCall(...@@ -4347,7 +4541,7 @@ fn airCall(
4347 }).?;4541 }).?;
4348 const ret_ty = Type.fromInterned(fn_info.return_type);4542 const ret_ty = Type.fromInterned(fn_info.return_type);
4349 const ret_ctype: CType = if (ret_ty.isNoReturn(zcu))4543 const ret_ctype: CType = if (ret_ty.isNoReturn(zcu))
4350 .{ .index = .void }4544 CType.void
4351 else4545 else
4352 try f.ctypeFromType(ret_ty, .parameter);4546 try f.ctypeFromType(ret_ty, .parameter);
43534547
...@@ -4359,7 +4553,7 @@ fn airCall(...@@ -4359,7 +4553,7 @@ fn airCall(
4359 break :result .none;4553 break :result .none;
4360 } else if (f.liveness.isUnused(inst)) {4554 } else if (f.liveness.isUnused(inst)) {
4361 try writer.writeByte('(');4555 try writer.writeByte('(');
4362 try f.renderCType(writer, .{ .index = .void });4556 try f.renderCType(writer, CType.void);
4363 try writer.writeByte(')');4557 try writer.writeByte(')');
4364 break :result .none;4558 break :result .none;
4365 } else {4559 } else {
...@@ -4414,10 +4608,7 @@ fn airCall(...@@ -4414,10 +4608,7 @@ fn airCall(
4414 if (need_comma) try writer.writeAll(", ");4608 if (need_comma) try writer.writeAll(", ");
4415 need_comma = true;4609 need_comma = true;
4416 try f.writeCValue(writer, resolved_arg, .FunctionArgument);4610 try f.writeCValue(writer, resolved_arg, .FunctionArgument);
4417 switch (resolved_arg) {4611 try f.freeCValue(inst, resolved_arg);
4418 .new_local => |local| try freeLocal(f, inst, local, null),
4419 else => {},
4420 }
4421 }4612 }
4422 try writer.writeAll(");\n");4613 try writer.writeAll(");\n");
44234614
...@@ -4601,7 +4792,7 @@ fn lowerTry(...@@ -4601,7 +4792,7 @@ fn lowerTry(
4601 }4792 }
46024793
4603 const local = try f.allocLocal(inst, inst_ty);4794 const local = try f.allocLocal(inst, inst_ty);
4604 const a = try Assignment.start(f, writer, inst_ty);4795 const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete));
4605 try f.writeCValue(writer, local, .Other);4796 try f.writeCValue(writer, local, .Other);
4606 try a.assign(f, writer);4797 try a.assign(f, writer);
4607 if (is_ptr) {4798 if (is_ptr) {
...@@ -4624,7 +4815,7 @@ fn airBr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4624,7 +4815,7 @@ fn airBr(f: *Function, inst: Air.Inst.Index) !CValue {
4624 const operand = try f.resolveInst(branch.operand);4815 const operand = try f.resolveInst(branch.operand);
4625 try reap(f, inst, &.{branch.operand});4816 try reap(f, inst, &.{branch.operand});
46264817
4627 const a = try Assignment.start(f, writer, operand_ty);4818 const a = try Assignment.start(f, writer, try f.ctypeFromType(operand_ty, .complete));
4628 try f.writeCValue(writer, result, .Other);4819 try f.writeCValue(writer, result, .Other);
4629 try a.assign(f, writer);4820 try a.assign(f, writer);
4630 try f.writeCValue(writer, operand, .Other);4821 try f.writeCValue(writer, operand, .Other);
...@@ -4637,53 +4828,17 @@ fn airBr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4637,53 +4828,17 @@ fn airBr(f: *Function, inst: Air.Inst.Index) !CValue {
46374828
4638fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {4829fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {
4639 const ty_op = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;4830 const ty_op = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
4640 const dest_ty = f.typeOfIndex(inst);4831 const inst_ty = f.typeOfIndex(inst);
46414832
4642 const operand = try f.resolveInst(ty_op.operand);4833 const operand = try f.resolveInst(ty_op.operand);
4643 const operand_ty = f.typeOf(ty_op.operand);4834 const operand_ty = f.typeOf(ty_op.operand);
46444835
4645 const bitcasted = try bitcast(f, dest_ty, operand, operand_ty);4836 const bitcasted = try bitcast(f, inst_ty, operand, operand_ty);
4646 try reap(f, inst, &.{ty_op.operand});4837 try reap(f, inst, &.{ty_op.operand});
4647 return bitcasted.move(f, inst, dest_ty);4838 return f.moveCValue(inst, inst_ty, bitcasted);
4648}4839}
46494840
4650const LocalResult = struct {4841fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !CValue {
4651 c_value: CValue,
4652 need_free: bool,
4653
4654 fn move(lr: LocalResult, f: *Function, inst: Air.Inst.Index, dest_ty: Type) !CValue {
4655 const zcu = f.object.dg.zcu;
4656
4657 if (lr.need_free) {
4658 // Move the freshly allocated local to be owned by this instruction,
4659 // by returning it here instead of freeing it.
4660 return lr.c_value;
4661 }
4662
4663 const local = try f.allocLocal(inst, dest_ty);
4664 try lr.free(f);
4665 const writer = f.object.writer();
4666 try f.writeCValue(writer, local, .Other);
4667 if (dest_ty.isAbiInt(zcu)) {
4668 try writer.writeAll(" = ");
4669 } else {
4670 try writer.writeAll(" = (");
4671 try f.renderType(writer, dest_ty);
4672 try writer.writeByte(')');
4673 }
4674 try f.writeCValue(writer, lr.c_value, .Initializer);
4675 try writer.writeAll(";\n");
4676 return local;
4677 }
4678
4679 fn free(lr: LocalResult, f: *Function) !void {
4680 if (lr.need_free) {
4681 try freeLocal(f, null, lr.c_value.new_local, null);
4682 }
4683 }
4684};
4685
4686fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !LocalResult {
4687 const zcu = f.object.dg.zcu;4842 const zcu = f.object.dg.zcu;
4688 const target = &f.object.dg.mod.resolved_target.result;4843 const target = &f.object.dg.mod.resolved_target.result;
4689 const ctype_pool = &f.object.dg.ctype_pool;4844 const ctype_pool = &f.object.dg.ctype_pool;
...@@ -4693,13 +4848,7 @@ fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !Loca...@@ -4693,13 +4848,7 @@ fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !Loca
4693 const src_info = dest_ty.intInfo(zcu);4848 const src_info = dest_ty.intInfo(zcu);
4694 const dest_info = operand_ty.intInfo(zcu);4849 const dest_info = operand_ty.intInfo(zcu);
4695 if (src_info.signedness == dest_info.signedness and4850 if (src_info.signedness == dest_info.signedness and
4696 src_info.bits == dest_info.bits)4851 src_info.bits == dest_info.bits) return operand;
4697 {
4698 return .{
4699 .c_value = operand,
4700 .need_free = false,
4701 };
4702 }
4703 }4852 }
47044853
4705 if (dest_ty.isPtrAtRuntime(zcu) and operand_ty.isPtrAtRuntime(zcu)) {4854 if (dest_ty.isPtrAtRuntime(zcu) and operand_ty.isPtrAtRuntime(zcu)) {
...@@ -4710,10 +4859,7 @@ fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !Loca...@@ -4710,10 +4859,7 @@ fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !Loca
4710 try writer.writeByte(')');4859 try writer.writeByte(')');
4711 try f.writeCValue(writer, operand, .Other);4860 try f.writeCValue(writer, operand, .Other);
4712 try writer.writeAll(";\n");4861 try writer.writeAll(";\n");
4713 return .{4862 return local;
4714 .c_value = local,
4715 .need_free = true,
4716 };
4717 }4863 }
47184864
4719 const operand_lval = if (operand == .constant) blk: {4865 const operand_lval = if (operand == .constant) blk: {
...@@ -4800,14 +4946,8 @@ fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !Loca...@@ -4800,14 +4946,8 @@ fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !Loca
4800 try writer.writeAll(");\n");4946 try writer.writeAll(");\n");
4801 }4947 }
48024948
4803 if (operand == .constant) {4949 try f.freeCValue(null, operand_lval);
4804 try freeLocal(f, null, operand_lval.new_local, null);4950 return local;
4805 }
4806
4807 return .{
4808 .c_value = local,
4809 .need_free = true,
4810 };
4811}4951}
48124952
4813fn airTrap(f: *Function, writer: anytype) !CValue {4953fn airTrap(f: *Function, writer: anytype) !CValue {
...@@ -4918,13 +5058,16 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4918,13 +5058,16 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {
4918 const writer = f.object.writer();5058 const writer = f.object.writer();
49195059
4920 try writer.writeAll("switch (");5060 try writer.writeAll("switch (");
4921 if (condition_ty.zigTypeTag(zcu) == .Bool) {5061
4922 try writer.writeByte('(');5062 const lowered_condition_ty = if (condition_ty.toIntern() == .bool_type)
4923 try f.renderType(writer, Type.u1);5063 Type.u1
4924 try writer.writeByte(')');5064 else if (condition_ty.isPtrAtRuntime(zcu))
4925 } else if (condition_ty.isPtrAtRuntime(zcu)) {5065 Type.usize
5066 else
5067 condition_ty;
5068 if (condition_ty.toIntern() != lowered_condition_ty.toIntern()) {
4926 try writer.writeByte('(');5069 try writer.writeByte('(');
4927 try f.renderType(writer, Type.usize);5070 try f.renderType(writer, lowered_condition_ty);
4928 try writer.writeByte(')');5071 try writer.writeByte(')');
4929 }5072 }
4930 try f.writeCValue(writer, condition, .Other);5073 try f.writeCValue(writer, condition, .Other);
...@@ -4943,18 +5086,24 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4943,18 +5086,24 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {
4943 for (0..switch_br.data.cases_len) |case_i| {5086 for (0..switch_br.data.cases_len) |case_i| {
4944 const case = f.air.extraData(Air.SwitchBr.Case, extra_index);5087 const case = f.air.extraData(Air.SwitchBr.Case, extra_index);
4945 const items = @as([]const Air.Inst.Ref, @ptrCast(f.air.extra[case.end..][0..case.data.items_len]));5088 const items = @as([]const Air.Inst.Ref, @ptrCast(f.air.extra[case.end..][0..case.data.items_len]));
4946 const case_body: []const Air.Inst.Index = @ptrCast(f.air.extra[case.end + items.len ..][0..case.data.body_len]);5089 const case_body: []const Air.Inst.Index =
5090 @ptrCast(f.air.extra[case.end + items.len ..][0..case.data.body_len]);
4947 extra_index = case.end + case.data.items_len + case_body.len;5091 extra_index = case.end + case.data.items_len + case_body.len;
49485092
4949 for (items) |item| {5093 for (items) |item| {
4950 try f.object.indent_writer.insertNewline();5094 try f.object.indent_writer.insertNewline();
4951 try writer.writeAll("case ");5095 try writer.writeAll("case ");
4952 if (condition_ty.isPtrAtRuntime(zcu)) {5096 const item_value = try f.air.value(item, zcu);
4953 try writer.writeByte('(');5097 if (item_value.?.getUnsignedInt(zcu)) |item_int| try writer.print("{}\n", .{
4954 try f.renderType(writer, Type.usize);5098 try f.fmtIntLiteral(try zcu.intValue(lowered_condition_ty, item_int)),
4955 try writer.writeByte(')');5099 }) else {
5100 if (condition_ty.isPtrAtRuntime(zcu)) {
5101 try writer.writeByte('(');
5102 try f.renderType(writer, Type.usize);
5103 try writer.writeByte(')');
5104 }
5105 try f.object.dg.renderValue(writer, (try f.air.value(item, zcu)).?, .Other);
4956 }5106 }
4957 try f.object.dg.renderValue(writer, (try f.air.value(item, zcu)).?, .Other);
4958 try writer.writeByte(':');5107 try writer.writeByte(':');
4959 }5108 }
4960 try writer.writeByte(' ');5109 try writer.writeByte(' ');
...@@ -5276,10 +5425,11 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5276,10 +5425,11 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
5276fn airIsNull(5425fn airIsNull(
5277 f: *Function,5426 f: *Function,
5278 inst: Air.Inst.Index,5427 inst: Air.Inst.Index,
5279 operator: []const u8,5428 operator: std.math.CompareOperator,
5280 is_ptr: bool,5429 is_ptr: bool,
5281) !CValue {5430) !CValue {
5282 const zcu = f.object.dg.zcu;5431 const zcu = f.object.dg.zcu;
5432 const ctype_pool = &f.object.dg.ctype_pool;
5283 const un_op = f.air.instructions.items(.data)[@intFromEnum(inst)].un_op;5433 const un_op = f.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
52845434
5285 const writer = f.object.writer();5435 const writer = f.object.writer();
...@@ -5287,106 +5437,84 @@ fn airIsNull(...@@ -5287,106 +5437,84 @@ fn airIsNull(
5287 try reap(f, inst, &.{un_op});5437 try reap(f, inst, &.{un_op});
52885438
5289 const local = try f.allocLocal(inst, Type.bool);5439 const local = try f.allocLocal(inst, Type.bool);
5440 const a = try Assignment.start(f, writer, CType.bool);
5290 try f.writeCValue(writer, local, .Other);5441 try f.writeCValue(writer, local, .Other);
5291 try writer.writeAll(" = ");5442 try a.assign(f, writer);
5292 if (is_ptr) {
5293 try f.writeCValueDeref(writer, operand);
5294 } else {
5295 try f.writeCValue(writer, operand, .Other);
5296 }
52975443
5298 const operand_ty = f.typeOf(un_op);5444 const operand_ty = f.typeOf(un_op);
5299 const optional_ty = if (is_ptr) operand_ty.childType(zcu) else operand_ty;5445 const optional_ty = if (is_ptr) operand_ty.childType(zcu) else operand_ty;
5300 const payload_ty = optional_ty.optionalChild(zcu);5446 const opt_ctype = try f.ctypeFromType(optional_ty, .complete);
5301 const err_int_ty = try zcu.errorIntType();5447 const rhs = switch (opt_ctype.info(ctype_pool)) {
53025448 .basic, .pointer => rhs: {
5303 const rhs = if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu))5449 if (is_ptr)
5304 Value.true5450 try f.writeCValueDeref(writer, operand)
5305 else if (optional_ty.isPtrLikeOptional(zcu))5451 else
5306 // operand is a regular pointer, test `operand !=/== NULL`5452 try f.writeCValue(writer, operand, .Other);
5307 try zcu.getCoerced(Value.null, optional_ty)5453 break :rhs if (opt_ctype.isBool())
5308 else if (payload_ty.zigTypeTag(zcu) == .ErrorSet)5454 "true"
5309 try zcu.intValue(err_int_ty, 0)5455 else if (opt_ctype.isInteger())
5310 else if (payload_ty.isSlice(zcu) and optional_ty.optionalReprIsPayload(zcu)) rhs: {5456 "0"
5311 try writer.writeAll(".ptr");5457 else
5312 const slice_ptr_ty = payload_ty.slicePtrFieldType(zcu);5458 "NULL";
5313 const opt_slice_ptr_ty = try zcu.optionalType(slice_ptr_ty.toIntern());5459 },
5314 break :rhs try zcu.nullValue(opt_slice_ptr_ty);5460 .aligned, .array, .vector, .fwd_decl, .function => unreachable,
5315 } else rhs: {5461 .aggregate => |aggregate| switch (aggregate.fields.at(0, ctype_pool).name.index) {
5316 try writer.writeAll(".is_null");5462 .is_null, .payload => rhs: {
5317 break :rhs Value.true;5463 if (is_ptr)
5464 try f.writeCValueDerefMember(writer, operand, .{ .identifier = "is_null" })
5465 else
5466 try f.writeCValueMember(writer, operand, .{ .identifier = "is_null" });
5467 break :rhs "true";
5468 },
5469 .ptr, .len => rhs: {
5470 if (is_ptr)
5471 try f.writeCValueDerefMember(writer, operand, .{ .identifier = "ptr" })
5472 else
5473 try f.writeCValueMember(writer, operand, .{ .identifier = "ptr" });
5474 break :rhs "NULL";
5475 },
5476 else => unreachable,
5477 },
5318 };5478 };
5319 try writer.writeByte(' ');5479 try writer.writeAll(compareOperatorC(operator));
5320 try writer.writeAll(operator);5480 try writer.writeAll(rhs);
5321 try writer.writeByte(' ');
5322 try f.object.dg.renderValue(writer, rhs, .Other);
5323 try writer.writeAll(";\n");
5324 return local;
5325}
5326
5327fn airOptionalPayload(f: *Function, inst: Air.Inst.Index) !CValue {
5328 const zcu = f.object.dg.zcu;
5329 const ty_op = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
5330
5331 const operand = try f.resolveInst(ty_op.operand);
5332 try reap(f, inst, &.{ty_op.operand});
5333 const opt_ty = f.typeOf(ty_op.operand);
5334
5335 const payload_ty = opt_ty.optionalChild(zcu);
5336
5337 if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
5338 return .none;
5339 }
5340
5341 const inst_ty = f.typeOfIndex(inst);
5342 const writer = f.object.writer();
5343 const local = try f.allocLocal(inst, inst_ty);
5344
5345 if (opt_ty.optionalReprIsPayload(zcu)) {
5346 try f.writeCValue(writer, local, .Other);
5347 try writer.writeAll(" = ");
5348 try f.writeCValue(writer, operand, .Other);
5349 try writer.writeAll(";\n");
5350 return local;
5351 }
5352
5353 const a = try Assignment.start(f, writer, inst_ty);
5354 try f.writeCValue(writer, local, .Other);
5355 try a.assign(f, writer);
5356 try f.writeCValueMember(writer, operand, .{ .identifier = "payload" });
5357 try a.end(f, writer);5481 try a.end(f, writer);
5358 return local;5482 return local;
5359}5483}
53605484
5361fn airOptionalPayloadPtr(f: *Function, inst: Air.Inst.Index) !CValue {5485fn airOptionalPayload(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue {
5362 const zcu = f.object.dg.zcu;5486 const zcu = f.object.dg.zcu;
5487 const ctype_pool = &f.object.dg.ctype_pool;
5363 const ty_op = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;5488 const ty_op = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
53645489
5365 const writer = f.object.writer();
5366 const operand = try f.resolveInst(ty_op.operand);
5367 try reap(f, inst, &.{ty_op.operand});
5368 const ptr_ty = f.typeOf(ty_op.operand);
5369 const opt_ty = ptr_ty.childType(zcu);
5370 const inst_ty = f.typeOfIndex(inst);5490 const inst_ty = f.typeOfIndex(inst);
5491 const operand_ty = f.typeOf(ty_op.operand);
5492 const opt_ty = if (is_ptr) operand_ty.childType(zcu) else operand_ty;
5493 const opt_ctype = try f.ctypeFromType(opt_ty, .complete);
5494 if (opt_ctype.isBool()) return if (is_ptr) .{ .undef = inst_ty } else .none;
53715495
5372 if (!inst_ty.childType(zcu).hasRuntimeBitsIgnoreComptime(zcu)) {5496 const operand = try f.resolveInst(ty_op.operand);
5373 return .{ .undef = inst_ty };5497 switch (opt_ctype.info(ctype_pool)) {
5374 }5498 .basic, .pointer => return f.moveCValue(inst, inst_ty, operand),
53755499 .aligned, .array, .vector, .fwd_decl, .function => unreachable,
5376 const local = try f.allocLocal(inst, inst_ty);5500 .aggregate => |aggregate| switch (aggregate.fields.at(0, ctype_pool).name.index) {
5377 try f.writeCValue(writer, local, .Other);5501 .is_null, .payload => {
53785502 const writer = f.object.writer();
5379 if (opt_ty.optionalReprIsPayload(zcu)) {5503 const local = try f.allocLocal(inst, inst_ty);
5380 // the operand is just a regular pointer, no need to do anything special.5504 const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete));
5381 // *?*T -> **T and ?*T -> *T are **T -> **T and *T -> *T in C5505 try f.writeCValue(writer, local, .Other);
5382 try writer.writeAll(" = ");5506 try a.assign(f, writer);
5383 try f.writeCValue(writer, operand, .Other);5507 if (is_ptr) {
5384 } else {5508 try writer.writeByte('&');
5385 try writer.writeAll(" = &");5509 try f.writeCValueDerefMember(writer, operand, .{ .identifier = "payload" });
5386 try f.writeCValueDerefMember(writer, operand, .{ .identifier = "payload" });5510 } else try f.writeCValueMember(writer, operand, .{ .identifier = "payload" });
5511 try a.end(f, writer);
5512 return local;
5513 },
5514 .ptr, .len => return f.moveCValue(inst, inst_ty, operand),
5515 else => unreachable,
5516 },
5387 }5517 }
5388 try writer.writeAll(";\n");
5389 return local;
5390}5518}
53915519
5392fn airOptionalPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {5520fn airOptionalPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
...@@ -5397,38 +5525,46 @@ fn airOptionalPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5397,38 +5525,46 @@ fn airOptionalPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
5397 try reap(f, inst, &.{ty_op.operand});5525 try reap(f, inst, &.{ty_op.operand});
5398 const operand_ty = f.typeOf(ty_op.operand);5526 const operand_ty = f.typeOf(ty_op.operand);
53995527
5400 const opt_ty = operand_ty.childType(zcu);
5401
5402 const inst_ty = f.typeOfIndex(inst);5528 const inst_ty = f.typeOfIndex(inst);
54035529 const opt_ctype = try f.ctypeFromType(operand_ty.childType(zcu), .complete);
5404 if (opt_ty.optionalReprIsPayload(zcu)) {5530 switch (opt_ctype.info(&f.object.dg.ctype_pool)) {
5405 if (f.liveness.isUnused(inst)) {5531 .basic => {
5406 return .none;5532 const a = try Assignment.start(f, writer, opt_ctype);
5407 }5533 try f.writeCValueDeref(writer, operand);
5408 const local = try f.allocLocal(inst, inst_ty);5534 try a.assign(f, writer);
5409 // The payload and the optional are the same value.5535 try f.object.dg.renderValue(writer, Value.false, .Initializer);
5410 // Setting to non-null will be done when the payload is set.5536 try a.end(f, writer);
5411 try f.writeCValue(writer, local, .Other);
5412 try writer.writeAll(" = ");
5413 try f.writeCValue(writer, operand, .Other);
5414 try writer.writeAll(";\n");
5415 return local;
5416 } else {
5417 try f.writeCValueDeref(writer, operand);
5418 try writer.writeAll(".is_null = ");
5419 try f.object.dg.renderValue(writer, Value.false, .Initializer);
5420 try writer.writeAll(";\n");
5421
5422 if (f.liveness.isUnused(inst)) {
5423 return .none;5537 return .none;
5424 }5538 },
54255539 .pointer => {
5426 const local = try f.allocLocal(inst, inst_ty);5540 if (f.liveness.isUnused(inst)) return .none;
5427 try f.writeCValue(writer, local, .Other);5541 const local = try f.allocLocal(inst, inst_ty);
5428 try writer.writeAll(" = &");5542 const a = try Assignment.start(f, writer, opt_ctype);
5429 try f.writeCValueDeref(writer, operand);5543 try f.writeCValue(writer, local, .Other);
5430 try writer.writeAll(".payload;\n");5544 try a.assign(f, writer);
5431 return local;5545 try f.writeCValue(writer, operand, .Other);
5546 try a.end(f, writer);
5547 return local;
5548 },
5549 .aligned, .array, .vector, .fwd_decl, .function => unreachable,
5550 .aggregate => {
5551 {
5552 const a = try Assignment.start(f, writer, opt_ctype);
5553 try f.writeCValueDerefMember(writer, operand, .{ .identifier = "is_null" });
5554 try a.assign(f, writer);
5555 try f.object.dg.renderValue(writer, Value.false, .Initializer);
5556 try a.end(f, writer);
5557 }
5558 if (f.liveness.isUnused(inst)) return .none;
5559 const local = try f.allocLocal(inst, inst_ty);
5560 const a = try Assignment.start(f, writer, opt_ctype);
5561 try f.writeCValue(writer, local, .Other);
5562 try a.assign(f, writer);
5563 try writer.writeByte('&');
5564 try f.writeCValueDerefMember(writer, operand, .{ .identifier = "payload" });
5565 try a.end(f, writer);
5566 return local;
5567 },
5432 }5568 }
5433}5569}
54345570
...@@ -5688,13 +5824,15 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5688,13 +5824,15 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
5688 if (inst_ty.eql(field_int_ty, f.object.dg.zcu)) return temp_local;5824 if (inst_ty.eql(field_int_ty, f.object.dg.zcu)) return temp_local;
56895825
5690 const local = try f.allocLocal(inst, inst_ty);5826 const local = try f.allocLocal(inst, inst_ty);
5691 try writer.writeAll("memcpy(");5827 if (local.new_local != temp_local.new_local) {
5692 try f.writeCValue(writer, .{ .local_ref = local.new_local }, .FunctionArgument);5828 try writer.writeAll("memcpy(");
5693 try writer.writeAll(", ");5829 try f.writeCValue(writer, .{ .local_ref = local.new_local }, .FunctionArgument);
5694 try f.writeCValue(writer, .{ .local_ref = temp_local.new_local }, .FunctionArgument);5830 try writer.writeAll(", ");
5695 try writer.writeAll(", sizeof(");5831 try f.writeCValue(writer, .{ .local_ref = temp_local.new_local }, .FunctionArgument);
5696 try f.renderType(writer, inst_ty);5832 try writer.writeAll(", sizeof(");
5697 try writer.writeAll("));\n");5833 try f.renderType(writer, inst_ty);
5834 try writer.writeAll("));\n");
5835 }
5698 try freeLocal(f, inst, temp_local.new_local, null);5836 try freeLocal(f, inst, temp_local.new_local, null);
5699 return local;5837 return local;
5700 },5838 },
...@@ -5723,20 +5861,23 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5723,20 +5861,23 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
5723 try writer.writeAll(";\n");5861 try writer.writeAll(";\n");
5724 break :blk operand_local;5862 break :blk operand_local;
5725 } else struct_byval;5863 } else struct_byval;
5726
5727 const local = try f.allocLocal(inst, inst_ty);5864 const local = try f.allocLocal(inst, inst_ty);
5728 try writer.writeAll("memcpy(&");5865 if (switch (local) {
5729 try f.writeCValue(writer, local, .Other);5866 .new_local, .local => |local_index| switch (operand_lval) {
5730 try writer.writeAll(", &");5867 .new_local, .local => |operand_local_index| local_index != operand_local_index,
5731 try f.writeCValue(writer, operand_lval, .Other);5868 else => true,
5732 try writer.writeAll(", sizeof(");5869 },
5733 try f.renderType(writer, inst_ty);5870 else => true,
5734 try writer.writeAll("));\n");5871 }) {
57355872 try writer.writeAll("memcpy(&");
5736 if (struct_byval == .constant) {5873 try f.writeCValue(writer, local, .Other);
5737 try freeLocal(f, inst, operand_lval.new_local, null);5874 try writer.writeAll(", &");
5875 try f.writeCValue(writer, operand_lval, .Other);
5876 try writer.writeAll(", sizeof(");
5877 try f.renderType(writer, inst_ty);
5878 try writer.writeAll("));\n");
5738 }5879 }
57395880 try f.freeCValue(inst, operand_lval);
5740 return local;5881 return local;
5741 },5882 },
5742 }5883 }
...@@ -5745,7 +5886,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5745,7 +5886,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
5745 };5886 };
57465887
5747 const local = try f.allocLocal(inst, inst_ty);5888 const local = try f.allocLocal(inst, inst_ty);
5748 const a = try Assignment.start(f, writer, inst_ty);5889 const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete));
5749 try f.writeCValue(writer, local, .Other);5890 try f.writeCValue(writer, local, .Other);
5750 try a.assign(f, writer);5891 try a.assign(f, writer);
5751 try f.writeCValueMember(writer, struct_byval, field_name);5892 try f.writeCValueMember(writer, struct_byval, field_name);
...@@ -5818,7 +5959,7 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValu...@@ -5818,7 +5959,7 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValu
5818 }5959 }
58195960
5820 const local = try f.allocLocal(inst, inst_ty);5961 const local = try f.allocLocal(inst, inst_ty);
5821 const a = try Assignment.start(f, writer, inst_ty);5962 const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete));
5822 try f.writeCValue(writer, local, .Other);5963 try f.writeCValue(writer, local, .Other);
5823 try a.assign(f, writer);5964 try a.assign(f, writer);
5824 if (is_ptr) {5965 if (is_ptr) {
...@@ -5830,35 +5971,42 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValu...@@ -5830,35 +5971,42 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValu
5830}5971}
58315972
5832fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue {5973fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue {
5833 const zcu = f.object.dg.zcu;5974 const ctype_pool = &f.object.dg.ctype_pool;
5834 const ty_op = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;5975 const ty_op = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
58355976
5836 const inst_ty = f.typeOfIndex(inst);5977 const inst_ty = f.typeOfIndex(inst);
5837 const repr_is_payload = inst_ty.optionalReprIsPayload(zcu);5978 const inst_ctype = try f.ctypeFromType(inst_ty, .complete);
5838 const payload_ty = f.typeOf(ty_op.operand);5979 if (inst_ctype.isBool()) return .{ .constant = Value.true };
5839 const payload = try f.resolveInst(ty_op.operand);
5840 try reap(f, inst, &.{ty_op.operand});
58415980
5842 const writer = f.object.writer();5981 const operand = try f.resolveInst(ty_op.operand);
5843 const local = try f.allocLocal(inst, inst_ty);5982 switch (inst_ctype.info(ctype_pool)) {
5844 {5983 .basic, .pointer => return f.moveCValue(inst, inst_ty, operand),
5845 const a = try Assignment.start(f, writer, payload_ty);5984 .aligned, .array, .vector, .fwd_decl, .function => unreachable,
5846 if (repr_is_payload)5985 .aggregate => |aggregate| switch (aggregate.fields.at(0, ctype_pool).name.index) {
5847 try f.writeCValue(writer, local, .Other)5986 .is_null, .payload => {
5848 else5987 const operand_ctype = try f.ctypeFromType(f.typeOf(ty_op.operand), .complete);
5849 try f.writeCValueMember(writer, local, .{ .identifier = "payload" });5988 const writer = f.object.writer();
5850 try a.assign(f, writer);5989 const local = try f.allocLocal(inst, inst_ty);
5851 try f.writeCValue(writer, payload, .Other);5990 {
5852 try a.end(f, writer);5991 const a = try Assignment.start(f, writer, CType.bool);
5853 }5992 try f.writeCValueMember(writer, local, .{ .identifier = "is_null" });
5854 if (!repr_is_payload) {5993 try a.assign(f, writer);
5855 const a = try Assignment.start(f, writer, Type.bool);5994 try writer.writeAll("false");
5856 try f.writeCValueMember(writer, local, .{ .identifier = "is_null" });5995 try a.end(f, writer);
5857 try a.assign(f, writer);5996 }
5858 try f.object.dg.renderValue(writer, Value.false, .Other);5997 {
5859 try a.end(f, writer);5998 const a = try Assignment.start(f, writer, operand_ctype);
5999 try f.writeCValueMember(writer, local, .{ .identifier = "payload" });
6000 try a.assign(f, writer);
6001 try f.writeCValue(writer, operand, .Initializer);
6002 try a.end(f, writer);
6003 }
6004 return local;
6005 },
6006 .ptr, .len => return f.moveCValue(inst, inst_ty, operand),
6007 else => unreachable,
6008 },
5860 }6009 }
5861 return local;
5862}6010}
58636011
5864fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {6012fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
...@@ -5881,14 +6029,14 @@ fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5881,14 +6029,14 @@ fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
5881 }6029 }
58826030
5883 if (!repr_is_err) {6031 if (!repr_is_err) {
5884 const a = try Assignment.start(f, writer, payload_ty);6032 const a = try Assignment.start(f, writer, try f.ctypeFromType(payload_ty, .complete));
5885 try f.writeCValueMember(writer, local, .{ .identifier = "payload" });6033 try f.writeCValueMember(writer, local, .{ .identifier = "payload" });
5886 try a.assign(f, writer);6034 try a.assign(f, writer);
5887 try f.object.dg.renderUndefValue(writer, payload_ty, .Other);6035 try f.object.dg.renderUndefValue(writer, payload_ty, .Other);
5888 try a.end(f, writer);6036 try a.end(f, writer);
5889 }6037 }
5890 {6038 {
5891 const a = try Assignment.start(f, writer, err_ty);6039 const a = try Assignment.start(f, writer, try f.ctypeFromType(err_ty, .complete));
5892 if (repr_is_err)6040 if (repr_is_err)
5893 try f.writeCValue(writer, local, .Other)6041 try f.writeCValue(writer, local, .Other)
5894 else6042 else
...@@ -5904,31 +6052,43 @@ fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5904,31 +6052,43 @@ fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
5904 const zcu = f.object.dg.zcu;6052 const zcu = f.object.dg.zcu;
5905 const writer = f.object.writer();6053 const writer = f.object.writer();
5906 const ty_op = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;6054 const ty_op = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
6055 const inst_ty = f.typeOfIndex(inst);
5907 const operand = try f.resolveInst(ty_op.operand);6056 const operand = try f.resolveInst(ty_op.operand);
5908 const error_union_ty = f.typeOf(ty_op.operand).childType(zcu);6057 const operand_ty = f.typeOf(ty_op.operand);
6058 const error_union_ty = operand_ty.childType(zcu);
59096059
5910 const payload_ty = error_union_ty.errorUnionPayload(zcu);6060 const payload_ty = error_union_ty.errorUnionPayload(zcu);
5911 const err_int_ty = try zcu.errorIntType();6061 const err_int_ty = try zcu.errorIntType();
5912 const no_err = try zcu.intValue(err_int_ty, 0);6062 const no_err = try zcu.intValue(err_int_ty, 0);
6063 try reap(f, inst, &.{ty_op.operand});
59136064
5914 // First, set the non-error value.6065 // First, set the non-error value.
5915 if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {6066 if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
6067 const a = try Assignment.start(f, writer, try f.ctypeFromType(operand_ty, .complete));
5916 try f.writeCValueDeref(writer, operand);6068 try f.writeCValueDeref(writer, operand);
5917 try writer.print(" = {};\n", .{try f.fmtIntLiteral(no_err)});6069 try a.assign(f, writer);
5918 return operand;6070 try writer.print("{}", .{try f.fmtIntLiteral(no_err)});
6071 try a.end(f, writer);
6072 return .none;
6073 }
6074 {
6075 const a = try Assignment.start(f, writer, try f.ctypeFromType(err_int_ty, .complete));
6076 try f.writeCValueDerefMember(writer, operand, .{ .identifier = "error" });
6077 try a.assign(f, writer);
6078 try writer.print("{}", .{try f.fmtIntLiteral(no_err)});
6079 try a.end(f, writer);
5919 }6080 }
5920 try reap(f, inst, &.{ty_op.operand});
5921 try f.writeCValueDeref(writer, operand);
5922 try writer.print(".error = {};\n", .{try f.fmtIntLiteral(no_err)});
59236081
5924 // Then return the payload pointer (only if it is used)6082 // Then return the payload pointer (only if it is used)
5925 if (f.liveness.isUnused(inst)) return .none;6083 if (f.liveness.isUnused(inst)) return .none;
59266084
5927 const local = try f.allocLocal(inst, f.typeOfIndex(inst));6085 const local = try f.allocLocal(inst, inst_ty);
6086 const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete));
5928 try f.writeCValue(writer, local, .Other);6087 try f.writeCValue(writer, local, .Other);
5929 try writer.writeAll(" = &(");6088 try a.assign(f, writer);
5930 try f.writeCValueDeref(writer, operand);6089 try writer.writeByte('&');
5931 try writer.writeAll(").payload;\n");6090 try f.writeCValueDerefMember(writer, operand, .{ .identifier = "payload" });
6091 try a.end(f, writer);
5932 return local;6092 return local;
5933}6093}
59346094
...@@ -5961,14 +6121,14 @@ fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5961,14 +6121,14 @@ fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {
5961 const writer = f.object.writer();6121 const writer = f.object.writer();
5962 const local = try f.allocLocal(inst, inst_ty);6122 const local = try f.allocLocal(inst, inst_ty);
5963 if (!repr_is_err) {6123 if (!repr_is_err) {
5964 const a = try Assignment.start(f, writer, payload_ty);6124 const a = try Assignment.start(f, writer, try f.ctypeFromType(payload_ty, .complete));
5965 try f.writeCValueMember(writer, local, .{ .identifier = "payload" });6125 try f.writeCValueMember(writer, local, .{ .identifier = "payload" });
5966 try a.assign(f, writer);6126 try a.assign(f, writer);
5967 try f.writeCValue(writer, payload, .Other);6127 try f.writeCValue(writer, payload, .Other);
5968 try a.end(f, writer);6128 try a.end(f, writer);
5969 }6129 }
5970 {6130 {
5971 const a = try Assignment.start(f, writer, err_ty);6131 const a = try Assignment.start(f, writer, try f.ctypeFromType(err_ty, .complete));
5972 if (repr_is_err)6132 if (repr_is_err)
5973 try f.writeCValue(writer, local, .Other)6133 try f.writeCValue(writer, local, .Other)
5974 else6134 else
...@@ -5993,7 +6153,7 @@ fn airIsErr(f: *Function, inst: Air.Inst.Index, is_ptr: bool, operator: []const...@@ -5993,7 +6153,7 @@ fn airIsErr(f: *Function, inst: Air.Inst.Index, is_ptr: bool, operator: []const
5993 const payload_ty = err_union_ty.errorUnionPayload(zcu);6153 const payload_ty = err_union_ty.errorUnionPayload(zcu);
5994 const error_ty = err_union_ty.errorUnionSet(zcu);6154 const error_ty = err_union_ty.errorUnionSet(zcu);
59956155
5996 const a = try Assignment.start(f, writer, Type.bool);6156 const a = try Assignment.start(f, writer, CType.bool);
5997 try f.writeCValue(writer, local, .Other);6157 try f.writeCValue(writer, local, .Other);
5998 try a.assign(f, writer);6158 try a.assign(f, writer);
5999 const err_int_ty = try zcu.errorIntType();6159 const err_int_ty = try zcu.errorIntType();
...@@ -6030,7 +6190,7 @@ fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6030,7 +6190,7 @@ fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue {
6030 const array_ty = operand_ty.childType(zcu);6190 const array_ty = operand_ty.childType(zcu);
60316191
6032 {6192 {
6033 const a = try Assignment.start(f, writer, ptr_ty);6193 const a = try Assignment.start(f, writer, try f.ctypeFromType(ptr_ty, .complete));
6034 try f.writeCValueMember(writer, local, .{ .identifier = "ptr" });6194 try f.writeCValueMember(writer, local, .{ .identifier = "ptr" });
6035 try a.assign(f, writer);6195 try a.assign(f, writer);
6036 if (operand == .undef) {6196 if (operand == .undef) {
...@@ -6056,7 +6216,7 @@ fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6056,7 +6216,7 @@ fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue {
6056 try a.end(f, writer);6216 try a.end(f, writer);
6057 }6217 }
6058 {6218 {
6059 const a = try Assignment.start(f, writer, Type.usize);6219 const a = try Assignment.start(f, writer, CType.usize);
6060 try f.writeCValueMember(writer, local, .{ .identifier = "len" });6220 try f.writeCValueMember(writer, local, .{ .identifier = "len" });
6061 try a.assign(f, writer);6221 try a.assign(f, writer);
6062 try writer.print("{}", .{6222 try writer.print("{}", .{
...@@ -6091,7 +6251,7 @@ fn airFloatCast(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6091,7 +6251,7 @@ fn airFloatCast(f: *Function, inst: Air.Inst.Index) !CValue {
6091 const writer = f.object.writer();6251 const writer = f.object.writer();
6092 const local = try f.allocLocal(inst, inst_ty);6252 const local = try f.allocLocal(inst, inst_ty);
6093 const v = try Vectorize.start(f, inst, writer, operand_ty);6253 const v = try Vectorize.start(f, inst, writer, operand_ty);
6094 const a = try Assignment.start(f, writer, scalar_ty);6254 const a = try Assignment.start(f, writer, try f.ctypeFromType(scalar_ty, .complete));
6095 try f.writeCValue(writer, local, .Other);6255 try f.writeCValue(writer, local, .Other);
6096 try v.elem(f, writer);6256 try v.elem(f, writer);
6097 try a.assign(f, writer);6257 try a.assign(f, writer);
...@@ -6133,11 +6293,10 @@ fn airIntFromPtr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6133,11 +6293,10 @@ fn airIntFromPtr(f: *Function, inst: Air.Inst.Index) !CValue {
6133 try writer.writeAll(" = (");6293 try writer.writeAll(" = (");
6134 try f.renderType(writer, inst_ty);6294 try f.renderType(writer, inst_ty);
6135 try writer.writeByte(')');6295 try writer.writeByte(')');
6136 if (operand_ty.isSlice(zcu)) {6296 if (operand_ty.isSlice(zcu))
6137 try f.writeCValueMember(writer, operand, .{ .identifier = "ptr" });6297 try f.writeCValueMember(writer, operand, .{ .identifier = "ptr" })
6138 } else {6298 else
6139 try f.writeCValue(writer, operand, .Other);6299 try f.writeCValue(writer, operand, .Other);
6140 }
6141 try writer.writeAll(";\n");6300 try writer.writeAll(";\n");
6142 return local;6301 return local;
6143}6302}
...@@ -6306,9 +6465,10 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue...@@ -6306,9 +6465,10 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue
6306 const new_value = try f.resolveInst(extra.new_value);6465 const new_value = try f.resolveInst(extra.new_value);
6307 const ptr_ty = f.typeOf(extra.ptr);6466 const ptr_ty = f.typeOf(extra.ptr);
6308 const ty = ptr_ty.childType(zcu);6467 const ty = ptr_ty.childType(zcu);
6468 const ctype = try f.ctypeFromType(ty, .complete);
63096469
6310 const writer = f.object.writer();6470 const writer = f.object.writer();
6311 const new_value_mat = try Materialize.start(f, inst, writer, ty, new_value);6471 const new_value_mat = try Materialize.start(f, inst, ty, new_value);
6312 try reap(f, inst, &.{ extra.ptr, extra.expected_value, extra.new_value });6472 try reap(f, inst, &.{ extra.ptr, extra.expected_value, extra.new_value });
63136473
6314 const repr_ty = if (ty.isRuntimeFloat())6474 const repr_ty = if (ty.isRuntimeFloat())
...@@ -6319,7 +6479,7 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue...@@ -6319,7 +6479,7 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue
6319 const local = try f.allocLocal(inst, inst_ty);6479 const local = try f.allocLocal(inst, inst_ty);
6320 if (inst_ty.isPtrLikeOptional(zcu)) {6480 if (inst_ty.isPtrLikeOptional(zcu)) {
6321 {6481 {
6322 const a = try Assignment.start(f, writer, ty);6482 const a = try Assignment.start(f, writer, ctype);
6323 try f.writeCValue(writer, local, .Other);6483 try f.writeCValue(writer, local, .Other);
6324 try a.assign(f, writer);6484 try a.assign(f, writer);
6325 try f.writeCValue(writer, expected_value, .Other);6485 try f.writeCValue(writer, expected_value, .Other);
...@@ -6349,7 +6509,7 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue...@@ -6349,7 +6509,7 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue
6349 try writer.writeAll(") {\n");6509 try writer.writeAll(") {\n");
6350 f.object.indent_writer.pushIndent();6510 f.object.indent_writer.pushIndent();
6351 {6511 {
6352 const a = try Assignment.start(f, writer, ty);6512 const a = try Assignment.start(f, writer, ctype);
6353 try f.writeCValue(writer, local, .Other);6513 try f.writeCValue(writer, local, .Other);
6354 try a.assign(f, writer);6514 try a.assign(f, writer);
6355 try writer.writeAll("NULL");6515 try writer.writeAll("NULL");
...@@ -6359,14 +6519,14 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue...@@ -6359,14 +6519,14 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue
6359 try writer.writeAll("}\n");6519 try writer.writeAll("}\n");
6360 } else {6520 } else {
6361 {6521 {
6362 const a = try Assignment.start(f, writer, ty);6522 const a = try Assignment.start(f, writer, ctype);
6363 try f.writeCValueMember(writer, local, .{ .identifier = "payload" });6523 try f.writeCValueMember(writer, local, .{ .identifier = "payload" });
6364 try a.assign(f, writer);6524 try a.assign(f, writer);
6365 try f.writeCValue(writer, expected_value, .Other);6525 try f.writeCValue(writer, expected_value, .Other);
6366 try a.end(f, writer);6526 try a.end(f, writer);
6367 }6527 }
6368 {6528 {
6369 const a = try Assignment.start(f, writer, Type.bool);6529 const a = try Assignment.start(f, writer, CType.bool);
6370 try f.writeCValueMember(writer, local, .{ .identifier = "is_null" });6530 try f.writeCValueMember(writer, local, .{ .identifier = "is_null" });
6371 try a.assign(f, writer);6531 try a.assign(f, writer);
6372 try writer.print("zig_cmpxchg_{s}((zig_atomic(", .{flavor});6532 try writer.print("zig_cmpxchg_{s}((zig_atomic(", .{flavor});
...@@ -6412,7 +6572,7 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6412,7 +6572,7 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue {
6412 const operand = try f.resolveInst(extra.operand);6572 const operand = try f.resolveInst(extra.operand);
64136573
6414 const writer = f.object.writer();6574 const writer = f.object.writer();
6415 const operand_mat = try Materialize.start(f, inst, writer, ty, operand);6575 const operand_mat = try Materialize.start(f, inst, ty, operand);
6416 try reap(f, inst, &.{ pl_op.operand, extra.operand });6576 try reap(f, inst, &.{ pl_op.operand, extra.operand });
64176577
6418 const repr_bits = @as(u16, @intCast(ty.abiSize(zcu) * 8));6578 const repr_bits = @as(u16, @intCast(ty.abiSize(zcu) * 8));
...@@ -6501,7 +6661,7 @@ fn airAtomicStore(f: *Function, inst: Air.Inst.Index, order: [*:0]const u8) !CVa...@@ -6501,7 +6661,7 @@ fn airAtomicStore(f: *Function, inst: Air.Inst.Index, order: [*:0]const u8) !CVa
6501 const element = try f.resolveInst(bin_op.rhs);6661 const element = try f.resolveInst(bin_op.rhs);
65026662
6503 const writer = f.object.writer();6663 const writer = f.object.writer();
6504 const element_mat = try Materialize.start(f, inst, writer, ty, element);6664 const element_mat = try Materialize.start(f, inst, ty, element);
6505 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });6665 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
65066666
6507 const repr_ty = if (ty.isRuntimeFloat())6667 const repr_ty = if (ty.isRuntimeFloat())
...@@ -6612,7 +6772,7 @@ fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {...@@ -6612,7 +6772,7 @@ fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
6612 try f.writeCValue(writer, index, .Other);6772 try f.writeCValue(writer, index, .Other);
6613 try writer.writeAll(") ");6773 try writer.writeAll(") ");
66146774
6615 const a = try Assignment.start(f, writer, elem_ty);6775 const a = try Assignment.start(f, writer, try f.ctypeFromType(elem_ty, .complete));
6616 try writer.writeAll("((");6776 try writer.writeAll("((");
6617 try f.renderType(writer, elem_ptr_ty);6777 try f.renderType(writer, elem_ptr_ty);
6618 try writer.writeByte(')');6778 try writer.writeByte(')');
...@@ -6637,7 +6797,7 @@ fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {...@@ -6637,7 +6797,7 @@ fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
6637 .Slice => {6797 .Slice => {
6638 try f.writeCValueMember(writer, dest_slice, .{ .identifier = "ptr" });6798 try f.writeCValueMember(writer, dest_slice, .{ .identifier = "ptr" });
6639 try writer.writeAll(", ");6799 try writer.writeAll(", ");
6640 try f.writeCValue(writer, bitcasted.c_value, .FunctionArgument);6800 try f.writeCValue(writer, bitcasted, .FunctionArgument);
6641 try writer.writeAll(", ");6801 try writer.writeAll(", ");
6642 try f.writeCValueMember(writer, dest_slice, .{ .identifier = "len" });6802 try f.writeCValueMember(writer, dest_slice, .{ .identifier = "len" });
6643 try writer.writeAll(");\n");6803 try writer.writeAll(");\n");
...@@ -6648,12 +6808,12 @@ fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {...@@ -6648,12 +6808,12 @@ fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
66486808
6649 try f.writeCValue(writer, dest_slice, .FunctionArgument);6809 try f.writeCValue(writer, dest_slice, .FunctionArgument);
6650 try writer.writeAll(", ");6810 try writer.writeAll(", ");
6651 try f.writeCValue(writer, bitcasted.c_value, .FunctionArgument);6811 try f.writeCValue(writer, bitcasted, .FunctionArgument);
6652 try writer.print(", {d});\n", .{len});6812 try writer.print(", {d});\n", .{len});
6653 },6813 },
6654 .Many, .C => unreachable,6814 .Many, .C => unreachable,
6655 }6815 }
6656 try bitcasted.free(f);6816 try f.freeCValue(inst, bitcasted);
6657 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });6817 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
6658 return .none;6818 return .none;
6659}6819}
...@@ -6700,7 +6860,7 @@ fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6700,7 +6860,7 @@ fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
6700 const tag_ty = union_ty.unionTagTypeSafety(zcu).?;6860 const tag_ty = union_ty.unionTagTypeSafety(zcu).?;
67016861
6702 const writer = f.object.writer();6862 const writer = f.object.writer();
6703 const a = try Assignment.start(f, writer, tag_ty);6863 const a = try Assignment.start(f, writer, try f.ctypeFromType(tag_ty, .complete));
6704 try f.writeCValueDerefMember(writer, union_ptr, .{ .identifier = "tag" });6864 try f.writeCValueDerefMember(writer, union_ptr, .{ .identifier = "tag" });
6705 try a.assign(f, writer);6865 try a.assign(f, writer);
6706 try f.writeCValue(writer, new_tag, .Other);6866 try f.writeCValue(writer, new_tag, .Other);
...@@ -6722,7 +6882,7 @@ fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6722,7 +6882,7 @@ fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
6722 const inst_ty = f.typeOfIndex(inst);6882 const inst_ty = f.typeOfIndex(inst);
6723 const writer = f.object.writer();6883 const writer = f.object.writer();
6724 const local = try f.allocLocal(inst, inst_ty);6884 const local = try f.allocLocal(inst, inst_ty);
6725 const a = try Assignment.start(f, writer, inst_ty);6885 const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete));
6726 try f.writeCValue(writer, local, .Other);6886 try f.writeCValue(writer, local, .Other);
6727 try a.assign(f, writer);6887 try a.assign(f, writer);
6728 try f.writeCValueMember(writer, operand, .{ .identifier = "tag" });6888 try f.writeCValueMember(writer, operand, .{ .identifier = "tag" });
...@@ -6780,7 +6940,7 @@ fn airSplat(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6780,7 +6940,7 @@ fn airSplat(f: *Function, inst: Air.Inst.Index) !CValue {
6780 const writer = f.object.writer();6940 const writer = f.object.writer();
6781 const local = try f.allocLocal(inst, inst_ty);6941 const local = try f.allocLocal(inst, inst_ty);
6782 const v = try Vectorize.start(f, inst, writer, inst_ty);6942 const v = try Vectorize.start(f, inst, writer, inst_ty);
6783 const a = try Assignment.init(f, inst_scalar_ty);6943 const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_scalar_ty, .complete));
6784 try f.writeCValue(writer, local, .Other);6944 try f.writeCValue(writer, local, .Other);
6785 try v.elem(f, writer);6945 try v.elem(f, writer);
6786 try a.assign(f, writer);6946 try a.assign(f, writer);
...@@ -7033,7 +7193,9 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -7033,7 +7193,9 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
7033 const local = try f.allocLocal(inst, inst_ty);7193 const local = try f.allocLocal(inst, inst_ty);
7034 switch (ip.indexToKey(inst_ty.toIntern())) {7194 switch (ip.indexToKey(inst_ty.toIntern())) {
7035 inline .array_type, .vector_type => |info, tag| {7195 inline .array_type, .vector_type => |info, tag| {
7036 const a = try Assignment.init(f, Type.fromInterned(info.child));7196 const a: Assignment = .{
7197 .ctype = try f.ctypeFromType(Type.fromInterned(info.child), .complete),
7198 };
7037 for (resolved_elements, 0..) |element, i| {7199 for (resolved_elements, 0..) |element, i| {
7038 try a.restart(f, writer);7200 try a.restart(f, writer);
7039 try f.writeCValue(writer, local, .Other);7201 try f.writeCValue(writer, local, .Other);
...@@ -7060,7 +7222,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -7060,7 +7222,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
7060 const field_ty = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]);7222 const field_ty = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]);
7061 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;7223 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
70627224
7063 const a = try Assignment.start(f, writer, field_ty);7225 const a = try Assignment.start(f, writer, try f.ctypeFromType(field_ty, .complete));
7064 try f.writeCValueMember(writer, local, if (loaded_struct.fieldName(ip, field_index).unwrap()) |field_name|7226 try f.writeCValueMember(writer, local, if (loaded_struct.fieldName(ip, field_index).unwrap()) |field_name|
7065 .{ .identifier = field_name.toSlice(ip) }7227 .{ .identifier = field_name.toSlice(ip) }
7066 else7228 else
...@@ -7140,7 +7302,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -7140,7 +7302,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
7140 const field_ty = Type.fromInterned(anon_struct_info.types.get(ip)[field_index]);7302 const field_ty = Type.fromInterned(anon_struct_info.types.get(ip)[field_index]);
7141 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;7303 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
71427304
7143 const a = try Assignment.start(f, writer, field_ty);7305 const a = try Assignment.start(f, writer, try f.ctypeFromType(field_ty, .complete));
7144 try f.writeCValueMember(writer, local, if (anon_struct_info.fieldName(ip, field_index).unwrap()) |field_name|7306 try f.writeCValueMember(writer, local, if (anon_struct_info.fieldName(ip, field_index).unwrap()) |field_name|
7145 .{ .identifier = field_name.toSlice(ip) }7307 .{ .identifier = field_name.toSlice(ip) }
7146 else7308 else
...@@ -7170,13 +7332,7 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -7170,13 +7332,7 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {
71707332
7171 const writer = f.object.writer();7333 const writer = f.object.writer();
7172 const local = try f.allocLocal(inst, union_ty);7334 const local = try f.allocLocal(inst, union_ty);
7173 if (loaded_union.getLayout(ip) == .@"packed") {7335 if (loaded_union.getLayout(ip) == .@"packed") return f.moveCValue(inst, union_ty, payload);
7174 try f.writeCValue(writer, local, .Other);
7175 try writer.writeAll(" = ");
7176 try f.writeCValue(writer, payload, .Initializer);
7177 try writer.writeAll(";\n");
7178 return local;
7179 }
71807336
7181 const field: CValue = if (union_ty.unionTagTypeSafety(zcu)) |tag_ty| field: {7337 const field: CValue = if (union_ty.unionTagTypeSafety(zcu)) |tag_ty| field: {
7182 const layout = union_ty.unionGetLayout(zcu);7338 const layout = union_ty.unionGetLayout(zcu);
...@@ -7184,7 +7340,7 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -7184,7 +7340,7 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {
7184 const field_index = tag_ty.enumFieldIndex(field_name, zcu).?;7340 const field_index = tag_ty.enumFieldIndex(field_name, zcu).?;
7185 const tag_val = try zcu.enumValueFieldIndex(tag_ty, field_index);7341 const tag_val = try zcu.enumValueFieldIndex(tag_ty, field_index);
71867342
7187 const a = try Assignment.start(f, writer, tag_ty);7343 const a = try Assignment.start(f, writer, try f.ctypeFromType(tag_ty, .complete));
7188 try f.writeCValueMember(writer, local, .{ .identifier = "tag" });7344 try f.writeCValueMember(writer, local, .{ .identifier = "tag" });
7189 try a.assign(f, writer);7345 try a.assign(f, writer);
7190 try writer.print("{}", .{try f.fmtIntLiteral(try tag_val.intFromEnum(tag_ty, zcu))});7346 try writer.print("{}", .{try f.fmtIntLiteral(try tag_val.intFromEnum(tag_ty, zcu))});
...@@ -7193,7 +7349,7 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -7193,7 +7349,7 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {
7193 break :field .{ .payload_identifier = field_name.toSlice(ip) };7349 break :field .{ .payload_identifier = field_name.toSlice(ip) };
7194 } else .{ .identifier = field_name.toSlice(ip) };7350 } else .{ .identifier = field_name.toSlice(ip) };
71957351
7196 const a = try Assignment.start(f, writer, payload_ty);7352 const a = try Assignment.start(f, writer, try f.ctypeFromType(payload_ty, .complete));
7197 try f.writeCValueMember(writer, local, field);7353 try f.writeCValueMember(writer, local, field);
7198 try a.assign(f, writer);7354 try a.assign(f, writer);
7199 try f.writeCValue(writer, payload, .Other);7355 try f.writeCValue(writer, payload, .Other);
...@@ -7648,11 +7804,13 @@ fn StringLiteral(comptime WriterType: type) type {...@@ -7648,11 +7804,13 @@ fn StringLiteral(comptime WriterType: type) type {
7648 // MSVC throws C2078 if an array of size 65536 or greater is initialized with a string literal,7804 // MSVC throws C2078 if an array of size 65536 or greater is initialized with a string literal,
7649 // regardless of the length of the string literal initializing it. Array initializer syntax is7805 // regardless of the length of the string literal initializing it. Array initializer syntax is
7650 // used instead.7806 // used instead.
7651 const max_string_initializer_len = 65535;7807 // C99 only requires 4095.
7808 const max_string_initializer_len = @min(65535, 4095);
76527809
7653 // MSVC has a length limit of 16380 per string literal (before concatenation)7810 // MSVC has a length limit of 16380 per string literal (before concatenation)
7811 // C99 only requires 4095.
7654 const max_char_len = 4;7812 const max_char_len = 4;
7655 const max_literal_len = 16380 - max_char_len;7813 const max_literal_len = @min(16380 - max_char_len, 4095);
76567814
7657 return struct {7815 return struct {
7658 len: u64,7816 len: u64,
...@@ -7824,13 +7982,13 @@ fn formatIntLiteral(...@@ -7824,13 +7982,13 @@ fn formatIntLiteral(
7824 } = switch (data.ctype.info(ctype_pool)) {7982 } = switch (data.ctype.info(ctype_pool)) {
7825 .basic => |basic_info| switch (basic_info) {7983 .basic => |basic_info| switch (basic_info) {
7826 else => .{7984 else => .{
7827 .ctype = .{ .index = .void },7985 .ctype = CType.void,
7828 .count = 1,7986 .count = 1,
7829 .endian = .little,7987 .endian = .little,
7830 .homogeneous = true,7988 .homogeneous = true,
7831 },7989 },
7832 .zig_u128, .zig_i128 => .{7990 .zig_u128, .zig_i128 => .{
7833 .ctype = .{ .index = .uint64_t },7991 .ctype = CType.u64,
7834 .count = 2,7992 .count = 2,
7835 .endian = .big,7993 .endian = .big,
7836 .homogeneous = false,7994 .homogeneous = false,
...@@ -7946,28 +8104,12 @@ fn formatIntLiteral(...@@ -7946,28 +8104,12 @@ fn formatIntLiteral(
7946const Materialize = struct {8104const Materialize = struct {
7947 local: CValue,8105 local: CValue,
79488106
7949 pub fn start(8107 pub fn start(f: *Function, inst: Air.Inst.Index, ty: Type, value: CValue) !Materialize {
7950 f: *Function,8108 return .{ .local = switch (value) {
7951 inst: Air.Inst.Index,8109 .local_ref, .constant, .decl_ref, .undef => try f.moveCValue(inst, ty, value),
7952 writer: anytype,8110 .new_local => |local| .{ .local = local },
7953 ty: Type,8111 else => value,
7954 value: CValue,8112 } };
7955 ) !Materialize {
7956 switch (value) {
7957 .local_ref, .constant, .decl_ref, .undef => {
7958 const local = try f.allocLocal(inst, ty);
7959
7960 const a = try Assignment.start(f, writer, ty);
7961 try f.writeCValue(writer, local, .Other);
7962 try a.assign(f, writer);
7963 try f.writeCValue(writer, value, .Other);
7964 try a.end(f, writer);
7965
7966 return .{ .local = local };
7967 },
7968 .new_local => |local| return .{ .local = .{ .local = local } },
7969 else => return .{ .local = value },
7970 }
7971 }8113 }
79728114
7973 pub fn mat(self: Materialize, f: *Function, writer: anytype) !void {8115 pub fn mat(self: Materialize, f: *Function, writer: anytype) !void {
...@@ -7975,22 +8117,15 @@ const Materialize = struct {...@@ -7975,22 +8117,15 @@ const Materialize = struct {
7975 }8117 }
79768118
7977 pub fn end(self: Materialize, f: *Function, inst: Air.Inst.Index) !void {8119 pub fn end(self: Materialize, f: *Function, inst: Air.Inst.Index) !void {
7978 switch (self.local) {8120 try f.freeCValue(inst, self.local);
7979 .new_local => |local| try freeLocal(f, inst, local, null),
7980 else => {},
7981 }
7982 }8121 }
7983};8122};
79848123
7985const Assignment = struct {8124const Assignment = struct {
7986 ctype: CType,8125 ctype: CType,
79878126
7988 pub fn init(f: *Function, ty: Type) !Assignment {8127 pub fn start(f: *Function, writer: anytype, ctype: CType) !Assignment {
7989 return .{ .ctype = try f.ctypeFromType(ty, .complete) };8128 const self: Assignment = .{ .ctype = ctype };
7990 }
7991
7992 pub fn start(f: *Function, writer: anytype, ty: Type) !Assignment {
7993 const self = try init(f, ty);
7994 try self.restart(f, writer);8129 try self.restart(f, writer);
7995 return self;8130 return self;
7996 }8131 }
src/codegen/c/Type.zig+213-115
...@@ -1,13 +1,33 @@...@@ -1,13 +1,33 @@
1index: CType.Index,1index: CType.Index,
22
3pub const @"void": CType = .{ .index = .void };
4pub const @"bool": CType = .{ .index = .bool };
5pub const @"i8": CType = .{ .index = .int8_t };
6pub const @"u8": CType = .{ .index = .uint8_t };
7pub const @"i16": CType = .{ .index = .int16_t };
8pub const @"u16": CType = .{ .index = .uint16_t };
9pub const @"i32": CType = .{ .index = .int32_t };
10pub const @"u32": CType = .{ .index = .uint32_t };
11pub const @"i64": CType = .{ .index = .int64_t };
12pub const @"u64": CType = .{ .index = .uint64_t };
13pub const @"i128": CType = .{ .index = .zig_i128 };
14pub const @"u128": CType = .{ .index = .zig_u128 };
15pub const @"isize": CType = .{ .index = .intptr_t };
16pub const @"usize": CType = .{ .index = .uintptr_t };
17pub const @"f16": CType = .{ .index = .zig_f16 };
18pub const @"f32": CType = .{ .index = .zig_f32 };
19pub const @"f64": CType = .{ .index = .zig_f64 };
20pub const @"f80": CType = .{ .index = .zig_f80 };
21pub const @"f128": CType = .{ .index = .zig_f128 };
22
3pub fn fromPoolIndex(pool_index: usize) CType {23pub fn fromPoolIndex(pool_index: usize) CType {
4 return .{ .index = @enumFromInt(CType.Index.first_pool_index + pool_index) };24 return .{ .index = @enumFromInt(CType.Index.first_pool_index + pool_index) };
5}25}
626
7pub fn toPoolIndex(ctype: CType) ?u32 {27pub fn toPoolIndex(ctype: CType) ?u32 {
8 const pool_index, const is_basic =28 const pool_index, const is_null =
9 @subWithOverflow(@intFromEnum(ctype.index), CType.Index.first_pool_index);29 @subWithOverflow(@intFromEnum(ctype.index), CType.Index.first_pool_index);
10 return switch (is_basic) {30 return switch (is_null) {
11 0 => pool_index,31 0 => pool_index,
12 1 => null,32 1 => null,
13 };33 };
...@@ -710,20 +730,6 @@ pub const Kind = enum {...@@ -710,20 +730,6 @@ pub const Kind = enum {
710 }730 }
711};731};
712732
713pub const String = struct {
714 index: String.Index,
715
716 const Index = enum(u32) {
717 _,
718 };
719
720 pub fn slice(string: String, pool: *const Pool) []const u8 {
721 const start = pool.string_indices.items[@intFromEnum(string.index)];
722 const end = pool.string_indices.items[@intFromEnum(string.index) + 1];
723 return pool.string_bytes.items[start..end];
724 }
725};
726
727pub const Info = union(enum) {733pub const Info = union(enum) {
728 basic: CType.Index,734 basic: CType.Index,
729 pointer: Pointer,735 pointer: Pointer,
...@@ -766,7 +772,7 @@ pub const Info = union(enum) {...@@ -766,7 +772,7 @@ pub const Info = union(enum) {
766 pub const AggregateTag = enum { @"enum", @"struct", @"union" };772 pub const AggregateTag = enum { @"enum", @"struct", @"union" };
767773
768 pub const Field = struct {774 pub const Field = struct {
769 name: String,775 name: Pool.String,
770 ctype: CType,776 ctype: CType,
771 alignas: AlignAs,777 alignas: AlignAs,
772778
...@@ -812,12 +818,15 @@ pub const Info = union(enum) {...@@ -812,12 +818,15 @@ pub const Info = union(enum) {
812 rhs_pool: *const Pool,818 rhs_pool: *const Pool,
813 pool_adapter: anytype,819 pool_adapter: anytype,
814 ) bool {820 ) bool {
815 return std.meta.eql(lhs_field.alignas, rhs_field.alignas) and821 if (!std.meta.eql(lhs_field.alignas, rhs_field.alignas)) return false;
816 pool_adapter.eql(lhs_field.ctype, rhs_field.ctype) and std.mem.eql(822 if (!pool_adapter.eql(lhs_field.ctype, rhs_field.ctype)) return false;
817 u8,823 return if (lhs_field.name.toPoolSlice(lhs_pool)) |lhs_name|
818 lhs_field.name.slice(lhs_pool),824 if (rhs_field.name.toPoolSlice(rhs_pool)) |rhs_name|
819 rhs_field.name.slice(rhs_pool),825 std.mem.eql(u8, lhs_name, rhs_name)
820 );826 else
827 false
828 else
829 lhs_field.name.index == rhs_field.name.index;
821 }830 }
822 };831 };
823832
...@@ -918,6 +927,86 @@ pub const Pool = struct {...@@ -918,6 +927,86 @@ pub const Pool = struct {
918927
919 const Map = std.AutoArrayHashMapUnmanaged(void, void);928 const Map = std.AutoArrayHashMapUnmanaged(void, void);
920929
930 pub const String = struct {
931 index: String.Index,
932
933 const FormatData = struct { string: String, pool: *const Pool };
934 fn format(
935 data: FormatData,
936 comptime fmt_str: []const u8,
937 _: std.fmt.FormatOptions,
938 writer: anytype,
939 ) @TypeOf(writer).Error!void {
940 if (fmt_str.len > 0) @compileError("invalid format string '" ++ fmt_str ++ "'");
941 if (data.string.toSlice(data.pool)) |slice|
942 try writer.writeAll(slice)
943 else
944 try writer.print("f{d}", .{@intFromEnum(data.string.index)});
945 }
946 pub fn fmt(str: String, pool: *const Pool) std.fmt.Formatter(format) {
947 return .{ .data = .{ .string = str, .pool = pool } };
948 }
949
950 fn fromUnnamed(index: u31) String {
951 return .{ .index = @enumFromInt(index) };
952 }
953
954 fn isNamed(str: String) bool {
955 return @intFromEnum(str.index) >= String.Index.first_named_index;
956 }
957
958 pub fn toSlice(str: String, pool: *const Pool) ?[]const u8 {
959 return str.toPoolSlice(pool) orelse if (str.isNamed()) @tagName(str.index) else null;
960 }
961
962 fn toPoolSlice(str: String, pool: *const Pool) ?[]const u8 {
963 if (str.toPoolIndex()) |pool_index| {
964 const start = pool.string_indices.items[pool_index + 0];
965 const end = pool.string_indices.items[pool_index + 1];
966 return pool.string_bytes.items[start..end];
967 } else return null;
968 }
969
970 fn fromPoolIndex(pool_index: usize) String {
971 return .{ .index = @enumFromInt(String.Index.first_pool_index + pool_index) };
972 }
973
974 fn toPoolIndex(str: String) ?u32 {
975 const pool_index, const is_null =
976 @subWithOverflow(@intFromEnum(str.index), String.Index.first_pool_index);
977 return switch (is_null) {
978 0 => pool_index,
979 1 => null,
980 };
981 }
982
983 const Index = enum(u32) {
984 array = first_named_index,
985 @"error",
986 is_null,
987 len,
988 payload,
989 ptr,
990 tag,
991 _,
992
993 const first_named_index: u32 = 1 << 31;
994 const first_pool_index: u32 = first_named_index + @typeInfo(String.Index).Enum.fields.len;
995 };
996
997 const Adapter = struct {
998 pool: *const Pool,
999 pub fn hash(_: @This(), slice: []const u8) Map.Hash {
1000 return @truncate(Hasher.Impl.hash(1, slice));
1001 }
1002 pub fn eql(string_adapter: @This(), lhs_slice: []const u8, _: void, rhs_index: usize) bool {
1003 const rhs_string = String.fromPoolIndex(rhs_index);
1004 const rhs_slice = rhs_string.toPoolSlice(string_adapter.pool).?;
1005 return std.mem.eql(u8, lhs_slice, rhs_slice);
1006 }
1007 };
1008 };
1009
921 pub const empty: Pool = .{1010 pub const empty: Pool = .{
922 .map = .{},1011 .map = .{},
923 .items = .{},1012 .items = .{},
...@@ -1200,26 +1289,26 @@ pub const Pool = struct {...@@ -1200,26 +1289,26 @@ pub const Pool = struct {
1200 kind: Kind,1289 kind: Kind,
1201 ) !CType {1290 ) !CType {
1202 switch (int_info.bits) {1291 switch (int_info.bits) {
1203 0 => return .{ .index = .void },1292 0 => return CType.void,
1204 1...8 => switch (int_info.signedness) {1293 1...8 => switch (int_info.signedness) {
1205 .unsigned => return .{ .index = .uint8_t },1294 .signed => return CType.i8,
1206 .signed => return .{ .index = .int8_t },1295 .unsigned => return CType.u8,
1207 },1296 },
1208 9...16 => switch (int_info.signedness) {1297 9...16 => switch (int_info.signedness) {
1209 .unsigned => return .{ .index = .uint16_t },1298 .signed => return CType.i16,
1210 .signed => return .{ .index = .int16_t },1299 .unsigned => return CType.u16,
1211 },1300 },
1212 17...32 => switch (int_info.signedness) {1301 17...32 => switch (int_info.signedness) {
1213 .unsigned => return .{ .index = .uint32_t },1302 .signed => return CType.i32,
1214 .signed => return .{ .index = .int32_t },1303 .unsigned => return CType.u32,
1215 },1304 },
1216 33...64 => switch (int_info.signedness) {1305 33...64 => switch (int_info.signedness) {
1217 .unsigned => return .{ .index = .uint64_t },1306 .signed => return CType.i64,
1218 .signed => return .{ .index = .int64_t },1307 .unsigned => return CType.u64,
1219 },1308 },
1220 65...128 => switch (int_info.signedness) {1309 65...128 => switch (int_info.signedness) {
1221 .unsigned => return .{ .index = .zig_u128 },1310 .signed => return CType.i128,
1222 .signed => return .{ .index = .zig_i128 },1311 .unsigned => return CType.u128,
1223 },1312 },
1224 else => {1313 else => {
1225 const target = &mod.resolved_target.result;1314 const target = &mod.resolved_target.result;
...@@ -1235,7 +1324,7 @@ pub const Pool = struct {...@@ -1235,7 +1324,7 @@ pub const Pool = struct {
1235 if (!kind.isParameter()) return array_ctype;1324 if (!kind.isParameter()) return array_ctype;
1236 var fields = [_]Info.Field{1325 var fields = [_]Info.Field{
1237 .{1326 .{
1238 .name = try pool.string(allocator, "array"),1327 .name = .{ .index = .array },
1239 .ctype = array_ctype,1328 .ctype = array_ctype,
1240 .alignas = AlignAs.fromAbiAlignment(abi_align),1329 .alignas = AlignAs.fromAbiAlignment(abi_align),
1241 },1330 },
...@@ -1267,19 +1356,19 @@ pub const Pool = struct {...@@ -1267,19 +1356,19 @@ pub const Pool = struct {
1267 .null_type,1356 .null_type,
1268 .undefined_type,1357 .undefined_type,
1269 .enum_literal_type,1358 .enum_literal_type,
1270 => return .{ .index = .void },1359 => return CType.void,
1271 .u1_type, .u8_type => return .{ .index = .uint8_t },1360 .u1_type, .u8_type => return CType.u8,
1272 .i8_type => return .{ .index = .int8_t },1361 .i8_type => return CType.i8,
1273 .u16_type => return .{ .index = .uint16_t },1362 .u16_type => return CType.u16,
1274 .i16_type => return .{ .index = .int16_t },1363 .i16_type => return CType.i16,
1275 .u29_type, .u32_type => return .{ .index = .uint32_t },1364 .u29_type, .u32_type => return CType.u32,
1276 .i32_type => return .{ .index = .int32_t },1365 .i32_type => return CType.i32,
1277 .u64_type => return .{ .index = .uint64_t },1366 .u64_type => return CType.u64,
1278 .i64_type => return .{ .index = .int64_t },1367 .i64_type => return CType.i64,
1279 .u80_type, .u128_type => return .{ .index = .zig_u128 },1368 .u80_type, .u128_type => return CType.u128,
1280 .i128_type => return .{ .index = .zig_i128 },1369 .i128_type => return CType.i128,
1281 .usize_type => return .{ .index = .uintptr_t },1370 .usize_type => return CType.usize,
1282 .isize_type => return .{ .index = .intptr_t },1371 .isize_type => return CType.isize,
1283 .c_char_type => return .{ .index = .char },1372 .c_char_type => return .{ .index = .char },
1284 .c_short_type => return .{ .index = .short },1373 .c_short_type => return .{ .index = .short },
1285 .c_ushort_type => return .{ .index = .@"unsigned short" },1374 .c_ushort_type => return .{ .index = .@"unsigned short" },
...@@ -1290,12 +1379,12 @@ pub const Pool = struct {...@@ -1290,12 +1379,12 @@ pub const Pool = struct {
1290 .c_longlong_type => return .{ .index = .@"long long" },1379 .c_longlong_type => return .{ .index = .@"long long" },
1291 .c_ulonglong_type => return .{ .index = .@"unsigned long long" },1380 .c_ulonglong_type => return .{ .index = .@"unsigned long long" },
1292 .c_longdouble_type => return .{ .index = .@"long double" },1381 .c_longdouble_type => return .{ .index = .@"long double" },
1293 .f16_type => return .{ .index = .zig_f16 },1382 .f16_type => return CType.f16,
1294 .f32_type => return .{ .index = .zig_f32 },1383 .f32_type => return CType.f32,
1295 .f64_type => return .{ .index = .zig_f64 },1384 .f64_type => return CType.f64,
1296 .f80_type => return .{ .index = .zig_f80 },1385 .f80_type => return CType.f80,
1297 .f128_type => return .{ .index = .zig_f128 },1386 .f128_type => return CType.f128,
1298 .bool_type, .optional_noreturn_type => return .{ .index = .bool },1387 .bool_type, .optional_noreturn_type => return CType.bool,
1299 .noreturn_type,1388 .noreturn_type,
1300 .anyframe_type,1389 .anyframe_type,
1301 .generic_poison_type,1390 .generic_poison_type,
...@@ -1324,17 +1413,17 @@ pub const Pool = struct {...@@ -1324,17 +1413,17 @@ pub const Pool = struct {
1324 }, mod, kind),1413 }, mod, kind),
1325 .manyptr_u8_type,1414 .manyptr_u8_type,
1326 => return pool.getPointer(allocator, .{1415 => return pool.getPointer(allocator, .{
1327 .elem_ctype = .{ .index = .uint8_t },1416 .elem_ctype = CType.u8,
1328 }),1417 }),
1329 .manyptr_const_u8_type,1418 .manyptr_const_u8_type,
1330 .manyptr_const_u8_sentinel_0_type,1419 .manyptr_const_u8_sentinel_0_type,
1331 => return pool.getPointer(allocator, .{1420 => return pool.getPointer(allocator, .{
1332 .elem_ctype = .{ .index = .uint8_t },1421 .elem_ctype = CType.u8,
1333 .@"const" = true,1422 .@"const" = true,
1334 }),1423 }),
1335 .single_const_pointer_to_comptime_int_type,1424 .single_const_pointer_to_comptime_int_type,
1336 => return pool.getPointer(allocator, .{1425 => return pool.getPointer(allocator, .{
1337 .elem_ctype = .{ .index = .void },1426 .elem_ctype = CType.void,
1338 .@"const" = true,1427 .@"const" = true,
1339 }),1428 }),
1340 .slice_const_u8_type,1429 .slice_const_u8_type,
...@@ -1343,16 +1432,16 @@ pub const Pool = struct {...@@ -1343,16 +1432,16 @@ pub const Pool = struct {
1343 const target = &mod.resolved_target.result;1432 const target = &mod.resolved_target.result;
1344 var fields = [_]Info.Field{1433 var fields = [_]Info.Field{
1345 .{1434 .{
1346 .name = try pool.string(allocator, "ptr"),1435 .name = .{ .index = .ptr },
1347 .ctype = try pool.getPointer(allocator, .{1436 .ctype = try pool.getPointer(allocator, .{
1348 .elem_ctype = .{ .index = .uint8_t },1437 .elem_ctype = CType.u8,
1349 .@"const" = true,1438 .@"const" = true,
1350 }),1439 }),
1351 .alignas = AlignAs.fromAbiAlignment(Type.ptrAbiAlignment(target.*)),1440 .alignas = AlignAs.fromAbiAlignment(Type.ptrAbiAlignment(target.*)),
1352 },1441 },
1353 .{1442 .{
1354 .name = try pool.string(allocator, "len"),1443 .name = .{ .index = .len },
1355 .ctype = .{ .index = .uintptr_t },1444 .ctype = CType.usize,
1356 .alignas = AlignAs.fromAbiAlignment(1445 .alignas = AlignAs.fromAbiAlignment(
1357 Type.intAbiAlignment(target.ptrBitWidth(), target.*),1446 Type.intAbiAlignment(target.ptrBitWidth(), target.*),
1358 ),1447 ),
...@@ -1442,7 +1531,7 @@ pub const Pool = struct {...@@ -1442,7 +1531,7 @@ pub const Pool = struct {
1442 const target = &mod.resolved_target.result;1531 const target = &mod.resolved_target.result;
1443 var fields = [_]Info.Field{1532 var fields = [_]Info.Field{
1444 .{1533 .{
1445 .name = try pool.string(allocator, "ptr"),1534 .name = .{ .index = .ptr },
1446 .ctype = try pool.fromType(1535 .ctype = try pool.fromType(
1447 allocator,1536 allocator,
1448 scratch,1537 scratch,
...@@ -1454,8 +1543,8 @@ pub const Pool = struct {...@@ -1454,8 +1543,8 @@ pub const Pool = struct {
1454 .alignas = AlignAs.fromAbiAlignment(Type.ptrAbiAlignment(target.*)),1543 .alignas = AlignAs.fromAbiAlignment(Type.ptrAbiAlignment(target.*)),
1455 },1544 },
1456 .{1545 .{
1457 .name = try pool.string(allocator, "len"),1546 .name = .{ .index = .len },
1458 .ctype = .{ .index = .uintptr_t },1547 .ctype = CType.usize,
1459 .alignas = AlignAs.fromAbiAlignment(1548 .alignas = AlignAs.fromAbiAlignment(
1460 Type.intAbiAlignment(target.ptrBitWidth(), target.*),1549 Type.intAbiAlignment(target.ptrBitWidth(), target.*),
1461 ),1550 ),
...@@ -1466,7 +1555,7 @@ pub const Pool = struct {...@@ -1466,7 +1555,7 @@ pub const Pool = struct {
1466 },1555 },
1467 .array_type => |array_info| {1556 .array_type => |array_info| {
1468 const len = array_info.lenIncludingSentinel();1557 const len = array_info.lenIncludingSentinel();
1469 if (len == 0) return .{ .index = .void };1558 if (len == 0) return CType.void;
1470 const elem_type = Type.fromInterned(array_info.child);1559 const elem_type = Type.fromInterned(array_info.child);
1471 const elem_ctype = try pool.fromType(1560 const elem_ctype = try pool.fromType(
1472 allocator,1561 allocator,
...@@ -1476,7 +1565,7 @@ pub const Pool = struct {...@@ -1476,7 +1565,7 @@ pub const Pool = struct {
1476 mod,1565 mod,
1477 kind.noParameter(),1566 kind.noParameter(),
1478 );1567 );
1479 if (elem_ctype.index == .void) return .{ .index = .void };1568 if (elem_ctype.index == .void) return CType.void;
1480 const array_ctype = try pool.getArray(allocator, .{1569 const array_ctype = try pool.getArray(allocator, .{
1481 .elem_ctype = elem_ctype,1570 .elem_ctype = elem_ctype,
1482 .len = len,1571 .len = len,
...@@ -1484,7 +1573,7 @@ pub const Pool = struct {...@@ -1484,7 +1573,7 @@ pub const Pool = struct {
1484 if (!kind.isParameter()) return array_ctype;1573 if (!kind.isParameter()) return array_ctype;
1485 var fields = [_]Info.Field{1574 var fields = [_]Info.Field{
1486 .{1575 .{
1487 .name = try pool.string(allocator, "array"),1576 .name = .{ .index = .array },
1488 .ctype = array_ctype,1577 .ctype = array_ctype,
1489 .alignas = AlignAs.fromAbiAlignment(elem_type.abiAlignment(zcu)),1578 .alignas = AlignAs.fromAbiAlignment(elem_type.abiAlignment(zcu)),
1490 },1579 },
...@@ -1492,7 +1581,7 @@ pub const Pool = struct {...@@ -1492,7 +1581,7 @@ pub const Pool = struct {
1492 return pool.fromFields(allocator, .@"struct", &fields, kind);1581 return pool.fromFields(allocator, .@"struct", &fields, kind);
1493 },1582 },
1494 .vector_type => |vector_info| {1583 .vector_type => |vector_info| {
1495 if (vector_info.len == 0) return .{ .index = .void };1584 if (vector_info.len == 0) return CType.void;
1496 const elem_type = Type.fromInterned(vector_info.child);1585 const elem_type = Type.fromInterned(vector_info.child);
1497 const elem_ctype = try pool.fromType(1586 const elem_ctype = try pool.fromType(
1498 allocator,1587 allocator,
...@@ -1502,7 +1591,7 @@ pub const Pool = struct {...@@ -1502,7 +1591,7 @@ pub const Pool = struct {
1502 mod,1591 mod,
1503 kind.noParameter(),1592 kind.noParameter(),
1504 );1593 );
1505 if (elem_ctype.index == .void) return .{ .index = .void };1594 if (elem_ctype.index == .void) return CType.void;
1506 const vector_ctype = try pool.getVector(allocator, .{1595 const vector_ctype = try pool.getVector(allocator, .{
1507 .elem_ctype = elem_ctype,1596 .elem_ctype = elem_ctype,
1508 .len = vector_info.len,1597 .len = vector_info.len,
...@@ -1510,7 +1599,7 @@ pub const Pool = struct {...@@ -1510,7 +1599,7 @@ pub const Pool = struct {
1510 if (!kind.isParameter()) return vector_ctype;1599 if (!kind.isParameter()) return vector_ctype;
1511 var fields = [_]Info.Field{1600 var fields = [_]Info.Field{
1512 .{1601 .{
1513 .name = try pool.string(allocator, "array"),1602 .name = .{ .index = .array },
1514 .ctype = vector_ctype,1603 .ctype = vector_ctype,
1515 .alignas = AlignAs.fromAbiAlignment(elem_type.abiAlignment(zcu)),1604 .alignas = AlignAs.fromAbiAlignment(elem_type.abiAlignment(zcu)),
1516 },1605 },
...@@ -1518,7 +1607,7 @@ pub const Pool = struct {...@@ -1518,7 +1607,7 @@ pub const Pool = struct {
1518 return pool.fromFields(allocator, .@"struct", &fields, kind);1607 return pool.fromFields(allocator, .@"struct", &fields, kind);
1519 },1608 },
1520 .opt_type => |payload_type| {1609 .opt_type => |payload_type| {
1521 if (ip.isNoReturn(payload_type)) return .{ .index = .void };1610 if (ip.isNoReturn(payload_type)) return CType.void;
1522 const payload_ctype = try pool.fromType(1611 const payload_ctype = try pool.fromType(
1523 allocator,1612 allocator,
1524 scratch,1613 scratch,
...@@ -1527,7 +1616,7 @@ pub const Pool = struct {...@@ -1527,7 +1616,7 @@ pub const Pool = struct {
1527 mod,1616 mod,
1528 kind.noParameter(),1617 kind.noParameter(),
1529 );1618 );
1530 if (payload_ctype.index == .void) return .{ .index = .bool };1619 if (payload_ctype.index == .void) return CType.bool;
1531 switch (payload_type) {1620 switch (payload_type) {
1532 .anyerror_type => return payload_ctype,1621 .anyerror_type => return payload_ctype,
1533 else => switch (ip.indexToKey(payload_type)) {1622 else => switch (ip.indexToKey(payload_type)) {
...@@ -1539,12 +1628,12 @@ pub const Pool = struct {...@@ -1539,12 +1628,12 @@ pub const Pool = struct {
1539 }1628 }
1540 var fields = [_]Info.Field{1629 var fields = [_]Info.Field{
1541 .{1630 .{
1542 .name = try pool.string(allocator, "is_null"),1631 .name = .{ .index = .is_null },
1543 .ctype = .{ .index = .bool },1632 .ctype = CType.bool,
1544 .alignas = AlignAs.fromAbiAlignment(.@"1"),1633 .alignas = AlignAs.fromAbiAlignment(.@"1"),
1545 },1634 },
1546 .{1635 .{
1547 .name = try pool.string(allocator, "payload"),1636 .name = .{ .index = .payload },
1548 .ctype = payload_ctype,1637 .ctype = payload_ctype,
1549 .alignas = AlignAs.fromAbiAlignment(1638 .alignas = AlignAs.fromAbiAlignment(
1550 Type.fromInterned(payload_type).abiAlignment(zcu),1639 Type.fromInterned(payload_type).abiAlignment(zcu),
...@@ -1574,14 +1663,14 @@ pub const Pool = struct {...@@ -1574,14 +1663,14 @@ pub const Pool = struct {
1574 const target = &mod.resolved_target.result;1663 const target = &mod.resolved_target.result;
1575 var fields = [_]Info.Field{1664 var fields = [_]Info.Field{
1576 .{1665 .{
1577 .name = try pool.string(allocator, "error"),1666 .name = .{ .index = .@"error" },
1578 .ctype = error_set_ctype,1667 .ctype = error_set_ctype,
1579 .alignas = AlignAs.fromAbiAlignment(1668 .alignas = AlignAs.fromAbiAlignment(
1580 Type.intAbiAlignment(error_set_bits, target.*),1669 Type.intAbiAlignment(error_set_bits, target.*),
1581 ),1670 ),
1582 },1671 },
1583 .{1672 .{
1584 .name = try pool.string(allocator, "payload"),1673 .name = .{ .index = .payload },
1585 .ctype = payload_ctype,1674 .ctype = payload_ctype,
1586 .alignas = AlignAs.fromAbiAlignment(payload_type.abiAlignment(zcu)),1675 .alignas = AlignAs.fromAbiAlignment(payload_type.abiAlignment(zcu)),
1587 },1676 },
...@@ -1600,7 +1689,7 @@ pub const Pool = struct {...@@ -1600,7 +1689,7 @@ pub const Pool = struct {
1600 if (kind.isForward()) return if (ty.hasRuntimeBitsIgnoreComptime(zcu))1689 if (kind.isForward()) return if (ty.hasRuntimeBitsIgnoreComptime(zcu))
1601 fwd_decl1690 fwd_decl
1602 else1691 else
1603 .{ .index = .void };1692 CType.void;
1604 const scratch_top = scratch.items.len;1693 const scratch_top = scratch.items.len;
1605 defer scratch.shrinkRetainingCapacity(scratch_top);1694 defer scratch.shrinkRetainingCapacity(scratch_top);
1606 try scratch.ensureUnusedCapacity(1695 try scratch.ensureUnusedCapacity(
...@@ -1627,7 +1716,7 @@ pub const Pool = struct {...@@ -1627,7 +1716,7 @@ pub const Pool = struct {
1627 .unwrap()) |field_name|1716 .unwrap()) |field_name|
1628 try pool.string(allocator, field_name.toSlice(ip))1717 try pool.string(allocator, field_name.toSlice(ip))
1629 else1718 else
1630 try pool.fmt(allocator, "f{d}", .{field_index});1719 String.fromUnnamed(@intCast(field_index));
1631 const field_alignas = AlignAs.fromAlignment(.{1720 const field_alignas = AlignAs.fromAlignment(.{
1632 .@"align" = loaded_struct.fieldAlign(ip, field_index),1721 .@"align" = loaded_struct.fieldAlign(ip, field_index),
1633 .abi = field_type.abiAlignment(zcu),1722 .abi = field_type.abiAlignment(zcu),
...@@ -1644,7 +1733,7 @@ pub const Pool = struct {...@@ -1644,7 +1733,7 @@ pub const Pool = struct {
1644 scratch.items.len - scratch_top,1733 scratch.items.len - scratch_top,
1645 @typeInfo(Field).Struct.fields.len,1734 @typeInfo(Field).Struct.fields.len,
1646 ));1735 ));
1647 if (fields_len == 0) return .{ .index = .void };1736 if (fields_len == 0) return CType.void;
1648 try pool.ensureUnusedCapacity(allocator, 1);1737 try pool.ensureUnusedCapacity(allocator, 1);
1649 const extra_index = try pool.addHashedExtra(allocator, &hasher, Aggregate, .{1738 const extra_index = try pool.addHashedExtra(allocator, &hasher, Aggregate, .{
1650 .fwd_decl = fwd_decl.index,1739 .fwd_decl = fwd_decl.index,
...@@ -1700,7 +1789,7 @@ pub const Pool = struct {...@@ -1700,7 +1789,7 @@ pub const Pool = struct {
1700 scratch.items.len - scratch_top,1789 scratch.items.len - scratch_top,
1701 @typeInfo(Field).Struct.fields.len,1790 @typeInfo(Field).Struct.fields.len,
1702 ));1791 ));
1703 if (fields_len == 0) return .{ .index = .void };1792 if (fields_len == 0) return CType.void;
1704 if (kind.isForward()) {1793 if (kind.isForward()) {
1705 try pool.ensureUnusedCapacity(allocator, 1);1794 try pool.ensureUnusedCapacity(allocator, 1);
1706 const extra_index = try pool.addHashedExtra(1795 const extra_index = try pool.addHashedExtra(
...@@ -1739,7 +1828,7 @@ pub const Pool = struct {...@@ -1739,7 +1828,7 @@ pub const Pool = struct {
1739 if (kind.isForward()) return if (ty.hasRuntimeBitsIgnoreComptime(zcu))1828 if (kind.isForward()) return if (ty.hasRuntimeBitsIgnoreComptime(zcu))
1740 fwd_decl1829 fwd_decl
1741 else1830 else
1742 .{ .index = .void };1831 CType.void;
1743 const loaded_tag = loaded_union.loadTagType(ip);1832 const loaded_tag = loaded_union.loadTagType(ip);
1744 const scratch_top = scratch.items.len;1833 const scratch_top = scratch.items.len;
1745 defer scratch.shrinkRetainingCapacity(scratch_top);1834 defer scratch.shrinkRetainingCapacity(scratch_top);
...@@ -1786,7 +1875,7 @@ pub const Pool = struct {...@@ -1786,7 +1875,7 @@ pub const Pool = struct {
1786 @typeInfo(Field).Struct.fields.len,1875 @typeInfo(Field).Struct.fields.len,
1787 ));1876 ));
1788 if (!has_tag) {1877 if (!has_tag) {
1789 if (fields_len == 0) return .{ .index = .void };1878 if (fields_len == 0) return CType.void;
1790 try pool.ensureUnusedCapacity(allocator, 1);1879 try pool.ensureUnusedCapacity(allocator, 1);
1791 const extra_index = try pool.addHashedExtra(1880 const extra_index = try pool.addHashedExtra(
1792 allocator,1881 allocator,
...@@ -1813,7 +1902,7 @@ pub const Pool = struct {...@@ -1813,7 +1902,7 @@ pub const Pool = struct {
1813 );1902 );
1814 if (tag_ctype.index != .void) {1903 if (tag_ctype.index != .void) {
1815 struct_fields[struct_fields_len] = .{1904 struct_fields[struct_fields_len] = .{
1816 .name = try pool.string(allocator, "tag"),1905 .name = .{ .index = .tag },
1817 .ctype = tag_ctype,1906 .ctype = tag_ctype,
1818 .alignas = AlignAs.fromAbiAlignment(tag_type.abiAlignment(zcu)),1907 .alignas = AlignAs.fromAbiAlignment(tag_type.abiAlignment(zcu)),
1819 };1908 };
...@@ -1846,14 +1935,14 @@ pub const Pool = struct {...@@ -1846,14 +1935,14 @@ pub const Pool = struct {
1846 };1935 };
1847 if (payload_ctype.index != .void) {1936 if (payload_ctype.index != .void) {
1848 struct_fields[struct_fields_len] = .{1937 struct_fields[struct_fields_len] = .{
1849 .name = try pool.string(allocator, "payload"),1938 .name = .{ .index = .payload },
1850 .ctype = payload_ctype,1939 .ctype = payload_ctype,
1851 .alignas = AlignAs.fromAbiAlignment(payload_align),1940 .alignas = AlignAs.fromAbiAlignment(payload_align),
1852 };1941 };
1853 struct_fields_len += 1;1942 struct_fields_len += 1;
1854 }1943 }
1855 }1944 }
1856 if (struct_fields_len == 0) return .{ .index = .void };1945 if (struct_fields_len == 0) return CType.void;
1857 sortFields(struct_fields[0..struct_fields_len]);1946 sortFields(struct_fields[0..struct_fields_len]);
1858 return pool.getAggregate(allocator, .{1947 return pool.getAggregate(allocator, .{
1859 .tag = .@"struct",1948 .tag = .@"struct",
...@@ -1867,7 +1956,7 @@ pub const Pool = struct {...@@ -1867,7 +1956,7 @@ pub const Pool = struct {
1867 }, mod, kind),1956 }, mod, kind),
1868 }1957 }
1869 },1958 },
1870 .opaque_type => return .{ .index = .void },1959 .opaque_type => return CType.void,
1871 .enum_type => return pool.fromType(1960 .enum_type => return pool.fromType(
1872 allocator,1961 allocator,
1873 scratch,1962 scratch,
...@@ -1876,7 +1965,7 @@ pub const Pool = struct {...@@ -1876,7 +1965,7 @@ pub const Pool = struct {
1876 mod,1965 mod,
1877 kind,1966 kind,
1878 ),1967 ),
1879 .func_type => |func_info| if (func_info.is_generic) return .{ .index = .void } else {1968 .func_type => |func_info| if (func_info.is_generic) return CType.void else {
1880 const scratch_top = scratch.items.len;1969 const scratch_top = scratch.items.len;
1881 defer scratch.shrinkRetainingCapacity(scratch_top);1970 defer scratch.shrinkRetainingCapacity(scratch_top);
1882 try scratch.ensureUnusedCapacity(allocator, func_info.param_types.len);1971 try scratch.ensureUnusedCapacity(allocator, func_info.param_types.len);
...@@ -1890,7 +1979,7 @@ pub const Pool = struct {...@@ -1890,7 +1979,7 @@ pub const Pool = struct {
1890 zcu,1979 zcu,
1891 mod,1980 mod,
1892 kind.asParameter(),1981 kind.asParameter(),
1893 ) else .{ .index = .void };1982 ) else CType.void;
1894 for (0..func_info.param_types.len) |param_index| {1983 for (0..func_info.param_types.len) |param_index| {
1895 const param_type = Type.fromInterned(1984 const param_type = Type.fromInterned(
1896 func_info.param_types.get(ip)[param_index],1985 func_info.param_types.get(ip)[param_index],
...@@ -2024,7 +2113,10 @@ pub const Pool = struct {...@@ -2024,7 +2113,10 @@ pub const Pool = struct {
2024 });2113 });
2025 for (0..fields.len) |field_index| {2114 for (0..fields.len) |field_index| {
2026 const field = fields.at(field_index, source_pool);2115 const field = fields.at(field_index, source_pool);
2027 const field_name = try pool.string(allocator, field.name.slice(source_pool));2116 const field_name = if (field.name.toPoolSlice(source_pool)) |slice|
2117 try pool.string(allocator, slice)
2118 else
2119 field.name;
2028 pool.addExtraAssumeCapacity(Field, .{2120 pool.addExtraAssumeCapacity(Field, .{
2029 .name = field_name.index,2121 .name = field_name.index,
2030 .ctype = pool_adapter.copy(field.ctype).index,2122 .ctype = pool_adapter.copy(field.ctype).index,
...@@ -2054,7 +2146,10 @@ pub const Pool = struct {...@@ -2054,7 +2146,10 @@ pub const Pool = struct {
2054 });2146 });
2055 for (0..aggregate_info.fields.len) |field_index| {2147 for (0..aggregate_info.fields.len) |field_index| {
2056 const field = aggregate_info.fields.at(field_index, source_pool);2148 const field = aggregate_info.fields.at(field_index, source_pool);
2057 const field_name = try pool.string(allocator, field.name.slice(source_pool));2149 const field_name = if (field.name.toPoolSlice(source_pool)) |slice|
2150 try pool.string(allocator, slice)
2151 else
2152 field.name;
2058 pool.addExtraAssumeCapacity(Field, .{2153 pool.addExtraAssumeCapacity(Field, .{
2059 .name = field_name.index,2154 .name = field_name.index,
2060 .ctype = pool_adapter.copy(field.ctype).index,2155 .ctype = pool_adapter.copy(field.ctype).index,
...@@ -2082,8 +2177,8 @@ pub const Pool = struct {...@@ -2082,8 +2177,8 @@ pub const Pool = struct {
2082 return .{ ctype, gop.found_existing };2177 return .{ ctype, gop.found_existing };
2083 }2178 }
20842179
2085 pub fn string(pool: *Pool, allocator: std.mem.Allocator, str: []const u8) !String {2180 pub fn string(pool: *Pool, allocator: std.mem.Allocator, slice: []const u8) !String {
2086 try pool.string_bytes.appendSlice(allocator, str);2181 try pool.string_bytes.appendSlice(allocator, slice);
2087 return pool.trailingString(allocator);2182 return pool.trailingString(allocator);
2088 }2183 }
20892184
...@@ -2111,12 +2206,15 @@ pub const Pool = struct {...@@ -2111,12 +2206,15 @@ pub const Pool = struct {
2111 fn updateExtra(hasher: *Hasher, comptime Extra: type, extra: Extra, pool: *const Pool) void {2206 fn updateExtra(hasher: *Hasher, comptime Extra: type, extra: Extra, pool: *const Pool) void {
2112 inline for (@typeInfo(Extra).Struct.fields) |field| {2207 inline for (@typeInfo(Extra).Struct.fields) |field| {
2113 const value = @field(extra, field.name);2208 const value = @field(extra, field.name);
2114 hasher.update(switch (field.type) {2209 switch (field.type) {
2115 Pool.Tag, String, CType => unreachable,2210 Pool.Tag, String, CType => unreachable,
2116 CType.Index => (CType{ .index = value }).hash(pool),2211 CType.Index => hasher.update((CType{ .index = value }).hash(pool)),
2117 String.Index => (String{ .index = value }).slice(pool),2212 String.Index => if ((String{ .index = value }).toPoolSlice(pool)) |slice|
2118 else => value,2213 hasher.update(slice)
2119 });2214 else
2215 hasher.update(@intFromEnum(value)),
2216 else => hasher.update(value),
2217 }
2120 }2218 }
2121 }2219 }
2122 fn update(hasher: *Hasher, data: anytype) void {2220 fn update(hasher: *Hasher, data: anytype) void {
...@@ -2231,30 +2329,30 @@ pub const Pool = struct {...@@ -2231,30 +2329,30 @@ pub const Pool = struct {
2231 }2329 }
22322330
2233 fn trailingString(pool: *Pool, allocator: std.mem.Allocator) !String {2331 fn trailingString(pool: *Pool, allocator: std.mem.Allocator) !String {
2234 const StringAdapter = struct {2332 const start = pool.string_indices.getLast();
2235 pool: *const Pool,2333 const slice: []const u8 = pool.string_bytes.items[start..];
2236 pub fn hash(_: @This(), slice: []const u8) Map.Hash {2334 if (slice.len >= 2 and slice[0] == 'f' and switch (slice[1]) {
2237 return @truncate(Hasher.Impl.hash(1, slice));2335 '0' => slice.len == 2,
2238 }2336 '1'...'9' => true,
2239 pub fn eql(string_adapter: @This(), lhs_slice: []const u8, _: void, rhs_index: usize) bool {2337 else => false,
2240 const rhs_string: String = .{ .index = @enumFromInt(rhs_index) };2338 }) if (std.fmt.parseInt(u31, slice[1..], 10)) |unnamed| {
2241 const rhs_slice = rhs_string.slice(string_adapter.pool);2339 pool.string_bytes.shrinkRetainingCapacity(start);
2242 return std.mem.eql(u8, lhs_slice, rhs_slice);2340 return String.fromUnnamed(unnamed);
2243 }2341 } else |_| {};
2244 };2342 if (std.meta.stringToEnum(String.Index, slice)) |index| {
2343 pool.string_bytes.shrinkRetainingCapacity(start);
2344 return .{ .index = index };
2345 }
2346
2245 try pool.string_map.ensureUnusedCapacity(allocator, 1);2347 try pool.string_map.ensureUnusedCapacity(allocator, 1);
2246 try pool.string_indices.ensureUnusedCapacity(allocator, 1);2348 try pool.string_indices.ensureUnusedCapacity(allocator, 1);
22472349
2248 const start = pool.string_indices.getLast();2350 const gop = pool.string_map.getOrPutAssumeCapacityAdapted(slice, String.Adapter{ .pool = pool });
2249 const gop = pool.string_map.getOrPutAssumeCapacityAdapted(
2250 @as([]const u8, pool.string_bytes.items[start..]),
2251 StringAdapter{ .pool = pool },
2252 );
2253 if (gop.found_existing)2351 if (gop.found_existing)
2254 pool.string_bytes.shrinkRetainingCapacity(start)2352 pool.string_bytes.shrinkRetainingCapacity(start)
2255 else2353 else
2256 pool.string_indices.appendAssumeCapacity(@intCast(pool.string_bytes.items.len));2354 pool.string_indices.appendAssumeCapacity(@intCast(pool.string_bytes.items.len));
2257 return .{ .index = @enumFromInt(gop.index) };2355 return String.fromPoolIndex(gop.index);
2258 }2356 }
22592357
2260 const Item = struct {2358 const Item = struct {
test/behavior/abs.zig-2
...@@ -214,7 +214,6 @@ fn testAbsIntVectors(comptime len: comptime_int) !void {...@@ -214,7 +214,6 @@ fn testAbsIntVectors(comptime len: comptime_int) !void {
214}214}
215215
216test "@abs unsigned int vectors" {216test "@abs unsigned int vectors" {
217 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
218 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO217 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
219 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO218 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
220 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO219 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
...@@ -274,7 +273,6 @@ fn testAbsUnsignedIntVectors(comptime len: comptime_int) !void {...@@ -274,7 +273,6 @@ fn testAbsUnsignedIntVectors(comptime len: comptime_int) !void {
274}273}
275274
276test "@abs float vectors" {275test "@abs float vectors" {
277 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
278 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO276 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
279 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO277 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
280 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO278 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
test/behavior/call.zig+4-4
...@@ -267,7 +267,6 @@ test "arguments to comptime parameters generated in comptime blocks" {...@@ -267,7 +267,6 @@ test "arguments to comptime parameters generated in comptime blocks" {
267test "forced tail call" {267test "forced tail call" {
268 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO268 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
269 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO269 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
270 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
271 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO270 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
272 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO271 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
273 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO272 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -280,6 +279,8 @@ test "forced tail call" {...@@ -280,6 +279,8 @@ test "forced tail call" {
280 }279 }
281 }280 }
282281
282 if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // MSVC doesn't support always tail calls
283
283 const S = struct {284 const S = struct {
284 fn fibonacciTailInternal(n: u16, a: u16, b: u16) u16 {285 fn fibonacciTailInternal(n: u16, a: u16, b: u16) u16 {
285 if (n == 0) return a;286 if (n == 0) return a;
...@@ -301,7 +302,6 @@ test "forced tail call" {...@@ -301,7 +302,6 @@ test "forced tail call" {
301test "inline call preserves tail call" {302test "inline call preserves tail call" {
302 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO303 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
303 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO304 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
304 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
305 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO305 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
306 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO306 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
307 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO307 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -314,6 +314,8 @@ test "inline call preserves tail call" {...@@ -314,6 +314,8 @@ test "inline call preserves tail call" {
314 }314 }
315 }315 }
316316
317 if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // MSVC doesn't support always tail calls
318
317 const max = std.math.maxInt(u16);319 const max = std.math.maxInt(u16);
318 const S = struct {320 const S = struct {
319 var a: u16 = 0;321 var a: u16 = 0;
...@@ -432,7 +434,6 @@ test "method call as parameter type" {...@@ -432,7 +434,6 @@ test "method call as parameter type" {
432434
433test "non-anytype generic parameters provide result type" {435test "non-anytype generic parameters provide result type" {
434 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO436 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
435 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
436 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO437 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
437 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO438 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
438 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO439 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -463,7 +464,6 @@ test "non-anytype generic parameters provide result type" {...@@ -463,7 +464,6 @@ test "non-anytype generic parameters provide result type" {
463464
464test "argument to generic function has correct result type" {465test "argument to generic function has correct result type" {
465 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO466 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
466 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
467 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO467 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
468 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO468 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
469 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO469 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/call_tail.zig+2-1
...@@ -45,9 +45,10 @@ test "arguments pointed to on stack into tailcall" {...@@ -45,9 +45,10 @@ test "arguments pointed to on stack into tailcall" {
45 else => {},45 else => {},
46 }46 }
47 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;47 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
48 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
49 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;48 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
5049
50 if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // MSVC doesn't support always tail calls
51
51 var data = [_]u64{ 1, 6, 2, 7, 1, 9, 3 };52 var data = [_]u64{ 1, 6, 2, 7, 1, 9, 3 };
52 base = @intFromPtr(&data);53 base = @intFromPtr(&data);
53 insertionSort(data[0..]);54 insertionSort(data[0..]);
test/behavior/cast.zig+1-2
...@@ -1119,7 +1119,6 @@ fn foobar(func: PFN_void) !void {...@@ -1119,7 +1119,6 @@ fn foobar(func: PFN_void) !void {
1119}1119}
11201120
1121test "cast function with an opaque parameter" {1121test "cast function with an opaque parameter" {
1122 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1123 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;1122 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
11241123
1125 if (builtin.zig_backend == .stage2_c) {1124 if (builtin.zig_backend == .stage2_c) {
...@@ -1461,6 +1460,7 @@ test "pointer to empty struct literal to mutable slice" {...@@ -1461,6 +1460,7 @@ test "pointer to empty struct literal to mutable slice" {
1461test "coerce between pointers of compatible differently-named floats" {1460test "coerce between pointers of compatible differently-named floats" {
1462 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1461 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1463 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1462 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1463 if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows and !builtin.link_libc) return error.SkipZigTest;
1464 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1464 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1465 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;1465 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1466 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;1466 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
...@@ -2558,7 +2558,6 @@ test "@intCast vector of signed integer" {...@@ -2558,7 +2558,6 @@ test "@intCast vector of signed integer" {
2558 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO2558 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2559 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO2559 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
2560 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO2560 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2561 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
2562 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO2561 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
25632562
2564 var x: @Vector(4, i32) = .{ 1, 2, 3, 4 };2563 var x: @Vector(4, i32) = .{ 1, 2, 3, 4 };
test/behavior/export_builtin.zig-3
...@@ -5,7 +5,6 @@ const expect = std.testing.expect;...@@ -5,7 +5,6 @@ const expect = std.testing.expect;
5test "exporting enum type and value" {5test "exporting enum type and value" {
6 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;6 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
7 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;7 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
8 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
98
10 const S = struct {9 const S = struct {
11 const E = enum(c_int) { one, two };10 const E = enum(c_int) { one, two };
...@@ -20,7 +19,6 @@ test "exporting enum type and value" {...@@ -20,7 +19,6 @@ test "exporting enum type and value" {
20test "exporting with internal linkage" {19test "exporting with internal linkage" {
21 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;20 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
22 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;21 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
23 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
2422
25 const S = struct {23 const S = struct {
26 fn foo() callconv(.C) void {}24 fn foo() callconv(.C) void {}
...@@ -34,7 +32,6 @@ test "exporting with internal linkage" {...@@ -34,7 +32,6 @@ test "exporting with internal linkage" {
34test "exporting using field access" {32test "exporting using field access" {
35 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;33 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
36 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;34 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
37 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
3835
39 const S = struct {36 const S = struct {
40 const Inner = struct {37 const Inner = struct {
test/behavior/extern.zig-2
...@@ -16,7 +16,6 @@ test "anyopaque extern symbol" {...@@ -16,7 +16,6 @@ test "anyopaque extern symbol" {
16export var a_mystery_symbol: i32 = 1234;16export var a_mystery_symbol: i32 = 1234;
1717
18test "function extern symbol" {18test "function extern symbol" {
19 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
20 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;19 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
21 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;20 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
22 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;21 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
...@@ -30,7 +29,6 @@ export fn a_mystery_function() i32 {...@@ -30,7 +29,6 @@ export fn a_mystery_function() i32 {
30}29}
3130
32test "function extern symbol matches extern decl" {31test "function extern symbol matches extern decl" {
33 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
34 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;32 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
35 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;33 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
36 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;34 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
test/behavior/fn.zig-1
...@@ -582,7 +582,6 @@ test "pass and return comptime-only types" {...@@ -582,7 +582,6 @@ test "pass and return comptime-only types" {
582test "pointer to alias behaves same as pointer to function" {582test "pointer to alias behaves same as pointer to function" {
583 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;583 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
584 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;584 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
585 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
586 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;585 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
587586
588 const S = struct {587 const S = struct {
test/behavior/globals.zig-3
...@@ -7,7 +7,6 @@ test "store to global array" {...@@ -7,7 +7,6 @@ test "store to global array" {
7 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;7 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
8 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;8 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
9 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;9 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1110
12 try expect(pos[1] == 0.0);11 try expect(pos[1] == 0.0);
13 pos = [2]f32{ 0.0, 1.0 };12 pos = [2]f32{ 0.0, 1.0 };
...@@ -19,7 +18,6 @@ test "store to global vector" {...@@ -19,7 +18,6 @@ test "store to global vector" {
19 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;18 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
20 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;19 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
21 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;20 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
22 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
2321
24 try expect(vpos[1] == 0.0);22 try expect(vpos[1] == 0.0);
25 vpos = @Vector(2, f32){ 0.0, 1.0 };23 vpos = @Vector(2, f32){ 0.0, 1.0 };
...@@ -49,7 +47,6 @@ test "global loads can affect liveness" {...@@ -49,7 +47,6 @@ test "global loads can affect liveness" {
49 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;47 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
50 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;48 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
51 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;49 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
52 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
5350
54 const S = struct {51 const S = struct {
55 const ByRef = struct {52 const ByRef = struct {
test/behavior/optional.zig+49-9
...@@ -55,17 +55,57 @@ fn testNullPtrsEql() !void {...@@ -55,17 +55,57 @@ fn testNullPtrsEql() !void {
55 try expect(&number == x);55 try expect(&number == x);
56}56}
5757
58test "optional with void type" {58test "optional with zero-bit type" {
59 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;59 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
60 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO60 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
61 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
6261
63 const Foo = struct {62 const S = struct {
64 x: ?void,63 fn doTheTest(comptime ZeroBit: type, comptime zero_bit: ZeroBit) !void {
64 const WithRuntime = struct {
65 zero_bit: ZeroBit,
66 runtime: u1,
67 };
68 var with_runtime: WithRuntime = undefined;
69 with_runtime = .{ .zero_bit = zero_bit, .runtime = 0 };
70
71 const Opt = struct { opt: ?ZeroBit };
72 var opt: Opt = .{ .opt = null };
73 try expect(opt.opt == null);
74 try expect(opt.opt != zero_bit);
75 try expect(opt.opt != with_runtime.zero_bit);
76 opt.opt = zero_bit;
77 try expect(opt.opt != null);
78 try expect(opt.opt == zero_bit);
79 try expect(opt.opt == with_runtime.zero_bit);
80 opt = .{ .opt = zero_bit };
81 try expect(opt.opt != null);
82 try expect(opt.opt == zero_bit);
83 try expect(opt.opt == with_runtime.zero_bit);
84 opt.opt = with_runtime.zero_bit;
85 try expect(opt.opt != null);
86 try expect(opt.opt == zero_bit);
87 try expect(opt.opt == with_runtime.zero_bit);
88 opt = .{ .opt = with_runtime.zero_bit };
89 try expect(opt.opt != null);
90 try expect(opt.opt == zero_bit);
91 try expect(opt.opt == with_runtime.zero_bit);
92
93 var two: ?struct { ZeroBit, ZeroBit } = undefined;
94 two = .{ with_runtime.zero_bit, with_runtime.zero_bit };
95 if (!@inComptime()) {
96 try expect(two != null);
97 try expect(two.?[0] == zero_bit);
98 try expect(two.?[0] == with_runtime.zero_bit);
99 try expect(two.?[1] == zero_bit);
100 try expect(two.?[1] == with_runtime.zero_bit);
101 }
102 }
65 };103 };
66 var x = Foo{ .x = null };104
67 _ = &x;105 try S.doTheTest(void, {});
68 try expect(x.x == null);106 try comptime S.doTheTest(void, {});
107 try S.doTheTest(enum { only }, .only);
108 try comptime S.doTheTest(enum { only }, .only);
69}109}
70110
71test "address of unwrap optional" {111test "address of unwrap optional" {
test/behavior/packed-struct.zig+2-1
...@@ -1125,12 +1125,13 @@ test "pointer loaded correctly from packed struct" {...@@ -1125,12 +1125,13 @@ test "pointer loaded correctly from packed struct" {
1125 }1125 }
1126 }1126 }
1127 };1127 };
1128 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1129 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;1128 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1130 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;1129 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1131 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;1130 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
1132 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;1131 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
11331132
1133 if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // crashes MSVC
1134
1134 var ram = try RAM.new();1135 var ram = try RAM.new();
1135 var cpu = try CPU.new(&ram);1136 var cpu = try CPU.new(&ram);
1136 try cpu.tick();1137 try cpu.tick();
test/behavior/undefined.zig-1
...@@ -101,7 +101,6 @@ test "reslice of undefined global var slice" {...@@ -101,7 +101,6 @@ test "reslice of undefined global var slice" {
101test "returned undef is 0xaa bytes when runtime safety is enabled" {101test "returned undef is 0xaa bytes when runtime safety is enabled" {
102 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO102 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
103 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO103 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
104 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
105 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO104 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
106 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;105 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
107106
test/behavior/union.zig-1
...@@ -1644,7 +1644,6 @@ test "undefined-layout union field pointer has correct alignment" {...@@ -1644,7 +1644,6 @@ test "undefined-layout union field pointer has correct alignment" {
1644}1644}
16451645
1646test "packed union field pointer has correct alignment" {1646test "packed union field pointer has correct alignment" {
1647 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
1648 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1647 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1649 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1648 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1650 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1649 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/vector.zig-1
...@@ -1392,7 +1392,6 @@ test "store vector with memset" {...@@ -1392,7 +1392,6 @@ test "store vector with memset" {
1392 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO1392 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1393 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1393 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1394 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO1394 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
1395 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
13961395
1397 if (builtin.zig_backend == .stage2_llvm) {1396 if (builtin.zig_backend == .stage2_llvm) {
1398 switch (builtin.target.cpu.arch) {1397 switch (builtin.target.cpu.arch) {
test/tests.zig+15-7
...@@ -1092,9 +1092,17 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {...@@ -1092,9 +1092,17 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {
1092 // Tracking issue for making the C backend generate C89 compatible code:1092 // Tracking issue for making the C backend generate C89 compatible code:
1093 // https://github.com/ziglang/zig/issues/194681093 // https://github.com/ziglang/zig/issues/19468
1094 "-std=c99",1094 "-std=c99",
1095 "-pedantic",
1096 "-Werror",1095 "-Werror",
10971096
1097 "-Wall",
1098 "-Wembedded-directive",
1099 "-Wempty-translation-unit",
1100 "-Wextra",
1101 "-Wgnu",
1102 "-Winvalid-utf8",
1103 "-Wkeyword-macro",
1104 "-Woverlength-strings",
1105
1098 // Tracking issue for making the C backend generate code1106 // Tracking issue for making the C backend generate code
1099 // that does not trigger warnings:1107 // that does not trigger warnings:
1100 // https://github.com/ziglang/zig/issues/194671108 // https://github.com/ziglang/zig/issues/19467
...@@ -1103,14 +1111,14 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {...@@ -1103,14 +1111,14 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {
1103 "-Wno-builtin-requires-header",1111 "-Wno-builtin-requires-header",
11041112
1105 // spotted on linux1113 // spotted on linux
1106 "-Wno-gnu-folding-constant",1114 "-Wno-braced-scalar-init",
1107 "-Wno-incompatible-function-pointer-types",1115 "-Wno-excess-initializers",
1108 "-Wno-incompatible-pointer-types",1116 "-Wno-incompatible-pointer-types-discards-qualifiers",
1109 "-Wno-overlength-strings",1117 "-Wno-unused",
1118 "-Wno-unused-parameter",
11101119
1111 // spotted on darwin1120 // spotted on darwin
1112 "-Wno-dollar-in-identifier-extension",1121 "-Wno-incompatible-pointer-types",
1113 "-Wno-absolute-value",
1114 },1122 },
1115 });1123 });
1116 compile_c.addIncludePath(b.path("lib")); // for zig.h1124 compile_c.addIncludePath(b.path("lib")); // for zig.h