authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-02-24 21:23:54-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-02-24 21:23:54-05:00
log6398aabb87cc39ddbc4e8fd650545ffcc864f9a6
treef0a5047f5284532f5e86d0e0424b87583298976d
parentc7f479c3cb1f8d876f2169dd5ee1390c46d9cdaa
parentf8aecef6705a75a4c35754bcac32c27602b84711
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #14713 from jacobly0/cbe-behavior

CBE: fix more behavior tests

9 files changed, 1062 insertions(+), 932 deletions(-)

lib/zig.h+63-28
......@@ -5,6 +5,7 @@
55#endif
66#include <float.h>
77#include <limits.h>
8#include <stdarg.h>
89#include <stddef.h>
910#include <stdint.h>
1011
......@@ -77,6 +78,32 @@ typedef char bool;
7778#define zig_cold
7879#endif
7980
81#if zig_has_attribute(flatten)
82#define zig_maybe_flatten __attribute__((flatten))
83#else
84#define zig_maybe_flatten
85#endif
86
87#if zig_has_attribute(noinline)
88#define zig_never_inline __attribute__((noinline)) zig_maybe_flatten
89#elif defined(_MSC_VER)
90#define zig_never_inline __declspec(noinline) zig_maybe_flatten
91#else
92#define zig_never_inline zig_never_inline_unavailable
93#endif
94
95#if zig_has_attribute(not_tail_called)
96#define zig_never_tail __attribute__((not_tail_called)) zig_never_inline
97#else
98#define zig_never_tail zig_never_tail_unavailable
99#endif
100
101#if zig_has_attribute(always_inline)
102#define zig_always_tail __attribute__((musttail))
103#else
104#define zig_always_tail zig_always_tail_unavailable
105#endif
106
80107#if __STDC_VERSION__ >= 199901L
81108#define zig_restrict restrict
82109#elif defined(__GNUC__)
......@@ -1049,7 +1076,7 @@ static inline void zig_vmulo_i16(uint8_t *ov, int16_t *res, int n,
10491076\
10501077 static inline int##w##_t zig_shls_i##w(int##w##_t lhs, int##w##_t rhs, uint8_t bits) { \
10511078 int##w##_t res; \
1052 if ((uint##w##_t)rhs < (uint##w##_t)bits && !zig_shlo_i##w(&res, lhs, rhs, bits)) return res; \
1079 if ((uint##w##_t)rhs < (uint##w##_t)bits && !zig_shlo_i##w(&res, lhs, (uint8_t)rhs, bits)) return res; \
10531080 return lhs < INT##w##_C(0) ? zig_minInt_i(w, bits) : zig_maxInt_i(w, bits); \
10541081 } \
10551082\
......@@ -2383,39 +2410,47 @@ zig_msvc_atomics(i64, int64_t, 64)
23832410
23842411#define zig_msvc_flt_atomics(Type, ReprType, suffix) \
23852412 static inline bool zig_msvc_cmpxchg_##Type(zig_##Type volatile* obj, zig_##Type* expected, zig_##Type desired) { \
2386 ReprType comparand = *((ReprType*)expected); \
2387 ReprType initial = _InterlockedCompareExchange##suffix((ReprType volatile*)obj, *((ReprType*)&desired), comparand); \
2388 bool exchanged = initial == comparand; \
2389 if (!exchanged) { \
2390 *expected = *((zig_##Type*)&initial); \
2391 } \
2392 return exchanged; \
2413 ReprType exchange; \
2414 ReprType comparand; \
2415 ReprType initial; \
2416 bool success; \
2417 memcpy(&comparand, expected, sizeof(comparand)); \
2418 memcpy(&exchange, &desired, sizeof(exchange)); \
2419 initial = _InterlockedCompareExchange##suffix((ReprType volatile*)obj, exchange, comparand); \
2420 success = initial == comparand; \
2421 if (!success) memcpy(expected, &initial, sizeof(*expected)); \
2422 return success; \
23932423 } \
23942424 static inline zig_##Type zig_msvc_atomicrmw_xchg_##Type(zig_##Type volatile* obj, zig_##Type value) { \
2395 ReprType initial = _InterlockedExchange##suffix((ReprType volatile*)obj, *((ReprType*)&value)); \
2396 return *((zig_##Type*)&initial); \
2425 ReprType repr; \
2426 ReprType initial; \
2427 zig_##Type result; \
2428 memcpy(&repr, &value, sizeof(repr)); \
2429 initial = _InterlockedExchange##suffix((ReprType volatile*)obj, repr); \
2430 memcpy(&result, &initial, sizeof(result)); \
2431 return result; \
23972432 } \
23982433 static inline zig_##Type zig_msvc_atomicrmw_add_##Type(zig_##Type volatile* obj, zig_##Type value) { \
2399 bool success = false; \
2400 ReprType new; \
2401 zig_##Type prev; \
2402 while (!success) { \
2403 prev = *obj; \
2404 new = prev + value; \
2405 success = zig_msvc_cmpxchg_##Type(obj, &prev, *((ReprType*)&new)); \
2406 } \
2407 return prev; \
2434 ReprType repr; \
2435 zig_##Type expected; \
2436 zig_##Type desired; \
2437 repr = *(ReprType volatile*)obj; \
2438 memcpy(&expected, &repr, sizeof(expected)); \
2439 do { \
2440 desired = expected + value; \
2441 } while (!zig_msvc_cmpxchg_##Type(obj, &expected, desired)); \
2442 return expected; \
24082443 } \
24092444 static inline zig_##Type zig_msvc_atomicrmw_sub_##Type(zig_##Type volatile* obj, zig_##Type value) { \
2410 bool success = false; \
2411 ReprType new; \
2412 zig_##Type prev; \
2413 while (!success) { \
2414 prev = *obj; \
2415 new = prev - value; \
2416 success = zig_msvc_cmpxchg_##Type(obj, &prev, *((ReprType*)&new)); \
2417 } \
2418 return prev; \
2445 ReprType repr; \
2446 zig_##Type expected; \
2447 zig_##Type desired; \
2448 repr = *(ReprType volatile*)obj; \
2449 memcpy(&expected, &repr, sizeof(expected)); \
2450 do { \
2451 desired = expected - value; \
2452 } while (!zig_msvc_cmpxchg_##Type(obj, &expected, desired)); \
2453 return expected; \
24192454 }
24202455
24212456zig_msvc_flt_atomics(f32, uint32_t, )
src/codegen/c.zig+827-723
......@@ -23,7 +23,6 @@ const libcFloatSuffix = target_util.libcFloatSuffix;
2323const compilerRtFloatAbbrev = target_util.compilerRtFloatAbbrev;
2424const compilerRtIntAbbrev = target_util.compilerRtIntAbbrev;
2525
26const Mutability = enum { @"const", mut };
2726const BigIntLimb = std.math.big.Limb;
2827const BigInt = std.math.big.int;
2928
......@@ -39,7 +38,7 @@ pub const CValue = union(enum) {
3938 constant: Air.Inst.Ref,
4039 /// Index into the parameters
4140 arg: usize,
42 /// The payload field of a parameter
41 /// The array field of a parameter
4342 arg_array: usize,
4443 /// Index into a tuple's fields
4544 field: usize,
......@@ -50,6 +49,8 @@ pub const CValue = union(enum) {
5049 undef: Type,
5150 /// Render the slice as an identifier (using fmtIdent)
5251 identifier: []const u8,
52 /// Render the slice as an payload.identifier (using fmtIdent)
53 payload_identifier: []const u8,
5354 /// Render these bytes literally.
5455 /// TODO make this a [*:0]const u8 to save memory
5556 bytes: []const u8,
......@@ -60,21 +61,22 @@ const BlockData = struct {
6061 result: CValue,
6162};
6263
63const TypedefKind = enum {
64 Forward,
65 Complete,
66};
67
6864pub const CValueMap = std.AutoHashMap(Air.Inst.Ref, CValue);
6965
7066pub const LazyFnKey = union(enum) {
7167 tag_name: Decl.Index,
68 never_tail: Decl.Index,
69 never_inline: Decl.Index,
7270};
7371pub const LazyFnValue = struct {
7472 fn_name: []const u8,
75 data: union {
73 data: Data,
74
75 pub const Data = union {
7676 tag_name: Type,
77 },
77 never_tail: void,
78 never_inline: void,
79 };
7880};
7981pub const LazyFnMap = std.AutoArrayHashMapUnmanaged(LazyFnKey, LazyFnValue);
8082
......@@ -209,6 +211,15 @@ const reserved_idents = std.ComptimeStringMap(void, .{
209211 .{ "volatile", {} },
210212 .{ "while ", {} },
211213
214 // stdarg.h
215 .{ "va_start", {} },
216 .{ "va_arg", {} },
217 .{ "va_end", {} },
218 .{ "va_copy", {} },
219
220 // stddef.h
221 .{ "offsetof", {} },
222
212223 // windows.h
213224 .{ "max", {} },
214225 .{ "min", {} },
......@@ -296,19 +307,19 @@ pub const Function = struct {
296307 const val = f.air.value(inst).?;
297308 const ty = f.air.typeOf(inst);
298309
299 const result = if (lowersToArray(ty, f.object.dg.module.getTarget())) result: {
310 const result: CValue = if (lowersToArray(ty, f.object.dg.module.getTarget())) result: {
300311 const writer = f.object.code_header.writer();
301312 const alignment = 0;
302313 const decl_c_value = try f.allocLocalValue(ty, alignment);
303314 const gpa = f.object.dg.gpa;
304315 try f.allocs.put(gpa, decl_c_value.new_local, true);
305316 try writer.writeAll("static ");
306 try f.object.dg.renderTypeAndName(writer, ty, decl_c_value, .@"const", alignment, .Complete);
317 try f.object.dg.renderTypeAndName(writer, ty, decl_c_value, Const, alignment, .complete);
307318 try writer.writeAll(" = ");
308319 try f.object.dg.renderValue(writer, ty, val, .StaticInitializer);
309320 try writer.writeAll(";\n ");
310321 break :result decl_c_value;
311 } else CValue{ .constant = inst };
322 } else .{ .constant = inst };
312323
313324 gop.value_ptr.* = result;
314325 return result;
......@@ -333,26 +344,24 @@ pub const Function = struct {
333344 .alignment = alignment,
334345 .loop_depth = @intCast(LoopDepth, f.free_locals_stack.items.len - 1),
335346 });
336 return CValue{ .new_local = @intCast(LocalIndex, f.locals.items.len - 1) };
347 return .{ .new_local = @intCast(LocalIndex, f.locals.items.len - 1) };
337348 }
338349
339350 fn allocLocal(f: *Function, inst: Air.Inst.Index, ty: Type) !CValue {
340 const result = try f.allocAlignedLocal(ty, .mut, 0);
351 const result = try f.allocAlignedLocal(ty, .{}, 0);
341352 log.debug("%{d}: allocating t{d}", .{ inst, result.new_local });
342353 return result;
343354 }
344355
345356 /// Only allocates the local; does not print anything.
346 fn allocAlignedLocal(f: *Function, ty: Type, mutability: Mutability, alignment: u32) !CValue {
347 _ = mutability;
348
357 fn allocAlignedLocal(f: *Function, ty: Type, _: CQualifiers, alignment: u32) !CValue {
349358 if (f.getFreeLocals().getPtrContext(ty, f.tyHashCtx())) |locals_list| {
350359 for (locals_list.items, 0..) |local_index, i| {
351360 const local = &f.locals.items[local_index];
352361 if (local.alignment >= alignment) {
353362 local.loop_depth = @intCast(LoopDepth, f.free_locals_stack.items.len - 1);
354363 _ = locals_list.swapRemove(i);
355 return CValue{ .new_local = local_index };
364 return .{ .new_local = local_index };
356365 }
357366 }
358367 }
......@@ -416,12 +425,20 @@ pub const Function = struct {
416425 return f.object.dg.fail(format, args);
417426 }
418427
419 fn renderType(f: *Function, w: anytype, t: Type) !void {
420 return f.object.dg.renderType(w, t, .Complete);
428 fn indexToCType(f: *Function, idx: CType.Index) CType {
429 return f.object.dg.indexToCType(idx);
430 }
431
432 fn typeToIndex(f: *Function, ty: Type, kind: CType.Kind) !CType.Index {
433 return f.object.dg.typeToIndex(ty, kind);
421434 }
422435
423 fn renderTypecast(f: *Function, w: anytype, t: Type) !void {
424 return f.object.dg.renderTypecast(w, t);
436 fn typeToCType(f: *Function, ty: Type, kind: CType.Kind) !CType {
437 return f.object.dg.typeToCType(ty, kind);
438 }
439
440 fn renderType(f: *Function, w: anytype, t: Type) !void {
441 return f.object.dg.renderType(w, t);
425442 }
426443
427444 fn renderIntCast(f: *Function, w: anytype, dest_ty: Type, src: CValue, src_ty: Type, location: ValueRenderLocation) !void {
......@@ -432,11 +449,9 @@ pub const Function = struct {
432449 return f.object.dg.fmtIntLiteral(ty, val);
433450 }
434451
435 fn getTagNameFn(f: *Function, enum_ty: Type) ![]const u8 {
452 fn getLazyFnName(f: *Function, key: LazyFnKey, data: LazyFnValue.Data) ![]const u8 {
436453 const gpa = f.object.dg.gpa;
437 const owner_decl = enum_ty.getOwnerDecl();
438
439 const gop = try f.lazy_fns.getOrPut(gpa, .{ .tag_name = owner_decl });
454 const gop = try f.lazy_fns.getOrPut(gpa, key);
440455 if (!gop.found_existing) {
441456 errdefer _ = f.lazy_fns.pop();
442457
......@@ -445,11 +460,21 @@ pub const Function = struct {
445460 const arena = promoted.arena.allocator();
446461
447462 gop.value_ptr.* = .{
448 .fn_name = try std.fmt.allocPrint(arena, "zig_tagName_{}__{d}", .{
449 fmtIdent(mem.span(f.object.dg.module.declPtr(owner_decl).name)),
450 @enumToInt(owner_decl),
451 }),
452 .data = .{ .tag_name = try enum_ty.copy(arena) },
463 .fn_name = switch (key) {
464 .tag_name,
465 .never_tail,
466 .never_inline,
467 => |owner_decl| try std.fmt.allocPrint(arena, "zig_{s}_{}__{d}", .{
468 @tagName(key),
469 fmtIdent(mem.span(f.object.dg.module.declPtr(owner_decl).name)),
470 @enumToInt(owner_decl),
471 }),
472 },
473 .data = switch (key) {
474 .tag_name => .{ .tag_name = try data.tag_name.copy(arena) },
475 .never_tail => .{ .never_tail = data.never_tail },
476 .never_inline => .{ .never_inline = data.never_inline },
477 },
453478 };
454479 }
455480 return gop.value_ptr.fn_name;
......@@ -518,7 +543,7 @@ pub const DeclGen = struct {
518543
519544 // Render an undefined pointer if we have a pointer to a zero-bit or comptime type.
520545 if (ty.isPtrAtRuntime() and !decl.ty.isFnOrHasRuntimeBits()) {
521 return dg.writeCValue(writer, CValue{ .undef = ty });
546 return dg.writeCValue(writer, .{ .undef = ty });
522547 }
523548
524549 // Chase function values in order to be able to reference the original function.
......@@ -532,7 +557,7 @@ pub const DeclGen = struct {
532557 try writer.writeByte('{');
533558 } else {
534559 try writer.writeByte('(');
535 try dg.renderTypecast(writer, ty);
560 try dg.renderType(writer, ty);
536561 try writer.writeAll("){ .ptr = ");
537562 }
538563
......@@ -559,7 +584,7 @@ pub const DeclGen = struct {
559584 const need_typecast = if (ty.castPtrToFn()) |_| false else !ty.eql(decl.ty, dg.module);
560585 if (need_typecast) {
561586 try writer.writeAll("((");
562 try dg.renderTypecast(writer, ty);
587 try dg.renderType(writer, ty);
563588 try writer.writeByte(')');
564589 }
565590 try writer.writeByte('&');
......@@ -574,7 +599,7 @@ pub const DeclGen = struct {
574599 fn renderParentPtr(dg: *DeclGen, writer: anytype, ptr_val: Value, ptr_ty: Type, location: ValueRenderLocation) error{ OutOfMemory, AnalysisFail }!void {
575600 if (!ptr_ty.isSlice()) {
576601 try writer.writeByte('(');
577 try dg.renderTypecast(writer, ptr_ty);
602 try dg.renderType(writer, ptr_ty);
578603 try writer.writeByte(')');
579604 }
580605 switch (ptr_val.tag()) {
......@@ -589,90 +614,71 @@ pub const DeclGen = struct {
589614 try dg.renderDeclValue(writer, ptr_ty, ptr_val, decl_index, location);
590615 },
591616 .field_ptr => {
592 const ptr_info = ptr_ty.ptrInfo();
617 const target = dg.module.getTarget();
593618 const field_ptr = ptr_val.castTag(.field_ptr).?.data;
594 const container_ty = field_ptr.container_ty;
595 const index = field_ptr.field_index;
596
597 var container_ptr_ty_pl: Type.Payload.ElemType = .{
598 .base = .{ .tag = .c_mut_pointer },
599 .data = field_ptr.container_ty,
600 };
601 const container_ptr_ty = Type.initPayload(&container_ptr_ty_pl.base);
602
603 const FieldInfo = struct { name: []const u8, ty: Type };
604 const field_info: FieldInfo = switch (container_ty.zigTypeTag()) {
605 .Struct => switch (container_ty.containerLayout()) {
606 .Auto, .Extern => FieldInfo{
607 .name = container_ty.structFields().keys()[index],
608 .ty = container_ty.structFields().values()[index].ty,
609 },
610 .Packed => if (ptr_info.data.host_size == 0) {
611 const target = dg.module.getTarget();
612
613 const byte_offset = container_ty.packedStructFieldByteOffset(index, target);
614 var byte_offset_pl = Value.Payload.U64{
615 .base = .{ .tag = .int_u64 },
616 .data = byte_offset,
617 };
618 const byte_offset_val = Value.initPayload(&byte_offset_pl.base);
619
620 var u8_ptr_pl = ptr_info;
621 u8_ptr_pl.data.pointee_type = Type.u8;
622 const u8_ptr_ty = Type.initPayload(&u8_ptr_pl.base);
623
624 try writer.writeAll("&((");
625 try dg.renderTypecast(writer, u8_ptr_ty);
626 try writer.writeByte(')');
627 try dg.renderParentPtr(writer, field_ptr.container_ptr, container_ptr_ty, location);
628 return writer.print(")[{}]", .{try dg.fmtIntLiteral(Type.usize, byte_offset_val)});
629 } else {
630 var host_pl = Type.Payload.Bits{
631 .base = .{ .tag = .int_unsigned },
632 .data = ptr_info.data.host_size * 8,
633 };
634 const host_ty = Type.initPayload(&host_pl.base);
635619
636 try writer.writeByte('(');
637 try dg.renderTypecast(writer, ptr_ty);
638 try writer.writeByte(')');
639 return dg.renderParentPtr(writer, field_ptr.container_ptr, host_ty, location);
640 },
641 },
642 .Union => switch (container_ty.containerLayout()) {
643 .Auto, .Extern => FieldInfo{
644 .name = container_ty.unionFields().keys()[index],
645 .ty = container_ty.unionFields().values()[index].ty,
646 },
647 .Packed => {
648 return dg.renderParentPtr(writer, field_ptr.container_ptr, ptr_ty, location);
649 },
620 // Ensure complete type definition is visible before accessing fields.
621 _ = try dg.typeToIndex(field_ptr.container_ty, .complete);
622
623 var container_ptr_pl = ptr_ty.ptrInfo();
624 container_ptr_pl.data.pointee_type = field_ptr.container_ty;
625 const container_ptr_ty = Type.initPayload(&container_ptr_pl.base);
626
627 switch (fieldLocation(
628 field_ptr.container_ty,
629 ptr_ty,
630 @intCast(u32, field_ptr.field_index),
631 target,
632 )) {
633 .begin => try dg.renderParentPtr(
634 writer,
635 field_ptr.container_ptr,
636 container_ptr_ty,
637 location,
638 ),
639 .field => |field| {
640 try writer.writeAll("&(");
641 try dg.renderParentPtr(
642 writer,
643 field_ptr.container_ptr,
644 container_ptr_ty,
645 location,
646 );
647 try writer.writeAll(")->");
648 try dg.writeCValue(writer, field);
650649 },
651 .Pointer => field_info: {
652 assert(container_ty.isSlice());
653 break :field_info switch (index) {
654 0 => FieldInfo{ .name = "ptr", .ty = container_ty.childType() },
655 1 => FieldInfo{ .name = "len", .ty = Type.usize },
656 else => unreachable,
650 .byte_offset => |byte_offset| {
651 var u8_ptr_pl = ptr_ty.ptrInfo();
652 u8_ptr_pl.data.pointee_type = Type.u8;
653 const u8_ptr_ty = Type.initPayload(&u8_ptr_pl.base);
654
655 var byte_offset_pl = Value.Payload.U64{
656 .base = .{ .tag = .int_u64 },
657 .data = byte_offset,
657658 };
658 },
659 else => unreachable,
660 };
659 const byte_offset_val = Value.initPayload(&byte_offset_pl.base);
661660
662 if (field_info.ty.hasRuntimeBitsIgnoreComptime()) {
663 // Ensure complete type definition is visible before accessing fields.
664 try dg.renderType(std.io.null_writer, field_ptr.container_ty, .Complete);
665
666 try writer.writeAll("&(");
667 try dg.renderParentPtr(writer, field_ptr.container_ptr, container_ptr_ty, location);
668 try writer.writeAll(")->");
669 switch (field_ptr.container_ty.tag()) {
670 .union_tagged, .union_safety_tagged => try writer.writeAll("payload."),
671 else => {},
672 }
673 try writer.print("{ }", .{fmtIdent(field_info.name)});
674 } else {
675 try dg.renderParentPtr(writer, field_ptr.container_ptr, container_ptr_ty, location);
661 try writer.writeAll("((");
662 try dg.renderType(writer, u8_ptr_ty);
663 try writer.writeByte(')');
664 try dg.renderParentPtr(
665 writer,
666 field_ptr.container_ptr,
667 container_ptr_ty,
668 location,
669 );
670 try writer.print(" + {})", .{try dg.fmtIntLiteral(Type.usize, byte_offset_val)});
671 },
672 .end => {
673 try writer.writeAll("((");
674 try dg.renderParentPtr(
675 writer,
676 field_ptr.container_ptr,
677 container_ptr_ty,
678 location,
679 );
680 try writer.print(") + {})", .{try dg.fmtIntLiteral(Type.usize, Value.one)});
681 },
676682 }
677683 },
678684 .elem_ptr => {
......@@ -696,7 +702,7 @@ pub const DeclGen = struct {
696702 const container_ptr_ty = Type.initPayload(&container_ptr_ty_pl.base);
697703
698704 // Ensure complete type definition is visible before accessing fields.
699 try dg.renderType(std.io.null_writer, payload_ptr.container_ty, .Complete);
705 _ = try dg.typeToIndex(payload_ptr.container_ty, .complete);
700706
701707 try writer.writeAll("&(");
702708 try dg.renderParentPtr(writer, payload_ptr.container_ptr, container_ptr_ty, location);
......@@ -763,18 +769,18 @@ pub const DeclGen = struct {
763769 .Pointer => if (ty.isSlice()) {
764770 if (!location.isInitializer()) {
765771 try writer.writeByte('(');
766 try dg.renderTypecast(writer, ty);
772 try dg.renderType(writer, ty);
767773 try writer.writeByte(')');
768774 }
769775
770776 try writer.writeAll("{(");
771777 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
772778 const ptr_ty = ty.slicePtrFieldType(&buf);
773 try dg.renderTypecast(writer, ptr_ty);
779 try dg.renderType(writer, ptr_ty);
774780 return writer.print("){x}, {0x}}}", .{try dg.fmtIntLiteral(Type.usize, val)});
775781 } else {
776782 try writer.writeAll("((");
777 try dg.renderTypecast(writer, ty);
783 try dg.renderType(writer, ty);
778784 return writer.print("){x})", .{try dg.fmtIntLiteral(Type.usize, val)});
779785 },
780786 .Optional => {
......@@ -791,7 +797,7 @@ pub const DeclGen = struct {
791797
792798 if (!location.isInitializer()) {
793799 try writer.writeByte('(');
794 try dg.renderTypecast(writer, ty);
800 try dg.renderType(writer, ty);
795801 try writer.writeByte(')');
796802 }
797803
......@@ -805,7 +811,7 @@ pub const DeclGen = struct {
805811 .Auto, .Extern => {
806812 if (!location.isInitializer()) {
807813 try writer.writeByte('(');
808 try dg.renderTypecast(writer, ty);
814 try dg.renderType(writer, ty);
809815 try writer.writeByte(')');
810816 }
811817
......@@ -827,7 +833,7 @@ pub const DeclGen = struct {
827833 .Union => {
828834 if (!location.isInitializer()) {
829835 try writer.writeByte('(');
830 try dg.renderTypecast(writer, ty);
836 try dg.renderType(writer, ty);
831837 try writer.writeByte(')');
832838 }
833839
......@@ -852,7 +858,7 @@ pub const DeclGen = struct {
852858 .ErrorUnion => {
853859 if (!location.isInitializer()) {
854860 try writer.writeByte('(');
855 try dg.renderTypecast(writer, ty);
861 try dg.renderType(writer, ty);
856862 try writer.writeByte(')');
857863 }
858864
......@@ -865,7 +871,7 @@ pub const DeclGen = struct {
865871 .Array, .Vector => {
866872 if (!location.isInitializer()) {
867873 try writer.writeByte('(');
868 try dg.renderTypecast(writer, ty);
874 try dg.renderType(writer, ty);
869875 try writer.writeByte(')');
870876 }
871877
......@@ -874,14 +880,14 @@ pub const DeclGen = struct {
874880 var literal = stringLiteral(writer);
875881 try literal.start();
876882 const c_len = ty.arrayLenIncludingSentinel();
877 var index: usize = 0;
883 var index: u64 = 0;
878884 while (index < c_len) : (index += 1)
879885 try literal.writeChar(0xaa);
880886 return literal.end();
881887 } else {
882888 try writer.writeByte('{');
883889 const c_len = ty.arrayLenIncludingSentinel();
884 var index: usize = 0;
890 var index: u64 = 0;
885891 while (index < c_len) : (index += 1) {
886892 if (index > 0) try writer.writeAll(", ");
887893 try dg.renderValue(writer, ty.childType(), val, initializer_type);
......@@ -1026,7 +1032,7 @@ pub const DeclGen = struct {
10261032 return dg.renderValue(writer, ty, slice_val, location);
10271033 } else {
10281034 try writer.writeAll("((");
1029 try dg.renderTypecast(writer, ty);
1035 try dg.renderType(writer, ty);
10301036 try writer.writeAll(")NULL)");
10311037 },
10321038 .variable => {
......@@ -1036,7 +1042,7 @@ pub const DeclGen = struct {
10361042 .slice => {
10371043 if (!location.isInitializer()) {
10381044 try writer.writeByte('(');
1039 try dg.renderTypecast(writer, ty);
1045 try dg.renderType(writer, ty);
10401046 try writer.writeByte(')');
10411047 }
10421048
......@@ -1059,7 +1065,7 @@ pub const DeclGen = struct {
10591065 },
10601066 .int_u64, .one => {
10611067 try writer.writeAll("((");
1062 try dg.renderTypecast(writer, ty);
1068 try dg.renderType(writer, ty);
10631069 return writer.print("){x})", .{try dg.fmtIntLiteral(Type.usize, val)});
10641070 },
10651071 .field_ptr,
......@@ -1074,15 +1080,15 @@ pub const DeclGen = struct {
10741080 .Array, .Vector => {
10751081 if (location == .FunctionArgument) {
10761082 try writer.writeByte('(');
1077 try dg.renderTypecast(writer, ty);
1083 try dg.renderType(writer, ty);
10781084 try writer.writeByte(')');
10791085 }
10801086
10811087 // First try specific tag representations for more efficiency.
10821088 switch (val.tag()) {
10831089 .undef, .empty_struct_value, .empty_array => {
1084 try writer.writeByte('{');
10851090 const ai = ty.arrayInfo();
1091 try writer.writeByte('{');
10861092 if (ai.sentinel) |s| {
10871093 try dg.renderValue(writer, ai.elem_type, s, initializer_type);
10881094 } else {
......@@ -1090,13 +1096,19 @@ pub const DeclGen = struct {
10901096 }
10911097 try writer.writeByte('}');
10921098 },
1093 .bytes => {
1094 try writer.print("{s}", .{fmtStringLiteral(val.castTag(.bytes).?.data)});
1095 },
1096 .str_lit => {
1097 const str_lit = val.castTag(.str_lit).?.data;
1098 const bytes = dg.module.string_literal_bytes.items[str_lit.index..][0..str_lit.len];
1099 try writer.print("{s}", .{fmtStringLiteral(bytes)});
1099 .bytes, .str_lit => |t| {
1100 const bytes = switch (t) {
1101 .bytes => val.castTag(.bytes).?.data,
1102 .str_lit => bytes: {
1103 const str_lit = val.castTag(.str_lit).?.data;
1104 break :bytes dg.module.string_literal_bytes.items[str_lit.index..][0..str_lit.len];
1105 },
1106 else => unreachable,
1107 };
1108 const sentinel = if (ty.sentinel()) |sentinel| @intCast(u8, sentinel.toUnsignedInt(target)) else null;
1109 try writer.print("{s}", .{
1110 fmtStringLiteral(bytes[0..@intCast(usize, ty.arrayLen())], sentinel),
1111 });
11001112 },
11011113 else => {
11021114 // Fall back to generic implementation.
......@@ -1120,7 +1132,7 @@ pub const DeclGen = struct {
11201132 }
11211133 if (ai.sentinel) |s| {
11221134 const s_u8 = @intCast(u8, s.toUnsignedInt(target));
1123 try literal.writeChar(s_u8);
1135 if (s_u8 != 0) try literal.writeChar(s_u8);
11241136 }
11251137 try literal.end();
11261138 } else {
......@@ -1177,7 +1189,7 @@ pub const DeclGen = struct {
11771189
11781190 if (!location.isInitializer()) {
11791191 try writer.writeByte('(');
1180 try dg.renderTypecast(writer, ty);
1192 try dg.renderType(writer, ty);
11811193 try writer.writeByte(')');
11821194 }
11831195
......@@ -1211,7 +1223,7 @@ pub const DeclGen = struct {
12111223
12121224 if (!location.isInitializer()) {
12131225 try writer.writeByte('(');
1214 try dg.renderTypecast(writer, ty);
1226 try dg.renderType(writer, ty);
12151227 try writer.writeByte(')');
12161228 }
12171229
......@@ -1275,7 +1287,7 @@ pub const DeclGen = struct {
12751287
12761288 if (!location.isInitializer()) {
12771289 try writer.writeByte('(');
1278 try dg.renderTypecast(writer, ty);
1290 try dg.renderType(writer, ty);
12791291 try writer.writeByte(')');
12801292 }
12811293
......@@ -1362,7 +1374,7 @@ pub const DeclGen = struct {
13621374
13631375 if (!empty) try writer.writeAll(" | ");
13641376 try writer.writeByte('(');
1365 try dg.renderTypecast(writer, ty);
1377 try dg.renderType(writer, ty);
13661378 try writer.writeByte(')');
13671379
13681380 if (bit_offset_val_pl.data != 0) {
......@@ -1385,7 +1397,7 @@ pub const DeclGen = struct {
13851397
13861398 if (!location.isInitializer()) {
13871399 try writer.writeByte('(');
1388 try dg.renderTypecast(writer, ty);
1400 try dg.renderType(writer, ty);
13891401 try writer.writeByte(')');
13901402 }
13911403
......@@ -1396,11 +1408,11 @@ pub const DeclGen = struct {
13961408 if (field_ty.hasRuntimeBits()) {
13971409 if (field_ty.isPtrAtRuntime()) {
13981410 try writer.writeByte('(');
1399 try dg.renderTypecast(writer, ty);
1411 try dg.renderType(writer, ty);
14001412 try writer.writeByte(')');
14011413 } else if (field_ty.zigTypeTag() == .Float) {
14021414 try writer.writeByte('(');
1403 try dg.renderTypecast(writer, ty);
1415 try dg.renderType(writer, ty);
14041416 try writer.writeByte(')');
14051417 }
14061418 try dg.renderValue(writer, field_ty, union_obj.val, initializer_type);
......@@ -1457,24 +1469,31 @@ pub const DeclGen = struct {
14571469 }
14581470 }
14591471
1460 fn renderFunctionSignature(dg: *DeclGen, w: anytype, kind: TypedefKind, export_index: u32) !void {
1472 fn renderFunctionSignature(
1473 dg: *DeclGen,
1474 w: anytype,
1475 fn_decl_index: Decl.Index,
1476 kind: CType.Kind,
1477 name: union(enum) {
1478 export_index: u32,
1479 string: []const u8,
1480 },
1481 ) !void {
14611482 const store = &dg.ctypes.set;
14621483 const module = dg.module;
14631484
1464 const fn_ty = dg.decl.?.ty;
1465 const fn_cty_idx = try dg.typeToIndex(fn_ty, switch (kind) {
1466 .Forward => .forward,
1467 .Complete => .complete,
1468 });
1485 const fn_decl = module.declPtr(fn_decl_index);
1486 const fn_cty_idx = try dg.typeToIndex(fn_decl.ty, kind);
14691487
1470 const fn_info = fn_ty.fnInfo();
1488 const fn_info = fn_decl.ty.fnInfo();
14711489 if (fn_info.cc == .Naked) {
14721490 switch (kind) {
1473 .Forward => try w.writeAll("zig_naked_decl "),
1474 .Complete => try w.writeAll("zig_naked "),
1491 .forward => try w.writeAll("zig_naked_decl "),
1492 .complete => try w.writeAll("zig_naked "),
1493 else => unreachable,
14751494 }
14761495 }
1477 if (dg.decl.?.val.castTag(.function)) |func_payload|
1496 if (fn_decl.val.castTag(.function)) |func_payload|
14781497 if (func_payload.data.is_cold) try w.writeAll("zig_cold ");
14791498 if (fn_info.return_type.tag() == .noreturn) try w.writeAll("zig_noreturn ");
14801499
......@@ -1485,7 +1504,7 @@ pub const DeclGen = struct {
14851504 w,
14861505 fn_cty_idx,
14871506 .suffix,
1488 CQualifiers.init(.{}),
1507 .{},
14891508 );
14901509 try w.print("{}", .{trailing});
14911510
......@@ -1493,25 +1512,48 @@ pub const DeclGen = struct {
14931512 try w.print("zig_callconv({s}) ", .{call_conv});
14941513 }
14951514
1496 if (fn_info.alignment > 0 and kind == .Complete) {
1497 try w.print(" zig_align_fn({})", .{fn_info.alignment});
1515 switch (kind) {
1516 .forward => {},
1517 .complete => if (fn_info.alignment > 0)
1518 try w.print(" zig_align_fn({})", .{fn_info.alignment}),
1519 else => unreachable,
14981520 }
14991521
1500 try dg.renderDeclName(w, dg.decl_index.unwrap().?, export_index);
1522 switch (name) {
1523 .export_index => |export_index| try dg.renderDeclName(w, fn_decl_index, export_index),
1524 .string => |string| try w.writeAll(string),
1525 }
15011526
1502 try renderTypeSuffix(dg.decl_index, store.*, module, w, fn_cty_idx, .suffix);
1527 try renderTypeSuffix(
1528 dg.decl_index,
1529 store.*,
1530 module,
1531 w,
1532 fn_cty_idx,
1533 .suffix,
1534 CQualifiers.init(.{ .@"const" = switch (kind) {
1535 .forward => false,
1536 .complete => true,
1537 else => unreachable,
1538 } }),
1539 );
15031540
1504 if (fn_info.alignment > 0 and kind == .Forward) {
1505 try w.print(" zig_align_fn({})", .{fn_info.alignment});
1541 switch (kind) {
1542 .forward => if (fn_info.alignment > 0)
1543 try w.print(" zig_align_fn({})", .{fn_info.alignment}),
1544 .complete => {},
1545 else => unreachable,
15061546 }
15071547 }
15081548
15091549 fn indexToCType(dg: *DeclGen, idx: CType.Index) CType {
15101550 return dg.ctypes.indexToCType(idx);
15111551 }
1552
15121553 fn typeToIndex(dg: *DeclGen, ty: Type, kind: CType.Kind) !CType.Index {
15131554 return dg.ctypes.typeToIndex(dg.gpa, ty, dg.module, kind);
15141555 }
1556
15151557 fn typeToCType(dg: *DeclGen, ty: Type, kind: CType.Kind) !CType {
15161558 return dg.ctypes.typeToCType(dg.gpa, ty, dg.module, kind);
15171559 }
......@@ -1524,29 +1566,15 @@ pub const DeclGen = struct {
15241566 /// There are three type formats in total that we support rendering:
15251567 /// | Function | Example 1 (*u8) | Example 2 ([10]*u8) |
15261568 /// |---------------------|-----------------|---------------------|
1527 /// | `renderTypecast` | "uint8_t *" | "uint8_t *[10]" |
15281569 /// | `renderTypeAndName` | "uint8_t *name" | "uint8_t *name[10]" |
15291570 /// | `renderType` | "uint8_t *" | "uint8_t *[10]" |
15301571 ///
1531 fn renderType(
1532 dg: *DeclGen,
1533 w: anytype,
1534 t: Type,
1535 _: TypedefKind,
1536 ) error{ OutOfMemory, AnalysisFail }!void {
1572 fn renderType(dg: *DeclGen, w: anytype, t: Type) error{ OutOfMemory, AnalysisFail }!void {
15371573 const store = &dg.ctypes.set;
15381574 const module = dg.module;
15391575 const idx = try dg.typeToIndex(t, .complete);
1540 _ = try renderTypePrefix(
1541 dg.decl_index,
1542 store.*,
1543 module,
1544 w,
1545 idx,
1546 .suffix,
1547 CQualifiers.init(.{}),
1548 );
1549 try renderTypeSuffix(dg.decl_index, store.*, module, w, idx, .suffix);
1576 _ = try renderTypePrefix(dg.decl_index, store.*, module, w, idx, .suffix, .{});
1577 try renderTypeSuffix(dg.decl_index, store.*, module, w, idx, .suffix, .{});
15501578 }
15511579
15521580 const IntCastContext = union(enum) {
......@@ -1603,17 +1631,22 @@ pub const DeclGen = struct {
16031631
16041632 if (needs_cast) {
16051633 try w.writeByte('(');
1606 try dg.renderTypecast(w, dest_ty);
1634 try dg.renderType(w, dest_ty);
16071635 try w.writeByte(')');
16081636 }
16091637 if (src_is_ptr) {
16101638 try w.writeByte('(');
1611 try dg.renderTypecast(w, src_eff_ty);
1639 try dg.renderType(w, src_eff_ty);
16121640 try w.writeByte(')');
16131641 }
16141642 try context.writeValue(dg, w, src_ty, location);
16151643 } else if (dest_bits <= 64 and src_bits > 64) {
16161644 assert(!src_is_ptr);
1645 if (dest_bits < 64) {
1646 try w.writeByte('(');
1647 try dg.renderType(w, dest_ty);
1648 try w.writeByte(')');
1649 }
16171650 try w.writeAll("zig_lo_");
16181651 try dg.renderTypeForBuiltinFnName(w, src_eff_ty);
16191652 try w.writeByte('(');
......@@ -1625,7 +1658,7 @@ pub const DeclGen = struct {
16251658 try w.writeAll("(0, "); // TODO: Should the 0 go through fmtIntLiteral?
16261659 if (src_is_ptr) {
16271660 try w.writeByte('(');
1628 try dg.renderTypecast(w, src_eff_ty);
1661 try dg.renderType(w, src_eff_ty);
16291662 try w.writeByte(')');
16301663 }
16311664 try context.writeValue(dg, w, src_ty, .FunctionArgument);
......@@ -1646,28 +1679,11 @@ pub const DeclGen = struct {
16461679 }
16471680 }
16481681
1649 /// Renders a type in C typecast format.
1650 ///
1651 /// This is guaranteed to be valid in a typecast expression, but not
1652 /// necessarily in a variable/field declaration.
1653 ///
1654 /// There are three type formats in total that we support rendering:
1655 /// | Function | Example 1 (*u8) | Example 2 ([10]*u8) |
1656 /// |---------------------|-----------------|---------------------|
1657 /// | `renderTypecast` | "uint8_t *" | "uint8_t *[10]" |
1658 /// | `renderTypeAndName` | "uint8_t *name" | "uint8_t *name[10]" |
1659 /// | `renderType` | "uint8_t *" | "uint8_t *[10]" |
1660 ///
1661 fn renderTypecast(dg: *DeclGen, w: anytype, ty: Type) error{ OutOfMemory, AnalysisFail }!void {
1662 try dg.renderType(w, ty, undefined);
1663 }
1664
16651682 /// Renders a type and name in field declaration/definition format.
16661683 ///
16671684 /// There are three type formats in total that we support rendering:
16681685 /// | Function | Example 1 (*u8) | Example 2 ([10]*u8) |
16691686 /// |---------------------|-----------------|---------------------|
1670 /// | `renderTypecast` | "uint8_t *" | "uint8_t *[10]" |
16711687 /// | `renderTypeAndName` | "uint8_t *name" | "uint8_t *name[10]" |
16721688 /// | `renderType` | "uint8_t *" | "uint8_t *[10]" |
16731689 ///
......@@ -1676,9 +1692,9 @@ pub const DeclGen = struct {
16761692 w: anytype,
16771693 ty: Type,
16781694 name: CValue,
1679 mutability: Mutability,
1695 qualifiers: CQualifiers,
16801696 alignment: u32,
1681 _: TypedefKind,
1697 kind: CType.Kind,
16821698 ) error{ OutOfMemory, AnalysisFail }!void {
16831699 const store = &dg.ctypes.set;
16841700 const module = dg.module;
......@@ -1689,71 +1705,12 @@ pub const DeclGen = struct {
16891705 .gt => try w.print("zig_align({}) ", .{alignment}),
16901706 };
16911707
1692 const idx = try dg.typeToIndex(ty, .complete);
1693 const trailing = try renderTypePrefix(
1694 dg.decl_index,
1695 store.*,
1696 module,
1697 w,
1698 idx,
1699 .suffix,
1700 CQualifiers.init(.{ .@"const" = mutability == .@"const" }),
1701 );
1708 const idx = try dg.typeToIndex(ty, kind);
1709 const trailing =
1710 try renderTypePrefix(dg.decl_index, store.*, module, w, idx, .suffix, qualifiers);
17021711 try w.print("{}", .{trailing});
17031712 try dg.writeCValue(w, name);
1704 try renderTypeSuffix(dg.decl_index, store.*, module, w, idx, .suffix);
1705 }
1706
1707 fn renderTagNameFn(dg: *DeclGen, w: anytype, fn_name: []const u8, enum_ty: Type) !void {
1708 const name_slice_ty = Type.initTag(.const_slice_u8_sentinel_0);
1709
1710 try w.writeAll("static ");
1711 try dg.renderType(w, name_slice_ty, .Complete);
1712 try w.writeByte(' ');
1713 try w.writeAll(fn_name);
1714 try w.writeByte('(');
1715 try dg.renderTypeAndName(w, enum_ty, .{ .identifier = "tag" }, .@"const", 0, .Complete);
1716 try w.writeAll(") {\n switch (tag) {\n");
1717 for (enum_ty.enumFields().keys(), 0..) |name, index| {
1718 const name_z = try dg.gpa.dupeZ(u8, name);
1719 defer dg.gpa.free(name_z);
1720 const name_bytes = name_z[0 .. name_z.len + 1];
1721
1722 var tag_pl: Value.Payload.U32 = .{
1723 .base = .{ .tag = .enum_field_index },
1724 .data = @intCast(u32, index),
1725 };
1726 const tag_val = Value.initPayload(&tag_pl.base);
1727
1728 var int_pl: Value.Payload.U64 = undefined;
1729 const int_val = tag_val.enumToInt(enum_ty, &int_pl);
1730
1731 var name_ty_pl = Type.Payload.Len{ .base = .{ .tag = .array_u8_sentinel_0 }, .data = name.len };
1732 const name_ty = Type.initPayload(&name_ty_pl.base);
1733
1734 var name_pl = Value.Payload.Bytes{ .base = .{ .tag = .bytes }, .data = name_bytes };
1735 const name_val = Value.initPayload(&name_pl.base);
1736
1737 var len_pl = Value.Payload.U64{ .base = .{ .tag = .int_u64 }, .data = name.len };
1738 const len_val = Value.initPayload(&len_pl.base);
1739
1740 try w.print(" case {}: {{\n static ", .{try dg.fmtIntLiteral(enum_ty, int_val)});
1741 try dg.renderTypeAndName(w, name_ty, .{ .identifier = "name" }, .@"const", 0, .Complete);
1742 try w.writeAll(" = ");
1743 try dg.renderValue(w, name_ty, name_val, .Initializer);
1744 try w.writeAll(";\n return (");
1745 try dg.renderTypecast(w, name_slice_ty);
1746 try w.print("){{{}, {}}};\n", .{
1747 fmtIdent("name"), try dg.fmtIntLiteral(Type.usize, len_val),
1748 });
1749
1750 try w.writeAll(" }\n");
1751 }
1752 try w.writeAll(" }\n while (");
1753 try dg.renderValue(w, Type.bool, Value.true, .Other);
1754 try w.writeAll(") ");
1755 _ = try airBreakpoint(w);
1756 try w.writeAll("}\n");
1713 try renderTypeSuffix(dg.decl_index, store.*, module, w, idx, .suffix, .{});
17571714 }
17581715
17591716 fn declIsGlobal(dg: *DeclGen, tv: TypedValue) bool {
......@@ -1787,6 +1744,10 @@ pub const DeclGen = struct {
17871744 },
17881745 .undef => |ty| return dg.renderValue(w, ty, Value.undef, .Other),
17891746 .identifier => |ident| return w.print("{ }", .{fmtIdent(ident)}),
1747 .payload_identifier => |ident| return w.print("{ }.{ }", .{
1748 fmtIdent("payload"),
1749 fmtIdent(ident),
1750 }),
17901751 .bytes => |bytes| return w.writeAll(bytes),
17911752 }
17921753 }
......@@ -1812,6 +1773,10 @@ pub const DeclGen = struct {
18121773 .decl_ref => |decl| return dg.renderDeclName(w, decl, 0),
18131774 .undef => unreachable,
18141775 .identifier => |ident| return w.print("(*{ })", .{fmtIdent(ident)}),
1776 .payload_identifier => |ident| return w.print("(*{ }.{ })", .{
1777 fmtIdent("payload"),
1778 fmtIdent(ident),
1779 }),
18151780 .bytes => |bytes| {
18161781 try w.writeAll("(*");
18171782 try w.writeAll(bytes);
......@@ -1829,7 +1794,7 @@ pub const DeclGen = struct {
18291794 fn writeCValueDerefMember(dg: *DeclGen, writer: anytype, c_value: CValue, member: CValue) !void {
18301795 switch (c_value) {
18311796 .none, .constant, .field, .undef => unreachable,
1832 .new_local, .local, .arg, .arg_array, .decl, .identifier, .bytes => {
1797 .new_local, .local, .arg, .arg_array, .decl, .identifier, .payload_identifier, .bytes => {
18331798 try dg.writeCValue(writer, c_value);
18341799 try writer.writeAll("->");
18351800 },
......@@ -1958,7 +1923,8 @@ pub const DeclGen = struct {
19581923
19591924const CTypeFix = enum { prefix, suffix };
19601925const CQualifiers = std.enums.EnumSet(enum { @"const", @"volatile", restrict });
1961const CTypeRenderTrailing = enum {
1926const Const = CQualifiers.init(.{ .@"const" = true });
1927const RenderCTypeTrailing = enum {
19621928 no_space,
19631929 maybe_space,
19641930
......@@ -2017,8 +1983,8 @@ fn renderTypePrefix(
20171983 idx: CType.Index,
20181984 parent_fix: CTypeFix,
20191985 qualifiers: CQualifiers,
2020) @TypeOf(w).Error!CTypeRenderTrailing {
2021 var trailing = CTypeRenderTrailing.maybe_space;
1986) @TypeOf(w).Error!RenderCTypeTrailing {
1987 var trailing = RenderCTypeTrailing.maybe_space;
20221988
20231989 const cty = store.indexToCType(idx);
20241990 switch (cty.tag()) {
......@@ -2160,7 +2126,7 @@ fn renderTypePrefix(
21602126 w,
21612127 cty.cast(CType.Payload.Function).?.data.return_type,
21622128 .suffix,
2163 CQualifiers.init(.{}),
2129 .{},
21642130 );
21652131 switch (parent_fix) {
21662132 .prefix => {
......@@ -2187,6 +2153,7 @@ fn renderTypeSuffix(
21872153 w: anytype,
21882154 idx: CType.Index,
21892155 parent_fix: CTypeFix,
2156 qualifiers: CQualifiers,
21902157) @TypeOf(w).Error!void {
21912158 const cty = store.indexToCType(idx);
21922159 switch (cty.tag()) {
......@@ -2233,7 +2200,15 @@ fn renderTypeSuffix(
22332200 .pointer_const,
22342201 .pointer_volatile,
22352202 .pointer_const_volatile,
2236 => try renderTypeSuffix(decl, store, mod, w, cty.cast(CType.Payload.Child).?.data, .prefix),
2203 => try renderTypeSuffix(
2204 decl,
2205 store,
2206 mod,
2207 w,
2208 cty.cast(CType.Payload.Child).?.data,
2209 .prefix,
2210 .{},
2211 ),
22372212
22382213 .array,
22392214 .vector,
......@@ -2251,6 +2226,7 @@ fn renderTypeSuffix(
22512226 w,
22522227 cty.cast(CType.Payload.Sequence).?.data.elem_type,
22532228 .suffix,
2229 .{},
22542230 );
22552231 },
22562232
......@@ -2285,17 +2261,10 @@ fn renderTypeSuffix(
22852261 for (data.param_types, 0..) |param_type, param_i| {
22862262 if (need_comma) try w.writeAll(", ");
22872263 need_comma = true;
2288 const trailing = try renderTypePrefix(
2289 decl,
2290 store,
2291 mod,
2292 w,
2293 param_type,
2294 .suffix,
2295 CQualifiers.init(.{ .@"const" = true }),
2296 );
2297 try w.print("{}a{d}", .{ trailing, param_i });
2298 try renderTypeSuffix(decl, store, mod, w, param_type, .suffix);
2264 const trailing =
2265 try renderTypePrefix(decl, store, mod, w, param_type, .suffix, qualifiers);
2266 if (qualifiers.contains(.@"const")) try w.print("{}a{d}", .{ trailing, param_i });
2267 try renderTypeSuffix(decl, store, mod, w, param_type, .suffix, .{});
22992268 }
23002269 switch (tag) {
23012270 .function => {},
......@@ -2309,7 +2278,7 @@ fn renderTypeSuffix(
23092278 if (!need_comma) try w.writeAll("void");
23102279 try w.writeByte(')');
23112280
2312 try renderTypeSuffix(decl, store, mod, w, data.return_type, .suffix);
2281 try renderTypeSuffix(decl, store, mod, w, data.return_type, .suffix, .{});
23132282 },
23142283 }
23152284}
......@@ -2329,17 +2298,9 @@ fn renderAggregateFields(
23292298 .eq => {},
23302299 .gt => try writer.print("zig_align({}) ", .{field.alignas.getAlign()}),
23312300 }
2332 const trailing = try renderTypePrefix(
2333 .none,
2334 store,
2335 mod,
2336 writer,
2337 field.type,
2338 .suffix,
2339 CQualifiers.init(.{}),
2340 );
2301 const trailing = try renderTypePrefix(.none, store, mod, writer, field.type, .suffix, .{});
23412302 try writer.print("{}{ }", .{ trailing, fmtIdent(mem.span(field.name)) });
2342 try renderTypeSuffix(.none, store, mod, writer, field.type, .suffix);
2303 try renderTypeSuffix(.none, store, mod, writer, field.type, .suffix, .{});
23432304 try writer.writeAll(";\n");
23442305 }
23452306 try writer.writeByteNTimes(' ', indent);
......@@ -2360,25 +2321,9 @@ pub fn genTypeDecl(
23602321 switch (global_cty.tag()) {
23612322 .fwd_anon_struct => if (decl != .none) {
23622323 try writer.writeAll("typedef ");
2363 _ = try renderTypePrefix(
2364 .none,
2365 global_store,
2366 mod,
2367 writer,
2368 global_idx,
2369 .suffix,
2370 CQualifiers.init(.{}),
2371 );
2324 _ = try renderTypePrefix(.none, global_store, mod, writer, global_idx, .suffix, .{});
23722325 try writer.writeByte(' ');
2373 _ = try renderTypePrefix(
2374 decl,
2375 decl_store,
2376 mod,
2377 writer,
2378 decl_idx,
2379 .suffix,
2380 CQualifiers.init(.{}),
2381 );
2326 _ = try renderTypePrefix(decl, decl_store, mod, writer, decl_idx, .suffix, .{});
23822327 try writer.writeAll(";\n");
23832328 },
23842329
......@@ -2396,15 +2341,7 @@ pub fn genTypeDecl(
23962341 .fwd_union,
23972342 => {
23982343 const owner_decl = global_cty.cast(CType.Payload.FwdDecl).?.data;
2399 _ = try renderTypePrefix(
2400 .none,
2401 global_store,
2402 mod,
2403 writer,
2404 global_idx,
2405 .suffix,
2406 CQualifiers.init(.{}),
2407 );
2344 _ = try renderTypePrefix(.none, global_store, mod, writer, global_idx, .suffix, .{});
24082345 try writer.writeAll("; // ");
24092346 try mod.declPtr(owner_decl).renderFullyQualifiedName(mod, writer);
24102347 try writer.writeByte('\n');
......@@ -2441,9 +2378,7 @@ pub fn genTypeDecl(
24412378
24422379pub fn genGlobalAsm(mod: *Module, writer: anytype) !void {
24432380 var it = mod.global_assembly.valueIterator();
2444 while (it.next()) |asm_source| {
2445 try writer.print("__asm({s});\n", .{fmtStringLiteral(asm_source.*)});
2446 }
2381 while (it.next()) |asm_source| try writer.print("__asm({s});\n", .{fmtStringLiteral(asm_source.*, null)});
24472382}
24482383
24492384pub fn genErrDecls(o: *Object) !void {
......@@ -2461,26 +2396,24 @@ pub fn genErrDecls(o: *Object) !void {
24612396 o.indent_writer.popIndent();
24622397 try writer.writeAll("};\n");
24632398
2464 const name_prefix = "zig_errorName";
2465 const name_buf = try o.dg.gpa.alloc(u8, name_prefix.len + "_".len + max_name_len + 1);
2399 const array_identifier = "zig_errorName";
2400 const name_prefix = array_identifier ++ "_";
2401 const name_buf = try o.dg.gpa.alloc(u8, name_prefix.len + max_name_len);
24662402 defer o.dg.gpa.free(name_buf);
24672403
2468 std.mem.copy(u8, name_buf, name_prefix ++ "_");
2404 std.mem.copy(u8, name_buf, name_prefix);
24692405 for (o.dg.module.error_name_list.items) |name| {
2470 std.mem.copy(u8, name_buf[name_prefix.len + "_".len ..], name);
2471 name_buf[name_prefix.len + "_".len + name.len] = 0;
2472
2473 const identifier = name_buf[0 .. name_prefix.len + "_".len + name.len :0];
2474 const name_z = identifier[name_prefix.len + "_".len ..];
2406 std.mem.copy(u8, name_buf[name_prefix.len..], name);
2407 const identifier = name_buf[0 .. name_prefix.len + name.len];
24752408
24762409 var name_ty_pl = Type.Payload.Len{ .base = .{ .tag = .array_u8_sentinel_0 }, .data = name.len };
24772410 const name_ty = Type.initPayload(&name_ty_pl.base);
24782411
2479 var name_pl = Value.Payload.Bytes{ .base = .{ .tag = .bytes }, .data = name_z };
2412 var name_pl = Value.Payload.Bytes{ .base = .{ .tag = .bytes }, .data = name };
24802413 const name_val = Value.initPayload(&name_pl.base);
24812414
24822415 try writer.writeAll("static ");
2483 try o.dg.renderTypeAndName(writer, name_ty, .{ .identifier = identifier }, .@"const", 0, .Complete);
2416 try o.dg.renderTypeAndName(writer, name_ty, .{ .identifier = identifier }, Const, 0, .complete);
24842417 try writer.writeAll(" = ");
24852418 try o.dg.renderValue(writer, name_ty, name_val, .StaticInitializer);
24862419 try writer.writeAll(";\n");
......@@ -2493,7 +2426,7 @@ pub fn genErrDecls(o: *Object) !void {
24932426 const name_array_ty = Type.initPayload(&name_array_ty_pl.base);
24942427
24952428 try writer.writeAll("static ");
2496 try o.dg.renderTypeAndName(writer, name_array_ty, .{ .identifier = name_prefix }, .@"const", 0, .Complete);
2429 try o.dg.renderTypeAndName(writer, name_array_ty, .{ .identifier = array_identifier }, Const, 0, .complete);
24972430 try writer.writeAll(" = {");
24982431 for (o.dg.module.error_name_list.items, 0..) |name, value| {
24992432 if (value != 0) try writer.writeByte(',');
......@@ -2501,7 +2434,7 @@ pub fn genErrDecls(o: *Object) !void {
25012434 var len_pl = Value.Payload.U64{ .base = .{ .tag = .int_u64 }, .data = name.len };
25022435 const len_val = Value.initPayload(&len_pl.base);
25032436
2504 try writer.print("{{" ++ name_prefix ++ "_{}, {}}}", .{
2437 try writer.print("{{" ++ name_prefix ++ "{}, {}}}", .{
25052438 fmtIdent(name), try o.dg.fmtIntLiteral(Type.usize, len_val),
25062439 });
25072440 }
......@@ -2516,23 +2449,91 @@ fn genExports(o: *Object) !void {
25162449 if (o.dg.module.decl_exports.get(o.dg.decl_index.unwrap().?)) |exports| {
25172450 for (exports.items[1..], 1..) |@"export", i| {
25182451 try fwd_decl_writer.writeAll("zig_export(");
2519 try o.dg.renderFunctionSignature(fwd_decl_writer, .Forward, @intCast(u32, i));
2452 try o.dg.renderFunctionSignature(fwd_decl_writer, o.dg.decl_index.unwrap().?, .forward, .{ .export_index = @intCast(u32, i) });
25202453 try fwd_decl_writer.print(", {s}, {s});\n", .{
2521 fmtStringLiteral(exports.items[0].options.name),
2522 fmtStringLiteral(@"export".options.name),
2454 fmtStringLiteral(exports.items[0].options.name, null),
2455 fmtStringLiteral(@"export".options.name, null),
25232456 });
25242457 }
25252458 }
25262459}
25272460
25282461pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void {
2529 const writer = o.writer();
2530 switch (lazy_fn.key_ptr.*) {
2531 .tag_name => _ = try o.dg.renderTagNameFn(
2532 writer,
2533 lazy_fn.value_ptr.fn_name,
2534 lazy_fn.value_ptr.data.tag_name,
2535 ),
2462 const w = o.writer();
2463 const key = lazy_fn.key_ptr.*;
2464 const val = lazy_fn.value_ptr;
2465 const fn_name = val.fn_name;
2466 switch (key) {
2467 .tag_name => {
2468 const enum_ty = val.data.tag_name;
2469
2470 const name_slice_ty = Type.initTag(.const_slice_u8_sentinel_0);
2471
2472 try w.writeAll("static ");
2473 try o.dg.renderType(w, name_slice_ty);
2474 try w.writeByte(' ');
2475 try w.writeAll(fn_name);
2476 try w.writeByte('(');
2477 try o.dg.renderTypeAndName(w, enum_ty, .{ .identifier = "tag" }, Const, 0, .complete);
2478 try w.writeAll(") {\n switch (tag) {\n");
2479 for (enum_ty.enumFields().keys(), 0..) |name, index| {
2480 var tag_pl: Value.Payload.U32 = .{
2481 .base = .{ .tag = .enum_field_index },
2482 .data = @intCast(u32, index),
2483 };
2484 const tag_val = Value.initPayload(&tag_pl.base);
2485
2486 var int_pl: Value.Payload.U64 = undefined;
2487 const int_val = tag_val.enumToInt(enum_ty, &int_pl);
2488
2489 var name_ty_pl = Type.Payload.Len{ .base = .{ .tag = .array_u8_sentinel_0 }, .data = name.len };
2490 const name_ty = Type.initPayload(&name_ty_pl.base);
2491
2492 var name_pl = Value.Payload.Bytes{ .base = .{ .tag = .bytes }, .data = name };
2493 const name_val = Value.initPayload(&name_pl.base);
2494
2495 var len_pl = Value.Payload.U64{ .base = .{ .tag = .int_u64 }, .data = name.len };
2496 const len_val = Value.initPayload(&len_pl.base);
2497
2498 try w.print(" case {}: {{\n static ", .{try o.dg.fmtIntLiteral(enum_ty, int_val)});
2499 try o.dg.renderTypeAndName(w, name_ty, .{ .identifier = "name" }, Const, 0, .complete);
2500 try w.writeAll(" = ");
2501 try o.dg.renderValue(w, name_ty, name_val, .Initializer);
2502 try w.writeAll(";\n return (");
2503 try o.dg.renderType(w, name_slice_ty);
2504 try w.print("){{{}, {}}};\n", .{
2505 fmtIdent("name"), try o.dg.fmtIntLiteral(Type.usize, len_val),
2506 });
2507
2508 try w.writeAll(" }\n");
2509 }
2510 try w.writeAll(" }\n while (");
2511 try o.dg.renderValue(w, Type.bool, Value.true, .Other);
2512 try w.writeAll(") ");
2513 _ = try airBreakpoint(w);
2514 try w.writeAll("}\n");
2515 },
2516 .never_tail, .never_inline => |fn_decl_index| {
2517 const fn_decl = o.dg.module.declPtr(fn_decl_index);
2518 const fn_cty = try o.dg.typeToCType(fn_decl.ty, .complete);
2519 const fn_info = fn_cty.cast(CType.Payload.Function).?.data;
2520
2521 const fwd_decl_writer = o.dg.fwd_decl.writer();
2522 try fwd_decl_writer.print("static zig_{s} ", .{@tagName(key)});
2523 try o.dg.renderFunctionSignature(fwd_decl_writer, fn_decl_index, .forward, .{ .string = fn_name });
2524 try fwd_decl_writer.writeAll(";\n");
2525
2526 try w.print("static zig_{s} ", .{@tagName(key)});
2527 try o.dg.renderFunctionSignature(w, fn_decl_index, .complete, .{ .string = fn_name });
2528 try w.writeAll(" {\n return ");
2529 try o.dg.renderDeclName(w, fn_decl_index, 0);
2530 try w.writeByte('(');
2531 for (0..fn_info.param_types.len) |arg| {
2532 if (arg > 0) try w.writeAll(", ");
2533 try o.dg.writeCValue(w, .{ .arg = arg });
2534 }
2535 try w.writeAll(");\n}\n");
2536 },
25362537 }
25372538}
25382539
......@@ -2542,6 +2543,7 @@ pub fn genFunc(f: *Function) !void {
25422543
25432544 const o = &f.object;
25442545 const gpa = o.dg.gpa;
2546 const decl_index = o.dg.decl_index.unwrap().?;
25452547 const tv: TypedValue = .{
25462548 .ty = o.dg.decl.?.ty,
25472549 .val = o.dg.decl.?.val,
......@@ -2553,13 +2555,13 @@ pub fn genFunc(f: *Function) !void {
25532555 const is_global = o.dg.declIsGlobal(tv);
25542556 const fwd_decl_writer = o.dg.fwd_decl.writer();
25552557 try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static ");
2556 try o.dg.renderFunctionSignature(fwd_decl_writer, .Forward, 0);
2558 try o.dg.renderFunctionSignature(fwd_decl_writer, decl_index, .forward, .{ .export_index = 0 });
25572559 try fwd_decl_writer.writeAll(";\n");
25582560 try genExports(o);
25592561
25602562 try o.indent_writer.insertNewline();
25612563 if (!is_global) try o.writer().writeAll("static ");
2562 try o.dg.renderFunctionSignature(o.writer(), .Complete, 0);
2564 try o.dg.renderFunctionSignature(o.writer(), decl_index, .complete, .{ .export_index = 0 });
25632565 try o.writer().writeByte(' ');
25642566
25652567 // In case we need to use the header, populate it with a copy of the function
......@@ -2613,9 +2615,9 @@ pub fn genFunc(f: *Function) !void {
26132615 w,
26142616 local.ty,
26152617 .{ .local = local_index },
2616 .mut,
2618 .{},
26172619 local.alignment,
2618 .Complete,
2620 .complete,
26192621 );
26202622 try w.writeAll(";\n ");
26212623 }
......@@ -2634,14 +2636,14 @@ pub fn genDecl(o: *Object) !void {
26342636 defer tracy.end();
26352637
26362638 const decl = o.dg.decl.?;
2637 const decl_c_value: CValue = .{ .decl = o.dg.decl_index.unwrap().? };
2639 const decl_c_value = .{ .decl = o.dg.decl_index.unwrap().? };
26382640 const tv: TypedValue = .{ .ty = decl.ty, .val = decl.val };
26392641
26402642 if (!tv.ty.isFnOrHasRuntimeBitsIgnoreComptime()) return;
26412643 if (tv.val.tag() == .extern_fn) {
26422644 const fwd_decl_writer = o.dg.fwd_decl.writer();
26432645 try fwd_decl_writer.writeAll("zig_extern ");
2644 try o.dg.renderFunctionSignature(fwd_decl_writer, .Forward, 0);
2646 try o.dg.renderFunctionSignature(fwd_decl_writer, decl_c_value.decl, .forward, .{ .export_index = 0 });
26452647 try fwd_decl_writer.writeAll(";\n");
26462648 try genExports(o);
26472649 } else if (tv.val.castTag(.variable)) |var_payload| {
......@@ -2652,7 +2654,7 @@ pub fn genDecl(o: *Object) !void {
26522654
26532655 try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static ");
26542656 if (variable.is_threadlocal) try fwd_decl_writer.writeAll("zig_threadlocal ");
2655 try o.dg.renderTypeAndName(fwd_decl_writer, decl.ty, decl_c_value, .mut, decl.@"align", .Complete);
2657 try o.dg.renderTypeAndName(fwd_decl_writer, decl.ty, decl_c_value, .{}, decl.@"align", .complete);
26562658 try fwd_decl_writer.writeAll(";\n");
26572659 try genExports(o);
26582660
......@@ -2662,7 +2664,7 @@ pub fn genDecl(o: *Object) !void {
26622664 if (!is_global) try w.writeAll("static ");
26632665 if (variable.is_threadlocal) try w.writeAll("zig_threadlocal ");
26642666 if (decl.@"linksection") |section| try w.print("zig_linksection(\"{s}\", ", .{section});
2665 try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, .mut, decl.@"align", .Complete);
2667 try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, .{}, decl.@"align", .complete);
26662668 if (decl.@"linksection" != null) try w.writeAll(", read, write)");
26672669 try w.writeAll(" = ");
26682670 try o.dg.renderValue(w, tv.ty, variable.init, .StaticInitializer);
......@@ -2673,13 +2675,13 @@ pub fn genDecl(o: *Object) !void {
26732675 const fwd_decl_writer = o.dg.fwd_decl.writer();
26742676
26752677 try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static ");
2676 try o.dg.renderTypeAndName(fwd_decl_writer, tv.ty, decl_c_value, .@"const", decl.@"align", .Complete);
2678 try o.dg.renderTypeAndName(fwd_decl_writer, tv.ty, decl_c_value, Const, decl.@"align", .complete);
26772679 try fwd_decl_writer.writeAll(";\n");
26782680
26792681 const w = o.writer();
26802682 if (!is_global) try w.writeAll("static ");
26812683 if (decl.@"linksection") |section| try w.print("zig_linksection(\"{s}\", ", .{section});
2682 try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, .@"const", decl.@"align", .Complete);
2684 try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, Const, decl.@"align", .complete);
26832685 if (decl.@"linksection" != null) try w.writeAll(", read)");
26842686 try w.writeAll(" = ");
26852687 try o.dg.renderValue(w, tv.ty, tv.val, .StaticInitializer);
......@@ -2702,7 +2704,7 @@ pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void {
27022704 const is_global = dg.declIsGlobal(tv);
27032705 if (is_global) {
27042706 try writer.writeAll("zig_extern ");
2705 try dg.renderFunctionSignature(writer, .Complete, 0);
2707 try dg.renderFunctionSignature(writer, dg.decl_index.unwrap().?, .complete, .{ .export_index = 0 });
27062708 try dg.fwd_decl.appendSlice(";\n");
27072709 }
27082710 },
......@@ -2892,10 +2894,10 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
28922894
28932895 .dbg_block_begin,
28942896 .dbg_block_end,
2895 => CValue{ .none = {} },
2897 => .none,
28962898
28972899 .call => try airCall(f, inst, .auto),
2898 .call_always_tail => try airCall(f, inst, .always_tail),
2900 .call_always_tail => .none,
28992901 .call_never_tail => try airCall(f, inst, .never_tail),
29002902 .call_never_inline => try airCall(f, inst, .never_inline),
29012903
......@@ -2974,10 +2976,10 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
29742976 .error_set_has_value => return f.fail("TODO: C backend: implement error_set_has_value", .{}),
29752977 .vector_store_elem => return f.fail("TODO: C backend: implement vector_store_elem", .{}),
29762978
2977 .c_va_arg => return f.fail("TODO implement c_va_arg", .{}),
2978 .c_va_copy => return f.fail("TODO implement c_va_copy", .{}),
2979 .c_va_end => return f.fail("TODO implement c_va_end", .{}),
2980 .c_va_start => return f.fail("TODO implement c_va_start", .{}),
2979 .c_va_start => try airCVaStart(f, inst),
2980 .c_va_arg => try airCVaArg(f, inst),
2981 .c_va_end => try airCVaEnd(f, inst),
2982 .c_va_copy => try airCVaCopy(f, inst),
29812983 // zig fmt: on
29822984 };
29832985 if (result_value == .new_local) {
......@@ -2996,7 +2998,7 @@ fn airSliceField(f: *Function, inst: Air.Inst.Index, is_ptr: bool, field_name: [
29962998
29972999 if (f.liveness.isUnused(inst)) {
29983000 try reap(f, inst, &.{ty_op.operand});
2999 return CValue.none;
3001 return .none;
30003002 }
30013003
30023004 const inst_ty = f.air.typeOfIndex(inst);
......@@ -3022,7 +3024,7 @@ fn airPtrElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
30223024 !inst_ty.hasRuntimeBitsIgnoreComptime())
30233025 {
30243026 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
3025 return CValue.none;
3027 return .none;
30263028 }
30273029
30283030 const ptr = try f.resolveInst(bin_op.lhs);
......@@ -3048,7 +3050,7 @@ fn airPtrElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
30483050 try writer.writeByte(']');
30493051 if (is_array) {
30503052 try writer.writeAll(", sizeof(");
3051 try f.renderTypecast(writer, inst_ty);
3053 try f.renderType(writer, inst_ty);
30523054 try writer.writeAll("))");
30533055 }
30543056 try writer.writeAll(";\n");
......@@ -3061,7 +3063,7 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
30613063
30623064 if (f.liveness.isUnused(inst)) {
30633065 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
3064 return CValue.none;
3066 return .none;
30653067 }
30663068
30673069 const inst_ty = f.air.typeOfIndex(inst);
......@@ -3080,7 +3082,7 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
30803082 const local = try f.allocLocal(inst, f.air.typeOfIndex(inst));
30813083 try f.writeCValue(writer, local, .Other);
30823084 try writer.writeAll(" = (");
3083 try f.renderTypecast(writer, inst_ty);
3085 try f.renderType(writer, inst_ty);
30843086 try writer.writeAll(")&(");
30853087 if (ptr_ty.ptrSize() == .One) {
30863088 // It's a pointer to an array, so we need to de-reference.
......@@ -3102,7 +3104,7 @@ fn airSliceElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
31023104 !inst_ty.hasRuntimeBitsIgnoreComptime())
31033105 {
31043106 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
3105 return CValue.none;
3107 return .none;
31063108 }
31073109
31083110 const slice = try f.resolveInst(bin_op.lhs);
......@@ -3128,7 +3130,7 @@ fn airSliceElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
31283130 try writer.writeByte(']');
31293131 if (is_array) {
31303132 try writer.writeAll(", sizeof(");
3131 try f.renderTypecast(writer, inst_ty);
3133 try f.renderType(writer, inst_ty);
31323134 try writer.writeAll("))");
31333135 }
31343136 try writer.writeAll(";\n");
......@@ -3141,7 +3143,7 @@ fn airSliceElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
31413143
31423144 if (f.liveness.isUnused(inst)) {
31433145 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
3144 return CValue.none;
3146 return .none;
31453147 }
31463148
31473149 const slice_ty = f.air.typeOf(bin_op.lhs);
......@@ -3171,7 +3173,7 @@ fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
31713173 const inst_ty = f.air.typeOfIndex(inst);
31723174 if (f.liveness.isUnused(inst) or !inst_ty.hasRuntimeBitsIgnoreComptime()) {
31733175 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
3174 return CValue.none;
3176 return .none;
31753177 }
31763178
31773179 const array = try f.resolveInst(bin_op.lhs);
......@@ -3197,7 +3199,7 @@ fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
31973199 try writer.writeByte(']');
31983200 if (is_array) {
31993201 try writer.writeAll(", sizeof(");
3200 try f.renderTypecast(writer, inst_ty);
3202 try f.renderType(writer, inst_ty);
32013203 try writer.writeAll("))");
32023204 }
32033205 try writer.writeAll(";\n");
......@@ -3209,16 +3211,19 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue {
32093211
32103212 const elem_type = inst_ty.elemType();
32113213 if (!elem_type.isFnOrHasRuntimeBitsIgnoreComptime()) {
3212 return CValue{ .undef = inst_ty };
3214 return .{ .undef = inst_ty };
32133215 }
32143216
3215 const mutability: Mutability = if (inst_ty.isConstPtr()) .@"const" else .mut;
32163217 const target = f.object.dg.module.getTarget();
3217 const local = try f.allocAlignedLocal(elem_type, mutability, inst_ty.ptrAlignment(target));
3218 const local = try f.allocAlignedLocal(
3219 elem_type,
3220 CQualifiers.init(.{ .@"const" = inst_ty.isConstPtr() }),
3221 inst_ty.ptrAlignment(target),
3222 );
32183223 log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.new_local });
32193224 const gpa = f.object.dg.module.gpa;
32203225 try f.allocs.put(gpa, local.new_local, false);
3221 return CValue{ .local_ref = local.new_local };
3226 return .{ .local_ref = local.new_local };
32223227}
32233228
32243229fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue {
......@@ -3226,25 +3231,28 @@ fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue {
32263231
32273232 const elem_ty = inst_ty.elemType();
32283233 if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime()) {
3229 return CValue{ .undef = inst_ty };
3234 return .{ .undef = inst_ty };
32303235 }
32313236
3232 const mutability: Mutability = if (inst_ty.isConstPtr()) .@"const" else .mut;
32333237 const target = f.object.dg.module.getTarget();
3234 const local = try f.allocAlignedLocal(elem_ty, mutability, inst_ty.ptrAlignment(target));
3238 const local = try f.allocAlignedLocal(
3239 elem_ty,
3240 CQualifiers.init(.{ .@"const" = inst_ty.isConstPtr() }),
3241 inst_ty.ptrAlignment(target),
3242 );
32353243 log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.new_local });
32363244 const gpa = f.object.dg.module.gpa;
32373245 try f.allocs.put(gpa, local.new_local, false);
3238 return CValue{ .local_ref = local.new_local };
3246 return .{ .local_ref = local.new_local };
32393247}
32403248
32413249fn airArg(f: *Function, inst: Air.Inst.Index) !CValue {
32423250 const inst_ty = f.air.typeOfIndex(inst);
3243 const inst_cty = try f.object.dg.typeToIndex(inst_ty, .parameter);
3251 const inst_cty = try f.typeToIndex(inst_ty, .parameter);
32443252
32453253 const i = f.next_arg_index;
32463254 f.next_arg_index += 1;
3247 return if (inst_cty != try f.object.dg.typeToIndex(inst_ty, .complete))
3255 return if (inst_cty != try f.typeToIndex(inst_ty, .complete))
32483256 .{ .arg_array = i }
32493257 else
32503258 .{ .arg = i };
......@@ -3259,7 +3267,7 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
32593267 (!ptr_info.@"volatile" and f.liveness.isUnused(inst)))
32603268 {
32613269 try reap(f, inst, &.{ty_op.operand});
3262 return CValue.none;
3270 return .none;
32633271 }
32643272
32653273 const operand = try f.resolveInst(ty_op.operand);
......@@ -3281,7 +3289,7 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
32813289 try writer.writeAll(", (const char *)");
32823290 try f.writeCValue(writer, operand, .Other);
32833291 try writer.writeAll(", sizeof(");
3284 try f.renderTypecast(writer, src_ty);
3292 try f.renderType(writer, src_ty);
32853293 try writer.writeAll("))");
32863294 } else if (ptr_info.host_size != 0) {
32873295 var host_pl = Type.Payload.Bits{
......@@ -3310,11 +3318,11 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
33103318
33113319 try f.writeCValue(writer, local, .Other);
33123320 try writer.writeAll(" = (");
3313 try f.renderTypecast(writer, src_ty);
3321 try f.renderType(writer, src_ty);
33143322 try writer.writeAll(")zig_wrap_");
33153323 try f.object.dg.renderTypeForBuiltinFnName(writer, field_ty);
33163324 try writer.writeAll("((");
3317 try f.renderTypecast(writer, field_ty);
3325 try f.renderType(writer, field_ty);
33183326 try writer.writeByte(')');
33193327 const cant_cast = host_ty.isInt() and host_ty.bitSize(target) > 64;
33203328 if (cant_cast) {
......@@ -3344,15 +3352,19 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue {
33443352 const un_op = f.air.instructions.items(.data)[inst].un_op;
33453353 const writer = f.object.writer();
33463354 const target = f.object.dg.module.getTarget();
3355 const op_inst = Air.refToIndex(un_op);
33473356 const op_ty = f.air.typeOf(un_op);
33483357 const ret_ty = if (is_ptr) op_ty.childType() else op_ty;
33493358 var lowered_ret_buf: LowerFnRetTyBuffer = undefined;
33503359 const lowered_ret_ty = lowerFnRetTy(ret_ty, &lowered_ret_buf, target);
33513360
3352 if (lowered_ret_ty.hasRuntimeBitsIgnoreComptime()) {
3353 var deref = is_ptr;
3361 if (op_inst != null and f.air.instructions.items(.tag)[op_inst.?] == .call_always_tail) {
3362 try reap(f, inst, &.{un_op});
3363 _ = try airCall(f, op_inst.?, .always_tail);
3364 } else if (lowered_ret_ty.hasRuntimeBitsIgnoreComptime()) {
33543365 const operand = try f.resolveInst(un_op);
33553366 try reap(f, inst, &.{un_op});
3367 var deref = is_ptr;
33563368 const is_array = lowersToArray(ret_ty, target);
33573369 const ret_val = if (is_array) ret_val: {
33583370 const array_local = try f.allocLocal(inst, try lowered_ret_ty.copy(f.arena.allocator()));
......@@ -3365,7 +3377,7 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue {
33653377 try f.writeCValue(writer, operand, .FunctionArgument);
33663378 deref = false;
33673379 try writer.writeAll(", sizeof(");
3368 try f.renderTypecast(writer, ret_ty);
3380 try f.renderType(writer, ret_ty);
33693381 try writer.writeAll("));\n");
33703382 break :ret_val array_local;
33713383 } else operand;
......@@ -3381,11 +3393,11 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue {
33813393 }
33823394 } else {
33833395 try reap(f, inst, &.{un_op});
3384 if (f.object.dg.decl) |decl| if (decl.ty.fnCallingConvention() != .Naked)
3385 // Not even allowed to return void in a naked function.
3396 // Not even allowed to return void in a naked function.
3397 if (if (f.object.dg.decl) |decl| decl.ty.fnCallingConvention() != .Naked else true)
33863398 try writer.writeAll("return;\n");
33873399 }
3388 return CValue.none;
3400 return .none;
33893401}
33903402
33913403fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue {
......@@ -3393,7 +3405,7 @@ fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue {
33933405
33943406 if (f.liveness.isUnused(inst)) {
33953407 try reap(f, inst, &.{ty_op.operand});
3396 return CValue.none;
3408 return .none;
33973409 }
33983410
33993411 const operand = try f.resolveInst(ty_op.operand);
......@@ -3414,7 +3426,7 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {
34143426 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
34153427 if (f.liveness.isUnused(inst)) {
34163428 try reap(f, inst, &.{ty_op.operand});
3417 return CValue.none;
3429 return .none;
34183430 }
34193431
34203432 const operand = try f.resolveInst(ty_op.operand);
......@@ -3433,15 +3445,17 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {
34333445 try f.writeCValue(writer, local, .Other);
34343446 try writer.writeAll(" = ");
34353447
3448 if (dest_c_bits < 64) {
3449 try writer.writeByte('(');
3450 try f.renderType(writer, inst_ty);
3451 try writer.writeByte(')');
3452 }
3453
34363454 const needs_lo = operand_int_info.bits > 64 and dest_bits <= 64;
34373455 if (needs_lo) {
34383456 try writer.writeAll("zig_lo_");
34393457 try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty);
34403458 try writer.writeByte('(');
3441 } else if (dest_c_bits <= 64) {
3442 try writer.writeByte('(');
3443 try f.renderTypecast(writer, inst_ty);
3444 try writer.writeByte(')');
34453459 }
34463460
34473461 if (dest_bits >= 8 and std.math.isPowerOfTwo(dest_bits)) {
......@@ -3501,7 +3515,7 @@ fn airBoolToInt(f: *Function, inst: Air.Inst.Index) !CValue {
35013515 const un_op = f.air.instructions.items(.data)[inst].un_op;
35023516 if (f.liveness.isUnused(inst)) {
35033517 try reap(f, inst, &.{un_op});
3504 return CValue.none;
3518 return .none;
35053519 }
35063520 const operand = try f.resolveInst(un_op);
35073521 try reap(f, inst, &.{un_op});
......@@ -3521,10 +3535,10 @@ fn storeUndefined(f: *Function, lhs_child_ty: Type, dest_ptr: CValue) !CValue {
35213535 try writer.writeAll("memset(");
35223536 try f.writeCValue(writer, dest_ptr, .FunctionArgument);
35233537 try writer.print(", {x}, sizeof(", .{try f.fmtIntLiteral(Type.u8, Value.undef)});
3524 try f.renderTypecast(writer, lhs_child_ty);
3538 try f.renderType(writer, lhs_child_ty);
35253539 try writer.writeAll("));\n");
35263540 }
3527 return CValue.none;
3541 return .none;
35283542}
35293543
35303544fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {
......@@ -3533,7 +3547,7 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {
35333547 const ptr_info = f.air.typeOf(bin_op.lhs).ptrInfo().data;
35343548 if (!ptr_info.pointee_type.hasRuntimeBitsIgnoreComptime()) {
35353549 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
3536 return CValue.none;
3550 return .none;
35373551 }
35383552
35393553 const ptr_val = try f.resolveInst(bin_op.lhs);
......@@ -3582,7 +3596,7 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {
35823596 if (!is_array) try writer.writeByte('&');
35833597 try f.writeCValue(writer, array_src, .FunctionArgument);
35843598 try writer.writeAll(", sizeof(");
3585 try f.renderTypecast(writer, src_ty);
3599 try f.renderType(writer, src_ty);
35863600 try writer.writeAll("))");
35873601 if (src_val == .constant) {
35883602 try freeLocal(f, inst, array_src.new_local, 0);
......@@ -3641,13 +3655,13 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {
36413655 try writer.writeAll("(0, ");
36423656 } else {
36433657 try writer.writeByte('(');
3644 try f.renderTypecast(writer, host_ty);
3658 try f.renderType(writer, host_ty);
36453659 try writer.writeByte(')');
36463660 }
36473661
36483662 if (src_ty.isPtrAtRuntime()) {
36493663 try writer.writeByte('(');
3650 try f.renderTypecast(writer, Type.usize);
3664 try f.renderType(writer, Type.usize);
36513665 try writer.writeByte(')');
36523666 }
36533667 try f.writeCValue(writer, src_val, .Other);
......@@ -3659,7 +3673,7 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {
36593673 try f.writeCValue(writer, src_val, .Other);
36603674 }
36613675 try writer.writeAll(";\n");
3662 return CValue.none;
3676 return .none;
36633677}
36643678
36653679fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info: BuiltinInfo) !CValue {
......@@ -3668,7 +3682,7 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info:
36683682
36693683 if (f.liveness.isUnused(inst)) {
36703684 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
3671 return CValue.none;
3685 return .none;
36723686 }
36733687
36743688 const lhs = try f.resolveInst(bin_op.lhs);
......@@ -3724,7 +3738,7 @@ fn airNot(f: *Function, inst: Air.Inst.Index) !CValue {
37243738
37253739 if (f.liveness.isUnused(inst)) {
37263740 try reap(f, inst, &.{ty_op.operand});
3727 return CValue.none;
3741 return .none;
37283742 }
37293743
37303744 const op = try f.resolveInst(ty_op.operand);
......@@ -3759,7 +3773,7 @@ fn airBinOp(
37593773
37603774 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
37613775
3762 if (f.liveness.isUnused(inst)) return CValue.none;
3776 if (f.liveness.isUnused(inst)) return .none;
37633777
37643778 const inst_ty = f.air.typeOfIndex(inst);
37653779
......@@ -3782,7 +3796,7 @@ fn airCmpOp(f: *Function, inst: Air.Inst.Index, operator: []const u8, operation:
37823796
37833797 if (f.liveness.isUnused(inst)) {
37843798 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
3785 return CValue.none;
3799 return .none;
37863800 }
37873801
37883802 const operand_ty = f.air.typeOf(bin_op.lhs);
......@@ -3822,7 +3836,7 @@ fn airEquality(
38223836
38233837 if (f.liveness.isUnused(inst)) {
38243838 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
3825 return CValue.none;
3839 return .none;
38263840 }
38273841
38283842 const operand_ty = f.air.typeOf(bin_op.lhs);
......@@ -3878,7 +3892,7 @@ fn airCmpLtErrorsLen(f: *Function, inst: Air.Inst.Index) !CValue {
38783892
38793893 if (f.liveness.isUnused(inst)) {
38803894 try reap(f, inst, &.{un_op});
3881 return CValue.none;
3895 return .none;
38823896 }
38833897
38843898 const inst_ty = f.air.typeOfIndex(inst);
......@@ -3899,7 +3913,7 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue {
38993913 const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data;
39003914 if (f.liveness.isUnused(inst)) {
39013915 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
3902 return CValue.none;
3916 return .none;
39033917 }
39043918
39053919 const lhs = try f.resolveInst(bin_op.lhs);
......@@ -3919,7 +3933,7 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue {
39193933 // results in a NULL pointer, or if LHS is NULL. The operation is only UB
39203934 // if the result is NULL and then dereferenced.
39213935 try writer.writeByte('(');
3922 try f.renderTypecast(writer, inst_ty);
3936 try f.renderType(writer, inst_ty);
39233937 try writer.writeAll(")(((uintptr_t)");
39243938 try f.writeCValue(writer, lhs, .Other);
39253939 try writer.writeAll(") ");
......@@ -3927,7 +3941,7 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue {
39273941 try writer.writeAll(" (");
39283942 try f.writeCValue(writer, rhs, .Other);
39293943 try writer.writeAll("*sizeof(");
3930 try f.renderTypecast(writer, elem_ty);
3944 try f.renderType(writer, elem_ty);
39313945 try writer.writeAll(")))");
39323946 } else try f.writeCValue(writer, lhs, .Initializer);
39333947
......@@ -3940,7 +3954,7 @@ fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: u8, operation: []cons
39403954
39413955 if (f.liveness.isUnused(inst)) {
39423956 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
3943 return CValue.none;
3957 return .none;
39443958 }
39453959
39463960 const inst_ty = f.air.typeOfIndex(inst);
......@@ -3979,7 +3993,7 @@ fn airSlice(f: *Function, inst: Air.Inst.Index) !CValue {
39793993
39803994 if (f.liveness.isUnused(inst)) {
39813995 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
3982 return CValue.none;
3996 return .none;
39833997 }
39843998
39853999 const ptr = try f.resolveInst(bin_op.lhs);
......@@ -3992,7 +4006,7 @@ fn airSlice(f: *Function, inst: Air.Inst.Index) !CValue {
39924006 try f.writeCValue(writer, local, .Other);
39934007 try writer.writeAll(".ptr = (");
39944008 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
3995 try f.renderTypecast(writer, inst_ty.slicePtrFieldType(&buf));
4009 try f.renderType(writer, inst_ty.slicePtrFieldType(&buf));
39964010 try writer.writeByte(')');
39974011 try f.writeCValue(writer, ptr, .Other);
39984012 try writer.writeAll("; ");
......@@ -4017,13 +4031,6 @@ fn airCall(
40174031 const target = module.getTarget();
40184032 const writer = f.object.writer();
40194033
4020 switch (modifier) {
4021 .auto => {},
4022 .always_tail => return f.fail("TODO: C backend: call with always_tail attribute", .{}),
4023 .never_tail => return f.fail("TODO: C backend: call with never_tail attribute", .{}),
4024 .never_inline => return f.fail("TODO: C backend: call with never_inline attribute", .{}),
4025 else => unreachable,
4026 }
40274034 const pl_op = f.air.instructions.items(.data)[inst].pl_op;
40284035 const extra = f.air.extraData(Air.Call, pl_op.payload);
40294036 const args = @ptrCast([]const Air.Inst.Ref, f.air.extra[extra.end..][0..extra.data.args_len]);
......@@ -4032,13 +4039,13 @@ fn airCall(
40324039 defer gpa.free(resolved_args);
40334040 for (resolved_args, args) |*resolved_arg, arg| {
40344041 const arg_ty = f.air.typeOf(arg);
4035 const arg_cty = try f.object.dg.typeToIndex(arg_ty, .parameter);
4036 if (f.object.dg.indexToCType(arg_cty).tag() == .void) {
4042 const arg_cty = try f.typeToIndex(arg_ty, .parameter);
4043 if (f.indexToCType(arg_cty).tag() == .void) {
40374044 resolved_arg.* = .none;
40384045 continue;
40394046 }
40404047 resolved_arg.* = try f.resolveInst(arg);
4041 if (arg_cty != try f.object.dg.typeToIndex(arg_ty, .complete)) {
4048 if (arg_cty != try f.typeToIndex(arg_ty, .complete)) {
40424049 var lowered_arg_buf: LowerFnRetTyBuffer = undefined;
40434050 const lowered_arg_ty = lowerFnRetTy(arg_ty, &lowered_arg_buf, target);
40444051
......@@ -4048,7 +4055,7 @@ fn airCall(
40484055 try writer.writeAll(", ");
40494056 try f.writeCValue(writer, resolved_arg.*, .FunctionArgument);
40504057 try writer.writeAll(", sizeof(");
4051 try f.renderTypecast(writer, lowered_arg_ty);
4058 try f.renderType(writer, lowered_arg_ty);
40524059 try writer.writeAll("));\n");
40534060 resolved_arg.* = array_local;
40544061 }
......@@ -4073,11 +4080,14 @@ fn airCall(
40734080 var lowered_ret_buf: LowerFnRetTyBuffer = undefined;
40744081 const lowered_ret_ty = lowerFnRetTy(ret_ty, &lowered_ret_buf, target);
40754082
4076 const result_local: CValue = if (!lowered_ret_ty.hasRuntimeBitsIgnoreComptime())
4083 const result_local = if (modifier == .always_tail) r: {
4084 try writer.writeAll("zig_always_tail return ");
4085 break :r .none;
4086 } else if (!lowered_ret_ty.hasRuntimeBitsIgnoreComptime())
40774087 .none
40784088 else if (f.liveness.isUnused(inst)) r: {
40794089 try writer.writeByte('(');
4080 try f.renderTypecast(writer, Type.void);
4090 try f.renderType(writer, Type.void);
40814091 try writer.writeByte(')');
40824092 break :r .none;
40834093 } else r: {
......@@ -4087,26 +4097,33 @@ fn airCall(
40874097 break :r local;
40884098 };
40894099
4090 var is_extern = false;
4091 var name: [*:0]const u8 = "";
40924100 callee: {
40934101 known: {
40944102 const fn_decl = fn_decl: {
40954103 const callee_val = f.air.value(pl_op.operand) orelse break :known;
40964104 break :fn_decl switch (callee_val.tag()) {
4097 .extern_fn => blk: {
4098 is_extern = true;
4099 break :blk callee_val.castTag(.extern_fn).?.data.owner_decl;
4100 },
4105 .extern_fn => callee_val.castTag(.extern_fn).?.data.owner_decl,
41014106 .function => callee_val.castTag(.function).?.data.owner_decl,
41024107 .decl_ref => callee_val.castTag(.decl_ref).?.data,
41034108 else => break :known,
41044109 };
41054110 };
4106 name = module.declPtr(fn_decl).name;
4107 try f.object.dg.renderDeclName(writer, fn_decl, 0);
4111 switch (modifier) {
4112 .auto, .always_tail => try f.object.dg.renderDeclName(writer, fn_decl, 0),
4113 inline .never_tail, .never_inline => |mod| try writer.writeAll(try f.getLazyFnName(
4114 @unionInit(LazyFnKey, @tagName(mod), fn_decl),
4115 @unionInit(LazyFnValue.Data, @tagName(mod), {}),
4116 )),
4117 else => unreachable,
4118 }
41084119 break :callee;
41094120 }
4121 switch (modifier) {
4122 .auto, .always_tail => {},
4123 .never_tail => return f.fail("CBE: runtime callee with never_tail attribute unsupported", .{}),
4124 .never_inline => return f.fail("CBE: runtime callee with never_inline attribute unsupported", .{}),
4125 else => unreachable,
4126 }
41104127 // Fall back to function pointer call.
41114128 try f.writeCValue(writer, callee, .Other);
41124129 }
......@@ -4132,7 +4149,7 @@ fn airCall(
41324149 try writer.writeAll(", ");
41334150 try f.writeCValueMember(writer, result_local, .{ .identifier = "array" });
41344151 try writer.writeAll(", sizeof(");
4135 try f.renderTypecast(writer, ret_ty);
4152 try f.renderType(writer, ret_ty);
41364153 try writer.writeAll("));\n");
41374154 try freeLocal(f, inst, result_local.new_local, 0);
41384155 break :r array_local;
......@@ -4153,7 +4170,7 @@ fn airDbgStmt(f: *Function, inst: Air.Inst.Index) !CValue {
41534170 // Perhaps an additional compilation option is in order?
41544171 //try writer.print("#line {d}\n", .{dbg_stmt.line + 1});
41554172 try writer.print("/* file:{d}:{d} */\n", .{ dbg_stmt.line + 1, dbg_stmt.column + 1 });
4156 return CValue.none;
4173 return .none;
41574174}
41584175
41594176fn airDbgInline(f: *Function, inst: Air.Inst.Index) !CValue {
......@@ -4162,7 +4179,7 @@ fn airDbgInline(f: *Function, inst: Air.Inst.Index) !CValue {
41624179 const function = f.air.values[ty_pl.payload].castTag(.function).?.data;
41634180 const mod = f.object.dg.module;
41644181 try writer.print("/* dbg func:{s} */\n", .{mod.declPtr(function.owner_decl).name});
4165 return CValue.none;
4182 return .none;
41664183}
41674184
41684185fn airDbgVar(f: *Function, inst: Air.Inst.Index) !CValue {
......@@ -4174,7 +4191,7 @@ fn airDbgVar(f: *Function, inst: Air.Inst.Index) !CValue {
41744191 try reap(f, inst, &.{pl_op.operand});
41754192 const writer = f.object.writer();
41764193 try writer.print("/* var:{s} */\n", .{name});
4177 return CValue.none;
4194 return .none;
41784195}
41794196
41804197fn airBlock(f: *Function, inst: Air.Inst.Index) !CValue {
......@@ -4190,7 +4207,7 @@ fn airBlock(f: *Function, inst: Air.Inst.Index) !CValue {
41904207 const result = if (inst_ty.tag() != .void and !f.liveness.isUnused(inst))
41914208 try f.allocLocal(inst, inst_ty)
41924209 else
4193 CValue{ .none = {} };
4210 .none;
41944211
41954212 try f.blocks.putNoClobber(f.object.dg.gpa, inst, .{
41964213 .block_id = block_id,
......@@ -4199,8 +4216,9 @@ fn airBlock(f: *Function, inst: Air.Inst.Index) !CValue {
41994216
42004217 try genBodyInner(f, body);
42014218 try f.object.indent_writer.insertNewline();
4219 // label might be unused, add a dummy goto
42024220 // label must be followed by an expression, add an empty one.
4203 try writer.print("zig_block_{d}:;\n", .{block_id});
4221 try writer.print("goto zig_block_{d};\nzig_block_{d}: (void)0;\n", .{ block_id, block_id });
42044222 return result;
42054223}
42064224
......@@ -4259,7 +4277,7 @@ fn lowerTry(
42594277
42604278 if (!payload_has_bits) {
42614279 if (!operand_is_ptr) {
4262 return CValue.none;
4280 return .none;
42634281 } else {
42644282 return err_union;
42654283 }
......@@ -4268,7 +4286,7 @@ fn lowerTry(
42684286 try reap(f, inst, &.{operand});
42694287
42704288 if (f.liveness.isUnused(inst)) {
4271 return CValue.none;
4289 return .none;
42724290 }
42734291
42744292 const target = f.object.dg.module.getTarget();
......@@ -4280,7 +4298,7 @@ fn lowerTry(
42804298 try writer.writeAll(", ");
42814299 try f.writeCValueMember(writer, err_union, .{ .identifier = "payload" });
42824300 try writer.writeAll(", sizeof(");
4283 try f.renderTypecast(writer, payload_ty);
4301 try f.renderType(writer, payload_ty);
42844302 try writer.writeAll("));\n");
42854303 } else {
42864304 try f.writeCValue(writer, local, .Other);
......@@ -4313,7 +4331,7 @@ fn airBr(f: *Function, inst: Air.Inst.Index) !CValue {
43134331 try writer.writeAll(", ");
43144332 try f.writeCValue(writer, operand, .FunctionArgument);
43154333 try writer.writeAll(", sizeof(");
4316 try f.renderTypecast(writer, operand_ty);
4334 try f.renderType(writer, operand_ty);
43174335 try writer.writeAll("))");
43184336 } else {
43194337 try f.writeCValue(writer, result, .Other);
......@@ -4324,7 +4342,7 @@ fn airBr(f: *Function, inst: Air.Inst.Index) !CValue {
43244342 }
43254343
43264344 try writer.print("goto zig_block_{d};\n", .{block.block_id});
4327 return CValue.none;
4345 return .none;
43284346}
43294347
43304348fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {
......@@ -4334,7 +4352,7 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {
43344352 // https://github.com/ziglang/zig/issues/13410
43354353 if (f.liveness.isUnused(inst) or !dest_ty.hasRuntimeBits()) {
43364354 try reap(f, inst, &.{ty_op.operand});
4337 return CValue.none;
4355 return .none;
43384356 }
43394357
43404358 const operand = try f.resolveInst(ty_op.operand);
......@@ -4362,7 +4380,7 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {
43624380 if (dest_ty.isPtrAtRuntime() and operand_ty.isPtrAtRuntime()) {
43634381 try f.writeCValue(writer, local, .Other);
43644382 try writer.writeAll(" = (");
4365 try f.renderTypecast(writer, dest_ty);
4383 try f.renderType(writer, dest_ty);
43664384 try writer.writeByte(')');
43674385 try f.writeCValue(writer, operand, .Other);
43684386 try writer.writeAll(";\n");
......@@ -4383,7 +4401,7 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {
43834401 try writer.writeAll(", &");
43844402 try f.writeCValue(writer, operand_lval, .Other);
43854403 try writer.writeAll(", sizeof(");
4386 try f.renderTypecast(writer, dest_ty);
4404 try f.renderType(writer, dest_ty);
43874405 try writer.writeAll("));\n");
43884406
43894407 // Ensure padding bits have the expected value.
......@@ -4406,27 +4424,27 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {
44064424
44074425fn airBreakpoint(writer: anytype) !CValue {
44084426 try writer.writeAll("zig_breakpoint();\n");
4409 return CValue.none;
4427 return .none;
44104428}
44114429
44124430fn airRetAddr(f: *Function, inst: Air.Inst.Index) !CValue {
4413 if (f.liveness.isUnused(inst)) return CValue.none;
4431 if (f.liveness.isUnused(inst)) return .none;
44144432 const writer = f.object.writer();
44154433 const local = try f.allocLocal(inst, Type.usize);
44164434 try f.writeCValue(writer, local, .Other);
44174435 try writer.writeAll(" = (");
4418 try f.renderTypecast(writer, Type.usize);
4436 try f.renderType(writer, Type.usize);
44194437 try writer.writeAll(")zig_return_address();\n");
44204438 return local;
44214439}
44224440
44234441fn airFrameAddress(f: *Function, inst: Air.Inst.Index) !CValue {
4424 if (f.liveness.isUnused(inst)) return CValue.none;
4442 if (f.liveness.isUnused(inst)) return .none;
44254443 const writer = f.object.writer();
44264444 const local = try f.allocLocal(inst, Type.usize);
44274445 try f.writeCValue(writer, local, .Other);
44284446 try writer.writeAll(" = (");
4429 try f.renderTypecast(writer, Type.usize);
4447 try f.renderType(writer, Type.usize);
44304448 try writer.writeAll(")zig_frame_address();\n");
44314449 return local;
44324450}
......@@ -4439,7 +4457,7 @@ fn airFence(f: *Function, inst: Air.Inst.Index) !CValue {
44394457 try writeMemoryOrder(writer, atomic_order);
44404458 try writer.writeAll(");\n");
44414459
4442 return CValue.none;
4460 return .none;
44434461}
44444462
44454463fn airUnreach(f: *Function) !CValue {
......@@ -4447,7 +4465,7 @@ fn airUnreach(f: *Function) !CValue {
44474465 if (f.object.dg.decl) |decl| if (decl.ty.fnCallingConvention() == .Naked) return .none;
44484466
44494467 try f.object.writer().writeAll("zig_unreachable();\n");
4450 return CValue.none;
4468 return .none;
44514469}
44524470
44534471fn airLoop(f: *Function, inst: Air.Inst.Index) !CValue {
......@@ -4479,7 +4497,7 @@ fn airLoop(f: *Function, inst: Air.Inst.Index) !CValue {
44794497 deinitFreeLocalsMap(gpa, new_free_locals);
44804498 new_free_locals.* = old_free_locals.move();
44814499
4482 return CValue.none;
4500 return .none;
44834501}
44844502
44854503fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue {
......@@ -4544,7 +4562,7 @@ fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue {
45444562
45454563 try f.object.indent_writer.insertNewline();
45464564
4547 return CValue.none;
4565 return .none;
45484566}
45494567
45504568fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {
......@@ -4558,11 +4576,11 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {
45584576 try writer.writeAll("switch (");
45594577 if (condition_ty.zigTypeTag() == .Bool) {
45604578 try writer.writeByte('(');
4561 try f.renderTypecast(writer, Type.u1);
4579 try f.renderType(writer, Type.u1);
45624580 try writer.writeByte(')');
45634581 } else if (condition_ty.isPtrAtRuntime()) {
45644582 try writer.writeByte('(');
4565 try f.renderTypecast(writer, Type.usize);
4583 try f.renderType(writer, Type.usize);
45664584 try writer.writeByte(')');
45674585 }
45684586 try f.writeCValue(writer, condition, .Other);
......@@ -4579,8 +4597,7 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {
45794597 const last_case_i = switch_br.data.cases_len - @boolToInt(switch_br.data.else_body_len == 0);
45804598
45814599 var extra_index: usize = switch_br.end;
4582 var case_i: u32 = 0;
4583 while (case_i < switch_br.data.cases_len) : (case_i += 1) {
4600 for (0..switch_br.data.cases_len) |case_i| {
45844601 const case = f.air.extraData(Air.SwitchBr.Case, extra_index);
45854602 const items = @ptrCast([]const Air.Inst.Ref, f.air.extra[case.end..][0..case.data.items_len]);
45864603 const case_body = f.air.extra[case.end + items.len ..][0..case.data.body_len];
......@@ -4591,7 +4608,7 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {
45914608 try writer.writeAll("case ");
45924609 if (condition_ty.isPtrAtRuntime()) {
45934610 try writer.writeByte('(');
4594 try f.renderTypecast(writer, Type.usize);
4611 try f.renderType(writer, Type.usize);
45954612 try writer.writeByte(')');
45964613 }
45974614 try f.object.dg.renderValue(writer, condition_ty, f.air.value(item).?, .Other);
......@@ -4657,7 +4674,7 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {
46574674
46584675 f.object.indent_writer.popIndent();
46594676 try writer.writeAll("}\n");
4660 return CValue.none;
4677 return .none;
46614678}
46624679
46634680fn asmInputNeedsLocal(constraint: []const u8, value: CValue) bool {
......@@ -4679,8 +4696,8 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
46794696 const inputs = @ptrCast([]const Air.Inst.Ref, f.air.extra[extra_i..][0..extra.data.inputs_len]);
46804697 extra_i += inputs.len;
46814698
4682 const result: CValue = r: {
4683 if (!is_volatile and f.liveness.isUnused(inst)) break :r CValue.none;
4699 const result = r: {
4700 if (!is_volatile and f.liveness.isUnused(inst)) break :r .none;
46844701
46854702 const writer = f.object.writer();
46864703 const inst_ty = f.air.typeOfIndex(inst);
......@@ -4717,14 +4734,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
47174734 try writer.writeAll("register ");
47184735 const alignment = 0;
47194736 const local_value = try f.allocLocalValue(output_ty, alignment);
4720 try f.object.dg.renderTypeAndName(
4721 writer,
4722 output_ty,
4723 local_value,
4724 .mut,
4725 alignment,
4726 .Complete,
4727 );
4737 try f.object.dg.renderTypeAndName(writer, output_ty, local_value, .{}, alignment, .complete);
47284738 try writer.writeAll(" __asm(\"");
47294739 try writer.writeAll(constraint["={".len .. constraint.len - "}".len]);
47304740 try writer.writeAll("\")");
......@@ -4756,14 +4766,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
47564766 if (is_reg) try writer.writeAll("register ");
47574767 const alignment = 0;
47584768 const local_value = try f.allocLocalValue(input_ty, alignment);
4759 try f.object.dg.renderTypeAndName(
4760 writer,
4761 input_ty,
4762 local_value,
4763 .@"const",
4764 alignment,
4765 .Complete,
4766 );
4769 try f.object.dg.renderTypeAndName(writer, input_ty, local_value, Const, alignment, .complete);
47674770 if (is_reg) {
47684771 try writer.writeAll(" __asm(\"");
47694772 try writer.writeAll(constraint["{".len .. constraint.len - "}".len]);
......@@ -4774,14 +4777,11 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
47744777 try writer.writeAll(";\n");
47754778 }
47764779 }
4777 {
4778 var clobber_i: u32 = 0;
4779 while (clobber_i < clobbers_len) : (clobber_i += 1) {
4780 const clobber = std.mem.sliceTo(std.mem.sliceAsBytes(f.air.extra[extra_i..]), 0);
4781 // This equation accounts for the fact that even if we have exactly 4 bytes
4782 // for the string, we still use the next u32 for the null terminator.
4783 extra_i += clobber.len / 4 + 1;
4784 }
4780 for (0..clobbers_len) |_| {
4781 const clobber = std.mem.sliceTo(std.mem.sliceAsBytes(f.air.extra[extra_i..]), 0);
4782 // This equation accounts for the fact that even if we have exactly 4 bytes
4783 // for the string, we still use the next u32 for the null terminator.
4784 extra_i += clobber.len / 4 + 1;
47854785 }
47864786
47874787 {
......@@ -4836,7 +4836,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
48364836
48374837 try writer.writeAll("__asm");
48384838 if (is_volatile) try writer.writeAll(" volatile");
4839 try writer.print("({s}", .{fmtStringLiteral(fixed_asm_source[0..dst_i])});
4839 try writer.print("({s}", .{fmtStringLiteral(fixed_asm_source[0..dst_i], null)});
48404840 }
48414841
48424842 extra_i = constraints_extra_begin;
......@@ -4854,7 +4854,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
48544854 try writer.writeByte(' ');
48554855 if (!std.mem.eql(u8, name, "_")) try writer.print("[{s}]", .{name});
48564856 const is_reg = constraint[1] == '{';
4857 try writer.print("{s}(", .{fmtStringLiteral(if (is_reg) "=r" else constraint)});
4857 try writer.print("{s}(", .{fmtStringLiteral(if (is_reg) "=r" else constraint, null)});
48584858 if (is_reg) {
48594859 try f.writeCValue(writer, .{ .local = locals_index }, .Other);
48604860 locals_index += 1;
......@@ -4880,28 +4880,25 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
48804880
48814881 const is_reg = constraint[0] == '{';
48824882 const input_val = try f.resolveInst(input);
4883 try writer.print("{s}(", .{fmtStringLiteral(if (is_reg) "r" else constraint)});
4883 try writer.print("{s}(", .{fmtStringLiteral(if (is_reg) "r" else constraint, null)});
48844884 try f.writeCValue(writer, if (asmInputNeedsLocal(constraint, input_val)) local: {
4885 const input_local = CValue{ .local = locals_index };
4885 const input_local = .{ .local = locals_index };
48864886 locals_index += 1;
48874887 break :local input_local;
48884888 } else input_val, .Other);
48894889 try writer.writeByte(')');
48904890 }
48914891 try writer.writeByte(':');
4892 {
4893 var clobber_i: u32 = 0;
4894 while (clobber_i < clobbers_len) : (clobber_i += 1) {
4895 const clobber = std.mem.sliceTo(std.mem.sliceAsBytes(f.air.extra[extra_i..]), 0);
4896 // This equation accounts for the fact that even if we have exactly 4 bytes
4897 // for the string, we still use the next u32 for the null terminator.
4898 extra_i += clobber.len / 4 + 1;
4892 for (0..clobbers_len) |clobber_i| {
4893 const clobber = std.mem.sliceTo(std.mem.sliceAsBytes(f.air.extra[extra_i..]), 0);
4894 // This equation accounts for the fact that even if we have exactly 4 bytes
4895 // for the string, we still use the next u32 for the null terminator.
4896 extra_i += clobber.len / 4 + 1;
48994897
4900 if (clobber.len == 0) continue;
4898 if (clobber.len == 0) continue;
49014899
4902 if (clobber_i > 0) try writer.writeByte(',');
4903 try writer.print(" {s}", .{fmtStringLiteral(clobber)});
4904 }
4900 if (clobber_i > 0) try writer.writeByte(',');
4901 try writer.print(" {s}", .{fmtStringLiteral(clobber, null)});
49054902 }
49064903 try writer.writeAll(");\n");
49074904
......@@ -4918,7 +4915,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
49184915 const is_reg = constraint[1] == '{';
49194916 if (is_reg) {
49204917 try f.writeCValueDeref(writer, if (output == .none)
4921 CValue{ .local_ref = local.new_local }
4918 .{ .local_ref = local.new_local }
49224919 else
49234920 try f.resolveInst(output));
49244921 try writer.writeAll(" = ");
......@@ -4953,7 +4950,7 @@ fn airIsNull(
49534950
49544951 if (f.liveness.isUnused(inst)) {
49554952 try reap(f, inst, &.{un_op});
4956 return CValue.none;
4953 return .none;
49574954 }
49584955
49594956 const writer = f.object.writer();
......@@ -5003,7 +5000,7 @@ fn airOptionalPayload(f: *Function, inst: Air.Inst.Index) !CValue {
50035000
50045001 if (f.liveness.isUnused(inst)) {
50055002 try reap(f, inst, &.{ty_op.operand});
5006 return CValue.none;
5003 return .none;
50075004 }
50085005
50095006 const operand = try f.resolveInst(ty_op.operand);
......@@ -5014,7 +5011,7 @@ fn airOptionalPayload(f: *Function, inst: Air.Inst.Index) !CValue {
50145011 const payload_ty = opt_ty.optionalChild(&buf);
50155012
50165013 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
5017 return CValue.none;
5014 return .none;
50185015 }
50195016
50205017 const inst_ty = f.air.typeOfIndex(inst);
......@@ -5043,7 +5040,7 @@ fn airOptionalPayload(f: *Function, inst: Air.Inst.Index) !CValue {
50435040 try f.writeCValueMember(writer, operand, .{ .identifier = "payload" });
50445041 if (is_array) {
50455042 try writer.writeAll(", sizeof(");
5046 try f.renderTypecast(writer, inst_ty);
5043 try f.renderType(writer, inst_ty);
50475044 try writer.writeAll("))");
50485045 }
50495046 try writer.writeAll(";\n");
......@@ -5055,7 +5052,7 @@ fn airOptionalPayloadPtr(f: *Function, inst: Air.Inst.Index) !CValue {
50555052
50565053 if (f.liveness.isUnused(inst)) {
50575054 try reap(f, inst, &.{ty_op.operand});
5058 return CValue.none;
5055 return .none;
50595056 }
50605057
50615058 const writer = f.object.writer();
......@@ -5066,7 +5063,7 @@ fn airOptionalPayloadPtr(f: *Function, inst: Air.Inst.Index) !CValue {
50665063 const inst_ty = f.air.typeOfIndex(inst);
50675064
50685065 if (!inst_ty.childType().hasRuntimeBitsIgnoreComptime()) {
5069 return CValue{ .undef = inst_ty };
5066 return .{ .undef = inst_ty };
50705067 }
50715068
50725069 const local = try f.allocLocal(inst, inst_ty);
......@@ -5098,7 +5095,7 @@ fn airOptionalPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
50985095
50995096 if (opt_ty.optionalReprIsPayload()) {
51005097 if (f.liveness.isUnused(inst)) {
5101 return CValue.none;
5098 return .none;
51025099 }
51035100 const local = try f.allocLocal(inst, inst_ty);
51045101 // The payload and the optional are the same value.
......@@ -5115,7 +5112,7 @@ fn airOptionalPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
51155112 try writer.writeAll(";\n");
51165113
51175114 if (f.liveness.isUnused(inst)) {
5118 return CValue.none;
5115 return .none;
51195116 }
51205117
51215118 const local = try f.allocLocal(inst, inst_ty);
......@@ -5127,6 +5124,62 @@ fn airOptionalPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
51275124 }
51285125}
51295126
5127fn fieldLocation(
5128 container_ty: Type,
5129 field_ptr_ty: Type,
5130 field_index: u32,
5131 target: std.Target,
5132) union(enum) {
5133 begin: void,
5134 field: CValue,
5135 byte_offset: u32,
5136 end: void,
5137} {
5138 return switch (container_ty.zigTypeTag()) {
5139 .Struct => switch (container_ty.containerLayout()) {
5140 .Auto, .Extern => for (field_index..container_ty.structFieldCount()) |next_field_index| {
5141 if (container_ty.structFieldIsComptime(next_field_index)) continue;
5142 const field_ty = container_ty.structFieldType(next_field_index);
5143 if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue;
5144 break .{ .field = if (container_ty.isSimpleTuple())
5145 .{ .field = next_field_index }
5146 else
5147 .{ .identifier = container_ty.structFieldName(next_field_index) } };
5148 } else if (container_ty.hasRuntimeBitsIgnoreComptime()) .end else .begin,
5149 .Packed => if (field_ptr_ty.ptrInfo().data.host_size == 0)
5150 .{ .byte_offset = container_ty.packedStructFieldByteOffset(field_index, target) }
5151 else
5152 .begin,
5153 },
5154 .Union => switch (container_ty.containerLayout()) {
5155 .Auto, .Extern => {
5156 const field_ty = container_ty.structFieldType(field_index);
5157 if (!field_ty.hasRuntimeBitsIgnoreComptime())
5158 return if (container_ty.unionTagTypeSafety() != null and
5159 !container_ty.unionHasAllZeroBitFieldTypes())
5160 .{ .field = .{ .identifier = "payload" } }
5161 else
5162 .begin;
5163 const field_name = container_ty.unionFields().keys()[field_index];
5164 return .{ .field = if (container_ty.unionTagTypeSafety()) |_|
5165 .{ .payload_identifier = field_name }
5166 else
5167 .{ .identifier = field_name } };
5168 },
5169 .Packed => .begin,
5170 },
5171 .Pointer => switch (container_ty.ptrSize()) {
5172 .Slice => switch (field_index) {
5173 0 => .{ .field = .{ .identifier = "ptr" } },
5174 1 => .{ .field = .{ .identifier = "len" } },
5175 else => unreachable,
5176 },
5177 .One, .Many, .C => unreachable,
5178 },
5179 else => unreachable,
5180 };
5181}
5182
51305183fn airStructFieldPtr(f: *Function, inst: Air.Inst.Index) !CValue {
51315184 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
51325185 const extra = f.air.extraData(Air.StructField, ty_pl.payload).data;
......@@ -5136,10 +5189,10 @@ fn airStructFieldPtr(f: *Function, inst: Air.Inst.Index) !CValue {
51365189 return .none;
51375190 }
51385191
5139 const struct_ptr = try f.resolveInst(extra.struct_operand);
5192 const container_ptr_val = try f.resolveInst(extra.struct_operand);
51405193 try reap(f, inst, &.{extra.struct_operand});
5141 const struct_ptr_ty = f.air.typeOf(extra.struct_operand);
5142 return structFieldPtr(f, inst, struct_ptr_ty, struct_ptr, extra.field_index);
5194 const container_ptr_ty = f.air.typeOf(extra.struct_operand);
5195 return fieldPtr(f, inst, container_ptr_ty, container_ptr_val, extra.field_index);
51435196}
51445197
51455198fn airStructFieldPtrIndex(f: *Function, inst: Air.Inst.Index, index: u8) !CValue {
......@@ -5150,10 +5203,10 @@ fn airStructFieldPtrIndex(f: *Function, inst: Air.Inst.Index, index: u8) !CValue
51505203 return .none;
51515204 }
51525205
5153 const struct_ptr = try f.resolveInst(ty_op.operand);
5206 const container_ptr_val = try f.resolveInst(ty_op.operand);
51545207 try reap(f, inst, &.{ty_op.operand});
5155 const struct_ptr_ty = f.air.typeOf(ty_op.operand);
5156 return structFieldPtr(f, inst, struct_ptr_ty, struct_ptr, index);
5208 const container_ptr_ty = f.air.typeOf(ty_op.operand);
5209 return fieldPtr(f, inst, container_ptr_ty, container_ptr_val, index);
51575210}
51585211
51595212fn airFieldParentPtr(f: *Function, inst: Air.Inst.Index) !CValue {
......@@ -5162,133 +5215,119 @@ fn airFieldParentPtr(f: *Function, inst: Air.Inst.Index) !CValue {
51625215
51635216 if (f.liveness.isUnused(inst)) {
51645217 try reap(f, inst, &.{extra.field_ptr});
5165 return CValue.none;
5218 return .none;
51665219 }
51675220
5168 const struct_ptr_ty = f.air.typeOfIndex(inst);
5221 const target = f.object.dg.module.getTarget();
5222 const container_ptr_ty = f.air.typeOfIndex(inst);
5223 const container_ty = container_ptr_ty.childType();
51695224
51705225 const field_ptr_ty = f.air.typeOf(extra.field_ptr);
51715226 const field_ptr_val = try f.resolveInst(extra.field_ptr);
51725227 try reap(f, inst, &.{extra.field_ptr});
51735228
5174 const target = f.object.dg.module.getTarget();
5175 const struct_ty = struct_ptr_ty.childType();
5229 const writer = f.object.writer();
5230 const local = try f.allocLocal(inst, container_ptr_ty);
5231 try f.writeCValue(writer, local, .Other);
5232 try writer.writeAll(" = (");
5233 try f.renderType(writer, container_ptr_ty);
5234 try writer.writeByte(')');
51765235
5177 if (struct_ty.zigTypeTag() == .Union) {
5178 return f.fail("TODO: CBE: @fieldParentPtr for unions", .{});
5179 }
5236 switch (fieldLocation(container_ty, field_ptr_ty, extra.field_index, target)) {
5237 .begin => try f.writeCValue(writer, field_ptr_val, .Initializer),
5238 .field => |field| {
5239 var u8_ptr_pl = field_ptr_ty.ptrInfo();
5240 u8_ptr_pl.data.pointee_type = Type.u8;
5241 const u8_ptr_ty = Type.initPayload(&u8_ptr_pl.base);
51805242
5181 const field_offset = struct_ty.structFieldOffset(extra.field_index, target);
5243 try writer.writeAll("((");
5244 try f.renderType(writer, u8_ptr_ty);
5245 try writer.writeByte(')');
5246 try f.writeCValue(writer, field_ptr_val, .Other);
5247 try writer.writeAll(" - offsetof(");
5248 try f.renderType(writer, container_ty);
5249 try writer.writeAll(", ");
5250 try f.writeCValue(writer, field, .Other);
5251 try writer.writeAll("))");
5252 },
5253 .byte_offset => |byte_offset| {
5254 var u8_ptr_pl = field_ptr_ty.ptrInfo();
5255 u8_ptr_pl.data.pointee_type = Type.u8;
5256 const u8_ptr_ty = Type.initPayload(&u8_ptr_pl.base);
51825257
5183 var field_offset_pl = Value.Payload.I64{
5184 .base = .{ .tag = .int_i64 },
5185 .data = -@intCast(i64, field_offset),
5186 };
5187 const field_offset_val = Value.initPayload(&field_offset_pl.base);
5258 var byte_offset_pl = Value.Payload.U64{
5259 .base = .{ .tag = .int_u64 },
5260 .data = byte_offset,
5261 };
5262 const byte_offset_val = Value.initPayload(&byte_offset_pl.base);
51885263
5189 var u8_ptr_pl = field_ptr_ty.ptrInfo();
5190 u8_ptr_pl.data.pointee_type = Type.u8;
5191 const u8_ptr_ty = Type.initPayload(&u8_ptr_pl.base);
5264 try writer.writeAll("((");
5265 try f.renderType(writer, u8_ptr_ty);
5266 try writer.writeByte(')');
5267 try f.writeCValue(writer, field_ptr_val, .Other);
5268 try writer.print(" - {})", .{try f.fmtIntLiteral(Type.usize, byte_offset_val)});
5269 },
5270 .end => {
5271 try f.writeCValue(writer, field_ptr_val, .Other);
5272 try writer.print(" - {}", .{try f.fmtIntLiteral(Type.usize, Value.one)});
5273 },
5274 }
51925275
5193 const writer = f.object.writer();
5194 const local = try f.allocLocal(inst, struct_ptr_ty);
5195 try f.writeCValue(writer, local, .Other);
5196 try writer.writeAll(" = (");
5197 try f.renderTypecast(writer, struct_ptr_ty);
5198 try writer.writeAll(")&((");
5199 try f.renderTypecast(writer, u8_ptr_ty);
5200 try writer.writeByte(')');
5201 try f.writeCValue(writer, field_ptr_val, .Other);
5202 try writer.print(")[{}];\n", .{try f.fmtIntLiteral(Type.isize, field_offset_val)});
5276 try writer.writeAll(";\n");
52035277 return local;
52045278}
52055279
5206fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struct_ptr: CValue, index: u32) !CValue {
5207 const writer = f.object.writer();
5280fn fieldPtr(
5281 f: *Function,
5282 inst: Air.Inst.Index,
5283 container_ptr_ty: Type,
5284 container_ptr_val: CValue,
5285 field_index: u32,
5286) !CValue {
5287 const target = f.object.dg.module.getTarget();
5288 const container_ty = container_ptr_ty.elemType();
52085289 const field_ptr_ty = f.air.typeOfIndex(inst);
5209 const field_ptr_info = field_ptr_ty.ptrInfo();
5210 const struct_ty = struct_ptr_ty.elemType();
5211 const field_ty = struct_ty.structFieldType(index);
52125290
52135291 // Ensure complete type definition is visible before accessing fields.
5214 try f.renderType(std.io.null_writer, struct_ty);
5292 _ = try f.typeToIndex(container_ty, .complete);
52155293
5294 const writer = f.object.writer();
52165295 const local = try f.allocLocal(inst, field_ptr_ty);
52175296 try f.writeCValue(writer, local, .Other);
52185297 try writer.writeAll(" = (");
5219 try f.renderTypecast(writer, field_ptr_ty);
5298 try f.renderType(writer, field_ptr_ty);
52205299 try writer.writeByte(')');
52215300
5222 const extra_name: CValue = switch (struct_ty.tag()) {
5223 .union_tagged, .union_safety_tagged => .{ .identifier = "payload" },
5224 else => .none,
5225 };
5226
5227 const field_loc: union(enum) {
5228 begin: void,
5229 field: CValue,
5230 end: void,
5231 } = switch (struct_ty.tag()) {
5232 .tuple, .anon_struct, .@"struct" => switch (struct_ty.containerLayout()) {
5233 .Auto, .Extern => for (index..struct_ty.structFieldCount()) |field_i| {
5234 if (!struct_ty.structFieldIsComptime(field_i) and
5235 struct_ty.structFieldType(field_i).hasRuntimeBitsIgnoreComptime())
5236 break .{ .field = if (struct_ty.isSimpleTuple())
5237 .{ .field = field_i }
5238 else
5239 .{ .identifier = struct_ty.structFieldName(field_i) } };
5240 } else .end,
5241 .Packed => if (field_ptr_info.data.host_size == 0) {
5242 const target = f.object.dg.module.getTarget();
5243
5244 const byte_offset = struct_ty.packedStructFieldByteOffset(index, target);
5245 var byte_offset_pl = Value.Payload.U64{
5246 .base = .{ .tag = .int_u64 },
5247 .data = byte_offset,
5248 };
5249 const byte_offset_val = Value.initPayload(&byte_offset_pl.base);
5250
5251 var u8_ptr_pl = field_ptr_info;
5252 u8_ptr_pl.data.pointee_type = Type.u8;
5253 const u8_ptr_ty = Type.initPayload(&u8_ptr_pl.base);
5301 switch (fieldLocation(container_ty, field_ptr_ty, field_index, target)) {
5302 .begin => try f.writeCValue(writer, container_ptr_val, .Initializer),
5303 .field => |field| {
5304 try writer.writeByte('&');
5305 try f.writeCValueDerefMember(writer, container_ptr_val, field);
5306 },
5307 .byte_offset => |byte_offset| {
5308 var u8_ptr_pl = field_ptr_ty.ptrInfo();
5309 u8_ptr_pl.data.pointee_type = Type.u8;
5310 const u8_ptr_ty = Type.initPayload(&u8_ptr_pl.base);
52545311
5255 if (!std.mem.isAligned(byte_offset, field_ptr_ty.ptrAlignment(target))) {
5256 return f.fail("TODO: CBE: unaligned packed struct field pointer", .{});
5257 }
5312 var byte_offset_pl = Value.Payload.U64{
5313 .base = .{ .tag = .int_u64 },
5314 .data = byte_offset,
5315 };
5316 const byte_offset_val = Value.initPayload(&byte_offset_pl.base);
52585317
5259 try writer.writeAll("&((");
5260 try f.renderTypecast(writer, u8_ptr_ty);
5261 try writer.writeByte(')');
5262 try f.writeCValue(writer, struct_ptr, .Other);
5263 try writer.print(")[{}];\n", .{try f.fmtIntLiteral(Type.usize, byte_offset_val)});
5264 return local;
5265 } else .begin,
5318 try writer.writeAll("((");
5319 try f.renderType(writer, u8_ptr_ty);
5320 try writer.writeByte(')');
5321 try f.writeCValue(writer, container_ptr_val, .Other);
5322 try writer.print(" + {})", .{try f.fmtIntLiteral(Type.usize, byte_offset_val)});
52665323 },
5267 .@"union", .union_safety_tagged, .union_tagged => if (struct_ty.containerLayout() == .Packed) {
5268 try f.writeCValue(writer, struct_ptr, .Other);
5269 try writer.writeAll(";\n");
5270 return local;
5271 } else if (field_ty.hasRuntimeBitsIgnoreComptime()) .{ .field = .{
5272 .identifier = struct_ty.unionFields().keys()[index],
5273 } } else .end,
5274 else => unreachable,
5275 };
5324 .end => {
5325 try writer.writeByte('(');
5326 try f.writeCValue(writer, container_ptr_val, .Other);
5327 try writer.print(" + {})", .{try f.fmtIntLiteral(Type.usize, Value.one)});
5328 },
5329 }
52765330
5277 if (struct_ty.hasRuntimeBitsIgnoreComptime()) {
5278 try writer.writeByte('&');
5279 switch (field_loc) {
5280 .begin, .end => {
5281 try writer.writeByte('(');
5282 try f.writeCValue(writer, struct_ptr, .Other);
5283 try writer.print(")[{}]", .{@boolToInt(field_loc == .end)});
5284 },
5285 .field => |field| if (extra_name != .none) {
5286 try f.writeCValueDerefMember(writer, struct_ptr, extra_name);
5287 try writer.writeByte('.');
5288 try f.writeCValue(writer, field, .Other);
5289 } else try f.writeCValueDerefMember(writer, struct_ptr, field),
5290 }
5291 } else try f.writeCValue(writer, struct_ptr, .Other);
52925331 try writer.writeAll(";\n");
52935332 return local;
52945333}
......@@ -5299,13 +5338,13 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
52995338
53005339 if (f.liveness.isUnused(inst)) {
53015340 try reap(f, inst, &.{extra.struct_operand});
5302 return CValue.none;
5341 return .none;
53035342 }
53045343
53055344 const inst_ty = f.air.typeOfIndex(inst);
53065345 if (!inst_ty.hasRuntimeBitsIgnoreComptime()) {
53075346 try reap(f, inst, &.{extra.struct_operand});
5308 return CValue.none;
5347 return .none;
53095348 }
53105349
53115350 const target = f.object.dg.module.getTarget();
......@@ -5315,12 +5354,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
53155354 const writer = f.object.writer();
53165355
53175356 // Ensure complete type definition is visible before accessing fields.
5318 try f.renderType(std.io.null_writer, struct_ty);
5319
5320 const extra_name: CValue = switch (struct_ty.tag()) {
5321 .union_tagged, .union_safety_tagged => .{ .identifier = "payload" },
5322 else => .none,
5323 };
5357 _ = try f.typeToIndex(struct_ty, .complete);
53245358
53255359 const field_name: CValue = switch (struct_ty.tag()) {
53265360 .tuple, .anon_struct, .@"struct" => switch (struct_ty.containerLayout()) {
......@@ -5362,7 +5396,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
53625396 try writer.writeAll(" = zig_wrap_");
53635397 try f.object.dg.renderTypeForBuiltinFnName(writer, field_int_ty);
53645398 try writer.writeAll("((");
5365 try f.renderTypecast(writer, field_int_ty);
5399 try f.renderType(writer, field_int_ty);
53665400 try writer.writeByte(')');
53675401 const cant_cast = int_info.bits > 64;
53685402 if (cant_cast) {
......@@ -5389,7 +5423,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
53895423 try writer.writeAll(", ");
53905424 try f.writeCValue(writer, .{ .local_ref = temp_local.new_local }, .FunctionArgument);
53915425 try writer.writeAll(", sizeof(");
5392 try f.renderTypecast(writer, inst_ty);
5426 try f.renderType(writer, inst_ty);
53935427 try writer.writeAll("));\n");
53945428 try freeLocal(f, inst, temp_local.new_local, 0);
53955429 return local;
......@@ -5411,7 +5445,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
54115445 try writer.writeAll(", &");
54125446 try f.writeCValue(writer, operand_lval, .FunctionArgument);
54135447 try writer.writeAll(", sizeof(");
5414 try f.renderTypecast(writer, inst_ty);
5448 try f.renderType(writer, inst_ty);
54155449 try writer.writeAll("));\n");
54165450
54175451 if (struct_byval == .constant) {
......@@ -5419,31 +5453,29 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
54195453 }
54205454
54215455 return local;
5422 } else .{
5423 .identifier = struct_ty.unionFields().keys()[extra.field_index],
5456 } else field_name: {
5457 const name = struct_ty.unionFields().keys()[extra.field_index];
5458 break :field_name if (struct_ty.unionTagTypeSafety()) |_|
5459 .{ .payload_identifier = name }
5460 else
5461 .{ .identifier = name };
54245462 },
54255463 else => unreachable,
54265464 };
54275465
5428 const is_array = lowersToArray(inst_ty, target);
54295466 const local = try f.allocLocal(inst, inst_ty);
5430 if (is_array) {
5467 if (lowersToArray(inst_ty, target)) {
54315468 try writer.writeAll("memcpy(");
54325469 try f.writeCValue(writer, local, .FunctionArgument);
54335470 try writer.writeAll(", ");
5471 try f.writeCValueMember(writer, struct_byval, field_name);
5472 try writer.writeAll(", sizeof(");
5473 try f.renderType(writer, inst_ty);
5474 try writer.writeAll("))");
54345475 } else {
54355476 try f.writeCValue(writer, local, .Other);
54365477 try writer.writeAll(" = ");
5437 }
5438 if (extra_name != .none) {
5439 try f.writeCValueMember(writer, struct_byval, extra_name);
5440 try writer.writeByte('.');
5441 try f.writeCValue(writer, field_name, .Other);
5442 } else try f.writeCValueMember(writer, struct_byval, field_name);
5443 if (is_array) {
5444 try writer.writeAll(", sizeof(");
5445 try f.renderTypecast(writer, inst_ty);
5446 try writer.writeAll("))");
5478 try f.writeCValueMember(writer, struct_byval, field_name);
54475479 }
54485480 try writer.writeAll(";\n");
54495481 return local;
......@@ -5456,7 +5488,7 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
54565488
54575489 if (f.liveness.isUnused(inst)) {
54585490 try reap(f, inst, &.{ty_op.operand});
5459 return CValue.none;
5491 return .none;
54605492 }
54615493
54625494 const inst_ty = f.air.typeOfIndex(inst);
......@@ -5493,7 +5525,7 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValu
54935525
54945526 if (f.liveness.isUnused(inst)) {
54955527 try reap(f, inst, &.{ty_op.operand});
5496 return CValue.none;
5528 return .none;
54975529 }
54985530
54995531 const inst_ty = f.air.typeOfIndex(inst);
......@@ -5504,13 +5536,13 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValu
55045536 const error_union_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty;
55055537
55065538 if (!error_union_ty.errorUnionPayload().hasRuntimeBits()) {
5507 if (!is_ptr) return CValue.none;
5539 if (!is_ptr) return .none;
55085540
55095541 const w = f.object.writer();
55105542 const local = try f.allocLocal(inst, inst_ty);
55115543 try f.writeCValue(w, local, .Other);
55125544 try w.writeAll(" = (");
5513 try f.renderTypecast(w, inst_ty);
5545 try f.renderType(w, inst_ty);
55145546 try w.writeByte(')');
55155547 try f.writeCValue(w, operand, .Initializer);
55165548 try w.writeAll(";\n");
......@@ -5535,7 +5567,7 @@ fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue {
55355567
55365568 if (f.liveness.isUnused(inst)) {
55375569 try reap(f, inst, &.{ty_op.operand});
5538 return CValue.none;
5570 return .none;
55395571 }
55405572
55415573 const inst_ty = f.air.typeOfIndex(inst);
......@@ -5571,7 +5603,7 @@ fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue {
55715603 try writer.writeAll(", ");
55725604 try f.writeCValue(writer, payload, .FunctionArgument);
55735605 try writer.writeAll(", sizeof(");
5574 try f.renderTypecast(writer, payload_ty);
5606 try f.renderType(writer, payload_ty);
55755607 try writer.writeAll("));\n");
55765608 }
55775609 return local;
......@@ -5581,7 +5613,7 @@ fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
55815613 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
55825614 if (f.liveness.isUnused(inst)) {
55835615 try reap(f, inst, &.{ty_op.operand});
5584 return CValue.none;
5616 return .none;
55855617 }
55865618
55875619 const writer = f.object.writer();
......@@ -5635,7 +5667,7 @@ fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
56355667 try writer.writeAll(";\n");
56365668
56375669 // Then return the payload pointer (only if it is used)
5638 if (f.liveness.isUnused(inst)) return CValue.none;
5670 if (f.liveness.isUnused(inst)) return .none;
56395671
56405672 const local = try f.allocLocal(inst, f.air.typeOfIndex(inst));
56415673 try f.writeCValue(writer, local, .Other);
......@@ -5646,7 +5678,7 @@ fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
56465678}
56475679
56485680fn airErrReturnTrace(f: *Function, inst: Air.Inst.Index) !CValue {
5649 if (f.liveness.isUnused(inst)) return CValue.none;
5681 if (f.liveness.isUnused(inst)) return .none;
56505682 return f.fail("TODO: C backend: implement airErrReturnTrace", .{});
56515683}
56525684
......@@ -5664,7 +5696,7 @@ fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {
56645696 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
56655697 if (f.liveness.isUnused(inst)) {
56665698 try reap(f, inst, &.{ty_op.operand});
5667 return CValue.none;
5699 return .none;
56685700 }
56695701
56705702 const inst_ty = f.air.typeOfIndex(inst);
......@@ -5691,7 +5723,7 @@ fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {
56915723 try writer.writeAll(", ");
56925724 try f.writeCValue(writer, payload, .FunctionArgument);
56935725 try writer.writeAll(", sizeof(");
5694 try f.renderTypecast(writer, payload_ty);
5726 try f.renderType(writer, payload_ty);
56955727 try writer.writeAll("));\n");
56965728 }
56975729 return local;
......@@ -5702,7 +5734,7 @@ fn airIsErr(f: *Function, inst: Air.Inst.Index, is_ptr: bool, operator: []const
57025734
57035735 if (f.liveness.isUnused(inst)) {
57045736 try reap(f, inst, &.{un_op});
5705 return CValue.none;
5737 return .none;
57065738 }
57075739
57085740 const writer = f.object.writer();
......@@ -5740,7 +5772,7 @@ fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue {
57405772
57415773 if (f.liveness.isUnused(inst)) {
57425774 try reap(f, inst, &.{ty_op.operand});
5743 return CValue.none;
5775 return .none;
57445776 }
57455777
57465778 const operand = try f.resolveInst(ty_op.operand);
......@@ -5756,7 +5788,7 @@ fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue {
57565788 // &(*(void *)p)[0], although LLVM does via GetElementPtr
57575789 if (operand == .undef) {
57585790 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
5759 try f.writeCValue(writer, CValue{ .undef = inst_ty.slicePtrFieldType(&buf) }, .Initializer);
5791 try f.writeCValue(writer, .{ .undef = inst_ty.slicePtrFieldType(&buf) }, .Initializer);
57605792 } else if (array_ty.hasRuntimeBitsIgnoreComptime()) {
57615793 try writer.writeAll("&(");
57625794 try f.writeCValueDeref(writer, operand);
......@@ -5778,7 +5810,7 @@ fn airFloatCast(f: *Function, inst: Air.Inst.Index) !CValue {
57785810
57795811 if (f.liveness.isUnused(inst)) {
57805812 try reap(f, inst, &.{ty_op.operand});
5781 return CValue.none;
5813 return .none;
57825814 }
57835815
57845816 const inst_ty = f.air.typeOfIndex(inst);
......@@ -5826,7 +5858,7 @@ fn airPtrToInt(f: *Function, inst: Air.Inst.Index) !CValue {
58265858
58275859 if (f.liveness.isUnused(inst)) {
58285860 try reap(f, inst, &.{un_op});
5829 return CValue.none;
5861 return .none;
58305862 }
58315863
58325864 const operand = try f.resolveInst(un_op);
......@@ -5837,7 +5869,7 @@ fn airPtrToInt(f: *Function, inst: Air.Inst.Index) !CValue {
58375869 try f.writeCValue(writer, local, .Other);
58385870
58395871 try writer.writeAll(" = (");
5840 try f.renderTypecast(writer, inst_ty);
5872 try f.renderType(writer, inst_ty);
58415873 try writer.writeByte(')');
58425874 try f.writeCValue(writer, operand, .Other);
58435875 try writer.writeAll(";\n");
......@@ -5854,7 +5886,7 @@ fn airUnBuiltinCall(
58545886
58555887 if (f.liveness.isUnused(inst)) {
58565888 try reap(f, inst, &.{ty_op.operand});
5857 return CValue.none;
5889 return .none;
58585890 }
58595891
58605892 const operand = try f.resolveInst(ty_op.operand);
......@@ -5886,7 +5918,7 @@ fn airBinBuiltinCall(
58865918
58875919 if (f.liveness.isUnused(inst)) {
58885920 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
5889 return CValue.none;
5921 return .none;
58905922 }
58915923
58925924 const lhs = try f.resolveInst(bin_op.lhs);
......@@ -5959,7 +5991,7 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue
59595991 try writer.writeAll(";\n");
59605992 try writer.writeAll("if (");
59615993 try writer.print("zig_cmpxchg_{s}((zig_atomic(", .{flavor});
5962 try f.renderTypecast(writer, ptr_ty.childType());
5994 try f.renderType(writer, ptr_ty.childType());
59635995 try writer.writeByte(')');
59645996 if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile");
59655997 try writer.writeAll(" *)");
......@@ -5988,7 +6020,7 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue
59886020 try writer.writeAll(";\n");
59896021 try f.writeCValue(writer, local, .Other);
59906022 try writer.print(".is_null = zig_cmpxchg_{s}((zig_atomic(", .{flavor});
5991 try f.renderTypecast(writer, ptr_ty.childType());
6023 try f.renderType(writer, ptr_ty.childType());
59926024 try writer.writeByte(')');
59936025 if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile");
59946026 try writer.writeAll(" *)");
......@@ -6009,7 +6041,7 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue
60096041
60106042 if (f.liveness.isUnused(inst)) {
60116043 try freeLocal(f, inst, local.new_local, 0);
6012 return CValue.none;
6044 return .none;
60136045 }
60146046
60156047 return local;
......@@ -6031,12 +6063,12 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue {
60316063 switch (extra.op()) {
60326064 else => {
60336065 try writer.writeAll("zig_atomic(");
6034 try f.renderTypecast(writer, ptr_ty.elemType());
6066 try f.renderType(writer, ptr_ty.elemType());
60356067 try writer.writeByte(')');
60366068 },
60376069 .Nand, .Min, .Max => {
60386070 // These are missing from stdatomic.h, so no atomic types for now.
6039 try f.renderTypecast(writer, ptr_ty.elemType());
6071 try f.renderType(writer, ptr_ty.elemType());
60406072 },
60416073 }
60426074 if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile");
......@@ -6052,7 +6084,7 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue {
60526084
60536085 if (f.liveness.isUnused(inst)) {
60546086 try freeLocal(f, inst, local.new_local, 0);
6055 return CValue.none;
6087 return .none;
60566088 }
60576089
60586090 return local;
......@@ -6064,7 +6096,7 @@ fn airAtomicLoad(f: *Function, inst: Air.Inst.Index) !CValue {
60646096 try reap(f, inst, &.{atomic_load.ptr});
60656097 const ptr_ty = f.air.typeOf(atomic_load.ptr);
60666098 if (!ptr_ty.isVolatilePtr() and f.liveness.isUnused(inst)) {
6067 return CValue.none;
6099 return .none;
60686100 }
60696101
60706102 const inst_ty = f.air.typeOfIndex(inst);
......@@ -6073,7 +6105,7 @@ fn airAtomicLoad(f: *Function, inst: Air.Inst.Index) !CValue {
60736105 try f.writeCValue(writer, local, .Other);
60746106
60756107 try writer.writeAll(" = zig_atomic_load((zig_atomic(");
6076 try f.renderTypecast(writer, ptr_ty.elemType());
6108 try f.renderType(writer, ptr_ty.elemType());
60776109 try writer.writeByte(')');
60786110 if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile");
60796111 try writer.writeAll(" *)");
......@@ -6096,7 +6128,7 @@ fn airAtomicStore(f: *Function, inst: Air.Inst.Index, order: [*:0]const u8) !CVa
60966128 const writer = f.object.writer();
60976129
60986130 try writer.writeAll("zig_atomic_store((zig_atomic(");
6099 try f.renderTypecast(writer, ptr_ty.elemType());
6131 try f.renderType(writer, ptr_ty.elemType());
61006132 try writer.writeByte(')');
61016133 if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile");
61026134 try writer.writeAll(" *)");
......@@ -6107,7 +6139,7 @@ fn airAtomicStore(f: *Function, inst: Air.Inst.Index, order: [*:0]const u8) !CVa
61076139 try f.object.dg.renderTypeForBuiltinFnName(writer, ptr_ty.childType());
61086140 try writer.writeAll(");\n");
61096141
6110 return CValue.none;
6142 return .none;
61116143}
61126144
61136145fn airMemset(f: *Function, inst: Air.Inst.Index) !CValue {
......@@ -6138,7 +6170,7 @@ fn airMemset(f: *Function, inst: Air.Inst.Index) !CValue {
61386170 try writer.writeAll(" += ");
61396171 try f.object.dg.renderValue(writer, Type.usize, Value.one, .Other);
61406172 try writer.writeAll(") ((");
6141 try f.renderTypecast(writer, u8_ptr_ty);
6173 try f.renderType(writer, u8_ptr_ty);
61426174 try writer.writeByte(')');
61436175 try f.writeCValue(writer, dest_ptr, .FunctionArgument);
61446176 try writer.writeAll(")[");
......@@ -6150,7 +6182,7 @@ fn airMemset(f: *Function, inst: Air.Inst.Index) !CValue {
61506182 try reap(f, inst, &.{ pl_op.operand, extra.lhs, extra.rhs });
61516183 try freeLocal(f, inst, index.new_local, 0);
61526184
6153 return CValue.none;
6185 return .none;
61546186 }
61556187
61566188 try reap(f, inst, &.{ pl_op.operand, extra.lhs, extra.rhs });
......@@ -6162,7 +6194,7 @@ fn airMemset(f: *Function, inst: Air.Inst.Index) !CValue {
61626194 try f.writeCValue(writer, len, .FunctionArgument);
61636195 try writer.writeAll(");\n");
61646196
6165 return CValue.none;
6197 return .none;
61666198}
61676199
61686200fn airMemcpy(f: *Function, inst: Air.Inst.Index) !CValue {
......@@ -6182,7 +6214,7 @@ fn airMemcpy(f: *Function, inst: Air.Inst.Index) !CValue {
61826214 try f.writeCValue(writer, len, .FunctionArgument);
61836215 try writer.writeAll(");\n");
61846216
6185 return CValue.none;
6217 return .none;
61866218}
61876219
61886220fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
......@@ -6195,7 +6227,7 @@ fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
61956227 const union_ty = f.air.typeOf(bin_op.lhs).childType();
61966228 const target = f.object.dg.module.getTarget();
61976229 const layout = union_ty.unionGetLayout(target);
6198 if (layout.tag_size == 0) return CValue.none;
6230 if (layout.tag_size == 0) return .none;
61996231
62006232 try writer.writeByte('(');
62016233 try f.writeCValue(writer, union_ptr, .Other);
......@@ -6203,7 +6235,7 @@ fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
62036235 try f.writeCValue(writer, new_tag, .Other);
62046236 try writer.writeAll(";\n");
62056237
6206 return CValue.none;
6238 return .none;
62076239}
62086240
62096241fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
......@@ -6211,7 +6243,7 @@ fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
62116243
62126244 if (f.liveness.isUnused(inst)) {
62136245 try reap(f, inst, &.{ty_op.operand});
6214 return CValue.none;
6246 return .none;
62156247 }
62166248
62176249 const operand = try f.resolveInst(ty_op.operand);
......@@ -6221,7 +6253,7 @@ fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
62216253
62226254 const target = f.object.dg.module.getTarget();
62236255 const layout = un_ty.unionGetLayout(target);
6224 if (layout.tag_size == 0) return CValue.none;
6256 if (layout.tag_size == 0) return .none;
62256257
62266258 const inst_ty = f.air.typeOfIndex(inst);
62276259 const writer = f.object.writer();
......@@ -6239,7 +6271,7 @@ fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue {
62396271
62406272 if (f.liveness.isUnused(inst)) {
62416273 try reap(f, inst, &.{un_op});
6242 return CValue.none;
6274 return .none;
62436275 }
62446276
62456277 const inst_ty = f.air.typeOfIndex(inst);
......@@ -6250,7 +6282,9 @@ fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue {
62506282 const writer = f.object.writer();
62516283 const local = try f.allocLocal(inst, inst_ty);
62526284 try f.writeCValue(writer, local, .Other);
6253 try writer.print(" = {s}(", .{try f.getTagNameFn(enum_ty)});
6285 try writer.print(" = {s}(", .{
6286 try f.getLazyFnName(.{ .tag_name = enum_ty.getOwnerDecl() }, .{ .tag_name = enum_ty }),
6287 });
62546288 try f.writeCValue(writer, operand, .Other);
62556289 try writer.writeAll(");\n");
62566290
......@@ -6262,7 +6296,7 @@ fn airErrorName(f: *Function, inst: Air.Inst.Index) !CValue {
62626296
62636297 if (f.liveness.isUnused(inst)) {
62646298 try reap(f, inst, &.{un_op});
6265 return CValue.none;
6299 return .none;
62666300 }
62676301
62686302 const writer = f.object.writer();
......@@ -6282,7 +6316,7 @@ fn airSplat(f: *Function, inst: Air.Inst.Index) !CValue {
62826316 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
62836317 if (f.liveness.isUnused(inst)) {
62846318 try reap(f, inst, &.{ty_op.operand});
6285 return CValue.none;
6319 return .none;
62866320 }
62876321
62886322 const inst_ty = f.air.typeOfIndex(inst);
......@@ -6298,13 +6332,13 @@ fn airSplat(f: *Function, inst: Air.Inst.Index) !CValue {
62986332}
62996333
63006334fn airSelect(f: *Function, inst: Air.Inst.Index) !CValue {
6301 if (f.liveness.isUnused(inst)) return CValue.none;
6335 if (f.liveness.isUnused(inst)) return .none;
63026336
63036337 return f.fail("TODO: C backend: implement airSelect", .{});
63046338}
63056339
63066340fn airShuffle(f: *Function, inst: Air.Inst.Index) !CValue {
6307 if (f.liveness.isUnused(inst)) return CValue.none;
6341 if (f.liveness.isUnused(inst)) return .none;
63086342
63096343 return f.fail("TODO: C backend: implement airShuffle", .{});
63106344}
......@@ -6314,7 +6348,7 @@ fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue {
63146348
63156349 if (f.liveness.isUnused(inst)) {
63166350 try reap(f, inst, &.{reduce.operand});
6317 return CValue.none;
6351 return .none;
63186352 }
63196353
63206354 const target = f.object.dg.module.getTarget();
......@@ -6390,10 +6424,9 @@ fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue {
63906424 //
63916425 // Equivalent to:
63926426 // reduce: {
6393 // var i: usize = 0;
63946427 // var accum: T = init;
6395 // while (i < vec.len) : (i += 1) {
6396 // accum = func(accum, vec[i]);
6428 // for (vec) : (elem) {
6429 // accum = func(accum, elem);
63976430 // }
63986431 // break :reduce accum;
63996432 // }
......@@ -6488,7 +6521,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
64886521 }
64896522 }
64906523
6491 if (f.liveness.isUnused(inst)) return CValue.none;
6524 if (f.liveness.isUnused(inst)) return .none;
64926525
64936526 const target = f.object.dg.module.getTarget();
64946527
......@@ -6514,7 +6547,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
65146547 .Auto, .Extern => {
65156548 try f.writeCValue(writer, local, .Other);
65166549 try writer.writeAll(" = (");
6517 try f.renderTypecast(writer, inst_ty);
6550 try f.renderType(writer, inst_ty);
65186551 try writer.writeAll(")");
65196552 try writer.writeByte('{');
65206553 var empty = true;
......@@ -6533,7 +6566,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
65336566
65346567 const element_ty = f.air.typeOf(element);
65356568 try f.writeCValue(writer, switch (element_ty.zigTypeTag()) {
6536 .Array => CValue{ .undef = element_ty },
6569 .Array => .{ .undef = element_ty },
65376570 else => resolved_element,
65386571 }, .Initializer);
65396572 empty = false;
......@@ -6557,7 +6590,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
65576590 try writer.writeAll(", ");
65586591 try f.writeCValue(writer, resolved_element, .FunctionArgument);
65596592 try writer.writeAll(", sizeof(");
6560 try f.renderTypecast(writer, element_ty);
6593 try f.renderType(writer, element_ty);
65616594 try writer.writeAll("));\n");
65626595 }
65636596 },
......@@ -6602,11 +6635,11 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
66026635 try f.renderIntCast(writer, inst_ty, element, field_ty, .FunctionArgument);
66036636 } else {
66046637 try writer.writeByte('(');
6605 try f.renderTypecast(writer, inst_ty);
6638 try f.renderType(writer, inst_ty);
66066639 try writer.writeByte(')');
66076640 if (field_ty.isPtrAtRuntime()) {
66086641 try writer.writeByte('(');
6609 try f.renderTypecast(writer, switch (int_info.signedness) {
6642 try f.renderType(writer, switch (int_info.signedness) {
66106643 .unsigned => Type.usize,
66116644 .signed => Type.isize,
66126645 });
......@@ -6640,7 +6673,7 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {
66406673
66416674 if (f.liveness.isUnused(inst)) {
66426675 try reap(f, inst, &.{extra.init});
6643 return CValue.none;
6676 return .none;
66446677 }
66456678
66466679 const union_ty = f.air.typeOfIndex(inst);
......@@ -6660,7 +6693,7 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {
66606693 return local;
66616694 }
66626695
6663 if (union_ty.unionTagTypeSafety()) |tag_ty| {
6696 const field: CValue = if (union_ty.unionTagTypeSafety()) |tag_ty| field: {
66646697 const layout = union_ty.unionGetLayout(target);
66656698 if (layout.tag_size != 0) {
66666699 const field_index = tag_ty.enumFieldIndex(field_name).?;
......@@ -6677,18 +6710,13 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {
66776710 try f.writeCValue(writer, local, .Other);
66786711 try writer.print(".tag = {}; ", .{try f.fmtIntLiteral(tag_ty, int_val)});
66796712 }
6680 try f.writeCValue(writer, local, .Other);
6681 try writer.print(".payload.{ } = ", .{fmtIdent(field_name)});
6682 try f.writeCValue(writer, payload, .Other);
6683 try writer.writeAll(";\n");
6684 return local;
6685 }
6713 break :field .{ .payload_identifier = field_name };
6714 } else .{ .identifier = field_name };
66866715
6687 try f.writeCValue(writer, local, .Other);
6688 try writer.print(".{ } = ", .{fmtIdent(field_name)});
6716 try f.writeCValueMember(writer, local, field);
6717 try writer.writeAll(" = ");
66896718 try f.writeCValue(writer, payload, .Other);
66906719 try writer.writeAll(";\n");
6691
66926720 return local;
66936721}
66946722
......@@ -6699,7 +6727,7 @@ fn airPrefetch(f: *Function, inst: Air.Inst.Index) !CValue {
66996727 // The available prefetch intrinsics do not accept a cache argument; only
67006728 // address, rw, and locality. So unless the cache is data, we do not lower
67016729 // this instruction.
6702 .instruction => return CValue.none,
6730 .instruction => return .none,
67036731 }
67046732 const ptr = try f.resolveInst(prefetch.ptr);
67056733 try reap(f, inst, &.{prefetch.ptr});
......@@ -6709,11 +6737,11 @@ fn airPrefetch(f: *Function, inst: Air.Inst.Index) !CValue {
67096737 try writer.print(", {d}, {d});\n", .{
67106738 @enumToInt(prefetch.rw), prefetch.locality,
67116739 });
6712 return CValue.none;
6740 return .none;
67136741}
67146742
67156743fn airWasmMemorySize(f: *Function, inst: Air.Inst.Index) !CValue {
6716 if (f.liveness.isUnused(inst)) return CValue.none;
6744 if (f.liveness.isUnused(inst)) return .none;
67176745
67186746 const pl_op = f.air.instructions.items(.data)[inst].pl_op;
67196747
......@@ -6750,7 +6778,7 @@ fn airFloatNeg(f: *Function, inst: Air.Inst.Index) !CValue {
67506778 const un_op = f.air.instructions.items(.data)[inst].un_op;
67516779 if (f.liveness.isUnused(inst)) {
67526780 try reap(f, inst, &.{un_op});
6753 return CValue.none;
6781 return .none;
67546782 }
67556783
67566784 const operand = try f.resolveInst(un_op);
......@@ -6772,7 +6800,7 @@ fn airUnFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CVal
67726800 const un_op = f.air.instructions.items(.data)[inst].un_op;
67736801 if (f.liveness.isUnused(inst)) {
67746802 try reap(f, inst, &.{un_op});
6775 return CValue.none;
6803 return .none;
67766804 }
67776805 const operand = try f.resolveInst(un_op);
67786806 try reap(f, inst, &.{un_op});
......@@ -6794,7 +6822,7 @@ fn airBinFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CVa
67946822 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
67956823 if (f.liveness.isUnused(inst)) {
67966824 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
6797 return CValue.none;
6825 return .none;
67986826 }
67996827 const lhs = try f.resolveInst(bin_op.lhs);
68006828 const rhs = try f.resolveInst(bin_op.rhs);
......@@ -6821,7 +6849,7 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue {
68216849 const bin_op = f.air.extraData(Air.Bin, pl_op.payload).data;
68226850 if (f.liveness.isUnused(inst)) {
68236851 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs, pl_op.operand });
6824 return CValue.none;
6852 return .none;
68256853 }
68266854 const inst_ty = f.air.typeOfIndex(inst);
68276855 const mulend1 = try f.resolveInst(bin_op.lhs);
......@@ -6843,6 +6871,81 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue {
68436871 return local;
68446872}
68456873
6874fn airCVaStart(f: *Function, inst: Air.Inst.Index) !CValue {
6875 if (f.liveness.isUnused(inst)) return .none;
6876
6877 const inst_ty = f.air.typeOfIndex(inst);
6878 const fn_cty = try f.typeToCType(f.object.dg.decl.?.ty, .complete);
6879 const param_len = fn_cty.castTag(.varargs_function).?.data.param_types.len;
6880
6881 const writer = f.object.writer();
6882 const local = try f.allocLocal(inst, inst_ty);
6883 try writer.writeAll("va_start(*(va_list *)&");
6884 try f.writeCValue(writer, local, .Other);
6885 if (param_len > 0) {
6886 try writer.writeAll(", ");
6887 try f.writeCValue(writer, .{ .arg = param_len - 1 }, .FunctionArgument);
6888 }
6889 try writer.writeAll(");\n");
6890 return local;
6891}
6892
6893fn airCVaArg(f: *Function, inst: Air.Inst.Index) !CValue {
6894 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
6895 if (f.liveness.isUnused(inst)) {
6896 try reap(f, inst, &.{ty_op.operand});
6897 return .none;
6898 }
6899
6900 const inst_ty = f.air.typeOfIndex(inst);
6901 const va_list = try f.resolveInst(ty_op.operand);
6902 try reap(f, inst, &.{ty_op.operand});
6903
6904 const writer = f.object.writer();
6905 const local = try f.allocLocal(inst, inst_ty);
6906 try f.writeCValue(writer, local, .Other);
6907 try writer.writeAll(" = va_arg(*(va_list *)");
6908 try f.writeCValue(writer, va_list, .Other);
6909 try writer.writeAll(", ");
6910 try f.renderType(writer, f.air.getRefType(ty_op.ty));
6911 try writer.writeAll(");\n");
6912 return local;
6913}
6914
6915fn airCVaEnd(f: *Function, inst: Air.Inst.Index) !CValue {
6916 const un_op = f.air.instructions.items(.data)[inst].un_op;
6917
6918 const va_list = try f.resolveInst(un_op);
6919 try reap(f, inst, &.{un_op});
6920
6921 const writer = f.object.writer();
6922 try writer.writeAll("va_end(*(va_list *)");
6923 try f.writeCValue(writer, va_list, .Other);
6924 try writer.writeAll(");\n");
6925 return .none;
6926}
6927
6928fn airCVaCopy(f: *Function, inst: Air.Inst.Index) !CValue {
6929 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
6930 if (f.liveness.isUnused(inst)) {
6931 try reap(f, inst, &.{ty_op.operand});
6932 return .none;
6933 }
6934
6935 const inst_ty = f.air.typeOfIndex(inst);
6936 const va_list = try f.resolveInst(ty_op.operand);
6937 try reap(f, inst, &.{ty_op.operand});
6938
6939 const writer = f.object.writer();
6940 const local = try f.allocLocal(inst, inst_ty);
6941 try writer.writeAll("va_copy(*(va_list *)&");
6942 try f.writeCValue(writer, local, .Other);
6943 try writer.writeAll(", *(va_list *)");
6944 try f.writeCValue(writer, va_list, .Other);
6945 try writer.writeAll(");\n");
6946 return local;
6947}
6948
68466949fn toMemoryOrder(order: std.builtin.AtomicOrder) [:0]const u8 {
68476950 return switch (order) {
68486951 // Note: unordered is actually even less atomic than relaxed
......@@ -7028,8 +7131,9 @@ fn stringLiteral(child_stream: anytype) StringLiteral(@TypeOf(child_stream)) {
70287131 return .{ .counting_writer = std.io.countingWriter(child_stream) };
70297132}
70307133
7134const FormatStringContext = struct { str: []const u8, sentinel: ?u8 };
70317135fn formatStringLiteral(
7032 str: []const u8,
7136 data: FormatStringContext,
70337137 comptime fmt: []const u8,
70347138 _: std.fmt.FormatOptions,
70357139 writer: anytype,
......@@ -7038,13 +7142,13 @@ fn formatStringLiteral(
70387142
70397143 var literal = stringLiteral(writer);
70407144 try literal.start();
7041 for (str) |c|
7042 try literal.writeChar(c);
7145 for (data.str) |c| try literal.writeChar(c);
7146 if (data.sentinel) |sentinel| if (sentinel != 0) try literal.writeChar(sentinel);
70437147 try literal.end();
70447148}
70457149
7046fn fmtStringLiteral(str: []const u8) std.fmt.Formatter(formatStringLiteral) {
7047 return .{ .data = str };
7150fn fmtStringLiteral(str: []const u8, sentinel: ?u8) std.fmt.Formatter(formatStringLiteral) {
7151 return .{ .data = .{ .str = str, .sentinel = sentinel } };
70487152}
70497153
70507154fn undefPattern(comptime IntType: type) IntType {
src/codegen/c/type.zig+141-147
......@@ -1056,7 +1056,7 @@ pub const CType = extern union {
10561056 }
10571057 },
10581058
1059 .Struct, .Union => |zig_tag| if (ty.containerLayout() == .Packed) {
1059 .Struct, .Union => |zig_ty_tag| if (ty.containerLayout() == .Packed) {
10601060 if (ty.castTag(.@"struct")) |struct_obj| {
10611061 try self.initType(struct_obj.data.backing_int_ty, kind, lookup);
10621062 } else {
......@@ -1068,9 +1068,13 @@ pub const CType = extern union {
10681068 }
10691069 } else if (ty.isTupleOrAnonStruct()) {
10701070 if (lookup.isMutable()) {
1071 for (0..ty.structFieldCount()) |field_i| {
1071 for (0..switch (zig_ty_tag) {
1072 .Struct => ty.structFieldCount(),
1073 .Union => ty.unionFields().count(),
1074 else => unreachable,
1075 }) |field_i| {
10721076 const field_ty = ty.structFieldType(field_i);
1073 if (ty.structFieldIsComptime(field_i) or
1077 if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i)) or
10741078 !field_ty.hasRuntimeBitsIgnoreComptime()) continue;
10751079 _ = try lookup.typeToIndex(field_ty, switch (kind) {
10761080 .forward, .forward_parameter => .forward,
......@@ -1086,14 +1090,22 @@ pub const CType = extern union {
10861090 }
10871091 }
10881092 self.init(switch (kind) {
1089 .forward, .forward_parameter => .fwd_anon_struct,
1090 .complete, .parameter, .global => .anon_struct,
1093 .forward, .forward_parameter => switch (zig_ty_tag) {
1094 .Struct => .fwd_anon_struct,
1095 .Union => .fwd_anon_union,
1096 else => unreachable,
1097 },
1098 .complete, .parameter, .global => switch (zig_ty_tag) {
1099 .Struct => .anon_struct,
1100 .Union => .anon_union,
1101 else => unreachable,
1102 },
10911103 .payload => unreachable,
10921104 });
10931105 } else {
10941106 const tag_ty = ty.unionTagTypeSafety();
10951107 const is_tagged_union_wrapper = kind != .payload and tag_ty != null;
1096 const is_struct = zig_tag == .Struct or is_tagged_union_wrapper;
1108 const is_struct = zig_ty_tag == .Struct or is_tagged_union_wrapper;
10971109 switch (kind) {
10981110 .forward, .forward_parameter => {
10991111 self.storage = .{ .fwd = .{
......@@ -1138,7 +1150,7 @@ pub const CType = extern union {
11381150 self.init(.void);
11391151 } else {
11401152 var is_packed = false;
1141 for (0..switch (zig_tag) {
1153 for (0..switch (zig_ty_tag) {
11421154 .Struct => ty.structFieldCount(),
11431155 .Union => ty.unionFields().count(),
11441156 else => unreachable,
......@@ -1181,10 +1193,10 @@ pub const CType = extern union {
11811193 }
11821194 },
11831195
1184 .Array, .Vector => |zig_tag| {
1196 .Array, .Vector => |zig_ty_tag| {
11851197 switch (kind) {
11861198 .forward, .complete, .global => {
1187 const t: Tag = switch (zig_tag) {
1199 const t: Tag = switch (zig_ty_tag) {
11881200 .Array => .array,
11891201 .Vector => .vector,
11901202 else => unreachable,
......@@ -1296,19 +1308,21 @@ pub const CType = extern union {
12961308
12971309 .Fn => {
12981310 const info = ty.fnInfo();
1299 if (lookup.isMutable()) {
1300 const param_kind: Kind = switch (kind) {
1301 .forward, .forward_parameter => .forward_parameter,
1302 .complete, .parameter, .global => .parameter,
1303 .payload => unreachable,
1304 };
1305 _ = try lookup.typeToIndex(info.return_type, param_kind);
1306 for (info.param_types) |param_type| {
1307 if (!param_type.hasRuntimeBitsIgnoreComptime()) continue;
1308 _ = try lookup.typeToIndex(param_type, param_kind);
1311 if (!info.is_generic) {
1312 if (lookup.isMutable()) {
1313 const param_kind: Kind = switch (kind) {
1314 .forward, .forward_parameter => .forward_parameter,
1315 .complete, .parameter, .global => .parameter,
1316 .payload => unreachable,
1317 };
1318 _ = try lookup.typeToIndex(info.return_type, param_kind);
1319 for (info.param_types) |param_type| {
1320 if (!param_type.hasRuntimeBitsIgnoreComptime()) continue;
1321 _ = try lookup.typeToIndex(param_type, param_kind);
1322 }
13091323 }
1310 }
1311 self.init(if (info.is_var_args) .varargs_function else .function);
1324 self.init(if (info.is_var_args) .varargs_function else .function);
1325 } else self.init(.void);
13121326 },
13131327 }
13141328 }
......@@ -1499,126 +1513,95 @@ pub const CType = extern union {
14991513 .@"union",
15001514 .packed_struct,
15011515 .packed_union,
1502 => switch (ty.zigTypeTag()) {
1503 .Struct => {
1504 const fields_len = ty.structFieldCount();
1505
1506 var c_fields_len: usize = 0;
1507 for (0..fields_len) |field_i| {
1508 const field_ty = ty.structFieldType(field_i);
1509 if (ty.structFieldIsComptime(field_i) or
1510 !field_ty.hasRuntimeBitsIgnoreComptime()) continue;
1511 c_fields_len += 1;
1512 }
1513
1514 const fields_pl = try arena.alloc(Payload.Fields.Field, c_fields_len);
1515 var c_field_i: usize = 0;
1516 for (0..fields_len) |field_i| {
1517 const field_ty = ty.structFieldType(field_i);
1518 if (ty.structFieldIsComptime(field_i) or
1519 !field_ty.hasRuntimeBitsIgnoreComptime()) continue;
1520
1521 fields_pl[c_field_i] = .{
1522 .name = try if (ty.isSimpleTuple())
1523 std.fmt.allocPrintZ(arena, "f{}", .{field_i})
1524 else
1525 arena.dupeZ(u8, ty.structFieldName(field_i)),
1526 .type = store.set.typeToIndex(field_ty, target, switch (kind) {
1527 .forward, .forward_parameter => .forward,
1528 .complete, .parameter => .complete,
1529 .global => .global,
1530 .payload => unreachable,
1531 }).?,
1532 .alignas = Payload.Fields.AlignAs.fieldAlign(ty, field_i, target),
1533 };
1534 c_field_i += 1;
1535 }
1536
1537 switch (t) {
1538 .fwd_anon_struct => {
1539 const anon_pl = try arena.create(Payload.Fields);
1540 anon_pl.* = .{ .base = .{ .tag = t }, .data = fields_pl };
1541 return initPayload(anon_pl);
1542 },
1543
1544 .anon_struct,
1545 .@"struct",
1546 .@"union",
1547 .packed_struct,
1548 .packed_union,
1549 => {
1550 const struct_pl = try arena.create(Payload.Aggregate);
1551 struct_pl.* = .{ .base = .{ .tag = t }, .data = .{
1552 .fields = fields_pl,
1553 .fwd_decl = store.set.typeToIndex(ty, target, .forward).?,
1554 } };
1555 return initPayload(struct_pl);
1556 },
1516 => {
1517 const zig_ty_tag = ty.zigTypeTag();
1518 const fields_len = switch (zig_ty_tag) {
1519 .Struct => ty.structFieldCount(),
1520 .Union => ty.unionFields().count(),
1521 else => unreachable,
1522 };
15571523
1558 else => unreachable,
1559 }
1560 },
1524 var c_fields_len: usize = 0;
1525 for (0..fields_len) |field_i| {
1526 const field_ty = ty.structFieldType(field_i);
1527 if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i)) or
1528 !field_ty.hasRuntimeBitsIgnoreComptime()) continue;
1529 c_fields_len += 1;
1530 }
15611531
1562 .Union => {
1563 const union_fields = ty.unionFields();
1564 const fields_len = union_fields.count();
1532 const fields_pl = try arena.alloc(Payload.Fields.Field, c_fields_len);
1533 var c_field_i: usize = 0;
1534 for (0..fields_len) |field_i| {
1535 const field_ty = ty.structFieldType(field_i);
1536 if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i)) or
1537 !field_ty.hasRuntimeBitsIgnoreComptime()) continue;
1538
1539 defer c_field_i += 1;
1540 fields_pl[c_field_i] = .{
1541 .name = try if (ty.isSimpleTuple())
1542 std.fmt.allocPrintZ(arena, "f{}", .{field_i})
1543 else
1544 arena.dupeZ(u8, switch (zig_ty_tag) {
1545 .Struct => ty.structFieldName(field_i),
1546 .Union => ty.unionFields().keys()[field_i],
1547 else => unreachable,
1548 }),
1549 .type = store.set.typeToIndex(field_ty, target, switch (kind) {
1550 .forward, .forward_parameter => .forward,
1551 .complete, .parameter, .payload => .complete,
1552 .global => .global,
1553 }).?,
1554 .alignas = Payload.Fields.AlignAs.fieldAlign(ty, field_i, target),
1555 };
1556 }
15651557
1566 var c_fields_len: usize = 0;
1567 for (0..fields_len) |field_i| {
1568 const field_ty = ty.structFieldType(field_i);
1569 if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue;
1570 c_fields_len += 1;
1571 }
1558 switch (t) {
1559 .fwd_anon_struct,
1560 .fwd_anon_union,
1561 => {
1562 const anon_pl = try arena.create(Payload.Fields);
1563 anon_pl.* = .{ .base = .{ .tag = t }, .data = fields_pl };
1564 return initPayload(anon_pl);
1565 },
15721566
1573 const fields_pl = try arena.alloc(Payload.Fields.Field, c_fields_len);
1574 var field_i: usize = 0;
1575 var c_field_i: usize = 0;
1576 var field_it = union_fields.iterator();
1577 while (field_it.next()) |field| {
1578 defer field_i += 1;
1579 if (!field.value_ptr.ty.hasRuntimeBitsIgnoreComptime()) continue;
1580
1581 fields_pl[c_field_i] = .{
1582 .name = try arena.dupeZ(u8, field.key_ptr.*),
1583 .type = store.set.typeToIndex(field.value_ptr.ty, target, switch (kind) {
1584 .forward, .forward_parameter => unreachable,
1585 .complete, .parameter, .payload => .complete,
1586 .global => .global,
1587 }).?,
1588 .alignas = Payload.Fields.AlignAs.fieldAlign(ty, field_i, target),
1589 };
1590 c_field_i += 1;
1591 }
1567 .unnamed_struct,
1568 .unnamed_union,
1569 .packed_unnamed_struct,
1570 .packed_unnamed_union,
1571 => {
1572 const unnamed_pl = try arena.create(Payload.Unnamed);
1573 unnamed_pl.* = .{ .base = .{ .tag = t }, .data = .{
1574 .fields = fields_pl,
1575 .owner_decl = ty.getOwnerDecl(),
1576 .id = if (ty.unionTagTypeSafety()) |_| 0 else unreachable,
1577 } };
1578 return initPayload(unnamed_pl);
1579 },
15921580
1593 switch (kind) {
1594 .forward, .forward_parameter => unreachable,
1595 .complete, .parameter, .global => {
1596 const union_pl = try arena.create(Payload.Aggregate);
1597 union_pl.* = .{ .base = .{ .tag = t }, .data = .{
1598 .fields = fields_pl,
1599 .fwd_decl = store.set.typeToIndex(ty, target, .forward).?,
1600 } };
1601 return initPayload(union_pl);
1602 },
1603 .payload => if (ty.unionTagTypeSafety()) |_| {
1604 const union_pl = try arena.create(Payload.Unnamed);
1605 union_pl.* = .{ .base = .{ .tag = t }, .data = .{
1606 .fields = fields_pl,
1607 .owner_decl = ty.getOwnerDecl(),
1608 .id = 0,
1609 } };
1610 return initPayload(union_pl);
1611 } else unreachable,
1612 }
1613 },
1581 .anon_struct,
1582 .anon_union,
1583 .@"struct",
1584 .@"union",
1585 .packed_struct,
1586 .packed_union,
1587 => {
1588 const struct_pl = try arena.create(Payload.Aggregate);
1589 struct_pl.* = .{ .base = .{ .tag = t }, .data = .{
1590 .fields = fields_pl,
1591 .fwd_decl = store.set.typeToIndex(ty, target, .forward).?,
1592 } };
1593 return initPayload(struct_pl);
1594 },
16141595
1615 else => unreachable,
1596 else => unreachable,
1597 }
16161598 },
16171599
16181600 .function,
16191601 .varargs_function,
16201602 => {
16211603 const info = ty.fnInfo();
1604 assert(!info.is_generic);
16221605 const param_kind: Kind = switch (kind) {
16231606 .forward, .forward_parameter => .forward_parameter,
16241607 .complete, .parameter, .global => .parameter,
......@@ -1707,14 +1690,19 @@ pub const CType = extern union {
17071690 ]u8 = undefined;
17081691 const c_fields = cty.cast(Payload.Fields).?.data;
17091692
1693 const zig_ty_tag = ty.zigTypeTag();
17101694 var c_field_i: usize = 0;
1711 for (0..ty.structFieldCount()) |field_i| {
1695 for (0..switch (zig_ty_tag) {
1696 .Struct => ty.structFieldCount(),
1697 .Union => ty.unionFields().count(),
1698 else => unreachable,
1699 }) |field_i| {
17121700 const field_ty = ty.structFieldType(field_i);
1713 if (ty.structFieldIsComptime(field_i) or
1701 if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i)) or
17141702 !field_ty.hasRuntimeBitsIgnoreComptime()) continue;
17151703
1704 defer c_field_i += 1;
17161705 const c_field = &c_fields[c_field_i];
1717 c_field_i += 1;
17181706
17191707 if (!self.eqlRecurse(field_ty, c_field.type, switch (self.kind) {
17201708 .forward, .forward_parameter => .forward,
......@@ -1725,8 +1713,11 @@ pub const CType = extern union {
17251713 u8,
17261714 if (ty.isSimpleTuple())
17271715 std.fmt.bufPrint(&name_buf, "f{}", .{field_i}) catch unreachable
1728 else
1729 ty.structFieldName(field_i),
1716 else switch (zig_ty_tag) {
1717 .Struct => ty.structFieldName(field_i),
1718 .Union => ty.unionFields().keys()[field_i],
1719 else => unreachable,
1720 },
17301721 mem.span(c_field.name),
17311722 ) or Payload.Fields.AlignAs.fieldAlign(ty, field_i, target).@"align" !=
17321723 c_field.alignas.@"align") return false;
......@@ -1764,6 +1755,7 @@ pub const CType = extern union {
17641755 if (ty.zigTypeTag() != .Fn) return false;
17651756
17661757 const info = ty.fnInfo();
1758 assert(!info.is_generic);
17671759 const data = cty.cast(Payload.Function).?.data;
17681760 const param_kind: Kind = switch (self.kind) {
17691761 .forward, .forward_parameter => .forward_parameter,
......@@ -1824,29 +1816,30 @@ pub const CType = extern union {
18241816 var name_buf: [
18251817 std.fmt.count("f{}", .{std.math.maxInt(usize)})
18261818 ]u8 = undefined;
1819
1820 const zig_ty_tag = ty.zigTypeTag();
18271821 for (0..switch (ty.zigTypeTag()) {
18281822 .Struct => ty.structFieldCount(),
18291823 .Union => ty.unionFields().count(),
18301824 else => unreachable,
18311825 }) |field_i| {
18321826 const field_ty = ty.structFieldType(field_i);
1833 if (ty.structFieldIsComptime(field_i) or
1827 if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i)) or
18341828 !field_ty.hasRuntimeBitsIgnoreComptime()) continue;
18351829
1836 self.updateHasherRecurse(
1837 hasher,
1838 ty.structFieldType(field_i),
1839 switch (self.kind) {
1840 .forward, .forward_parameter => .forward,
1841 .complete, .parameter => .complete,
1842 .global => .global,
1843 .payload => unreachable,
1844 },
1845 );
1830 self.updateHasherRecurse(hasher, field_ty, switch (self.kind) {
1831 .forward, .forward_parameter => .forward,
1832 .complete, .parameter => .complete,
1833 .global => .global,
1834 .payload => unreachable,
1835 });
18461836 hasher.update(if (ty.isSimpleTuple())
18471837 std.fmt.bufPrint(&name_buf, "f{}", .{field_i}) catch unreachable
1848 else
1849 ty.structFieldName(field_i));
1838 else switch (zig_ty_tag) {
1839 .Struct => ty.structFieldName(field_i),
1840 .Union => ty.unionFields().keys()[field_i],
1841 else => unreachable,
1842 });
18501843 autoHash(
18511844 hasher,
18521845 Payload.Fields.AlignAs.fieldAlign(ty, field_i, target).@"align",
......@@ -1878,6 +1871,7 @@ pub const CType = extern union {
18781871 .varargs_function,
18791872 => {
18801873 const info = ty.fnInfo();
1874 assert(!info.is_generic);
18811875 const param_kind: Kind = switch (self.kind) {
18821876 .forward, .forward_parameter => .forward_parameter,
18831877 .complete, .parameter, .global => .parameter,
src/link/C.zig+14-21
......@@ -247,8 +247,8 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node)
247247
248248 const abi_define = abiDefine(comp);
249249
250 // Covers defines, zig.h, ctypes, asm, lazy fwd, lazy code.
251 try f.all_buffers.ensureUnusedCapacity(gpa, 6);
250 // Covers defines, zig.h, ctypes, asm, lazy fwd.
251 try f.all_buffers.ensureUnusedCapacity(gpa, 5);
252252
253253 if (abi_define) |buf| f.appendBufAssumeCapacity(buf);
254254 f.appendBufAssumeCapacity(zig_h);
......@@ -263,8 +263,8 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node)
263263 f.appendBufAssumeCapacity(asm_buf.items);
264264 }
265265
266 const lazy_indices = f.all_buffers.items.len;
267 f.all_buffers.items.len += 2;
266 const lazy_index = f.all_buffers.items.len;
267 f.all_buffers.items.len += 1;
268268
269269 try self.flushErrDecls(&f.lazy_db);
270270
......@@ -297,6 +297,7 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node)
297297
298298 {
299299 // We need to flush lazy ctypes after flushing all decls but before flushing any decl ctypes.
300 // This ensures that every lazy CType.Index exactly matches the global CType.Index.
300301 assert(f.ctypes.count() == 0);
301302 try self.flushCTypes(&f, .none, f.lazy_db.ctypes);
302303
......@@ -305,30 +306,22 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node)
305306 try self.flushCTypes(&f, entry.key_ptr.toOptional(), entry.value_ptr.ctypes);
306307 }
307308
308 {
309 f.all_buffers.items[lazy_indices + 0] = .{
310 .iov_base = if (f.lazy_db.fwd_decl.items.len > 0) f.lazy_db.fwd_decl.items.ptr else "",
311 .iov_len = f.lazy_db.fwd_decl.items.len,
312 };
313 f.file_size += f.lazy_db.fwd_decl.items.len;
314
315 f.all_buffers.items[lazy_indices + 1] = .{
316 .iov_base = if (f.lazy_db.code.items.len > 0) f.lazy_db.code.items.ptr else "",
317 .iov_len = f.lazy_db.code.items.len,
318 };
319 f.file_size += f.lazy_db.code.items.len;
320 }
321
322309 f.all_buffers.items[ctypes_index] = .{
323310 .iov_base = if (f.ctypes_buf.items.len > 0) f.ctypes_buf.items.ptr else "",
324311 .iov_len = f.ctypes_buf.items.len,
325312 };
326313 f.file_size += f.ctypes_buf.items.len;
327314
315 f.all_buffers.items[lazy_index] = .{
316 .iov_base = if (f.lazy_db.fwd_decl.items.len > 0) f.lazy_db.fwd_decl.items.ptr else "",
317 .iov_len = f.lazy_db.fwd_decl.items.len,
318 };
319 f.file_size += f.lazy_db.fwd_decl.items.len;
320
328321 // Now the code.
329 try f.all_buffers.ensureUnusedCapacity(gpa, decl_values.len);
330 for (decl_values) |decl|
331 f.appendBufAssumeCapacity(decl.code.items);
322 try f.all_buffers.ensureUnusedCapacity(gpa, 1 + decl_values.len);
323 f.appendBufAssumeCapacity(f.lazy_db.code.items);
324 for (decl_values) |decl| f.appendBufAssumeCapacity(decl.code.items);
332325
333326 const file = self.base.file.?;
334327 try file.setEndPos(f.file_size);
src/target.zig+1
......@@ -723,6 +723,7 @@ pub fn supportsFunctionAlignment(target: std.Target) bool {
723723pub fn supportsTailCall(target: std.Target, backend: std.builtin.CompilerBackend) bool {
724724 switch (backend) {
725725 .stage1, .stage2_llvm => return @import("codegen/llvm.zig").supportsTailCall(target),
726 .stage2_c => return true,
726727 else => return false,
727728 }
728729}
test/behavior/field_parent_ptr.zig-3
......@@ -48,7 +48,6 @@ fn testParentFieldPtrFirst(a: *const bool) !void {
4848test "@fieldParentPtr untagged union" {
4949 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
5050 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
51 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
5251 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
5352
5453 try testFieldParentPtrUnion(&bar.c);
......@@ -75,7 +74,6 @@ fn testFieldParentPtrUnion(c: *const i32) !void {
7574test "@fieldParentPtr tagged union" {
7675 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
7776 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
78 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
7977 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
8078
8179 try testFieldParentPtrTaggedUnion(&bar_tagged.c);
......@@ -102,7 +100,6 @@ fn testFieldParentPtrTaggedUnion(c: *const i32) !void {
102100test "@fieldParentPtr extern union" {
103101 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
104102 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
105 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
106103 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
107104
108105 try testFieldParentPtrExternUnion(&bar_extern.c);
test/behavior/packed-struct.zig-1
......@@ -603,7 +603,6 @@ test "packed struct initialized in bitcast" {
603603test "pointer to container level packed struct field" {
604604 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
605605 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
606 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
607606 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
608607 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
609608
test/behavior/pointers.zig-1
......@@ -507,7 +507,6 @@ test "ptrCast comptime known slice to C pointer" {
507507}
508508
509509test "ptrToInt on a generic function" {
510 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
511510 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
512511 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
513512 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
test/behavior/var_args.zig+16-8
......@@ -96,10 +96,9 @@ fn doNothingWithFirstArg(args: anytype) void {
9696test "simple variadic function" {
9797 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
9898 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
99 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
10099 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
101100 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
102 if (builtin.cpu.arch == .aarch64 and builtin.os.tag != .macos and builtin.zig_backend == .stage2_llvm) {
101 if (builtin.cpu.arch == .aarch64 and builtin.os.tag != .macos) {
103102 // https://github.com/ziglang/zig/issues/14096
104103 return error.SkipZigTest;
105104 }
......@@ -112,6 +111,12 @@ test "simple variadic function" {
112111 return @cVaArg(&ap, c_int);
113112 }
114113
114 fn compatible(_: c_int, ...) callconv(.C) c_int {
115 var ap = @cVaStart();
116 defer @cVaEnd(&ap);
117 return @cVaArg(&ap, c_int);
118 }
119
115120 fn add(count: c_int, ...) callconv(.C) c_int {
116121 var ap = @cVaStart();
117122 defer @cVaEnd(&ap);
......@@ -124,8 +129,13 @@ test "simple variadic function" {
124129 }
125130 };
126131
127 try std.testing.expectEqual(@as(c_int, 0), S.simple(@as(c_int, 0)));
128 try std.testing.expectEqual(@as(c_int, 1024), S.simple(@as(c_int, 1024)));
132 if (builtin.zig_backend != .stage2_c) {
133 // pre C23 doesn't support varargs without a preceding runtime arg.
134 try std.testing.expectEqual(@as(c_int, 0), S.simple(@as(c_int, 0)));
135 try std.testing.expectEqual(@as(c_int, 1024), S.simple(@as(c_int, 1024)));
136 }
137 try std.testing.expectEqual(@as(c_int, 0), S.compatible(undefined, @as(c_int, 0)));
138 try std.testing.expectEqual(@as(c_int, 1024), S.compatible(undefined, @as(c_int, 1024)));
129139 try std.testing.expectEqual(@as(c_int, 0), S.add(0));
130140 try std.testing.expectEqual(@as(c_int, 1), S.add(1, @as(c_int, 1)));
131141 try std.testing.expectEqual(@as(c_int, 3), S.add(2, @as(c_int, 1), @as(c_int, 2)));
......@@ -134,10 +144,9 @@ test "simple variadic function" {
134144test "variadic functions" {
135145 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
136146 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
137 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
138147 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
139148 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
140 if (builtin.cpu.arch == .aarch64 and builtin.os.tag != .macos and builtin.zig_backend == .stage2_llvm) {
149 if (builtin.cpu.arch == .aarch64 and builtin.os.tag != .macos) {
141150 // https://github.com/ziglang/zig/issues/14096
142151 return error.SkipZigTest;
143152 }
......@@ -178,10 +187,9 @@ test "variadic functions" {
178187test "copy VaList" {
179188 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
180189 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
181 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
182190 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
183191 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
184 if (builtin.cpu.arch == .aarch64 and builtin.os.tag != .macos and builtin.zig_backend == .stage2_llvm) {
192 if (builtin.cpu.arch == .aarch64 and builtin.os.tag != .macos) {
185193 // https://github.com/ziglang/zig/issues/14096
186194 return error.SkipZigTest;
187195 }