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 @@...@@ -5,6 +5,7 @@
5#endif5#endif
6#include <float.h>6#include <float.h>
7#include <limits.h>7#include <limits.h>
8#include <stdarg.h>
8#include <stddef.h>9#include <stddef.h>
9#include <stdint.h>10#include <stdint.h>
1011
...@@ -77,6 +78,32 @@ typedef char bool;...@@ -77,6 +78,32 @@ typedef char bool;
77#define zig_cold78#define zig_cold
78#endif79#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
80#if __STDC_VERSION__ >= 199901L107#if __STDC_VERSION__ >= 199901L
81#define zig_restrict restrict108#define zig_restrict restrict
82#elif defined(__GNUC__)109#elif defined(__GNUC__)
...@@ -1049,7 +1076,7 @@ static inline void zig_vmulo_i16(uint8_t *ov, int16_t *res, int n,...@@ -1049,7 +1076,7 @@ static inline void zig_vmulo_i16(uint8_t *ov, int16_t *res, int n,
1049\1076\
1050 static inline int##w##_t zig_shls_i##w(int##w##_t lhs, int##w##_t rhs, uint8_t bits) { \1077 static inline int##w##_t zig_shls_i##w(int##w##_t lhs, int##w##_t rhs, uint8_t bits) { \
1051 int##w##_t res; \1078 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; \
1053 return lhs < INT##w##_C(0) ? zig_minInt_i(w, bits) : zig_maxInt_i(w, bits); \1080 return lhs < INT##w##_C(0) ? zig_minInt_i(w, bits) : zig_maxInt_i(w, bits); \
1054 } \1081 } \
1055\1082\
...@@ -2383,39 +2410,47 @@ zig_msvc_atomics(i64, int64_t, 64)...@@ -2383,39 +2410,47 @@ zig_msvc_atomics(i64, int64_t, 64)
23832410
2384#define zig_msvc_flt_atomics(Type, ReprType, suffix) \2411#define zig_msvc_flt_atomics(Type, ReprType, suffix) \
2385 static inline bool zig_msvc_cmpxchg_##Type(zig_##Type volatile* obj, zig_##Type* expected, zig_##Type desired) { \2412 static inline bool zig_msvc_cmpxchg_##Type(zig_##Type volatile* obj, zig_##Type* expected, zig_##Type desired) { \
2386 ReprType comparand = *((ReprType*)expected); \2413 ReprType exchange; \
2387 ReprType initial = _InterlockedCompareExchange##suffix((ReprType volatile*)obj, *((ReprType*)&desired), comparand); \2414 ReprType comparand; \
2388 bool exchanged = initial == comparand; \2415 ReprType initial; \
2389 if (!exchanged) { \2416 bool success; \
2390 *expected = *((zig_##Type*)&initial); \2417 memcpy(&comparand, expected, sizeof(comparand)); \
2391 } \2418 memcpy(&exchange, &desired, sizeof(exchange)); \
2392 return exchanged; \2419 initial = _InterlockedCompareExchange##suffix((ReprType volatile*)obj, exchange, comparand); \
2420 success = initial == comparand; \
2421 if (!success) memcpy(expected, &initial, sizeof(*expected)); \
2422 return success; \
2393 } \2423 } \
2394 static inline zig_##Type zig_msvc_atomicrmw_xchg_##Type(zig_##Type volatile* obj, zig_##Type value) { \2424 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)); \2425 ReprType repr; \
2396 return *((zig_##Type*)&initial); \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; \
2397 } \2432 } \
2398 static inline zig_##Type zig_msvc_atomicrmw_add_##Type(zig_##Type volatile* obj, zig_##Type value) { \2433 static inline zig_##Type zig_msvc_atomicrmw_add_##Type(zig_##Type volatile* obj, zig_##Type value) { \
2399 bool success = false; \2434 ReprType repr; \
2400 ReprType new; \2435 zig_##Type expected; \
2401 zig_##Type prev; \2436 zig_##Type desired; \
2402 while (!success) { \2437 repr = *(ReprType volatile*)obj; \
2403 prev = *obj; \2438 memcpy(&expected, &repr, sizeof(expected)); \
2404 new = prev + value; \2439 do { \
2405 success = zig_msvc_cmpxchg_##Type(obj, &prev, *((ReprType*)&new)); \2440 desired = expected + value; \
2406 } \2441 } while (!zig_msvc_cmpxchg_##Type(obj, &expected, desired)); \
2407 return prev; \2442 return expected; \
2408 } \2443 } \
2409 static inline zig_##Type zig_msvc_atomicrmw_sub_##Type(zig_##Type volatile* obj, zig_##Type value) { \2444 static inline zig_##Type zig_msvc_atomicrmw_sub_##Type(zig_##Type volatile* obj, zig_##Type value) { \
2410 bool success = false; \2445 ReprType repr; \
2411 ReprType new; \2446 zig_##Type expected; \
2412 zig_##Type prev; \2447 zig_##Type desired; \
2413 while (!success) { \2448 repr = *(ReprType volatile*)obj; \
2414 prev = *obj; \2449 memcpy(&expected, &repr, sizeof(expected)); \
2415 new = prev - value; \2450 do { \
2416 success = zig_msvc_cmpxchg_##Type(obj, &prev, *((ReprType*)&new)); \2451 desired = expected - value; \
2417 } \2452 } while (!zig_msvc_cmpxchg_##Type(obj, &expected, desired)); \
2418 return prev; \2453 return expected; \
2419 }2454 }
24202455
2421zig_msvc_flt_atomics(f32, uint32_t, )2456zig_msvc_flt_atomics(f32, uint32_t, )
src/codegen/c.zig+827-723
...@@ -23,7 +23,6 @@ const libcFloatSuffix = target_util.libcFloatSuffix;...@@ -23,7 +23,6 @@ const libcFloatSuffix = target_util.libcFloatSuffix;
23const compilerRtFloatAbbrev = target_util.compilerRtFloatAbbrev;23const compilerRtFloatAbbrev = target_util.compilerRtFloatAbbrev;
24const compilerRtIntAbbrev = target_util.compilerRtIntAbbrev;24const compilerRtIntAbbrev = target_util.compilerRtIntAbbrev;
2525
26const Mutability = enum { @"const", mut };
27const BigIntLimb = std.math.big.Limb;26const BigIntLimb = std.math.big.Limb;
28const BigInt = std.math.big.int;27const BigInt = std.math.big.int;
2928
...@@ -39,7 +38,7 @@ pub const CValue = union(enum) {...@@ -39,7 +38,7 @@ pub const CValue = union(enum) {
39 constant: Air.Inst.Ref,38 constant: Air.Inst.Ref,
40 /// Index into the parameters39 /// Index into the parameters
41 arg: usize,40 arg: usize,
42 /// The payload field of a parameter41 /// The array field of a parameter
43 arg_array: usize,42 arg_array: usize,
44 /// Index into a tuple's fields43 /// Index into a tuple's fields
45 field: usize,44 field: usize,
...@@ -50,6 +49,8 @@ pub const CValue = union(enum) {...@@ -50,6 +49,8 @@ pub const CValue = union(enum) {
50 undef: Type,49 undef: Type,
51 /// Render the slice as an identifier (using fmtIdent)50 /// Render the slice as an identifier (using fmtIdent)
52 identifier: []const u8,51 identifier: []const u8,
52 /// Render the slice as an payload.identifier (using fmtIdent)
53 payload_identifier: []const u8,
53 /// Render these bytes literally.54 /// Render these bytes literally.
54 /// TODO make this a [*:0]const u8 to save memory55 /// TODO make this a [*:0]const u8 to save memory
55 bytes: []const u8,56 bytes: []const u8,
...@@ -60,21 +61,22 @@ const BlockData = struct {...@@ -60,21 +61,22 @@ const BlockData = struct {
60 result: CValue,61 result: CValue,
61};62};
6263
63const TypedefKind = enum {
64 Forward,
65 Complete,
66};
67
68pub const CValueMap = std.AutoHashMap(Air.Inst.Ref, CValue);64pub const CValueMap = std.AutoHashMap(Air.Inst.Ref, CValue);
6965
70pub const LazyFnKey = union(enum) {66pub const LazyFnKey = union(enum) {
71 tag_name: Decl.Index,67 tag_name: Decl.Index,
68 never_tail: Decl.Index,
69 never_inline: Decl.Index,
72};70};
73pub const LazyFnValue = struct {71pub const LazyFnValue = struct {
74 fn_name: []const u8,72 fn_name: []const u8,
75 data: union {73 data: Data,
74
75 pub const Data = union {
76 tag_name: Type,76 tag_name: Type,
77 },77 never_tail: void,
78 never_inline: void,
79 };
78};80};
79pub const LazyFnMap = std.AutoArrayHashMapUnmanaged(LazyFnKey, LazyFnValue);81pub const LazyFnMap = std.AutoArrayHashMapUnmanaged(LazyFnKey, LazyFnValue);
8082
...@@ -209,6 +211,15 @@ const reserved_idents = std.ComptimeStringMap(void, .{...@@ -209,6 +211,15 @@ const reserved_idents = std.ComptimeStringMap(void, .{
209 .{ "volatile", {} },211 .{ "volatile", {} },
210 .{ "while ", {} },212 .{ "while ", {} },
211213
214 // stdarg.h
215 .{ "va_start", {} },
216 .{ "va_arg", {} },
217 .{ "va_end", {} },
218 .{ "va_copy", {} },
219
220 // stddef.h
221 .{ "offsetof", {} },
222
212 // windows.h223 // windows.h
213 .{ "max", {} },224 .{ "max", {} },
214 .{ "min", {} },225 .{ "min", {} },
...@@ -296,19 +307,19 @@ pub const Function = struct {...@@ -296,19 +307,19 @@ pub const Function = struct {
296 const val = f.air.value(inst).?;307 const val = f.air.value(inst).?;
297 const ty = f.air.typeOf(inst);308 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: {
300 const writer = f.object.code_header.writer();311 const writer = f.object.code_header.writer();
301 const alignment = 0;312 const alignment = 0;
302 const decl_c_value = try f.allocLocalValue(ty, alignment);313 const decl_c_value = try f.allocLocalValue(ty, alignment);
303 const gpa = f.object.dg.gpa;314 const gpa = f.object.dg.gpa;
304 try f.allocs.put(gpa, decl_c_value.new_local, true);315 try f.allocs.put(gpa, decl_c_value.new_local, true);
305 try writer.writeAll("static ");316 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);
307 try writer.writeAll(" = ");318 try writer.writeAll(" = ");
308 try f.object.dg.renderValue(writer, ty, val, .StaticInitializer);319 try f.object.dg.renderValue(writer, ty, val, .StaticInitializer);
309 try writer.writeAll(";\n ");320 try writer.writeAll(";\n ");
310 break :result decl_c_value;321 break :result decl_c_value;
311 } else CValue{ .constant = inst };322 } else .{ .constant = inst };
312323
313 gop.value_ptr.* = result;324 gop.value_ptr.* = result;
314 return result;325 return result;
...@@ -333,26 +344,24 @@ pub const Function = struct {...@@ -333,26 +344,24 @@ pub const Function = struct {
333 .alignment = alignment,344 .alignment = alignment,
334 .loop_depth = @intCast(LoopDepth, f.free_locals_stack.items.len - 1),345 .loop_depth = @intCast(LoopDepth, f.free_locals_stack.items.len - 1),
335 });346 });
336 return CValue{ .new_local = @intCast(LocalIndex, f.locals.items.len - 1) };347 return .{ .new_local = @intCast(LocalIndex, f.locals.items.len - 1) };
337 }348 }
338349
339 fn allocLocal(f: *Function, inst: Air.Inst.Index, ty: Type) !CValue {350 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);
341 log.debug("%{d}: allocating t{d}", .{ inst, result.new_local });352 log.debug("%{d}: allocating t{d}", .{ inst, result.new_local });
342 return result;353 return result;
343 }354 }
344355
345 /// Only allocates the local; does not print anything.356 /// Only allocates the local; does not print anything.
346 fn allocAlignedLocal(f: *Function, ty: Type, mutability: Mutability, alignment: u32) !CValue {357 fn allocAlignedLocal(f: *Function, ty: Type, _: CQualifiers, alignment: u32) !CValue {
347 _ = mutability;
348
349 if (f.getFreeLocals().getPtrContext(ty, f.tyHashCtx())) |locals_list| {358 if (f.getFreeLocals().getPtrContext(ty, f.tyHashCtx())) |locals_list| {
350 for (locals_list.items, 0..) |local_index, i| {359 for (locals_list.items, 0..) |local_index, i| {
351 const local = &f.locals.items[local_index];360 const local = &f.locals.items[local_index];
352 if (local.alignment >= alignment) {361 if (local.alignment >= alignment) {
353 local.loop_depth = @intCast(LoopDepth, f.free_locals_stack.items.len - 1);362 local.loop_depth = @intCast(LoopDepth, f.free_locals_stack.items.len - 1);
354 _ = locals_list.swapRemove(i);363 _ = locals_list.swapRemove(i);
355 return CValue{ .new_local = local_index };364 return .{ .new_local = local_index };
356 }365 }
357 }366 }
358 }367 }
...@@ -416,12 +425,20 @@ pub const Function = struct {...@@ -416,12 +425,20 @@ pub const Function = struct {
416 return f.object.dg.fail(format, args);425 return f.object.dg.fail(format, args);
417 }426 }
418427
419 fn renderType(f: *Function, w: anytype, t: Type) !void {428 fn indexToCType(f: *Function, idx: CType.Index) CType {
420 return f.object.dg.renderType(w, t, .Complete);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);
421 }434 }
422435
423 fn renderTypecast(f: *Function, w: anytype, t: Type) !void {436 fn typeToCType(f: *Function, ty: Type, kind: CType.Kind) !CType {
424 return f.object.dg.renderTypecast(w, t);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);
425 }442 }
426443
427 fn renderIntCast(f: *Function, w: anytype, dest_ty: Type, src: CValue, src_ty: Type, location: ValueRenderLocation) !void {444 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 {...@@ -432,11 +449,9 @@ pub const Function = struct {
432 return f.object.dg.fmtIntLiteral(ty, val);449 return f.object.dg.fmtIntLiteral(ty, val);
433 }450 }
434451
435 fn getTagNameFn(f: *Function, enum_ty: Type) ![]const u8 {452 fn getLazyFnName(f: *Function, key: LazyFnKey, data: LazyFnValue.Data) ![]const u8 {
436 const gpa = f.object.dg.gpa;453 const gpa = f.object.dg.gpa;
437 const owner_decl = enum_ty.getOwnerDecl();454 const gop = try f.lazy_fns.getOrPut(gpa, key);
438
439 const gop = try f.lazy_fns.getOrPut(gpa, .{ .tag_name = owner_decl });
440 if (!gop.found_existing) {455 if (!gop.found_existing) {
441 errdefer _ = f.lazy_fns.pop();456 errdefer _ = f.lazy_fns.pop();
442457
...@@ -445,11 +460,21 @@ pub const Function = struct {...@@ -445,11 +460,21 @@ pub const Function = struct {
445 const arena = promoted.arena.allocator();460 const arena = promoted.arena.allocator();
446461
447 gop.value_ptr.* = .{462 gop.value_ptr.* = .{
448 .fn_name = try std.fmt.allocPrint(arena, "zig_tagName_{}__{d}", .{463 .fn_name = switch (key) {
449 fmtIdent(mem.span(f.object.dg.module.declPtr(owner_decl).name)),464 .tag_name,
450 @enumToInt(owner_decl),465 .never_tail,
451 }),466 .never_inline,
452 .data = .{ .tag_name = try enum_ty.copy(arena) },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 },
453 };478 };
454 }479 }
455 return gop.value_ptr.fn_name;480 return gop.value_ptr.fn_name;
...@@ -518,7 +543,7 @@ pub const DeclGen = struct {...@@ -518,7 +543,7 @@ pub const DeclGen = struct {
518543
519 // Render an undefined pointer if we have a pointer to a zero-bit or comptime type.544 // Render an undefined pointer if we have a pointer to a zero-bit or comptime type.
520 if (ty.isPtrAtRuntime() and !decl.ty.isFnOrHasRuntimeBits()) {545 if (ty.isPtrAtRuntime() and !decl.ty.isFnOrHasRuntimeBits()) {
521 return dg.writeCValue(writer, CValue{ .undef = ty });546 return dg.writeCValue(writer, .{ .undef = ty });
522 }547 }
523548
524 // Chase function values in order to be able to reference the original function.549 // Chase function values in order to be able to reference the original function.
...@@ -532,7 +557,7 @@ pub const DeclGen = struct {...@@ -532,7 +557,7 @@ pub const DeclGen = struct {
532 try writer.writeByte('{');557 try writer.writeByte('{');
533 } else {558 } else {
534 try writer.writeByte('(');559 try writer.writeByte('(');
535 try dg.renderTypecast(writer, ty);560 try dg.renderType(writer, ty);
536 try writer.writeAll("){ .ptr = ");561 try writer.writeAll("){ .ptr = ");
537 }562 }
538563
...@@ -559,7 +584,7 @@ pub const DeclGen = struct {...@@ -559,7 +584,7 @@ pub const DeclGen = struct {
559 const need_typecast = if (ty.castPtrToFn()) |_| false else !ty.eql(decl.ty, dg.module);584 const need_typecast = if (ty.castPtrToFn()) |_| false else !ty.eql(decl.ty, dg.module);
560 if (need_typecast) {585 if (need_typecast) {
561 try writer.writeAll("((");586 try writer.writeAll("((");
562 try dg.renderTypecast(writer, ty);587 try dg.renderType(writer, ty);
563 try writer.writeByte(')');588 try writer.writeByte(')');
564 }589 }
565 try writer.writeByte('&');590 try writer.writeByte('&');
...@@ -574,7 +599,7 @@ pub const DeclGen = struct {...@@ -574,7 +599,7 @@ pub const DeclGen = struct {
574 fn renderParentPtr(dg: *DeclGen, writer: anytype, ptr_val: Value, ptr_ty: Type, location: ValueRenderLocation) error{ OutOfMemory, AnalysisFail }!void {599 fn renderParentPtr(dg: *DeclGen, writer: anytype, ptr_val: Value, ptr_ty: Type, location: ValueRenderLocation) error{ OutOfMemory, AnalysisFail }!void {
575 if (!ptr_ty.isSlice()) {600 if (!ptr_ty.isSlice()) {
576 try writer.writeByte('(');601 try writer.writeByte('(');
577 try dg.renderTypecast(writer, ptr_ty);602 try dg.renderType(writer, ptr_ty);
578 try writer.writeByte(')');603 try writer.writeByte(')');
579 }604 }
580 switch (ptr_val.tag()) {605 switch (ptr_val.tag()) {
...@@ -589,90 +614,71 @@ pub const DeclGen = struct {...@@ -589,90 +614,71 @@ pub const DeclGen = struct {
589 try dg.renderDeclValue(writer, ptr_ty, ptr_val, decl_index, location);614 try dg.renderDeclValue(writer, ptr_ty, ptr_val, decl_index, location);
590 },615 },
591 .field_ptr => {616 .field_ptr => {
592 const ptr_info = ptr_ty.ptrInfo();617 const target = dg.module.getTarget();
593 const field_ptr = ptr_val.castTag(.field_ptr).?.data;618 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('(');620 // Ensure complete type definition is visible before accessing fields.
637 try dg.renderTypecast(writer, ptr_ty);621 _ = try dg.typeToIndex(field_ptr.container_ty, .complete);
638 try writer.writeByte(')');622
639 return dg.renderParentPtr(writer, field_ptr.container_ptr, host_ty, location);623 var container_ptr_pl = ptr_ty.ptrInfo();
640 },624 container_ptr_pl.data.pointee_type = field_ptr.container_ty;
641 },625 const container_ptr_ty = Type.initPayload(&container_ptr_pl.base);
642 .Union => switch (container_ty.containerLayout()) {626
643 .Auto, .Extern => FieldInfo{627 switch (fieldLocation(
644 .name = container_ty.unionFields().keys()[index],628 field_ptr.container_ty,
645 .ty = container_ty.unionFields().values()[index].ty,629 ptr_ty,
646 },630 @intCast(u32, field_ptr.field_index),
647 .Packed => {631 target,
648 return dg.renderParentPtr(writer, field_ptr.container_ptr, ptr_ty, location);632 )) {
649 },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);
650 },649 },
651 .Pointer => field_info: {650 .byte_offset => |byte_offset| {
652 assert(container_ty.isSlice());651 var u8_ptr_pl = ptr_ty.ptrInfo();
653 break :field_info switch (index) {652 u8_ptr_pl.data.pointee_type = Type.u8;
654 0 => FieldInfo{ .name = "ptr", .ty = container_ty.childType() },653 const u8_ptr_ty = Type.initPayload(&u8_ptr_pl.base);
655 1 => FieldInfo{ .name = "len", .ty = Type.usize },654
656 else => unreachable,655 var byte_offset_pl = Value.Payload.U64{
656 .base = .{ .tag = .int_u64 },
657 .data = byte_offset,
657 };658 };
658 },659 const byte_offset_val = Value.initPayload(&byte_offset_pl.base);
659 else => unreachable,
660 };
661660
662 if (field_info.ty.hasRuntimeBitsIgnoreComptime()) {661 try writer.writeAll("((");
663 // Ensure complete type definition is visible before accessing fields.662 try dg.renderType(writer, u8_ptr_ty);
664 try dg.renderType(std.io.null_writer, field_ptr.container_ty, .Complete);663 try writer.writeByte(')');
665664 try dg.renderParentPtr(
666 try writer.writeAll("&(");665 writer,
667 try dg.renderParentPtr(writer, field_ptr.container_ptr, container_ptr_ty, location);666 field_ptr.container_ptr,
668 try writer.writeAll(")->");667 container_ptr_ty,
669 switch (field_ptr.container_ty.tag()) {668 location,
670 .union_tagged, .union_safety_tagged => try writer.writeAll("payload."),669 );
671 else => {},670 try writer.print(" + {})", .{try dg.fmtIntLiteral(Type.usize, byte_offset_val)});
672 }671 },
673 try writer.print("{ }", .{fmtIdent(field_info.name)});672 .end => {
674 } else {673 try writer.writeAll("((");
675 try dg.renderParentPtr(writer, field_ptr.container_ptr, container_ptr_ty, location);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 },
676 }682 }
677 },683 },
678 .elem_ptr => {684 .elem_ptr => {
...@@ -696,7 +702,7 @@ pub const DeclGen = struct {...@@ -696,7 +702,7 @@ pub const DeclGen = struct {
696 const container_ptr_ty = Type.initPayload(&container_ptr_ty_pl.base);702 const container_ptr_ty = Type.initPayload(&container_ptr_ty_pl.base);
697703
698 // Ensure complete type definition is visible before accessing fields.704 // 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
701 try writer.writeAll("&(");707 try writer.writeAll("&(");
702 try dg.renderParentPtr(writer, payload_ptr.container_ptr, container_ptr_ty, location);708 try dg.renderParentPtr(writer, payload_ptr.container_ptr, container_ptr_ty, location);
...@@ -763,18 +769,18 @@ pub const DeclGen = struct {...@@ -763,18 +769,18 @@ pub const DeclGen = struct {
763 .Pointer => if (ty.isSlice()) {769 .Pointer => if (ty.isSlice()) {
764 if (!location.isInitializer()) {770 if (!location.isInitializer()) {
765 try writer.writeByte('(');771 try writer.writeByte('(');
766 try dg.renderTypecast(writer, ty);772 try dg.renderType(writer, ty);
767 try writer.writeByte(')');773 try writer.writeByte(')');
768 }774 }
769775
770 try writer.writeAll("{(");776 try writer.writeAll("{(");
771 var buf: Type.SlicePtrFieldTypeBuffer = undefined;777 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
772 const ptr_ty = ty.slicePtrFieldType(&buf);778 const ptr_ty = ty.slicePtrFieldType(&buf);
773 try dg.renderTypecast(writer, ptr_ty);779 try dg.renderType(writer, ptr_ty);
774 return writer.print("){x}, {0x}}}", .{try dg.fmtIntLiteral(Type.usize, val)});780 return writer.print("){x}, {0x}}}", .{try dg.fmtIntLiteral(Type.usize, val)});
775 } else {781 } else {
776 try writer.writeAll("((");782 try writer.writeAll("((");
777 try dg.renderTypecast(writer, ty);783 try dg.renderType(writer, ty);
778 return writer.print("){x})", .{try dg.fmtIntLiteral(Type.usize, val)});784 return writer.print("){x})", .{try dg.fmtIntLiteral(Type.usize, val)});
779 },785 },
780 .Optional => {786 .Optional => {
...@@ -791,7 +797,7 @@ pub const DeclGen = struct {...@@ -791,7 +797,7 @@ pub const DeclGen = struct {
791797
792 if (!location.isInitializer()) {798 if (!location.isInitializer()) {
793 try writer.writeByte('(');799 try writer.writeByte('(');
794 try dg.renderTypecast(writer, ty);800 try dg.renderType(writer, ty);
795 try writer.writeByte(')');801 try writer.writeByte(')');
796 }802 }
797803
...@@ -805,7 +811,7 @@ pub const DeclGen = struct {...@@ -805,7 +811,7 @@ pub const DeclGen = struct {
805 .Auto, .Extern => {811 .Auto, .Extern => {
806 if (!location.isInitializer()) {812 if (!location.isInitializer()) {
807 try writer.writeByte('(');813 try writer.writeByte('(');
808 try dg.renderTypecast(writer, ty);814 try dg.renderType(writer, ty);
809 try writer.writeByte(')');815 try writer.writeByte(')');
810 }816 }
811817
...@@ -827,7 +833,7 @@ pub const DeclGen = struct {...@@ -827,7 +833,7 @@ pub const DeclGen = struct {
827 .Union => {833 .Union => {
828 if (!location.isInitializer()) {834 if (!location.isInitializer()) {
829 try writer.writeByte('(');835 try writer.writeByte('(');
830 try dg.renderTypecast(writer, ty);836 try dg.renderType(writer, ty);
831 try writer.writeByte(')');837 try writer.writeByte(')');
832 }838 }
833839
...@@ -852,7 +858,7 @@ pub const DeclGen = struct {...@@ -852,7 +858,7 @@ pub const DeclGen = struct {
852 .ErrorUnion => {858 .ErrorUnion => {
853 if (!location.isInitializer()) {859 if (!location.isInitializer()) {
854 try writer.writeByte('(');860 try writer.writeByte('(');
855 try dg.renderTypecast(writer, ty);861 try dg.renderType(writer, ty);
856 try writer.writeByte(')');862 try writer.writeByte(')');
857 }863 }
858864
...@@ -865,7 +871,7 @@ pub const DeclGen = struct {...@@ -865,7 +871,7 @@ pub const DeclGen = struct {
865 .Array, .Vector => {871 .Array, .Vector => {
866 if (!location.isInitializer()) {872 if (!location.isInitializer()) {
867 try writer.writeByte('(');873 try writer.writeByte('(');
868 try dg.renderTypecast(writer, ty);874 try dg.renderType(writer, ty);
869 try writer.writeByte(')');875 try writer.writeByte(')');
870 }876 }
871877
...@@ -874,14 +880,14 @@ pub const DeclGen = struct {...@@ -874,14 +880,14 @@ pub const DeclGen = struct {
874 var literal = stringLiteral(writer);880 var literal = stringLiteral(writer);
875 try literal.start();881 try literal.start();
876 const c_len = ty.arrayLenIncludingSentinel();882 const c_len = ty.arrayLenIncludingSentinel();
877 var index: usize = 0;883 var index: u64 = 0;
878 while (index < c_len) : (index += 1)884 while (index < c_len) : (index += 1)
879 try literal.writeChar(0xaa);885 try literal.writeChar(0xaa);
880 return literal.end();886 return literal.end();
881 } else {887 } else {
882 try writer.writeByte('{');888 try writer.writeByte('{');
883 const c_len = ty.arrayLenIncludingSentinel();889 const c_len = ty.arrayLenIncludingSentinel();
884 var index: usize = 0;890 var index: u64 = 0;
885 while (index < c_len) : (index += 1) {891 while (index < c_len) : (index += 1) {
886 if (index > 0) try writer.writeAll(", ");892 if (index > 0) try writer.writeAll(", ");
887 try dg.renderValue(writer, ty.childType(), val, initializer_type);893 try dg.renderValue(writer, ty.childType(), val, initializer_type);
...@@ -1026,7 +1032,7 @@ pub const DeclGen = struct {...@@ -1026,7 +1032,7 @@ pub const DeclGen = struct {
1026 return dg.renderValue(writer, ty, slice_val, location);1032 return dg.renderValue(writer, ty, slice_val, location);
1027 } else {1033 } else {
1028 try writer.writeAll("((");1034 try writer.writeAll("((");
1029 try dg.renderTypecast(writer, ty);1035 try dg.renderType(writer, ty);
1030 try writer.writeAll(")NULL)");1036 try writer.writeAll(")NULL)");
1031 },1037 },
1032 .variable => {1038 .variable => {
...@@ -1036,7 +1042,7 @@ pub const DeclGen = struct {...@@ -1036,7 +1042,7 @@ pub const DeclGen = struct {
1036 .slice => {1042 .slice => {
1037 if (!location.isInitializer()) {1043 if (!location.isInitializer()) {
1038 try writer.writeByte('(');1044 try writer.writeByte('(');
1039 try dg.renderTypecast(writer, ty);1045 try dg.renderType(writer, ty);
1040 try writer.writeByte(')');1046 try writer.writeByte(')');
1041 }1047 }
10421048
...@@ -1059,7 +1065,7 @@ pub const DeclGen = struct {...@@ -1059,7 +1065,7 @@ pub const DeclGen = struct {
1059 },1065 },
1060 .int_u64, .one => {1066 .int_u64, .one => {
1061 try writer.writeAll("((");1067 try writer.writeAll("((");
1062 try dg.renderTypecast(writer, ty);1068 try dg.renderType(writer, ty);
1063 return writer.print("){x})", .{try dg.fmtIntLiteral(Type.usize, val)});1069 return writer.print("){x})", .{try dg.fmtIntLiteral(Type.usize, val)});
1064 },1070 },
1065 .field_ptr,1071 .field_ptr,
...@@ -1074,15 +1080,15 @@ pub const DeclGen = struct {...@@ -1074,15 +1080,15 @@ pub const DeclGen = struct {
1074 .Array, .Vector => {1080 .Array, .Vector => {
1075 if (location == .FunctionArgument) {1081 if (location == .FunctionArgument) {
1076 try writer.writeByte('(');1082 try writer.writeByte('(');
1077 try dg.renderTypecast(writer, ty);1083 try dg.renderType(writer, ty);
1078 try writer.writeByte(')');1084 try writer.writeByte(')');
1079 }1085 }
10801086
1081 // First try specific tag representations for more efficiency.1087 // First try specific tag representations for more efficiency.
1082 switch (val.tag()) {1088 switch (val.tag()) {
1083 .undef, .empty_struct_value, .empty_array => {1089 .undef, .empty_struct_value, .empty_array => {
1084 try writer.writeByte('{');
1085 const ai = ty.arrayInfo();1090 const ai = ty.arrayInfo();
1091 try writer.writeByte('{');
1086 if (ai.sentinel) |s| {1092 if (ai.sentinel) |s| {
1087 try dg.renderValue(writer, ai.elem_type, s, initializer_type);1093 try dg.renderValue(writer, ai.elem_type, s, initializer_type);
1088 } else {1094 } else {
...@@ -1090,13 +1096,19 @@ pub const DeclGen = struct {...@@ -1090,13 +1096,19 @@ pub const DeclGen = struct {
1090 }1096 }
1091 try writer.writeByte('}');1097 try writer.writeByte('}');
1092 },1098 },
1093 .bytes => {1099 .bytes, .str_lit => |t| {
1094 try writer.print("{s}", .{fmtStringLiteral(val.castTag(.bytes).?.data)});1100 const bytes = switch (t) {
1095 },1101 .bytes => val.castTag(.bytes).?.data,
1096 .str_lit => {1102 .str_lit => bytes: {
1097 const str_lit = val.castTag(.str_lit).?.data;1103 const str_lit = val.castTag(.str_lit).?.data;
1098 const bytes = dg.module.string_literal_bytes.items[str_lit.index..][0..str_lit.len];1104 break :bytes dg.module.string_literal_bytes.items[str_lit.index..][0..str_lit.len];
1099 try writer.print("{s}", .{fmtStringLiteral(bytes)});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 });
1100 },1112 },
1101 else => {1113 else => {
1102 // Fall back to generic implementation.1114 // Fall back to generic implementation.
...@@ -1120,7 +1132,7 @@ pub const DeclGen = struct {...@@ -1120,7 +1132,7 @@ pub const DeclGen = struct {
1120 }1132 }
1121 if (ai.sentinel) |s| {1133 if (ai.sentinel) |s| {
1122 const s_u8 = @intCast(u8, s.toUnsignedInt(target));1134 const s_u8 = @intCast(u8, s.toUnsignedInt(target));
1123 try literal.writeChar(s_u8);1135 if (s_u8 != 0) try literal.writeChar(s_u8);
1124 }1136 }
1125 try literal.end();1137 try literal.end();
1126 } else {1138 } else {
...@@ -1177,7 +1189,7 @@ pub const DeclGen = struct {...@@ -1177,7 +1189,7 @@ pub const DeclGen = struct {
11771189
1178 if (!location.isInitializer()) {1190 if (!location.isInitializer()) {
1179 try writer.writeByte('(');1191 try writer.writeByte('(');
1180 try dg.renderTypecast(writer, ty);1192 try dg.renderType(writer, ty);
1181 try writer.writeByte(')');1193 try writer.writeByte(')');
1182 }1194 }
11831195
...@@ -1211,7 +1223,7 @@ pub const DeclGen = struct {...@@ -1211,7 +1223,7 @@ pub const DeclGen = struct {
12111223
1212 if (!location.isInitializer()) {1224 if (!location.isInitializer()) {
1213 try writer.writeByte('(');1225 try writer.writeByte('(');
1214 try dg.renderTypecast(writer, ty);1226 try dg.renderType(writer, ty);
1215 try writer.writeByte(')');1227 try writer.writeByte(')');
1216 }1228 }
12171229
...@@ -1275,7 +1287,7 @@ pub const DeclGen = struct {...@@ -1275,7 +1287,7 @@ pub const DeclGen = struct {
12751287
1276 if (!location.isInitializer()) {1288 if (!location.isInitializer()) {
1277 try writer.writeByte('(');1289 try writer.writeByte('(');
1278 try dg.renderTypecast(writer, ty);1290 try dg.renderType(writer, ty);
1279 try writer.writeByte(')');1291 try writer.writeByte(')');
1280 }1292 }
12811293
...@@ -1362,7 +1374,7 @@ pub const DeclGen = struct {...@@ -1362,7 +1374,7 @@ pub const DeclGen = struct {
13621374
1363 if (!empty) try writer.writeAll(" | ");1375 if (!empty) try writer.writeAll(" | ");
1364 try writer.writeByte('(');1376 try writer.writeByte('(');
1365 try dg.renderTypecast(writer, ty);1377 try dg.renderType(writer, ty);
1366 try writer.writeByte(')');1378 try writer.writeByte(')');
13671379
1368 if (bit_offset_val_pl.data != 0) {1380 if (bit_offset_val_pl.data != 0) {
...@@ -1385,7 +1397,7 @@ pub const DeclGen = struct {...@@ -1385,7 +1397,7 @@ pub const DeclGen = struct {
13851397
1386 if (!location.isInitializer()) {1398 if (!location.isInitializer()) {
1387 try writer.writeByte('(');1399 try writer.writeByte('(');
1388 try dg.renderTypecast(writer, ty);1400 try dg.renderType(writer, ty);
1389 try writer.writeByte(')');1401 try writer.writeByte(')');
1390 }1402 }
13911403
...@@ -1396,11 +1408,11 @@ pub const DeclGen = struct {...@@ -1396,11 +1408,11 @@ pub const DeclGen = struct {
1396 if (field_ty.hasRuntimeBits()) {1408 if (field_ty.hasRuntimeBits()) {
1397 if (field_ty.isPtrAtRuntime()) {1409 if (field_ty.isPtrAtRuntime()) {
1398 try writer.writeByte('(');1410 try writer.writeByte('(');
1399 try dg.renderTypecast(writer, ty);1411 try dg.renderType(writer, ty);
1400 try writer.writeByte(')');1412 try writer.writeByte(')');
1401 } else if (field_ty.zigTypeTag() == .Float) {1413 } else if (field_ty.zigTypeTag() == .Float) {
1402 try writer.writeByte('(');1414 try writer.writeByte('(');
1403 try dg.renderTypecast(writer, ty);1415 try dg.renderType(writer, ty);
1404 try writer.writeByte(')');1416 try writer.writeByte(')');
1405 }1417 }
1406 try dg.renderValue(writer, field_ty, union_obj.val, initializer_type);1418 try dg.renderValue(writer, field_ty, union_obj.val, initializer_type);
...@@ -1457,24 +1469,31 @@ pub const DeclGen = struct {...@@ -1457,24 +1469,31 @@ pub const DeclGen = struct {
1457 }1469 }
1458 }1470 }
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 {
1461 const store = &dg.ctypes.set;1482 const store = &dg.ctypes.set;
1462 const module = dg.module;1483 const module = dg.module;
14631484
1464 const fn_ty = dg.decl.?.ty;1485 const fn_decl = module.declPtr(fn_decl_index);
1465 const fn_cty_idx = try dg.typeToIndex(fn_ty, switch (kind) {1486 const fn_cty_idx = try dg.typeToIndex(fn_decl.ty, kind);
1466 .Forward => .forward,
1467 .Complete => .complete,
1468 });
14691487
1470 const fn_info = fn_ty.fnInfo();1488 const fn_info = fn_decl.ty.fnInfo();
1471 if (fn_info.cc == .Naked) {1489 if (fn_info.cc == .Naked) {
1472 switch (kind) {1490 switch (kind) {
1473 .Forward => try w.writeAll("zig_naked_decl "),1491 .forward => try w.writeAll("zig_naked_decl "),
1474 .Complete => try w.writeAll("zig_naked "),1492 .complete => try w.writeAll("zig_naked "),
1493 else => unreachable,
1475 }1494 }
1476 }1495 }
1477 if (dg.decl.?.val.castTag(.function)) |func_payload|1496 if (fn_decl.val.castTag(.function)) |func_payload|
1478 if (func_payload.data.is_cold) try w.writeAll("zig_cold ");1497 if (func_payload.data.is_cold) try w.writeAll("zig_cold ");
1479 if (fn_info.return_type.tag() == .noreturn) try w.writeAll("zig_noreturn ");1498 if (fn_info.return_type.tag() == .noreturn) try w.writeAll("zig_noreturn ");
14801499
...@@ -1485,7 +1504,7 @@ pub const DeclGen = struct {...@@ -1485,7 +1504,7 @@ pub const DeclGen = struct {
1485 w,1504 w,
1486 fn_cty_idx,1505 fn_cty_idx,
1487 .suffix,1506 .suffix,
1488 CQualifiers.init(.{}),1507 .{},
1489 );1508 );
1490 try w.print("{}", .{trailing});1509 try w.print("{}", .{trailing});
14911510
...@@ -1493,25 +1512,48 @@ pub const DeclGen = struct {...@@ -1493,25 +1512,48 @@ pub const DeclGen = struct {
1493 try w.print("zig_callconv({s}) ", .{call_conv});1512 try w.print("zig_callconv({s}) ", .{call_conv});
1494 }1513 }
14951514
1496 if (fn_info.alignment > 0 and kind == .Complete) {1515 switch (kind) {
1497 try w.print(" zig_align_fn({})", .{fn_info.alignment});1516 .forward => {},
1517 .complete => if (fn_info.alignment > 0)
1518 try w.print(" zig_align_fn({})", .{fn_info.alignment}),
1519 else => unreachable,
1498 }1520 }
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) {1541 switch (kind) {
1505 try w.print(" zig_align_fn({})", .{fn_info.alignment});1542 .forward => if (fn_info.alignment > 0)
1543 try w.print(" zig_align_fn({})", .{fn_info.alignment}),
1544 .complete => {},
1545 else => unreachable,
1506 }1546 }
1507 }1547 }
15081548
1509 fn indexToCType(dg: *DeclGen, idx: CType.Index) CType {1549 fn indexToCType(dg: *DeclGen, idx: CType.Index) CType {
1510 return dg.ctypes.indexToCType(idx);1550 return dg.ctypes.indexToCType(idx);
1511 }1551 }
1552
1512 fn typeToIndex(dg: *DeclGen, ty: Type, kind: CType.Kind) !CType.Index {1553 fn typeToIndex(dg: *DeclGen, ty: Type, kind: CType.Kind) !CType.Index {
1513 return dg.ctypes.typeToIndex(dg.gpa, ty, dg.module, kind);1554 return dg.ctypes.typeToIndex(dg.gpa, ty, dg.module, kind);
1514 }1555 }
1556
1515 fn typeToCType(dg: *DeclGen, ty: Type, kind: CType.Kind) !CType {1557 fn typeToCType(dg: *DeclGen, ty: Type, kind: CType.Kind) !CType {
1516 return dg.ctypes.typeToCType(dg.gpa, ty, dg.module, kind);1558 return dg.ctypes.typeToCType(dg.gpa, ty, dg.module, kind);
1517 }1559 }
...@@ -1524,29 +1566,15 @@ pub const DeclGen = struct {...@@ -1524,29 +1566,15 @@ pub const DeclGen = struct {
1524 /// There are three type formats in total that we support rendering:1566 /// There are three type formats in total that we support rendering:
1525 /// | Function | Example 1 (*u8) | Example 2 ([10]*u8) |1567 /// | Function | Example 1 (*u8) | Example 2 ([10]*u8) |
1526 /// |---------------------|-----------------|---------------------|1568 /// |---------------------|-----------------|---------------------|
1527 /// | `renderTypecast` | "uint8_t *" | "uint8_t *[10]" |
1528 /// | `renderTypeAndName` | "uint8_t *name" | "uint8_t *name[10]" |1569 /// | `renderTypeAndName` | "uint8_t *name" | "uint8_t *name[10]" |
1529 /// | `renderType` | "uint8_t *" | "uint8_t *[10]" |1570 /// | `renderType` | "uint8_t *" | "uint8_t *[10]" |
1530 ///1571 ///
1531 fn renderType(1572 fn renderType(dg: *DeclGen, w: anytype, t: Type) error{ OutOfMemory, AnalysisFail }!void {
1532 dg: *DeclGen,
1533 w: anytype,
1534 t: Type,
1535 _: TypedefKind,
1536 ) error{ OutOfMemory, AnalysisFail }!void {
1537 const store = &dg.ctypes.set;1573 const store = &dg.ctypes.set;
1538 const module = dg.module;1574 const module = dg.module;
1539 const idx = try dg.typeToIndex(t, .complete);1575 const idx = try dg.typeToIndex(t, .complete);
1540 _ = try renderTypePrefix(1576 _ = try renderTypePrefix(dg.decl_index, store.*, module, w, idx, .suffix, .{});
1541 dg.decl_index,1577 try renderTypeSuffix(dg.decl_index, store.*, module, w, idx, .suffix, .{});
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);
1550 }1578 }
15511579
1552 const IntCastContext = union(enum) {1580 const IntCastContext = union(enum) {
...@@ -1603,17 +1631,22 @@ pub const DeclGen = struct {...@@ -1603,17 +1631,22 @@ pub const DeclGen = struct {
16031631
1604 if (needs_cast) {1632 if (needs_cast) {
1605 try w.writeByte('(');1633 try w.writeByte('(');
1606 try dg.renderTypecast(w, dest_ty);1634 try dg.renderType(w, dest_ty);
1607 try w.writeByte(')');1635 try w.writeByte(')');
1608 }1636 }
1609 if (src_is_ptr) {1637 if (src_is_ptr) {
1610 try w.writeByte('(');1638 try w.writeByte('(');
1611 try dg.renderTypecast(w, src_eff_ty);1639 try dg.renderType(w, src_eff_ty);
1612 try w.writeByte(')');1640 try w.writeByte(')');
1613 }1641 }
1614 try context.writeValue(dg, w, src_ty, location);1642 try context.writeValue(dg, w, src_ty, location);
1615 } else if (dest_bits <= 64 and src_bits > 64) {1643 } else if (dest_bits <= 64 and src_bits > 64) {
1616 assert(!src_is_ptr);1644 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 }
1617 try w.writeAll("zig_lo_");1650 try w.writeAll("zig_lo_");
1618 try dg.renderTypeForBuiltinFnName(w, src_eff_ty);1651 try dg.renderTypeForBuiltinFnName(w, src_eff_ty);
1619 try w.writeByte('(');1652 try w.writeByte('(');
...@@ -1625,7 +1658,7 @@ pub const DeclGen = struct {...@@ -1625,7 +1658,7 @@ pub const DeclGen = struct {
1625 try w.writeAll("(0, "); // TODO: Should the 0 go through fmtIntLiteral?1658 try w.writeAll("(0, "); // TODO: Should the 0 go through fmtIntLiteral?
1626 if (src_is_ptr) {1659 if (src_is_ptr) {
1627 try w.writeByte('(');1660 try w.writeByte('(');
1628 try dg.renderTypecast(w, src_eff_ty);1661 try dg.renderType(w, src_eff_ty);
1629 try w.writeByte(')');1662 try w.writeByte(')');
1630 }1663 }
1631 try context.writeValue(dg, w, src_ty, .FunctionArgument);1664 try context.writeValue(dg, w, src_ty, .FunctionArgument);
...@@ -1646,28 +1679,11 @@ pub const DeclGen = struct {...@@ -1646,28 +1679,11 @@ pub const DeclGen = struct {
1646 }1679 }
1647 }1680 }
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
1665 /// Renders a type and name in field declaration/definition format.1682 /// Renders a type and name in field declaration/definition format.
1666 ///1683 ///
1667 /// There are three type formats in total that we support rendering:1684 /// There are three type formats in total that we support rendering:
1668 /// | Function | Example 1 (*u8) | Example 2 ([10]*u8) |1685 /// | Function | Example 1 (*u8) | Example 2 ([10]*u8) |
1669 /// |---------------------|-----------------|---------------------|1686 /// |---------------------|-----------------|---------------------|
1670 /// | `renderTypecast` | "uint8_t *" | "uint8_t *[10]" |
1671 /// | `renderTypeAndName` | "uint8_t *name" | "uint8_t *name[10]" |1687 /// | `renderTypeAndName` | "uint8_t *name" | "uint8_t *name[10]" |
1672 /// | `renderType` | "uint8_t *" | "uint8_t *[10]" |1688 /// | `renderType` | "uint8_t *" | "uint8_t *[10]" |
1673 ///1689 ///
...@@ -1676,9 +1692,9 @@ pub const DeclGen = struct {...@@ -1676,9 +1692,9 @@ pub const DeclGen = struct {
1676 w: anytype,1692 w: anytype,
1677 ty: Type,1693 ty: Type,
1678 name: CValue,1694 name: CValue,
1679 mutability: Mutability,1695 qualifiers: CQualifiers,
1680 alignment: u32,1696 alignment: u32,
1681 _: TypedefKind,1697 kind: CType.Kind,
1682 ) error{ OutOfMemory, AnalysisFail }!void {1698 ) error{ OutOfMemory, AnalysisFail }!void {
1683 const store = &dg.ctypes.set;1699 const store = &dg.ctypes.set;
1684 const module = dg.module;1700 const module = dg.module;
...@@ -1689,71 +1705,12 @@ pub const DeclGen = struct {...@@ -1689,71 +1705,12 @@ pub const DeclGen = struct {
1689 .gt => try w.print("zig_align({}) ", .{alignment}),1705 .gt => try w.print("zig_align({}) ", .{alignment}),
1690 };1706 };
16911707
1692 const idx = try dg.typeToIndex(ty, .complete);1708 const idx = try dg.typeToIndex(ty, kind);
1693 const trailing = try renderTypePrefix(1709 const trailing =
1694 dg.decl_index,1710 try renderTypePrefix(dg.decl_index, store.*, module, w, idx, .suffix, qualifiers);
1695 store.*,
1696 module,
1697 w,
1698 idx,
1699 .suffix,
1700 CQualifiers.init(.{ .@"const" = mutability == .@"const" }),
1701 );
1702 try w.print("{}", .{trailing});1711 try w.print("{}", .{trailing});
1703 try dg.writeCValue(w, name);1712 try dg.writeCValue(w, name);
1704 try renderTypeSuffix(dg.decl_index, store.*, module, w, idx, .suffix);1713 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");
1757 }1714 }
17581715
1759 fn declIsGlobal(dg: *DeclGen, tv: TypedValue) bool {1716 fn declIsGlobal(dg: *DeclGen, tv: TypedValue) bool {
...@@ -1787,6 +1744,10 @@ pub const DeclGen = struct {...@@ -1787,6 +1744,10 @@ pub const DeclGen = struct {
1787 },1744 },
1788 .undef => |ty| return dg.renderValue(w, ty, Value.undef, .Other),1745 .undef => |ty| return dg.renderValue(w, ty, Value.undef, .Other),
1789 .identifier => |ident| return w.print("{ }", .{fmtIdent(ident)}),1746 .identifier => |ident| return w.print("{ }", .{fmtIdent(ident)}),
1747 .payload_identifier => |ident| return w.print("{ }.{ }", .{
1748 fmtIdent("payload"),
1749 fmtIdent(ident),
1750 }),
1790 .bytes => |bytes| return w.writeAll(bytes),1751 .bytes => |bytes| return w.writeAll(bytes),
1791 }1752 }
1792 }1753 }
...@@ -1812,6 +1773,10 @@ pub const DeclGen = struct {...@@ -1812,6 +1773,10 @@ pub const DeclGen = struct {
1812 .decl_ref => |decl| return dg.renderDeclName(w, decl, 0),1773 .decl_ref => |decl| return dg.renderDeclName(w, decl, 0),
1813 .undef => unreachable,1774 .undef => unreachable,
1814 .identifier => |ident| return w.print("(*{ })", .{fmtIdent(ident)}),1775 .identifier => |ident| return w.print("(*{ })", .{fmtIdent(ident)}),
1776 .payload_identifier => |ident| return w.print("(*{ }.{ })", .{
1777 fmtIdent("payload"),
1778 fmtIdent(ident),
1779 }),
1815 .bytes => |bytes| {1780 .bytes => |bytes| {
1816 try w.writeAll("(*");1781 try w.writeAll("(*");
1817 try w.writeAll(bytes);1782 try w.writeAll(bytes);
...@@ -1829,7 +1794,7 @@ pub const DeclGen = struct {...@@ -1829,7 +1794,7 @@ pub const DeclGen = struct {
1829 fn writeCValueDerefMember(dg: *DeclGen, writer: anytype, c_value: CValue, member: CValue) !void {1794 fn writeCValueDerefMember(dg: *DeclGen, writer: anytype, c_value: CValue, member: CValue) !void {
1830 switch (c_value) {1795 switch (c_value) {
1831 .none, .constant, .field, .undef => unreachable,1796 .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 => {
1833 try dg.writeCValue(writer, c_value);1798 try dg.writeCValue(writer, c_value);
1834 try writer.writeAll("->");1799 try writer.writeAll("->");
1835 },1800 },
...@@ -1958,7 +1923,8 @@ pub const DeclGen = struct {...@@ -1958,7 +1923,8 @@ pub const DeclGen = struct {
19581923
1959const CTypeFix = enum { prefix, suffix };1924const CTypeFix = enum { prefix, suffix };
1960const CQualifiers = std.enums.EnumSet(enum { @"const", @"volatile", restrict });1925const CQualifiers = std.enums.EnumSet(enum { @"const", @"volatile", restrict });
1961const CTypeRenderTrailing = enum {1926const Const = CQualifiers.init(.{ .@"const" = true });
1927const RenderCTypeTrailing = enum {
1962 no_space,1928 no_space,
1963 maybe_space,1929 maybe_space,
19641930
...@@ -2017,8 +1983,8 @@ fn renderTypePrefix(...@@ -2017,8 +1983,8 @@ fn renderTypePrefix(
2017 idx: CType.Index,1983 idx: CType.Index,
2018 parent_fix: CTypeFix,1984 parent_fix: CTypeFix,
2019 qualifiers: CQualifiers,1985 qualifiers: CQualifiers,
2020) @TypeOf(w).Error!CTypeRenderTrailing {1986) @TypeOf(w).Error!RenderCTypeTrailing {
2021 var trailing = CTypeRenderTrailing.maybe_space;1987 var trailing = RenderCTypeTrailing.maybe_space;
20221988
2023 const cty = store.indexToCType(idx);1989 const cty = store.indexToCType(idx);
2024 switch (cty.tag()) {1990 switch (cty.tag()) {
...@@ -2160,7 +2126,7 @@ fn renderTypePrefix(...@@ -2160,7 +2126,7 @@ fn renderTypePrefix(
2160 w,2126 w,
2161 cty.cast(CType.Payload.Function).?.data.return_type,2127 cty.cast(CType.Payload.Function).?.data.return_type,
2162 .suffix,2128 .suffix,
2163 CQualifiers.init(.{}),2129 .{},
2164 );2130 );
2165 switch (parent_fix) {2131 switch (parent_fix) {
2166 .prefix => {2132 .prefix => {
...@@ -2187,6 +2153,7 @@ fn renderTypeSuffix(...@@ -2187,6 +2153,7 @@ fn renderTypeSuffix(
2187 w: anytype,2153 w: anytype,
2188 idx: CType.Index,2154 idx: CType.Index,
2189 parent_fix: CTypeFix,2155 parent_fix: CTypeFix,
2156 qualifiers: CQualifiers,
2190) @TypeOf(w).Error!void {2157) @TypeOf(w).Error!void {
2191 const cty = store.indexToCType(idx);2158 const cty = store.indexToCType(idx);
2192 switch (cty.tag()) {2159 switch (cty.tag()) {
...@@ -2233,7 +2200,15 @@ fn renderTypeSuffix(...@@ -2233,7 +2200,15 @@ fn renderTypeSuffix(
2233 .pointer_const,2200 .pointer_const,
2234 .pointer_volatile,2201 .pointer_volatile,
2235 .pointer_const_volatile,2202 .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
2238 .array,2213 .array,
2239 .vector,2214 .vector,
...@@ -2251,6 +2226,7 @@ fn renderTypeSuffix(...@@ -2251,6 +2226,7 @@ fn renderTypeSuffix(
2251 w,2226 w,
2252 cty.cast(CType.Payload.Sequence).?.data.elem_type,2227 cty.cast(CType.Payload.Sequence).?.data.elem_type,
2253 .suffix,2228 .suffix,
2229 .{},
2254 );2230 );
2255 },2231 },
22562232
...@@ -2285,17 +2261,10 @@ fn renderTypeSuffix(...@@ -2285,17 +2261,10 @@ fn renderTypeSuffix(
2285 for (data.param_types, 0..) |param_type, param_i| {2261 for (data.param_types, 0..) |param_type, param_i| {
2286 if (need_comma) try w.writeAll(", ");2262 if (need_comma) try w.writeAll(", ");
2287 need_comma = true;2263 need_comma = true;
2288 const trailing = try renderTypePrefix(2264 const trailing =
2289 decl,2265 try renderTypePrefix(decl, store, mod, w, param_type, .suffix, qualifiers);
2290 store,2266 if (qualifiers.contains(.@"const")) try w.print("{}a{d}", .{ trailing, param_i });
2291 mod,2267 try renderTypeSuffix(decl, store, mod, w, param_type, .suffix, .{});
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);
2299 }2268 }
2300 switch (tag) {2269 switch (tag) {
2301 .function => {},2270 .function => {},
...@@ -2309,7 +2278,7 @@ fn renderTypeSuffix(...@@ -2309,7 +2278,7 @@ fn renderTypeSuffix(
2309 if (!need_comma) try w.writeAll("void");2278 if (!need_comma) try w.writeAll("void");
2310 try w.writeByte(')');2279 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, .{});
2313 },2282 },
2314 }2283 }
2315}2284}
...@@ -2329,17 +2298,9 @@ fn renderAggregateFields(...@@ -2329,17 +2298,9 @@ fn renderAggregateFields(
2329 .eq => {},2298 .eq => {},
2330 .gt => try writer.print("zig_align({}) ", .{field.alignas.getAlign()}),2299 .gt => try writer.print("zig_align({}) ", .{field.alignas.getAlign()}),
2331 }2300 }
2332 const trailing = try renderTypePrefix(2301 const trailing = try renderTypePrefix(.none, store, mod, writer, field.type, .suffix, .{});
2333 .none,
2334 store,
2335 mod,
2336 writer,
2337 field.type,
2338 .suffix,
2339 CQualifiers.init(.{}),
2340 );
2341 try writer.print("{}{ }", .{ trailing, fmtIdent(mem.span(field.name)) });2302 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, .{});
2343 try writer.writeAll(";\n");2304 try writer.writeAll(";\n");
2344 }2305 }
2345 try writer.writeByteNTimes(' ', indent);2306 try writer.writeByteNTimes(' ', indent);
...@@ -2360,25 +2321,9 @@ pub fn genTypeDecl(...@@ -2360,25 +2321,9 @@ pub fn genTypeDecl(
2360 switch (global_cty.tag()) {2321 switch (global_cty.tag()) {
2361 .fwd_anon_struct => if (decl != .none) {2322 .fwd_anon_struct => if (decl != .none) {
2362 try writer.writeAll("typedef ");2323 try writer.writeAll("typedef ");
2363 _ = try renderTypePrefix(2324 _ = try renderTypePrefix(.none, global_store, mod, writer, global_idx, .suffix, .{});
2364 .none,
2365 global_store,
2366 mod,
2367 writer,
2368 global_idx,
2369 .suffix,
2370 CQualifiers.init(.{}),
2371 );
2372 try writer.writeByte(' ');2325 try writer.writeByte(' ');
2373 _ = try renderTypePrefix(2326 _ = try renderTypePrefix(decl, decl_store, mod, writer, decl_idx, .suffix, .{});
2374 decl,
2375 decl_store,
2376 mod,
2377 writer,
2378 decl_idx,
2379 .suffix,
2380 CQualifiers.init(.{}),
2381 );
2382 try writer.writeAll(";\n");2327 try writer.writeAll(";\n");
2383 },2328 },
23842329
...@@ -2396,15 +2341,7 @@ pub fn genTypeDecl(...@@ -2396,15 +2341,7 @@ pub fn genTypeDecl(
2396 .fwd_union,2341 .fwd_union,
2397 => {2342 => {
2398 const owner_decl = global_cty.cast(CType.Payload.FwdDecl).?.data;2343 const owner_decl = global_cty.cast(CType.Payload.FwdDecl).?.data;
2399 _ = try renderTypePrefix(2344 _ = try renderTypePrefix(.none, global_store, mod, writer, global_idx, .suffix, .{});
2400 .none,
2401 global_store,
2402 mod,
2403 writer,
2404 global_idx,
2405 .suffix,
2406 CQualifiers.init(.{}),
2407 );
2408 try writer.writeAll("; // ");2345 try writer.writeAll("; // ");
2409 try mod.declPtr(owner_decl).renderFullyQualifiedName(mod, writer);2346 try mod.declPtr(owner_decl).renderFullyQualifiedName(mod, writer);
2410 try writer.writeByte('\n');2347 try writer.writeByte('\n');
...@@ -2441,9 +2378,7 @@ pub fn genTypeDecl(...@@ -2441,9 +2378,7 @@ pub fn genTypeDecl(
24412378
2442pub fn genGlobalAsm(mod: *Module, writer: anytype) !void {2379pub fn genGlobalAsm(mod: *Module, writer: anytype) !void {
2443 var it = mod.global_assembly.valueIterator();2380 var it = mod.global_assembly.valueIterator();
2444 while (it.next()) |asm_source| {2381 while (it.next()) |asm_source| try writer.print("__asm({s});\n", .{fmtStringLiteral(asm_source.*, null)});
2445 try writer.print("__asm({s});\n", .{fmtStringLiteral(asm_source.*)});
2446 }
2447}2382}
24482383
2449pub fn genErrDecls(o: *Object) !void {2384pub fn genErrDecls(o: *Object) !void {
...@@ -2461,26 +2396,24 @@ pub fn genErrDecls(o: *Object) !void {...@@ -2461,26 +2396,24 @@ pub fn genErrDecls(o: *Object) !void {
2461 o.indent_writer.popIndent();2396 o.indent_writer.popIndent();
2462 try writer.writeAll("};\n");2397 try writer.writeAll("};\n");
24632398
2464 const name_prefix = "zig_errorName";2399 const array_identifier = "zig_errorName";
2465 const name_buf = try o.dg.gpa.alloc(u8, name_prefix.len + "_".len + max_name_len + 1);2400 const name_prefix = array_identifier ++ "_";
2401 const name_buf = try o.dg.gpa.alloc(u8, name_prefix.len + max_name_len);
2466 defer o.dg.gpa.free(name_buf);2402 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);
2469 for (o.dg.module.error_name_list.items) |name| {2405 for (o.dg.module.error_name_list.items) |name| {
2470 std.mem.copy(u8, name_buf[name_prefix.len + "_".len ..], name);2406 std.mem.copy(u8, name_buf[name_prefix.len..], name);
2471 name_buf[name_prefix.len + "_".len + name.len] = 0;2407 const identifier = name_buf[0 .. name_prefix.len + name.len];
2472
2473 const identifier = name_buf[0 .. name_prefix.len + "_".len + name.len :0];
2474 const name_z = identifier[name_prefix.len + "_".len ..];
24752408
2476 var name_ty_pl = Type.Payload.Len{ .base = .{ .tag = .array_u8_sentinel_0 }, .data = name.len };2409 var name_ty_pl = Type.Payload.Len{ .base = .{ .tag = .array_u8_sentinel_0 }, .data = name.len };
2477 const name_ty = Type.initPayload(&name_ty_pl.base);2410 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 };
2480 const name_val = Value.initPayload(&name_pl.base);2413 const name_val = Value.initPayload(&name_pl.base);
24812414
2482 try writer.writeAll("static ");2415 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);
2484 try writer.writeAll(" = ");2417 try writer.writeAll(" = ");
2485 try o.dg.renderValue(writer, name_ty, name_val, .StaticInitializer);2418 try o.dg.renderValue(writer, name_ty, name_val, .StaticInitializer);
2486 try writer.writeAll(";\n");2419 try writer.writeAll(";\n");
...@@ -2493,7 +2426,7 @@ pub fn genErrDecls(o: *Object) !void {...@@ -2493,7 +2426,7 @@ pub fn genErrDecls(o: *Object) !void {
2493 const name_array_ty = Type.initPayload(&name_array_ty_pl.base);2426 const name_array_ty = Type.initPayload(&name_array_ty_pl.base);
24942427
2495 try writer.writeAll("static ");2428 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);
2497 try writer.writeAll(" = {");2430 try writer.writeAll(" = {");
2498 for (o.dg.module.error_name_list.items, 0..) |name, value| {2431 for (o.dg.module.error_name_list.items, 0..) |name, value| {
2499 if (value != 0) try writer.writeByte(',');2432 if (value != 0) try writer.writeByte(',');
...@@ -2501,7 +2434,7 @@ pub fn genErrDecls(o: *Object) !void {...@@ -2501,7 +2434,7 @@ pub fn genErrDecls(o: *Object) !void {
2501 var len_pl = Value.Payload.U64{ .base = .{ .tag = .int_u64 }, .data = name.len };2434 var len_pl = Value.Payload.U64{ .base = .{ .tag = .int_u64 }, .data = name.len };
2502 const len_val = Value.initPayload(&len_pl.base);2435 const len_val = Value.initPayload(&len_pl.base);
25032436
2504 try writer.print("{{" ++ name_prefix ++ "_{}, {}}}", .{2437 try writer.print("{{" ++ name_prefix ++ "{}, {}}}", .{
2505 fmtIdent(name), try o.dg.fmtIntLiteral(Type.usize, len_val),2438 fmtIdent(name), try o.dg.fmtIntLiteral(Type.usize, len_val),
2506 });2439 });
2507 }2440 }
...@@ -2516,23 +2449,91 @@ fn genExports(o: *Object) !void {...@@ -2516,23 +2449,91 @@ fn genExports(o: *Object) !void {
2516 if (o.dg.module.decl_exports.get(o.dg.decl_index.unwrap().?)) |exports| {2449 if (o.dg.module.decl_exports.get(o.dg.decl_index.unwrap().?)) |exports| {
2517 for (exports.items[1..], 1..) |@"export", i| {2450 for (exports.items[1..], 1..) |@"export", i| {
2518 try fwd_decl_writer.writeAll("zig_export(");2451 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) });
2520 try fwd_decl_writer.print(", {s}, {s});\n", .{2453 try fwd_decl_writer.print(", {s}, {s});\n", .{
2521 fmtStringLiteral(exports.items[0].options.name),2454 fmtStringLiteral(exports.items[0].options.name, null),
2522 fmtStringLiteral(@"export".options.name),2455 fmtStringLiteral(@"export".options.name, null),
2523 });2456 });
2524 }2457 }
2525 }2458 }
2526}2459}
25272460
2528pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void {2461pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void {
2529 const writer = o.writer();2462 const w = o.writer();
2530 switch (lazy_fn.key_ptr.*) {2463 const key = lazy_fn.key_ptr.*;
2531 .tag_name => _ = try o.dg.renderTagNameFn(2464 const val = lazy_fn.value_ptr;
2532 writer,2465 const fn_name = val.fn_name;
2533 lazy_fn.value_ptr.fn_name,2466 switch (key) {
2534 lazy_fn.value_ptr.data.tag_name,2467 .tag_name => {
2535 ),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 },
2536 }2537 }
2537}2538}
25382539
...@@ -2542,6 +2543,7 @@ pub fn genFunc(f: *Function) !void {...@@ -2542,6 +2543,7 @@ pub fn genFunc(f: *Function) !void {
25422543
2543 const o = &f.object;2544 const o = &f.object;
2544 const gpa = o.dg.gpa;2545 const gpa = o.dg.gpa;
2546 const decl_index = o.dg.decl_index.unwrap().?;
2545 const tv: TypedValue = .{2547 const tv: TypedValue = .{
2546 .ty = o.dg.decl.?.ty,2548 .ty = o.dg.decl.?.ty,
2547 .val = o.dg.decl.?.val,2549 .val = o.dg.decl.?.val,
...@@ -2553,13 +2555,13 @@ pub fn genFunc(f: *Function) !void {...@@ -2553,13 +2555,13 @@ pub fn genFunc(f: *Function) !void {
2553 const is_global = o.dg.declIsGlobal(tv);2555 const is_global = o.dg.declIsGlobal(tv);
2554 const fwd_decl_writer = o.dg.fwd_decl.writer();2556 const fwd_decl_writer = o.dg.fwd_decl.writer();
2555 try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static ");2557 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 });
2557 try fwd_decl_writer.writeAll(";\n");2559 try fwd_decl_writer.writeAll(";\n");
2558 try genExports(o);2560 try genExports(o);
25592561
2560 try o.indent_writer.insertNewline();2562 try o.indent_writer.insertNewline();
2561 if (!is_global) try o.writer().writeAll("static ");2563 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 });
2563 try o.writer().writeByte(' ');2565 try o.writer().writeByte(' ');
25642566
2565 // In case we need to use the header, populate it with a copy of the function2567 // 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 {...@@ -2613,9 +2615,9 @@ pub fn genFunc(f: *Function) !void {
2613 w,2615 w,
2614 local.ty,2616 local.ty,
2615 .{ .local = local_index },2617 .{ .local = local_index },
2616 .mut,2618 .{},
2617 local.alignment,2619 local.alignment,
2618 .Complete,2620 .complete,
2619 );2621 );
2620 try w.writeAll(";\n ");2622 try w.writeAll(";\n ");
2621 }2623 }
...@@ -2634,14 +2636,14 @@ pub fn genDecl(o: *Object) !void {...@@ -2634,14 +2636,14 @@ pub fn genDecl(o: *Object) !void {
2634 defer tracy.end();2636 defer tracy.end();
26352637
2636 const decl = o.dg.decl.?;2638 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().? };
2638 const tv: TypedValue = .{ .ty = decl.ty, .val = decl.val };2640 const tv: TypedValue = .{ .ty = decl.ty, .val = decl.val };
26392641
2640 if (!tv.ty.isFnOrHasRuntimeBitsIgnoreComptime()) return;2642 if (!tv.ty.isFnOrHasRuntimeBitsIgnoreComptime()) return;
2641 if (tv.val.tag() == .extern_fn) {2643 if (tv.val.tag() == .extern_fn) {
2642 const fwd_decl_writer = o.dg.fwd_decl.writer();2644 const fwd_decl_writer = o.dg.fwd_decl.writer();
2643 try fwd_decl_writer.writeAll("zig_extern ");2645 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 });
2645 try fwd_decl_writer.writeAll(";\n");2647 try fwd_decl_writer.writeAll(";\n");
2646 try genExports(o);2648 try genExports(o);
2647 } else if (tv.val.castTag(.variable)) |var_payload| {2649 } else if (tv.val.castTag(.variable)) |var_payload| {
...@@ -2652,7 +2654,7 @@ pub fn genDecl(o: *Object) !void {...@@ -2652,7 +2654,7 @@ pub fn genDecl(o: *Object) !void {
26522654
2653 try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static ");2655 try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static ");
2654 if (variable.is_threadlocal) try fwd_decl_writer.writeAll("zig_threadlocal ");2656 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);
2656 try fwd_decl_writer.writeAll(";\n");2658 try fwd_decl_writer.writeAll(";\n");
2657 try genExports(o);2659 try genExports(o);
26582660
...@@ -2662,7 +2664,7 @@ pub fn genDecl(o: *Object) !void {...@@ -2662,7 +2664,7 @@ pub fn genDecl(o: *Object) !void {
2662 if (!is_global) try w.writeAll("static ");2664 if (!is_global) try w.writeAll("static ");
2663 if (variable.is_threadlocal) try w.writeAll("zig_threadlocal ");2665 if (variable.is_threadlocal) try w.writeAll("zig_threadlocal ");
2664 if (decl.@"linksection") |section| try w.print("zig_linksection(\"{s}\", ", .{section});2666 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);
2666 if (decl.@"linksection" != null) try w.writeAll(", read, write)");2668 if (decl.@"linksection" != null) try w.writeAll(", read, write)");
2667 try w.writeAll(" = ");2669 try w.writeAll(" = ");
2668 try o.dg.renderValue(w, tv.ty, variable.init, .StaticInitializer);2670 try o.dg.renderValue(w, tv.ty, variable.init, .StaticInitializer);
...@@ -2673,13 +2675,13 @@ pub fn genDecl(o: *Object) !void {...@@ -2673,13 +2675,13 @@ pub fn genDecl(o: *Object) !void {
2673 const fwd_decl_writer = o.dg.fwd_decl.writer();2675 const fwd_decl_writer = o.dg.fwd_decl.writer();
26742676
2675 try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static ");2677 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);
2677 try fwd_decl_writer.writeAll(";\n");2679 try fwd_decl_writer.writeAll(";\n");
26782680
2679 const w = o.writer();2681 const w = o.writer();
2680 if (!is_global) try w.writeAll("static ");2682 if (!is_global) try w.writeAll("static ");
2681 if (decl.@"linksection") |section| try w.print("zig_linksection(\"{s}\", ", .{section});2683 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);
2683 if (decl.@"linksection" != null) try w.writeAll(", read)");2685 if (decl.@"linksection" != null) try w.writeAll(", read)");
2684 try w.writeAll(" = ");2686 try w.writeAll(" = ");
2685 try o.dg.renderValue(w, tv.ty, tv.val, .StaticInitializer);2687 try o.dg.renderValue(w, tv.ty, tv.val, .StaticInitializer);
...@@ -2702,7 +2704,7 @@ pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void {...@@ -2702,7 +2704,7 @@ pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void {
2702 const is_global = dg.declIsGlobal(tv);2704 const is_global = dg.declIsGlobal(tv);
2703 if (is_global) {2705 if (is_global) {
2704 try writer.writeAll("zig_extern ");2706 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 });
2706 try dg.fwd_decl.appendSlice(";\n");2708 try dg.fwd_decl.appendSlice(";\n");
2707 }2709 }
2708 },2710 },
...@@ -2892,10 +2894,10 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,...@@ -2892,10 +2894,10 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
28922894
2893 .dbg_block_begin,2895 .dbg_block_begin,
2894 .dbg_block_end,2896 .dbg_block_end,
2895 => CValue{ .none = {} },2897 => .none,
28962898
2897 .call => try airCall(f, inst, .auto),2899 .call => try airCall(f, inst, .auto),
2898 .call_always_tail => try airCall(f, inst, .always_tail),2900 .call_always_tail => .none,
2899 .call_never_tail => try airCall(f, inst, .never_tail),2901 .call_never_tail => try airCall(f, inst, .never_tail),
2900 .call_never_inline => try airCall(f, inst, .never_inline),2902 .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,...@@ -2974,10 +2976,10 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
2974 .error_set_has_value => return f.fail("TODO: C backend: implement error_set_has_value", .{}),2976 .error_set_has_value => return f.fail("TODO: C backend: implement error_set_has_value", .{}),
2975 .vector_store_elem => return f.fail("TODO: C backend: implement vector_store_elem", .{}),2977 .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", .{}),2979 .c_va_start => try airCVaStart(f, inst),
2978 .c_va_copy => return f.fail("TODO implement c_va_copy", .{}),2980 .c_va_arg => try airCVaArg(f, inst),
2979 .c_va_end => return f.fail("TODO implement c_va_end", .{}),2981 .c_va_end => try airCVaEnd(f, inst),
2980 .c_va_start => return f.fail("TODO implement c_va_start", .{}),2982 .c_va_copy => try airCVaCopy(f, inst),
2981 // zig fmt: on2983 // zig fmt: on
2982 };2984 };
2983 if (result_value == .new_local) {2985 if (result_value == .new_local) {
...@@ -2996,7 +2998,7 @@ fn airSliceField(f: *Function, inst: Air.Inst.Index, is_ptr: bool, field_name: [...@@ -2996,7 +2998,7 @@ fn airSliceField(f: *Function, inst: Air.Inst.Index, is_ptr: bool, field_name: [
29962998
2997 if (f.liveness.isUnused(inst)) {2999 if (f.liveness.isUnused(inst)) {
2998 try reap(f, inst, &.{ty_op.operand});3000 try reap(f, inst, &.{ty_op.operand});
2999 return CValue.none;3001 return .none;
3000 }3002 }
30013003
3002 const inst_ty = f.air.typeOfIndex(inst);3004 const inst_ty = f.air.typeOfIndex(inst);
...@@ -3022,7 +3024,7 @@ fn airPtrElemVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3022,7 +3024,7 @@ fn airPtrElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
3022 !inst_ty.hasRuntimeBitsIgnoreComptime())3024 !inst_ty.hasRuntimeBitsIgnoreComptime())
3023 {3025 {
3024 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });3026 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
3025 return CValue.none;3027 return .none;
3026 }3028 }
30273029
3028 const ptr = try f.resolveInst(bin_op.lhs);3030 const ptr = try f.resolveInst(bin_op.lhs);
...@@ -3048,7 +3050,7 @@ fn airPtrElemVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3048,7 +3050,7 @@ fn airPtrElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
3048 try writer.writeByte(']');3050 try writer.writeByte(']');
3049 if (is_array) {3051 if (is_array) {
3050 try writer.writeAll(", sizeof(");3052 try writer.writeAll(", sizeof(");
3051 try f.renderTypecast(writer, inst_ty);3053 try f.renderType(writer, inst_ty);
3052 try writer.writeAll("))");3054 try writer.writeAll("))");
3053 }3055 }
3054 try writer.writeAll(";\n");3056 try writer.writeAll(";\n");
...@@ -3061,7 +3063,7 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3061,7 +3063,7 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
30613063
3062 if (f.liveness.isUnused(inst)) {3064 if (f.liveness.isUnused(inst)) {
3063 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });3065 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
3064 return CValue.none;3066 return .none;
3065 }3067 }
30663068
3067 const inst_ty = f.air.typeOfIndex(inst);3069 const inst_ty = f.air.typeOfIndex(inst);
...@@ -3080,7 +3082,7 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3080,7 +3082,7 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
3080 const local = try f.allocLocal(inst, f.air.typeOfIndex(inst));3082 const local = try f.allocLocal(inst, f.air.typeOfIndex(inst));
3081 try f.writeCValue(writer, local, .Other);3083 try f.writeCValue(writer, local, .Other);
3082 try writer.writeAll(" = (");3084 try writer.writeAll(" = (");
3083 try f.renderTypecast(writer, inst_ty);3085 try f.renderType(writer, inst_ty);
3084 try writer.writeAll(")&(");3086 try writer.writeAll(")&(");
3085 if (ptr_ty.ptrSize() == .One) {3087 if (ptr_ty.ptrSize() == .One) {
3086 // It's a pointer to an array, so we need to de-reference.3088 // 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 {...@@ -3102,7 +3104,7 @@ fn airSliceElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
3102 !inst_ty.hasRuntimeBitsIgnoreComptime())3104 !inst_ty.hasRuntimeBitsIgnoreComptime())
3103 {3105 {
3104 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });3106 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
3105 return CValue.none;3107 return .none;
3106 }3108 }
31073109
3108 const slice = try f.resolveInst(bin_op.lhs);3110 const slice = try f.resolveInst(bin_op.lhs);
...@@ -3128,7 +3130,7 @@ fn airSliceElemVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3128,7 +3130,7 @@ fn airSliceElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
3128 try writer.writeByte(']');3130 try writer.writeByte(']');
3129 if (is_array) {3131 if (is_array) {
3130 try writer.writeAll(", sizeof(");3132 try writer.writeAll(", sizeof(");
3131 try f.renderTypecast(writer, inst_ty);3133 try f.renderType(writer, inst_ty);
3132 try writer.writeAll("))");3134 try writer.writeAll("))");
3133 }3135 }
3134 try writer.writeAll(";\n");3136 try writer.writeAll(";\n");
...@@ -3141,7 +3143,7 @@ fn airSliceElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3141,7 +3143,7 @@ fn airSliceElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
31413143
3142 if (f.liveness.isUnused(inst)) {3144 if (f.liveness.isUnused(inst)) {
3143 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });3145 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
3144 return CValue.none;3146 return .none;
3145 }3147 }
31463148
3147 const slice_ty = f.air.typeOf(bin_op.lhs);3149 const slice_ty = f.air.typeOf(bin_op.lhs);
...@@ -3171,7 +3173,7 @@ fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3171,7 +3173,7 @@ fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
3171 const inst_ty = f.air.typeOfIndex(inst);3173 const inst_ty = f.air.typeOfIndex(inst);
3172 if (f.liveness.isUnused(inst) or !inst_ty.hasRuntimeBitsIgnoreComptime()) {3174 if (f.liveness.isUnused(inst) or !inst_ty.hasRuntimeBitsIgnoreComptime()) {
3173 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });3175 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
3174 return CValue.none;3176 return .none;
3175 }3177 }
31763178
3177 const array = try f.resolveInst(bin_op.lhs);3179 const array = try f.resolveInst(bin_op.lhs);
...@@ -3197,7 +3199,7 @@ fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3197,7 +3199,7 @@ fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
3197 try writer.writeByte(']');3199 try writer.writeByte(']');
3198 if (is_array) {3200 if (is_array) {
3199 try writer.writeAll(", sizeof(");3201 try writer.writeAll(", sizeof(");
3200 try f.renderTypecast(writer, inst_ty);3202 try f.renderType(writer, inst_ty);
3201 try writer.writeAll("))");3203 try writer.writeAll("))");
3202 }3204 }
3203 try writer.writeAll(";\n");3205 try writer.writeAll(";\n");
...@@ -3209,16 +3211,19 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3209,16 +3211,19 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue {
32093211
3210 const elem_type = inst_ty.elemType();3212 const elem_type = inst_ty.elemType();
3211 if (!elem_type.isFnOrHasRuntimeBitsIgnoreComptime()) {3213 if (!elem_type.isFnOrHasRuntimeBitsIgnoreComptime()) {
3212 return CValue{ .undef = inst_ty };3214 return .{ .undef = inst_ty };
3213 }3215 }
32143216
3215 const mutability: Mutability = if (inst_ty.isConstPtr()) .@"const" else .mut;
3216 const target = f.object.dg.module.getTarget();3217 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 );
3218 log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.new_local });3223 log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.new_local });
3219 const gpa = f.object.dg.module.gpa;3224 const gpa = f.object.dg.module.gpa;
3220 try f.allocs.put(gpa, local.new_local, false);3225 try f.allocs.put(gpa, local.new_local, false);
3221 return CValue{ .local_ref = local.new_local };3226 return .{ .local_ref = local.new_local };
3222}3227}
32233228
3224fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue {3229fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue {
...@@ -3226,25 +3231,28 @@ fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3226,25 +3231,28 @@ fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue {
32263231
3227 const elem_ty = inst_ty.elemType();3232 const elem_ty = inst_ty.elemType();
3228 if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime()) {3233 if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime()) {
3229 return CValue{ .undef = inst_ty };3234 return .{ .undef = inst_ty };
3230 }3235 }
32313236
3232 const mutability: Mutability = if (inst_ty.isConstPtr()) .@"const" else .mut;
3233 const target = f.object.dg.module.getTarget();3237 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 );
3235 log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.new_local });3243 log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.new_local });
3236 const gpa = f.object.dg.module.gpa;3244 const gpa = f.object.dg.module.gpa;
3237 try f.allocs.put(gpa, local.new_local, false);3245 try f.allocs.put(gpa, local.new_local, false);
3238 return CValue{ .local_ref = local.new_local };3246 return .{ .local_ref = local.new_local };
3239}3247}
32403248
3241fn airArg(f: *Function, inst: Air.Inst.Index) !CValue {3249fn airArg(f: *Function, inst: Air.Inst.Index) !CValue {
3242 const inst_ty = f.air.typeOfIndex(inst);3250 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
3245 const i = f.next_arg_index;3253 const i = f.next_arg_index;
3246 f.next_arg_index += 1;3254 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))
3248 .{ .arg_array = i }3256 .{ .arg_array = i }
3249 else3257 else
3250 .{ .arg = i };3258 .{ .arg = i };
...@@ -3259,7 +3267,7 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3259,7 +3267,7 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
3259 (!ptr_info.@"volatile" and f.liveness.isUnused(inst)))3267 (!ptr_info.@"volatile" and f.liveness.isUnused(inst)))
3260 {3268 {
3261 try reap(f, inst, &.{ty_op.operand});3269 try reap(f, inst, &.{ty_op.operand});
3262 return CValue.none;3270 return .none;
3263 }3271 }
32643272
3265 const operand = try f.resolveInst(ty_op.operand);3273 const operand = try f.resolveInst(ty_op.operand);
...@@ -3281,7 +3289,7 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3281,7 +3289,7 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
3281 try writer.writeAll(", (const char *)");3289 try writer.writeAll(", (const char *)");
3282 try f.writeCValue(writer, operand, .Other);3290 try f.writeCValue(writer, operand, .Other);
3283 try writer.writeAll(", sizeof(");3291 try writer.writeAll(", sizeof(");
3284 try f.renderTypecast(writer, src_ty);3292 try f.renderType(writer, src_ty);
3285 try writer.writeAll("))");3293 try writer.writeAll("))");
3286 } else if (ptr_info.host_size != 0) {3294 } else if (ptr_info.host_size != 0) {
3287 var host_pl = Type.Payload.Bits{3295 var host_pl = Type.Payload.Bits{
...@@ -3310,11 +3318,11 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3310,11 +3318,11 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
33103318
3311 try f.writeCValue(writer, local, .Other);3319 try f.writeCValue(writer, local, .Other);
3312 try writer.writeAll(" = (");3320 try writer.writeAll(" = (");
3313 try f.renderTypecast(writer, src_ty);3321 try f.renderType(writer, src_ty);
3314 try writer.writeAll(")zig_wrap_");3322 try writer.writeAll(")zig_wrap_");
3315 try f.object.dg.renderTypeForBuiltinFnName(writer, field_ty);3323 try f.object.dg.renderTypeForBuiltinFnName(writer, field_ty);
3316 try writer.writeAll("((");3324 try writer.writeAll("((");
3317 try f.renderTypecast(writer, field_ty);3325 try f.renderType(writer, field_ty);
3318 try writer.writeByte(')');3326 try writer.writeByte(')');
3319 const cant_cast = host_ty.isInt() and host_ty.bitSize(target) > 64;3327 const cant_cast = host_ty.isInt() and host_ty.bitSize(target) > 64;
3320 if (cant_cast) {3328 if (cant_cast) {
...@@ -3344,15 +3352,19 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue {...@@ -3344,15 +3352,19 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue {
3344 const un_op = f.air.instructions.items(.data)[inst].un_op;3352 const un_op = f.air.instructions.items(.data)[inst].un_op;
3345 const writer = f.object.writer();3353 const writer = f.object.writer();
3346 const target = f.object.dg.module.getTarget();3354 const target = f.object.dg.module.getTarget();
3355 const op_inst = Air.refToIndex(un_op);
3347 const op_ty = f.air.typeOf(un_op);3356 const op_ty = f.air.typeOf(un_op);
3348 const ret_ty = if (is_ptr) op_ty.childType() else op_ty;3357 const ret_ty = if (is_ptr) op_ty.childType() else op_ty;
3349 var lowered_ret_buf: LowerFnRetTyBuffer = undefined;3358 var lowered_ret_buf: LowerFnRetTyBuffer = undefined;
3350 const lowered_ret_ty = lowerFnRetTy(ret_ty, &lowered_ret_buf, target);3359 const lowered_ret_ty = lowerFnRetTy(ret_ty, &lowered_ret_buf, target);
33513360
3352 if (lowered_ret_ty.hasRuntimeBitsIgnoreComptime()) {3361 if (op_inst != null and f.air.instructions.items(.tag)[op_inst.?] == .call_always_tail) {
3353 var deref = is_ptr;3362 try reap(f, inst, &.{un_op});
3363 _ = try airCall(f, op_inst.?, .always_tail);
3364 } else if (lowered_ret_ty.hasRuntimeBitsIgnoreComptime()) {
3354 const operand = try f.resolveInst(un_op);3365 const operand = try f.resolveInst(un_op);
3355 try reap(f, inst, &.{un_op});3366 try reap(f, inst, &.{un_op});
3367 var deref = is_ptr;
3356 const is_array = lowersToArray(ret_ty, target);3368 const is_array = lowersToArray(ret_ty, target);
3357 const ret_val = if (is_array) ret_val: {3369 const ret_val = if (is_array) ret_val: {
3358 const array_local = try f.allocLocal(inst, try lowered_ret_ty.copy(f.arena.allocator()));3370 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 {...@@ -3365,7 +3377,7 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue {
3365 try f.writeCValue(writer, operand, .FunctionArgument);3377 try f.writeCValue(writer, operand, .FunctionArgument);
3366 deref = false;3378 deref = false;
3367 try writer.writeAll(", sizeof(");3379 try writer.writeAll(", sizeof(");
3368 try f.renderTypecast(writer, ret_ty);3380 try f.renderType(writer, ret_ty);
3369 try writer.writeAll("));\n");3381 try writer.writeAll("));\n");
3370 break :ret_val array_local;3382 break :ret_val array_local;
3371 } else operand;3383 } else operand;
...@@ -3381,11 +3393,11 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue {...@@ -3381,11 +3393,11 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue {
3381 }3393 }
3382 } else {3394 } else {
3383 try reap(f, inst, &.{un_op});3395 try reap(f, inst, &.{un_op});
3384 if (f.object.dg.decl) |decl| if (decl.ty.fnCallingConvention() != .Naked)3396 // Not even allowed to return void in a naked function.
3385 // Not even allowed to return void in a naked function.3397 if (if (f.object.dg.decl) |decl| decl.ty.fnCallingConvention() != .Naked else true)
3386 try writer.writeAll("return;\n");3398 try writer.writeAll("return;\n");
3387 }3399 }
3388 return CValue.none;3400 return .none;
3389}3401}
33903402
3391fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue {3403fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue {
...@@ -3393,7 +3405,7 @@ fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3393,7 +3405,7 @@ fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue {
33933405
3394 if (f.liveness.isUnused(inst)) {3406 if (f.liveness.isUnused(inst)) {
3395 try reap(f, inst, &.{ty_op.operand});3407 try reap(f, inst, &.{ty_op.operand});
3396 return CValue.none;3408 return .none;
3397 }3409 }
33983410
3399 const operand = try f.resolveInst(ty_op.operand);3411 const operand = try f.resolveInst(ty_op.operand);
...@@ -3414,7 +3426,7 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3414,7 +3426,7 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {
3414 const ty_op = f.air.instructions.items(.data)[inst].ty_op;3426 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
3415 if (f.liveness.isUnused(inst)) {3427 if (f.liveness.isUnused(inst)) {
3416 try reap(f, inst, &.{ty_op.operand});3428 try reap(f, inst, &.{ty_op.operand});
3417 return CValue.none;3429 return .none;
3418 }3430 }
34193431
3420 const operand = try f.resolveInst(ty_op.operand);3432 const operand = try f.resolveInst(ty_op.operand);
...@@ -3433,15 +3445,17 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3433,15 +3445,17 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {
3433 try f.writeCValue(writer, local, .Other);3445 try f.writeCValue(writer, local, .Other);
3434 try writer.writeAll(" = ");3446 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
3436 const needs_lo = operand_int_info.bits > 64 and dest_bits <= 64;3454 const needs_lo = operand_int_info.bits > 64 and dest_bits <= 64;
3437 if (needs_lo) {3455 if (needs_lo) {
3438 try writer.writeAll("zig_lo_");3456 try writer.writeAll("zig_lo_");
3439 try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty);3457 try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty);
3440 try writer.writeByte('(');3458 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(')');
3445 }3459 }
34463460
3447 if (dest_bits >= 8 and std.math.isPowerOfTwo(dest_bits)) {3461 if (dest_bits >= 8 and std.math.isPowerOfTwo(dest_bits)) {
...@@ -3501,7 +3515,7 @@ fn airBoolToInt(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3501,7 +3515,7 @@ fn airBoolToInt(f: *Function, inst: Air.Inst.Index) !CValue {
3501 const un_op = f.air.instructions.items(.data)[inst].un_op;3515 const un_op = f.air.instructions.items(.data)[inst].un_op;
3502 if (f.liveness.isUnused(inst)) {3516 if (f.liveness.isUnused(inst)) {
3503 try reap(f, inst, &.{un_op});3517 try reap(f, inst, &.{un_op});
3504 return CValue.none;3518 return .none;
3505 }3519 }
3506 const operand = try f.resolveInst(un_op);3520 const operand = try f.resolveInst(un_op);
3507 try reap(f, inst, &.{un_op});3521 try reap(f, inst, &.{un_op});
...@@ -3521,10 +3535,10 @@ fn storeUndefined(f: *Function, lhs_child_ty: Type, dest_ptr: CValue) !CValue {...@@ -3521,10 +3535,10 @@ fn storeUndefined(f: *Function, lhs_child_ty: Type, dest_ptr: CValue) !CValue {
3521 try writer.writeAll("memset(");3535 try writer.writeAll("memset(");
3522 try f.writeCValue(writer, dest_ptr, .FunctionArgument);3536 try f.writeCValue(writer, dest_ptr, .FunctionArgument);
3523 try writer.print(", {x}, sizeof(", .{try f.fmtIntLiteral(Type.u8, Value.undef)});3537 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);
3525 try writer.writeAll("));\n");3539 try writer.writeAll("));\n");
3526 }3540 }
3527 return CValue.none;3541 return .none;
3528}3542}
35293543
3530fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {3544fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {
...@@ -3533,7 +3547,7 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3533,7 +3547,7 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {
3533 const ptr_info = f.air.typeOf(bin_op.lhs).ptrInfo().data;3547 const ptr_info = f.air.typeOf(bin_op.lhs).ptrInfo().data;
3534 if (!ptr_info.pointee_type.hasRuntimeBitsIgnoreComptime()) {3548 if (!ptr_info.pointee_type.hasRuntimeBitsIgnoreComptime()) {
3535 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });3549 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
3536 return CValue.none;3550 return .none;
3537 }3551 }
35383552
3539 const ptr_val = try f.resolveInst(bin_op.lhs);3553 const ptr_val = try f.resolveInst(bin_op.lhs);
...@@ -3582,7 +3596,7 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3582,7 +3596,7 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {
3582 if (!is_array) try writer.writeByte('&');3596 if (!is_array) try writer.writeByte('&');
3583 try f.writeCValue(writer, array_src, .FunctionArgument);3597 try f.writeCValue(writer, array_src, .FunctionArgument);
3584 try writer.writeAll(", sizeof(");3598 try writer.writeAll(", sizeof(");
3585 try f.renderTypecast(writer, src_ty);3599 try f.renderType(writer, src_ty);
3586 try writer.writeAll("))");3600 try writer.writeAll("))");
3587 if (src_val == .constant) {3601 if (src_val == .constant) {
3588 try freeLocal(f, inst, array_src.new_local, 0);3602 try freeLocal(f, inst, array_src.new_local, 0);
...@@ -3641,13 +3655,13 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3641,13 +3655,13 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {
3641 try writer.writeAll("(0, ");3655 try writer.writeAll("(0, ");
3642 } else {3656 } else {
3643 try writer.writeByte('(');3657 try writer.writeByte('(');
3644 try f.renderTypecast(writer, host_ty);3658 try f.renderType(writer, host_ty);
3645 try writer.writeByte(')');3659 try writer.writeByte(')');
3646 }3660 }
36473661
3648 if (src_ty.isPtrAtRuntime()) {3662 if (src_ty.isPtrAtRuntime()) {
3649 try writer.writeByte('(');3663 try writer.writeByte('(');
3650 try f.renderTypecast(writer, Type.usize);3664 try f.renderType(writer, Type.usize);
3651 try writer.writeByte(')');3665 try writer.writeByte(')');
3652 }3666 }
3653 try f.writeCValue(writer, src_val, .Other);3667 try f.writeCValue(writer, src_val, .Other);
...@@ -3659,7 +3673,7 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3659,7 +3673,7 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {
3659 try f.writeCValue(writer, src_val, .Other);3673 try f.writeCValue(writer, src_val, .Other);
3660 }3674 }
3661 try writer.writeAll(";\n");3675 try writer.writeAll(";\n");
3662 return CValue.none;3676 return .none;
3663}3677}
36643678
3665fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info: BuiltinInfo) !CValue {3679fn 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:...@@ -3668,7 +3682,7 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info:
36683682
3669 if (f.liveness.isUnused(inst)) {3683 if (f.liveness.isUnused(inst)) {
3670 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });3684 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
3671 return CValue.none;3685 return .none;
3672 }3686 }
36733687
3674 const lhs = try f.resolveInst(bin_op.lhs);3688 const lhs = try f.resolveInst(bin_op.lhs);
...@@ -3724,7 +3738,7 @@ fn airNot(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3724,7 +3738,7 @@ fn airNot(f: *Function, inst: Air.Inst.Index) !CValue {
37243738
3725 if (f.liveness.isUnused(inst)) {3739 if (f.liveness.isUnused(inst)) {
3726 try reap(f, inst, &.{ty_op.operand});3740 try reap(f, inst, &.{ty_op.operand});
3727 return CValue.none;3741 return .none;
3728 }3742 }
37293743
3730 const op = try f.resolveInst(ty_op.operand);3744 const op = try f.resolveInst(ty_op.operand);
...@@ -3759,7 +3773,7 @@ fn airBinOp(...@@ -3759,7 +3773,7 @@ fn airBinOp(
37593773
3760 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });3774 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
3764 const inst_ty = f.air.typeOfIndex(inst);3778 const inst_ty = f.air.typeOfIndex(inst);
37653779
...@@ -3782,7 +3796,7 @@ fn airCmpOp(f: *Function, inst: Air.Inst.Index, operator: []const u8, operation:...@@ -3782,7 +3796,7 @@ fn airCmpOp(f: *Function, inst: Air.Inst.Index, operator: []const u8, operation:
37823796
3783 if (f.liveness.isUnused(inst)) {3797 if (f.liveness.isUnused(inst)) {
3784 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });3798 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
3785 return CValue.none;3799 return .none;
3786 }3800 }
37873801
3788 const operand_ty = f.air.typeOf(bin_op.lhs);3802 const operand_ty = f.air.typeOf(bin_op.lhs);
...@@ -3822,7 +3836,7 @@ fn airEquality(...@@ -3822,7 +3836,7 @@ fn airEquality(
38223836
3823 if (f.liveness.isUnused(inst)) {3837 if (f.liveness.isUnused(inst)) {
3824 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });3838 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
3825 return CValue.none;3839 return .none;
3826 }3840 }
38273841
3828 const operand_ty = f.air.typeOf(bin_op.lhs);3842 const operand_ty = f.air.typeOf(bin_op.lhs);
...@@ -3878,7 +3892,7 @@ fn airCmpLtErrorsLen(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3878,7 +3892,7 @@ fn airCmpLtErrorsLen(f: *Function, inst: Air.Inst.Index) !CValue {
38783892
3879 if (f.liveness.isUnused(inst)) {3893 if (f.liveness.isUnused(inst)) {
3880 try reap(f, inst, &.{un_op});3894 try reap(f, inst, &.{un_op});
3881 return CValue.none;3895 return .none;
3882 }3896 }
38833897
3884 const inst_ty = f.air.typeOfIndex(inst);3898 const inst_ty = f.air.typeOfIndex(inst);
...@@ -3899,7 +3913,7 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue {...@@ -3899,7 +3913,7 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue {
3899 const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data;3913 const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data;
3900 if (f.liveness.isUnused(inst)) {3914 if (f.liveness.isUnused(inst)) {
3901 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });3915 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
3902 return CValue.none;3916 return .none;
3903 }3917 }
39043918
3905 const lhs = try f.resolveInst(bin_op.lhs);3919 const lhs = try f.resolveInst(bin_op.lhs);
...@@ -3919,7 +3933,7 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue {...@@ -3919,7 +3933,7 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue {
3919 // results in a NULL pointer, or if LHS is NULL. The operation is only UB3933 // results in a NULL pointer, or if LHS is NULL. The operation is only UB
3920 // if the result is NULL and then dereferenced.3934 // if the result is NULL and then dereferenced.
3921 try writer.writeByte('(');3935 try writer.writeByte('(');
3922 try f.renderTypecast(writer, inst_ty);3936 try f.renderType(writer, inst_ty);
3923 try writer.writeAll(")(((uintptr_t)");3937 try writer.writeAll(")(((uintptr_t)");
3924 try f.writeCValue(writer, lhs, .Other);3938 try f.writeCValue(writer, lhs, .Other);
3925 try writer.writeAll(") ");3939 try writer.writeAll(") ");
...@@ -3927,7 +3941,7 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue {...@@ -3927,7 +3941,7 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue {
3927 try writer.writeAll(" (");3941 try writer.writeAll(" (");
3928 try f.writeCValue(writer, rhs, .Other);3942 try f.writeCValue(writer, rhs, .Other);
3929 try writer.writeAll("*sizeof(");3943 try writer.writeAll("*sizeof(");
3930 try f.renderTypecast(writer, elem_ty);3944 try f.renderType(writer, elem_ty);
3931 try writer.writeAll(")))");3945 try writer.writeAll(")))");
3932 } else try f.writeCValue(writer, lhs, .Initializer);3946 } else try f.writeCValue(writer, lhs, .Initializer);
39333947
...@@ -3940,7 +3954,7 @@ fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: u8, operation: []cons...@@ -3940,7 +3954,7 @@ fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: u8, operation: []cons
39403954
3941 if (f.liveness.isUnused(inst)) {3955 if (f.liveness.isUnused(inst)) {
3942 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });3956 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
3943 return CValue.none;3957 return .none;
3944 }3958 }
39453959
3946 const inst_ty = f.air.typeOfIndex(inst);3960 const inst_ty = f.air.typeOfIndex(inst);
...@@ -3979,7 +3993,7 @@ fn airSlice(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3979,7 +3993,7 @@ fn airSlice(f: *Function, inst: Air.Inst.Index) !CValue {
39793993
3980 if (f.liveness.isUnused(inst)) {3994 if (f.liveness.isUnused(inst)) {
3981 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });3995 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
3982 return CValue.none;3996 return .none;
3983 }3997 }
39843998
3985 const ptr = try f.resolveInst(bin_op.lhs);3999 const ptr = try f.resolveInst(bin_op.lhs);
...@@ -3992,7 +4006,7 @@ fn airSlice(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3992,7 +4006,7 @@ fn airSlice(f: *Function, inst: Air.Inst.Index) !CValue {
3992 try f.writeCValue(writer, local, .Other);4006 try f.writeCValue(writer, local, .Other);
3993 try writer.writeAll(".ptr = (");4007 try writer.writeAll(".ptr = (");
3994 var buf: Type.SlicePtrFieldTypeBuffer = undefined;4008 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
3995 try f.renderTypecast(writer, inst_ty.slicePtrFieldType(&buf));4009 try f.renderType(writer, inst_ty.slicePtrFieldType(&buf));
3996 try writer.writeByte(')');4010 try writer.writeByte(')');
3997 try f.writeCValue(writer, ptr, .Other);4011 try f.writeCValue(writer, ptr, .Other);
3998 try writer.writeAll("; ");4012 try writer.writeAll("; ");
...@@ -4017,13 +4031,6 @@ fn airCall(...@@ -4017,13 +4031,6 @@ fn airCall(
4017 const target = module.getTarget();4031 const target = module.getTarget();
4018 const writer = f.object.writer();4032 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 }
4027 const pl_op = f.air.instructions.items(.data)[inst].pl_op;4034 const pl_op = f.air.instructions.items(.data)[inst].pl_op;
4028 const extra = f.air.extraData(Air.Call, pl_op.payload);4035 const extra = f.air.extraData(Air.Call, pl_op.payload);
4029 const args = @ptrCast([]const Air.Inst.Ref, f.air.extra[extra.end..][0..extra.data.args_len]);4036 const args = @ptrCast([]const Air.Inst.Ref, f.air.extra[extra.end..][0..extra.data.args_len]);
...@@ -4032,13 +4039,13 @@ fn airCall(...@@ -4032,13 +4039,13 @@ fn airCall(
4032 defer gpa.free(resolved_args);4039 defer gpa.free(resolved_args);
4033 for (resolved_args, args) |*resolved_arg, arg| {4040 for (resolved_args, args) |*resolved_arg, arg| {
4034 const arg_ty = f.air.typeOf(arg);4041 const arg_ty = f.air.typeOf(arg);
4035 const arg_cty = try f.object.dg.typeToIndex(arg_ty, .parameter);4042 const arg_cty = try f.typeToIndex(arg_ty, .parameter);
4036 if (f.object.dg.indexToCType(arg_cty).tag() == .void) {4043 if (f.indexToCType(arg_cty).tag() == .void) {
4037 resolved_arg.* = .none;4044 resolved_arg.* = .none;
4038 continue;4045 continue;
4039 }4046 }
4040 resolved_arg.* = try f.resolveInst(arg);4047 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)) {
4042 var lowered_arg_buf: LowerFnRetTyBuffer = undefined;4049 var lowered_arg_buf: LowerFnRetTyBuffer = undefined;
4043 const lowered_arg_ty = lowerFnRetTy(arg_ty, &lowered_arg_buf, target);4050 const lowered_arg_ty = lowerFnRetTy(arg_ty, &lowered_arg_buf, target);
40444051
...@@ -4048,7 +4055,7 @@ fn airCall(...@@ -4048,7 +4055,7 @@ fn airCall(
4048 try writer.writeAll(", ");4055 try writer.writeAll(", ");
4049 try f.writeCValue(writer, resolved_arg.*, .FunctionArgument);4056 try f.writeCValue(writer, resolved_arg.*, .FunctionArgument);
4050 try writer.writeAll(", sizeof(");4057 try writer.writeAll(", sizeof(");
4051 try f.renderTypecast(writer, lowered_arg_ty);4058 try f.renderType(writer, lowered_arg_ty);
4052 try writer.writeAll("));\n");4059 try writer.writeAll("));\n");
4053 resolved_arg.* = array_local;4060 resolved_arg.* = array_local;
4054 }4061 }
...@@ -4073,11 +4080,14 @@ fn airCall(...@@ -4073,11 +4080,14 @@ fn airCall(
4073 var lowered_ret_buf: LowerFnRetTyBuffer = undefined;4080 var lowered_ret_buf: LowerFnRetTyBuffer = undefined;
4074 const lowered_ret_ty = lowerFnRetTy(ret_ty, &lowered_ret_buf, target);4081 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())
4077 .none4087 .none
4078 else if (f.liveness.isUnused(inst)) r: {4088 else if (f.liveness.isUnused(inst)) r: {
4079 try writer.writeByte('(');4089 try writer.writeByte('(');
4080 try f.renderTypecast(writer, Type.void);4090 try f.renderType(writer, Type.void);
4081 try writer.writeByte(')');4091 try writer.writeByte(')');
4082 break :r .none;4092 break :r .none;
4083 } else r: {4093 } else r: {
...@@ -4087,26 +4097,33 @@ fn airCall(...@@ -4087,26 +4097,33 @@ fn airCall(
4087 break :r local;4097 break :r local;
4088 };4098 };
40894099
4090 var is_extern = false;
4091 var name: [*:0]const u8 = "";
4092 callee: {4100 callee: {
4093 known: {4101 known: {
4094 const fn_decl = fn_decl: {4102 const fn_decl = fn_decl: {
4095 const callee_val = f.air.value(pl_op.operand) orelse break :known;4103 const callee_val = f.air.value(pl_op.operand) orelse break :known;
4096 break :fn_decl switch (callee_val.tag()) {4104 break :fn_decl switch (callee_val.tag()) {
4097 .extern_fn => blk: {4105 .extern_fn => callee_val.castTag(.extern_fn).?.data.owner_decl,
4098 is_extern = true;
4099 break :blk callee_val.castTag(.extern_fn).?.data.owner_decl;
4100 },
4101 .function => callee_val.castTag(.function).?.data.owner_decl,4106 .function => callee_val.castTag(.function).?.data.owner_decl,
4102 .decl_ref => callee_val.castTag(.decl_ref).?.data,4107 .decl_ref => callee_val.castTag(.decl_ref).?.data,
4103 else => break :known,4108 else => break :known,
4104 };4109 };
4105 };4110 };
4106 name = module.declPtr(fn_decl).name;4111 switch (modifier) {
4107 try f.object.dg.renderDeclName(writer, fn_decl, 0);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 }
4108 break :callee;4119 break :callee;
4109 }4120 }
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 }
4110 // Fall back to function pointer call.4127 // Fall back to function pointer call.
4111 try f.writeCValue(writer, callee, .Other);4128 try f.writeCValue(writer, callee, .Other);
4112 }4129 }
...@@ -4132,7 +4149,7 @@ fn airCall(...@@ -4132,7 +4149,7 @@ fn airCall(
4132 try writer.writeAll(", ");4149 try writer.writeAll(", ");
4133 try f.writeCValueMember(writer, result_local, .{ .identifier = "array" });4150 try f.writeCValueMember(writer, result_local, .{ .identifier = "array" });
4134 try writer.writeAll(", sizeof(");4151 try writer.writeAll(", sizeof(");
4135 try f.renderTypecast(writer, ret_ty);4152 try f.renderType(writer, ret_ty);
4136 try writer.writeAll("));\n");4153 try writer.writeAll("));\n");
4137 try freeLocal(f, inst, result_local.new_local, 0);4154 try freeLocal(f, inst, result_local.new_local, 0);
4138 break :r array_local;4155 break :r array_local;
...@@ -4153,7 +4170,7 @@ fn airDbgStmt(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4153,7 +4170,7 @@ fn airDbgStmt(f: *Function, inst: Air.Inst.Index) !CValue {
4153 // Perhaps an additional compilation option is in order?4170 // Perhaps an additional compilation option is in order?
4154 //try writer.print("#line {d}\n", .{dbg_stmt.line + 1});4171 //try writer.print("#line {d}\n", .{dbg_stmt.line + 1});
4155 try writer.print("/* file:{d}:{d} */\n", .{ dbg_stmt.line + 1, dbg_stmt.column + 1 });4172 try writer.print("/* file:{d}:{d} */\n", .{ dbg_stmt.line + 1, dbg_stmt.column + 1 });
4156 return CValue.none;4173 return .none;
4157}4174}
41584175
4159fn airDbgInline(f: *Function, inst: Air.Inst.Index) !CValue {4176fn airDbgInline(f: *Function, inst: Air.Inst.Index) !CValue {
...@@ -4162,7 +4179,7 @@ fn airDbgInline(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4162,7 +4179,7 @@ fn airDbgInline(f: *Function, inst: Air.Inst.Index) !CValue {
4162 const function = f.air.values[ty_pl.payload].castTag(.function).?.data;4179 const function = f.air.values[ty_pl.payload].castTag(.function).?.data;
4163 const mod = f.object.dg.module;4180 const mod = f.object.dg.module;
4164 try writer.print("/* dbg func:{s} */\n", .{mod.declPtr(function.owner_decl).name});4181 try writer.print("/* dbg func:{s} */\n", .{mod.declPtr(function.owner_decl).name});
4165 return CValue.none;4182 return .none;
4166}4183}
41674184
4168fn airDbgVar(f: *Function, inst: Air.Inst.Index) !CValue {4185fn airDbgVar(f: *Function, inst: Air.Inst.Index) !CValue {
...@@ -4174,7 +4191,7 @@ fn airDbgVar(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4174,7 +4191,7 @@ fn airDbgVar(f: *Function, inst: Air.Inst.Index) !CValue {
4174 try reap(f, inst, &.{pl_op.operand});4191 try reap(f, inst, &.{pl_op.operand});
4175 const writer = f.object.writer();4192 const writer = f.object.writer();
4176 try writer.print("/* var:{s} */\n", .{name});4193 try writer.print("/* var:{s} */\n", .{name});
4177 return CValue.none;4194 return .none;
4178}4195}
41794196
4180fn airBlock(f: *Function, inst: Air.Inst.Index) !CValue {4197fn airBlock(f: *Function, inst: Air.Inst.Index) !CValue {
...@@ -4190,7 +4207,7 @@ fn airBlock(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4190,7 +4207,7 @@ fn airBlock(f: *Function, inst: Air.Inst.Index) !CValue {
4190 const result = if (inst_ty.tag() != .void and !f.liveness.isUnused(inst))4207 const result = if (inst_ty.tag() != .void and !f.liveness.isUnused(inst))
4191 try f.allocLocal(inst, inst_ty)4208 try f.allocLocal(inst, inst_ty)
4192 else4209 else
4193 CValue{ .none = {} };4210 .none;
41944211
4195 try f.blocks.putNoClobber(f.object.dg.gpa, inst, .{4212 try f.blocks.putNoClobber(f.object.dg.gpa, inst, .{
4196 .block_id = block_id,4213 .block_id = block_id,
...@@ -4199,8 +4216,9 @@ fn airBlock(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4199,8 +4216,9 @@ fn airBlock(f: *Function, inst: Air.Inst.Index) !CValue {
41994216
4200 try genBodyInner(f, body);4217 try genBodyInner(f, body);
4201 try f.object.indent_writer.insertNewline();4218 try f.object.indent_writer.insertNewline();
4219 // label might be unused, add a dummy goto
4202 // label must be followed by an expression, add an empty one.4220 // 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 });
4204 return result;4222 return result;
4205}4223}
42064224
...@@ -4259,7 +4277,7 @@ fn lowerTry(...@@ -4259,7 +4277,7 @@ fn lowerTry(
42594277
4260 if (!payload_has_bits) {4278 if (!payload_has_bits) {
4261 if (!operand_is_ptr) {4279 if (!operand_is_ptr) {
4262 return CValue.none;4280 return .none;
4263 } else {4281 } else {
4264 return err_union;4282 return err_union;
4265 }4283 }
...@@ -4268,7 +4286,7 @@ fn lowerTry(...@@ -4268,7 +4286,7 @@ fn lowerTry(
4268 try reap(f, inst, &.{operand});4286 try reap(f, inst, &.{operand});
42694287
4270 if (f.liveness.isUnused(inst)) {4288 if (f.liveness.isUnused(inst)) {
4271 return CValue.none;4289 return .none;
4272 }4290 }
42734291
4274 const target = f.object.dg.module.getTarget();4292 const target = f.object.dg.module.getTarget();
...@@ -4280,7 +4298,7 @@ fn lowerTry(...@@ -4280,7 +4298,7 @@ fn lowerTry(
4280 try writer.writeAll(", ");4298 try writer.writeAll(", ");
4281 try f.writeCValueMember(writer, err_union, .{ .identifier = "payload" });4299 try f.writeCValueMember(writer, err_union, .{ .identifier = "payload" });
4282 try writer.writeAll(", sizeof(");4300 try writer.writeAll(", sizeof(");
4283 try f.renderTypecast(writer, payload_ty);4301 try f.renderType(writer, payload_ty);
4284 try writer.writeAll("));\n");4302 try writer.writeAll("));\n");
4285 } else {4303 } else {
4286 try f.writeCValue(writer, local, .Other);4304 try f.writeCValue(writer, local, .Other);
...@@ -4313,7 +4331,7 @@ fn airBr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4313,7 +4331,7 @@ fn airBr(f: *Function, inst: Air.Inst.Index) !CValue {
4313 try writer.writeAll(", ");4331 try writer.writeAll(", ");
4314 try f.writeCValue(writer, operand, .FunctionArgument);4332 try f.writeCValue(writer, operand, .FunctionArgument);
4315 try writer.writeAll(", sizeof(");4333 try writer.writeAll(", sizeof(");
4316 try f.renderTypecast(writer, operand_ty);4334 try f.renderType(writer, operand_ty);
4317 try writer.writeAll("))");4335 try writer.writeAll("))");
4318 } else {4336 } else {
4319 try f.writeCValue(writer, result, .Other);4337 try f.writeCValue(writer, result, .Other);
...@@ -4324,7 +4342,7 @@ fn airBr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4324,7 +4342,7 @@ fn airBr(f: *Function, inst: Air.Inst.Index) !CValue {
4324 }4342 }
43254343
4326 try writer.print("goto zig_block_{d};\n", .{block.block_id});4344 try writer.print("goto zig_block_{d};\n", .{block.block_id});
4327 return CValue.none;4345 return .none;
4328}4346}
43294347
4330fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {4348fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {
...@@ -4334,7 +4352,7 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4334,7 +4352,7 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {
4334 // https://github.com/ziglang/zig/issues/134104352 // https://github.com/ziglang/zig/issues/13410
4335 if (f.liveness.isUnused(inst) or !dest_ty.hasRuntimeBits()) {4353 if (f.liveness.isUnused(inst) or !dest_ty.hasRuntimeBits()) {
4336 try reap(f, inst, &.{ty_op.operand});4354 try reap(f, inst, &.{ty_op.operand});
4337 return CValue.none;4355 return .none;
4338 }4356 }
43394357
4340 const operand = try f.resolveInst(ty_op.operand);4358 const operand = try f.resolveInst(ty_op.operand);
...@@ -4362,7 +4380,7 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4362,7 +4380,7 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {
4362 if (dest_ty.isPtrAtRuntime() and operand_ty.isPtrAtRuntime()) {4380 if (dest_ty.isPtrAtRuntime() and operand_ty.isPtrAtRuntime()) {
4363 try f.writeCValue(writer, local, .Other);4381 try f.writeCValue(writer, local, .Other);
4364 try writer.writeAll(" = (");4382 try writer.writeAll(" = (");
4365 try f.renderTypecast(writer, dest_ty);4383 try f.renderType(writer, dest_ty);
4366 try writer.writeByte(')');4384 try writer.writeByte(')');
4367 try f.writeCValue(writer, operand, .Other);4385 try f.writeCValue(writer, operand, .Other);
4368 try writer.writeAll(";\n");4386 try writer.writeAll(";\n");
...@@ -4383,7 +4401,7 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4383,7 +4401,7 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {
4383 try writer.writeAll(", &");4401 try writer.writeAll(", &");
4384 try f.writeCValue(writer, operand_lval, .Other);4402 try f.writeCValue(writer, operand_lval, .Other);
4385 try writer.writeAll(", sizeof(");4403 try writer.writeAll(", sizeof(");
4386 try f.renderTypecast(writer, dest_ty);4404 try f.renderType(writer, dest_ty);
4387 try writer.writeAll("));\n");4405 try writer.writeAll("));\n");
43884406
4389 // Ensure padding bits have the expected value.4407 // Ensure padding bits have the expected value.
...@@ -4406,27 +4424,27 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4406,27 +4424,27 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {
44064424
4407fn airBreakpoint(writer: anytype) !CValue {4425fn airBreakpoint(writer: anytype) !CValue {
4408 try writer.writeAll("zig_breakpoint();\n");4426 try writer.writeAll("zig_breakpoint();\n");
4409 return CValue.none;4427 return .none;
4410}4428}
44114429
4412fn airRetAddr(f: *Function, inst: Air.Inst.Index) !CValue {4430fn 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;
4414 const writer = f.object.writer();4432 const writer = f.object.writer();
4415 const local = try f.allocLocal(inst, Type.usize);4433 const local = try f.allocLocal(inst, Type.usize);
4416 try f.writeCValue(writer, local, .Other);4434 try f.writeCValue(writer, local, .Other);
4417 try writer.writeAll(" = (");4435 try writer.writeAll(" = (");
4418 try f.renderTypecast(writer, Type.usize);4436 try f.renderType(writer, Type.usize);
4419 try writer.writeAll(")zig_return_address();\n");4437 try writer.writeAll(")zig_return_address();\n");
4420 return local;4438 return local;
4421}4439}
44224440
4423fn airFrameAddress(f: *Function, inst: Air.Inst.Index) !CValue {4441fn 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;
4425 const writer = f.object.writer();4443 const writer = f.object.writer();
4426 const local = try f.allocLocal(inst, Type.usize);4444 const local = try f.allocLocal(inst, Type.usize);
4427 try f.writeCValue(writer, local, .Other);4445 try f.writeCValue(writer, local, .Other);
4428 try writer.writeAll(" = (");4446 try writer.writeAll(" = (");
4429 try f.renderTypecast(writer, Type.usize);4447 try f.renderType(writer, Type.usize);
4430 try writer.writeAll(")zig_frame_address();\n");4448 try writer.writeAll(")zig_frame_address();\n");
4431 return local;4449 return local;
4432}4450}
...@@ -4439,7 +4457,7 @@ fn airFence(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4439,7 +4457,7 @@ fn airFence(f: *Function, inst: Air.Inst.Index) !CValue {
4439 try writeMemoryOrder(writer, atomic_order);4457 try writeMemoryOrder(writer, atomic_order);
4440 try writer.writeAll(");\n");4458 try writer.writeAll(");\n");
44414459
4442 return CValue.none;4460 return .none;
4443}4461}
44444462
4445fn airUnreach(f: *Function) !CValue {4463fn airUnreach(f: *Function) !CValue {
...@@ -4447,7 +4465,7 @@ fn airUnreach(f: *Function) !CValue {...@@ -4447,7 +4465,7 @@ fn airUnreach(f: *Function) !CValue {
4447 if (f.object.dg.decl) |decl| if (decl.ty.fnCallingConvention() == .Naked) return .none;4465 if (f.object.dg.decl) |decl| if (decl.ty.fnCallingConvention() == .Naked) return .none;
44484466
4449 try f.object.writer().writeAll("zig_unreachable();\n");4467 try f.object.writer().writeAll("zig_unreachable();\n");
4450 return CValue.none;4468 return .none;
4451}4469}
44524470
4453fn airLoop(f: *Function, inst: Air.Inst.Index) !CValue {4471fn airLoop(f: *Function, inst: Air.Inst.Index) !CValue {
...@@ -4479,7 +4497,7 @@ fn airLoop(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4479,7 +4497,7 @@ fn airLoop(f: *Function, inst: Air.Inst.Index) !CValue {
4479 deinitFreeLocalsMap(gpa, new_free_locals);4497 deinitFreeLocalsMap(gpa, new_free_locals);
4480 new_free_locals.* = old_free_locals.move();4498 new_free_locals.* = old_free_locals.move();
44814499
4482 return CValue.none;4500 return .none;
4483}4501}
44844502
4485fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue {4503fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue {
...@@ -4544,7 +4562,7 @@ fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4544,7 +4562,7 @@ fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue {
45444562
4545 try f.object.indent_writer.insertNewline();4563 try f.object.indent_writer.insertNewline();
45464564
4547 return CValue.none;4565 return .none;
4548}4566}
45494567
4550fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {4568fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {
...@@ -4558,11 +4576,11 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4558,11 +4576,11 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {
4558 try writer.writeAll("switch (");4576 try writer.writeAll("switch (");
4559 if (condition_ty.zigTypeTag() == .Bool) {4577 if (condition_ty.zigTypeTag() == .Bool) {
4560 try writer.writeByte('(');4578 try writer.writeByte('(');
4561 try f.renderTypecast(writer, Type.u1);4579 try f.renderType(writer, Type.u1);
4562 try writer.writeByte(')');4580 try writer.writeByte(')');
4563 } else if (condition_ty.isPtrAtRuntime()) {4581 } else if (condition_ty.isPtrAtRuntime()) {
4564 try writer.writeByte('(');4582 try writer.writeByte('(');
4565 try f.renderTypecast(writer, Type.usize);4583 try f.renderType(writer, Type.usize);
4566 try writer.writeByte(')');4584 try writer.writeByte(')');
4567 }4585 }
4568 try f.writeCValue(writer, condition, .Other);4586 try f.writeCValue(writer, condition, .Other);
...@@ -4579,8 +4597,7 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4579,8 +4597,7 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {
4579 const last_case_i = switch_br.data.cases_len - @boolToInt(switch_br.data.else_body_len == 0);4597 const last_case_i = switch_br.data.cases_len - @boolToInt(switch_br.data.else_body_len == 0);
45804598
4581 var extra_index: usize = switch_br.end;4599 var extra_index: usize = switch_br.end;
4582 var case_i: u32 = 0;4600 for (0..switch_br.data.cases_len) |case_i| {
4583 while (case_i < switch_br.data.cases_len) : (case_i += 1) {
4584 const case = f.air.extraData(Air.SwitchBr.Case, extra_index);4601 const case = f.air.extraData(Air.SwitchBr.Case, extra_index);
4585 const items = @ptrCast([]const Air.Inst.Ref, f.air.extra[case.end..][0..case.data.items_len]);4602 const items = @ptrCast([]const Air.Inst.Ref, f.air.extra[case.end..][0..case.data.items_len]);
4586 const case_body = f.air.extra[case.end + items.len ..][0..case.data.body_len];4603 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 {...@@ -4591,7 +4608,7 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {
4591 try writer.writeAll("case ");4608 try writer.writeAll("case ");
4592 if (condition_ty.isPtrAtRuntime()) {4609 if (condition_ty.isPtrAtRuntime()) {
4593 try writer.writeByte('(');4610 try writer.writeByte('(');
4594 try f.renderTypecast(writer, Type.usize);4611 try f.renderType(writer, Type.usize);
4595 try writer.writeByte(')');4612 try writer.writeByte(')');
4596 }4613 }
4597 try f.object.dg.renderValue(writer, condition_ty, f.air.value(item).?, .Other);4614 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 {...@@ -4657,7 +4674,7 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {
46574674
4658 f.object.indent_writer.popIndent();4675 f.object.indent_writer.popIndent();
4659 try writer.writeAll("}\n");4676 try writer.writeAll("}\n");
4660 return CValue.none;4677 return .none;
4661}4678}
46624679
4663fn asmInputNeedsLocal(constraint: []const u8, value: CValue) bool {4680fn asmInputNeedsLocal(constraint: []const u8, value: CValue) bool {
...@@ -4679,8 +4696,8 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4679,8 +4696,8 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
4679 const inputs = @ptrCast([]const Air.Inst.Ref, f.air.extra[extra_i..][0..extra.data.inputs_len]);4696 const inputs = @ptrCast([]const Air.Inst.Ref, f.air.extra[extra_i..][0..extra.data.inputs_len]);
4680 extra_i += inputs.len;4697 extra_i += inputs.len;
46814698
4682 const result: CValue = r: {4699 const result = r: {
4683 if (!is_volatile and f.liveness.isUnused(inst)) break :r CValue.none;4700 if (!is_volatile and f.liveness.isUnused(inst)) break :r .none;
46844701
4685 const writer = f.object.writer();4702 const writer = f.object.writer();
4686 const inst_ty = f.air.typeOfIndex(inst);4703 const inst_ty = f.air.typeOfIndex(inst);
...@@ -4717,14 +4734,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4717,14 +4734,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
4717 try writer.writeAll("register ");4734 try writer.writeAll("register ");
4718 const alignment = 0;4735 const alignment = 0;
4719 const local_value = try f.allocLocalValue(output_ty, alignment);4736 const local_value = try f.allocLocalValue(output_ty, alignment);
4720 try f.object.dg.renderTypeAndName(4737 try f.object.dg.renderTypeAndName(writer, output_ty, local_value, .{}, alignment, .complete);
4721 writer,
4722 output_ty,
4723 local_value,
4724 .mut,
4725 alignment,
4726 .Complete,
4727 );
4728 try writer.writeAll(" __asm(\"");4738 try writer.writeAll(" __asm(\"");
4729 try writer.writeAll(constraint["={".len .. constraint.len - "}".len]);4739 try writer.writeAll(constraint["={".len .. constraint.len - "}".len]);
4730 try writer.writeAll("\")");4740 try writer.writeAll("\")");
...@@ -4756,14 +4766,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4756,14 +4766,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
4756 if (is_reg) try writer.writeAll("register ");4766 if (is_reg) try writer.writeAll("register ");
4757 const alignment = 0;4767 const alignment = 0;
4758 const local_value = try f.allocLocalValue(input_ty, alignment);4768 const local_value = try f.allocLocalValue(input_ty, alignment);
4759 try f.object.dg.renderTypeAndName(4769 try f.object.dg.renderTypeAndName(writer, input_ty, local_value, Const, alignment, .complete);
4760 writer,
4761 input_ty,
4762 local_value,
4763 .@"const",
4764 alignment,
4765 .Complete,
4766 );
4767 if (is_reg) {4770 if (is_reg) {
4768 try writer.writeAll(" __asm(\"");4771 try writer.writeAll(" __asm(\"");
4769 try writer.writeAll(constraint["{".len .. constraint.len - "}".len]);4772 try writer.writeAll(constraint["{".len .. constraint.len - "}".len]);
...@@ -4774,14 +4777,11 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4774,14 +4777,11 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
4774 try writer.writeAll(";\n");4777 try writer.writeAll(";\n");
4775 }4778 }
4776 }4779 }
4777 {4780 for (0..clobbers_len) |_| {
4778 var clobber_i: u32 = 0;4781 const clobber = std.mem.sliceTo(std.mem.sliceAsBytes(f.air.extra[extra_i..]), 0);
4779 while (clobber_i < clobbers_len) : (clobber_i += 1) {4782 // This equation accounts for the fact that even if we have exactly 4 bytes
4780 const clobber = std.mem.sliceTo(std.mem.sliceAsBytes(f.air.extra[extra_i..]), 0);4783 // for the string, we still use the next u32 for the null terminator.
4781 // This equation accounts for the fact that even if we have exactly 4 bytes4784 extra_i += clobber.len / 4 + 1;
4782 // for the string, we still use the next u32 for the null terminator.
4783 extra_i += clobber.len / 4 + 1;
4784 }
4785 }4785 }
47864786
4787 {4787 {
...@@ -4836,7 +4836,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4836,7 +4836,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
48364836
4837 try writer.writeAll("__asm");4837 try writer.writeAll("__asm");
4838 if (is_volatile) try writer.writeAll(" volatile");4838 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)});
4840 }4840 }
48414841
4842 extra_i = constraints_extra_begin;4842 extra_i = constraints_extra_begin;
...@@ -4854,7 +4854,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4854,7 +4854,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
4854 try writer.writeByte(' ');4854 try writer.writeByte(' ');
4855 if (!std.mem.eql(u8, name, "_")) try writer.print("[{s}]", .{name});4855 if (!std.mem.eql(u8, name, "_")) try writer.print("[{s}]", .{name});
4856 const is_reg = constraint[1] == '{';4856 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)});
4858 if (is_reg) {4858 if (is_reg) {
4859 try f.writeCValue(writer, .{ .local = locals_index }, .Other);4859 try f.writeCValue(writer, .{ .local = locals_index }, .Other);
4860 locals_index += 1;4860 locals_index += 1;
...@@ -4880,28 +4880,25 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4880,28 +4880,25 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
48804880
4881 const is_reg = constraint[0] == '{';4881 const is_reg = constraint[0] == '{';
4882 const input_val = try f.resolveInst(input);4882 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)});
4884 try f.writeCValue(writer, if (asmInputNeedsLocal(constraint, input_val)) local: {4884 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 };
4886 locals_index += 1;4886 locals_index += 1;
4887 break :local input_local;4887 break :local input_local;
4888 } else input_val, .Other);4888 } else input_val, .Other);
4889 try writer.writeByte(')');4889 try writer.writeByte(')');
4890 }4890 }
4891 try writer.writeByte(':');4891 try writer.writeByte(':');
4892 {4892 for (0..clobbers_len) |clobber_i| {
4893 var clobber_i: u32 = 0;4893 const clobber = std.mem.sliceTo(std.mem.sliceAsBytes(f.air.extra[extra_i..]), 0);
4894 while (clobber_i < clobbers_len) : (clobber_i += 1) {4894 // This equation accounts for the fact that even if we have exactly 4 bytes
4895 const clobber = std.mem.sliceTo(std.mem.sliceAsBytes(f.air.extra[extra_i..]), 0);4895 // for the string, we still use the next u32 for the null terminator.
4896 // This equation accounts for the fact that even if we have exactly 4 bytes4896 extra_i += clobber.len / 4 + 1;
4897 // for the string, we still use the next u32 for the null terminator.
4898 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(',');4900 if (clobber_i > 0) try writer.writeByte(',');
4903 try writer.print(" {s}", .{fmtStringLiteral(clobber)});4901 try writer.print(" {s}", .{fmtStringLiteral(clobber, null)});
4904 }
4905 }4902 }
4906 try writer.writeAll(");\n");4903 try writer.writeAll(");\n");
49074904
...@@ -4918,7 +4915,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4918,7 +4915,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
4918 const is_reg = constraint[1] == '{';4915 const is_reg = constraint[1] == '{';
4919 if (is_reg) {4916 if (is_reg) {
4920 try f.writeCValueDeref(writer, if (output == .none)4917 try f.writeCValueDeref(writer, if (output == .none)
4921 CValue{ .local_ref = local.new_local }4918 .{ .local_ref = local.new_local }
4922 else4919 else
4923 try f.resolveInst(output));4920 try f.resolveInst(output));
4924 try writer.writeAll(" = ");4921 try writer.writeAll(" = ");
...@@ -4953,7 +4950,7 @@ fn airIsNull(...@@ -4953,7 +4950,7 @@ fn airIsNull(
49534950
4954 if (f.liveness.isUnused(inst)) {4951 if (f.liveness.isUnused(inst)) {
4955 try reap(f, inst, &.{un_op});4952 try reap(f, inst, &.{un_op});
4956 return CValue.none;4953 return .none;
4957 }4954 }
49584955
4959 const writer = f.object.writer();4956 const writer = f.object.writer();
...@@ -5003,7 +5000,7 @@ fn airOptionalPayload(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5003,7 +5000,7 @@ fn airOptionalPayload(f: *Function, inst: Air.Inst.Index) !CValue {
50035000
5004 if (f.liveness.isUnused(inst)) {5001 if (f.liveness.isUnused(inst)) {
5005 try reap(f, inst, &.{ty_op.operand});5002 try reap(f, inst, &.{ty_op.operand});
5006 return CValue.none;5003 return .none;
5007 }5004 }
50085005
5009 const operand = try f.resolveInst(ty_op.operand);5006 const operand = try f.resolveInst(ty_op.operand);
...@@ -5014,7 +5011,7 @@ fn airOptionalPayload(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5014,7 +5011,7 @@ fn airOptionalPayload(f: *Function, inst: Air.Inst.Index) !CValue {
5014 const payload_ty = opt_ty.optionalChild(&buf);5011 const payload_ty = opt_ty.optionalChild(&buf);
50155012
5016 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {5013 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
5017 return CValue.none;5014 return .none;
5018 }5015 }
50195016
5020 const inst_ty = f.air.typeOfIndex(inst);5017 const inst_ty = f.air.typeOfIndex(inst);
...@@ -5043,7 +5040,7 @@ fn airOptionalPayload(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5043,7 +5040,7 @@ fn airOptionalPayload(f: *Function, inst: Air.Inst.Index) !CValue {
5043 try f.writeCValueMember(writer, operand, .{ .identifier = "payload" });5040 try f.writeCValueMember(writer, operand, .{ .identifier = "payload" });
5044 if (is_array) {5041 if (is_array) {
5045 try writer.writeAll(", sizeof(");5042 try writer.writeAll(", sizeof(");
5046 try f.renderTypecast(writer, inst_ty);5043 try f.renderType(writer, inst_ty);
5047 try writer.writeAll("))");5044 try writer.writeAll("))");
5048 }5045 }
5049 try writer.writeAll(";\n");5046 try writer.writeAll(";\n");
...@@ -5055,7 +5052,7 @@ fn airOptionalPayloadPtr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5055,7 +5052,7 @@ fn airOptionalPayloadPtr(f: *Function, inst: Air.Inst.Index) !CValue {
50555052
5056 if (f.liveness.isUnused(inst)) {5053 if (f.liveness.isUnused(inst)) {
5057 try reap(f, inst, &.{ty_op.operand});5054 try reap(f, inst, &.{ty_op.operand});
5058 return CValue.none;5055 return .none;
5059 }5056 }
50605057
5061 const writer = f.object.writer();5058 const writer = f.object.writer();
...@@ -5066,7 +5063,7 @@ fn airOptionalPayloadPtr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5066,7 +5063,7 @@ fn airOptionalPayloadPtr(f: *Function, inst: Air.Inst.Index) !CValue {
5066 const inst_ty = f.air.typeOfIndex(inst);5063 const inst_ty = f.air.typeOfIndex(inst);
50675064
5068 if (!inst_ty.childType().hasRuntimeBitsIgnoreComptime()) {5065 if (!inst_ty.childType().hasRuntimeBitsIgnoreComptime()) {
5069 return CValue{ .undef = inst_ty };5066 return .{ .undef = inst_ty };
5070 }5067 }
50715068
5072 const local = try f.allocLocal(inst, inst_ty);5069 const local = try f.allocLocal(inst, inst_ty);
...@@ -5098,7 +5095,7 @@ fn airOptionalPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5098,7 +5095,7 @@ fn airOptionalPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
50985095
5099 if (opt_ty.optionalReprIsPayload()) {5096 if (opt_ty.optionalReprIsPayload()) {
5100 if (f.liveness.isUnused(inst)) {5097 if (f.liveness.isUnused(inst)) {
5101 return CValue.none;5098 return .none;
5102 }5099 }
5103 const local = try f.allocLocal(inst, inst_ty);5100 const local = try f.allocLocal(inst, inst_ty);
5104 // The payload and the optional are the same value.5101 // The payload and the optional are the same value.
...@@ -5115,7 +5112,7 @@ fn airOptionalPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5115,7 +5112,7 @@ fn airOptionalPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
5115 try writer.writeAll(";\n");5112 try writer.writeAll(";\n");
51165113
5117 if (f.liveness.isUnused(inst)) {5114 if (f.liveness.isUnused(inst)) {
5118 return CValue.none;5115 return .none;
5119 }5116 }
51205117
5121 const local = try f.allocLocal(inst, inst_ty);5118 const local = try f.allocLocal(inst, inst_ty);
...@@ -5127,6 +5124,62 @@ fn airOptionalPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5127,6 +5124,62 @@ fn airOptionalPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
5127 }5124 }
5128}5125}
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
5130fn airStructFieldPtr(f: *Function, inst: Air.Inst.Index) !CValue {5183fn airStructFieldPtr(f: *Function, inst: Air.Inst.Index) !CValue {
5131 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;5184 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
5132 const extra = f.air.extraData(Air.StructField, ty_pl.payload).data;5185 const extra = f.air.extraData(Air.StructField, ty_pl.payload).data;
...@@ -5136,10 +5189,10 @@ fn airStructFieldPtr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5136,10 +5189,10 @@ fn airStructFieldPtr(f: *Function, inst: Air.Inst.Index) !CValue {
5136 return .none;5189 return .none;
5137 }5190 }
51385191
5139 const struct_ptr = try f.resolveInst(extra.struct_operand);5192 const container_ptr_val = try f.resolveInst(extra.struct_operand);
5140 try reap(f, inst, &.{extra.struct_operand});5193 try reap(f, inst, &.{extra.struct_operand});
5141 const struct_ptr_ty = f.air.typeOf(extra.struct_operand);5194 const container_ptr_ty = f.air.typeOf(extra.struct_operand);
5142 return structFieldPtr(f, inst, struct_ptr_ty, struct_ptr, extra.field_index);5195 return fieldPtr(f, inst, container_ptr_ty, container_ptr_val, extra.field_index);
5143}5196}
51445197
5145fn airStructFieldPtrIndex(f: *Function, inst: Air.Inst.Index, index: u8) !CValue {5198fn 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...@@ -5150,10 +5203,10 @@ fn airStructFieldPtrIndex(f: *Function, inst: Air.Inst.Index, index: u8) !CValue
5150 return .none;5203 return .none;
5151 }5204 }
51525205
5153 const struct_ptr = try f.resolveInst(ty_op.operand);5206 const container_ptr_val = try f.resolveInst(ty_op.operand);
5154 try reap(f, inst, &.{ty_op.operand});5207 try reap(f, inst, &.{ty_op.operand});
5155 const struct_ptr_ty = f.air.typeOf(ty_op.operand);5208 const container_ptr_ty = f.air.typeOf(ty_op.operand);
5156 return structFieldPtr(f, inst, struct_ptr_ty, struct_ptr, index);5209 return fieldPtr(f, inst, container_ptr_ty, container_ptr_val, index);
5157}5210}
51585211
5159fn airFieldParentPtr(f: *Function, inst: Air.Inst.Index) !CValue {5212fn airFieldParentPtr(f: *Function, inst: Air.Inst.Index) !CValue {
...@@ -5162,133 +5215,119 @@ fn airFieldParentPtr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5162,133 +5215,119 @@ fn airFieldParentPtr(f: *Function, inst: Air.Inst.Index) !CValue {
51625215
5163 if (f.liveness.isUnused(inst)) {5216 if (f.liveness.isUnused(inst)) {
5164 try reap(f, inst, &.{extra.field_ptr});5217 try reap(f, inst, &.{extra.field_ptr});
5165 return CValue.none;5218 return .none;
5166 }5219 }
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
5170 const field_ptr_ty = f.air.typeOf(extra.field_ptr);5225 const field_ptr_ty = f.air.typeOf(extra.field_ptr);
5171 const field_ptr_val = try f.resolveInst(extra.field_ptr);5226 const field_ptr_val = try f.resolveInst(extra.field_ptr);
5172 try reap(f, inst, &.{extra.field_ptr});5227 try reap(f, inst, &.{extra.field_ptr});
51735228
5174 const target = f.object.dg.module.getTarget();5229 const writer = f.object.writer();
5175 const struct_ty = struct_ptr_ty.childType();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) {5236 switch (fieldLocation(container_ty, field_ptr_ty, extra.field_index, target)) {
5178 return f.fail("TODO: CBE: @fieldParentPtr for unions", .{});5237 .begin => try f.writeCValue(writer, field_ptr_val, .Initializer),
5179 }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{5258 var byte_offset_pl = Value.Payload.U64{
5184 .base = .{ .tag = .int_i64 },5259 .base = .{ .tag = .int_u64 },
5185 .data = -@intCast(i64, field_offset),5260 .data = byte_offset,
5186 };5261 };
5187 const field_offset_val = Value.initPayload(&field_offset_pl.base);5262 const byte_offset_val = Value.initPayload(&byte_offset_pl.base);
51885263
5189 var u8_ptr_pl = field_ptr_ty.ptrInfo();5264 try writer.writeAll("((");
5190 u8_ptr_pl.data.pointee_type = Type.u8;5265 try f.renderType(writer, u8_ptr_ty);
5191 const u8_ptr_ty = Type.initPayload(&u8_ptr_pl.base);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();5276 try writer.writeAll(";\n");
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)});
5203 return local;5277 return local;
5204}5278}
52055279
5206fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struct_ptr: CValue, index: u32) !CValue {5280fn fieldPtr(
5207 const writer = f.object.writer();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();
5208 const field_ptr_ty = f.air.typeOfIndex(inst);5289 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
5213 // Ensure complete type definition is visible before accessing fields.5291 // 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();
5216 const local = try f.allocLocal(inst, field_ptr_ty);5295 const local = try f.allocLocal(inst, field_ptr_ty);
5217 try f.writeCValue(writer, local, .Other);5296 try f.writeCValue(writer, local, .Other);
5218 try writer.writeAll(" = (");5297 try writer.writeAll(" = (");
5219 try f.renderTypecast(writer, field_ptr_ty);5298 try f.renderType(writer, field_ptr_ty);
5220 try writer.writeByte(')');5299 try writer.writeByte(')');
52215300
5222 const extra_name: CValue = switch (struct_ty.tag()) {5301 switch (fieldLocation(container_ty, field_ptr_ty, field_index, target)) {
5223 .union_tagged, .union_safety_tagged => .{ .identifier = "payload" },5302 .begin => try f.writeCValue(writer, container_ptr_val, .Initializer),
5224 else => .none,5303 .field => |field| {
5225 };5304 try writer.writeByte('&');
52265305 try f.writeCValueDerefMember(writer, container_ptr_val, field);
5227 const field_loc: union(enum) {5306 },
5228 begin: void,5307 .byte_offset => |byte_offset| {
5229 field: CValue,5308 var u8_ptr_pl = field_ptr_ty.ptrInfo();
5230 end: void,5309 u8_ptr_pl.data.pointee_type = Type.u8;
5231 } = switch (struct_ty.tag()) {5310 const u8_ptr_ty = Type.initPayload(&u8_ptr_pl.base);
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);
52545311
5255 if (!std.mem.isAligned(byte_offset, field_ptr_ty.ptrAlignment(target))) {5312 var byte_offset_pl = Value.Payload.U64{
5256 return f.fail("TODO: CBE: unaligned packed struct field pointer", .{});5313 .base = .{ .tag = .int_u64 },
5257 }5314 .data = byte_offset,
5315 };
5316 const byte_offset_val = Value.initPayload(&byte_offset_pl.base);
52585317
5259 try writer.writeAll("&((");5318 try writer.writeAll("((");
5260 try f.renderTypecast(writer, u8_ptr_ty);5319 try f.renderType(writer, u8_ptr_ty);
5261 try writer.writeByte(')');5320 try writer.writeByte(')');
5262 try f.writeCValue(writer, struct_ptr, .Other);5321 try f.writeCValue(writer, container_ptr_val, .Other);
5263 try writer.print(")[{}];\n", .{try f.fmtIntLiteral(Type.usize, byte_offset_val)});5322 try writer.print(" + {})", .{try f.fmtIntLiteral(Type.usize, byte_offset_val)});
5264 return local;
5265 } else .begin,
5266 },5323 },
5267 .@"union", .union_safety_tagged, .union_tagged => if (struct_ty.containerLayout() == .Packed) {5324 .end => {
5268 try f.writeCValue(writer, struct_ptr, .Other);5325 try writer.writeByte('(');
5269 try writer.writeAll(";\n");5326 try f.writeCValue(writer, container_ptr_val, .Other);
5270 return local;5327 try writer.print(" + {})", .{try f.fmtIntLiteral(Type.usize, Value.one)});
5271 } else if (field_ty.hasRuntimeBitsIgnoreComptime()) .{ .field = .{5328 },
5272 .identifier = struct_ty.unionFields().keys()[index],5329 }
5273 } } else .end,
5274 else => unreachable,
5275 };
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);
5292 try writer.writeAll(";\n");5331 try writer.writeAll(";\n");
5293 return local;5332 return local;
5294}5333}
...@@ -5299,13 +5338,13 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5299,13 +5338,13 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
52995338
5300 if (f.liveness.isUnused(inst)) {5339 if (f.liveness.isUnused(inst)) {
5301 try reap(f, inst, &.{extra.struct_operand});5340 try reap(f, inst, &.{extra.struct_operand});
5302 return CValue.none;5341 return .none;
5303 }5342 }
53045343
5305 const inst_ty = f.air.typeOfIndex(inst);5344 const inst_ty = f.air.typeOfIndex(inst);
5306 if (!inst_ty.hasRuntimeBitsIgnoreComptime()) {5345 if (!inst_ty.hasRuntimeBitsIgnoreComptime()) {
5307 try reap(f, inst, &.{extra.struct_operand});5346 try reap(f, inst, &.{extra.struct_operand});
5308 return CValue.none;5347 return .none;
5309 }5348 }
53105349
5311 const target = f.object.dg.module.getTarget();5350 const target = f.object.dg.module.getTarget();
...@@ -5315,12 +5354,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5315,12 +5354,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
5315 const writer = f.object.writer();5354 const writer = f.object.writer();
53165355
5317 // Ensure complete type definition is visible before accessing fields.5356 // Ensure complete type definition is visible before accessing fields.
5318 try f.renderType(std.io.null_writer, struct_ty);5357 _ = try f.typeToIndex(struct_ty, .complete);
5319
5320 const extra_name: CValue = switch (struct_ty.tag()) {
5321 .union_tagged, .union_safety_tagged => .{ .identifier = "payload" },
5322 else => .none,
5323 };
53245358
5325 const field_name: CValue = switch (struct_ty.tag()) {5359 const field_name: CValue = switch (struct_ty.tag()) {
5326 .tuple, .anon_struct, .@"struct" => switch (struct_ty.containerLayout()) {5360 .tuple, .anon_struct, .@"struct" => switch (struct_ty.containerLayout()) {
...@@ -5362,7 +5396,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5362,7 +5396,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
5362 try writer.writeAll(" = zig_wrap_");5396 try writer.writeAll(" = zig_wrap_");
5363 try f.object.dg.renderTypeForBuiltinFnName(writer, field_int_ty);5397 try f.object.dg.renderTypeForBuiltinFnName(writer, field_int_ty);
5364 try writer.writeAll("((");5398 try writer.writeAll("((");
5365 try f.renderTypecast(writer, field_int_ty);5399 try f.renderType(writer, field_int_ty);
5366 try writer.writeByte(')');5400 try writer.writeByte(')');
5367 const cant_cast = int_info.bits > 64;5401 const cant_cast = int_info.bits > 64;
5368 if (cant_cast) {5402 if (cant_cast) {
...@@ -5389,7 +5423,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5389,7 +5423,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
5389 try writer.writeAll(", ");5423 try writer.writeAll(", ");
5390 try f.writeCValue(writer, .{ .local_ref = temp_local.new_local }, .FunctionArgument);5424 try f.writeCValue(writer, .{ .local_ref = temp_local.new_local }, .FunctionArgument);
5391 try writer.writeAll(", sizeof(");5425 try writer.writeAll(", sizeof(");
5392 try f.renderTypecast(writer, inst_ty);5426 try f.renderType(writer, inst_ty);
5393 try writer.writeAll("));\n");5427 try writer.writeAll("));\n");
5394 try freeLocal(f, inst, temp_local.new_local, 0);5428 try freeLocal(f, inst, temp_local.new_local, 0);
5395 return local;5429 return local;
...@@ -5411,7 +5445,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5411,7 +5445,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
5411 try writer.writeAll(", &");5445 try writer.writeAll(", &");
5412 try f.writeCValue(writer, operand_lval, .FunctionArgument);5446 try f.writeCValue(writer, operand_lval, .FunctionArgument);
5413 try writer.writeAll(", sizeof(");5447 try writer.writeAll(", sizeof(");
5414 try f.renderTypecast(writer, inst_ty);5448 try f.renderType(writer, inst_ty);
5415 try writer.writeAll("));\n");5449 try writer.writeAll("));\n");
54165450
5417 if (struct_byval == .constant) {5451 if (struct_byval == .constant) {
...@@ -5419,31 +5453,29 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5419,31 +5453,29 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
5419 }5453 }
54205454
5421 return local;5455 return local;
5422 } else .{5456 } else field_name: {
5423 .identifier = struct_ty.unionFields().keys()[extra.field_index],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 };
5424 },5462 },
5425 else => unreachable,5463 else => unreachable,
5426 };5464 };
54275465
5428 const is_array = lowersToArray(inst_ty, target);
5429 const local = try f.allocLocal(inst, inst_ty);5466 const local = try f.allocLocal(inst, inst_ty);
5430 if (is_array) {5467 if (lowersToArray(inst_ty, target)) {
5431 try writer.writeAll("memcpy(");5468 try writer.writeAll("memcpy(");
5432 try f.writeCValue(writer, local, .FunctionArgument);5469 try f.writeCValue(writer, local, .FunctionArgument);
5433 try writer.writeAll(", ");5470 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("))");
5434 } else {5475 } else {
5435 try f.writeCValue(writer, local, .Other);5476 try f.writeCValue(writer, local, .Other);
5436 try writer.writeAll(" = ");5477 try writer.writeAll(" = ");
5437 }5478 try f.writeCValueMember(writer, struct_byval, field_name);
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("))");
5447 }5479 }
5448 try writer.writeAll(";\n");5480 try writer.writeAll(";\n");
5449 return local;5481 return local;
...@@ -5456,7 +5488,7 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5456,7 +5488,7 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
54565488
5457 if (f.liveness.isUnused(inst)) {5489 if (f.liveness.isUnused(inst)) {
5458 try reap(f, inst, &.{ty_op.operand});5490 try reap(f, inst, &.{ty_op.operand});
5459 return CValue.none;5491 return .none;
5460 }5492 }
54615493
5462 const inst_ty = f.air.typeOfIndex(inst);5494 const inst_ty = f.air.typeOfIndex(inst);
...@@ -5493,7 +5525,7 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValu...@@ -5493,7 +5525,7 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValu
54935525
5494 if (f.liveness.isUnused(inst)) {5526 if (f.liveness.isUnused(inst)) {
5495 try reap(f, inst, &.{ty_op.operand});5527 try reap(f, inst, &.{ty_op.operand});
5496 return CValue.none;5528 return .none;
5497 }5529 }
54985530
5499 const inst_ty = f.air.typeOfIndex(inst);5531 const inst_ty = f.air.typeOfIndex(inst);
...@@ -5504,13 +5536,13 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValu...@@ -5504,13 +5536,13 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValu
5504 const error_union_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty;5536 const error_union_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty;
55055537
5506 if (!error_union_ty.errorUnionPayload().hasRuntimeBits()) {5538 if (!error_union_ty.errorUnionPayload().hasRuntimeBits()) {
5507 if (!is_ptr) return CValue.none;5539 if (!is_ptr) return .none;
55085540
5509 const w = f.object.writer();5541 const w = f.object.writer();
5510 const local = try f.allocLocal(inst, inst_ty);5542 const local = try f.allocLocal(inst, inst_ty);
5511 try f.writeCValue(w, local, .Other);5543 try f.writeCValue(w, local, .Other);
5512 try w.writeAll(" = (");5544 try w.writeAll(" = (");
5513 try f.renderTypecast(w, inst_ty);5545 try f.renderType(w, inst_ty);
5514 try w.writeByte(')');5546 try w.writeByte(')');
5515 try f.writeCValue(w, operand, .Initializer);5547 try f.writeCValue(w, operand, .Initializer);
5516 try w.writeAll(";\n");5548 try w.writeAll(";\n");
...@@ -5535,7 +5567,7 @@ fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5535,7 +5567,7 @@ fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue {
55355567
5536 if (f.liveness.isUnused(inst)) {5568 if (f.liveness.isUnused(inst)) {
5537 try reap(f, inst, &.{ty_op.operand});5569 try reap(f, inst, &.{ty_op.operand});
5538 return CValue.none;5570 return .none;
5539 }5571 }
55405572
5541 const inst_ty = f.air.typeOfIndex(inst);5573 const inst_ty = f.air.typeOfIndex(inst);
...@@ -5571,7 +5603,7 @@ fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5571,7 +5603,7 @@ fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue {
5571 try writer.writeAll(", ");5603 try writer.writeAll(", ");
5572 try f.writeCValue(writer, payload, .FunctionArgument);5604 try f.writeCValue(writer, payload, .FunctionArgument);
5573 try writer.writeAll(", sizeof(");5605 try writer.writeAll(", sizeof(");
5574 try f.renderTypecast(writer, payload_ty);5606 try f.renderType(writer, payload_ty);
5575 try writer.writeAll("));\n");5607 try writer.writeAll("));\n");
5576 }5608 }
5577 return local;5609 return local;
...@@ -5581,7 +5613,7 @@ fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5581,7 +5613,7 @@ fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
5581 const ty_op = f.air.instructions.items(.data)[inst].ty_op;5613 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
5582 if (f.liveness.isUnused(inst)) {5614 if (f.liveness.isUnused(inst)) {
5583 try reap(f, inst, &.{ty_op.operand});5615 try reap(f, inst, &.{ty_op.operand});
5584 return CValue.none;5616 return .none;
5585 }5617 }
55865618
5587 const writer = f.object.writer();5619 const writer = f.object.writer();
...@@ -5635,7 +5667,7 @@ fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5635,7 +5667,7 @@ fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
5635 try writer.writeAll(";\n");5667 try writer.writeAll(";\n");
56365668
5637 // Then return the payload pointer (only if it is used)5669 // 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
5640 const local = try f.allocLocal(inst, f.air.typeOfIndex(inst));5672 const local = try f.allocLocal(inst, f.air.typeOfIndex(inst));
5641 try f.writeCValue(writer, local, .Other);5673 try f.writeCValue(writer, local, .Other);
...@@ -5646,7 +5678,7 @@ fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5646,7 +5678,7 @@ fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
5646}5678}
56475679
5648fn airErrReturnTrace(f: *Function, inst: Air.Inst.Index) !CValue {5680fn 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;
5650 return f.fail("TODO: C backend: implement airErrReturnTrace", .{});5682 return f.fail("TODO: C backend: implement airErrReturnTrace", .{});
5651}5683}
56525684
...@@ -5664,7 +5696,7 @@ fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5664,7 +5696,7 @@ fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {
5664 const ty_op = f.air.instructions.items(.data)[inst].ty_op;5696 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
5665 if (f.liveness.isUnused(inst)) {5697 if (f.liveness.isUnused(inst)) {
5666 try reap(f, inst, &.{ty_op.operand});5698 try reap(f, inst, &.{ty_op.operand});
5667 return CValue.none;5699 return .none;
5668 }5700 }
56695701
5670 const inst_ty = f.air.typeOfIndex(inst);5702 const inst_ty = f.air.typeOfIndex(inst);
...@@ -5691,7 +5723,7 @@ fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5691,7 +5723,7 @@ fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {
5691 try writer.writeAll(", ");5723 try writer.writeAll(", ");
5692 try f.writeCValue(writer, payload, .FunctionArgument);5724 try f.writeCValue(writer, payload, .FunctionArgument);
5693 try writer.writeAll(", sizeof(");5725 try writer.writeAll(", sizeof(");
5694 try f.renderTypecast(writer, payload_ty);5726 try f.renderType(writer, payload_ty);
5695 try writer.writeAll("));\n");5727 try writer.writeAll("));\n");
5696 }5728 }
5697 return local;5729 return local;
...@@ -5702,7 +5734,7 @@ fn airIsErr(f: *Function, inst: Air.Inst.Index, is_ptr: bool, operator: []const...@@ -5702,7 +5734,7 @@ fn airIsErr(f: *Function, inst: Air.Inst.Index, is_ptr: bool, operator: []const
57025734
5703 if (f.liveness.isUnused(inst)) {5735 if (f.liveness.isUnused(inst)) {
5704 try reap(f, inst, &.{un_op});5736 try reap(f, inst, &.{un_op});
5705 return CValue.none;5737 return .none;
5706 }5738 }
57075739
5708 const writer = f.object.writer();5740 const writer = f.object.writer();
...@@ -5740,7 +5772,7 @@ fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5740,7 +5772,7 @@ fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue {
57405772
5741 if (f.liveness.isUnused(inst)) {5773 if (f.liveness.isUnused(inst)) {
5742 try reap(f, inst, &.{ty_op.operand});5774 try reap(f, inst, &.{ty_op.operand});
5743 return CValue.none;5775 return .none;
5744 }5776 }
57455777
5746 const operand = try f.resolveInst(ty_op.operand);5778 const operand = try f.resolveInst(ty_op.operand);
...@@ -5756,7 +5788,7 @@ fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5756,7 +5788,7 @@ fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue {
5756 // &(*(void *)p)[0], although LLVM does via GetElementPtr5788 // &(*(void *)p)[0], although LLVM does via GetElementPtr
5757 if (operand == .undef) {5789 if (operand == .undef) {
5758 var buf: Type.SlicePtrFieldTypeBuffer = undefined;5790 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);
5760 } else if (array_ty.hasRuntimeBitsIgnoreComptime()) {5792 } else if (array_ty.hasRuntimeBitsIgnoreComptime()) {
5761 try writer.writeAll("&(");5793 try writer.writeAll("&(");
5762 try f.writeCValueDeref(writer, operand);5794 try f.writeCValueDeref(writer, operand);
...@@ -5778,7 +5810,7 @@ fn airFloatCast(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5778,7 +5810,7 @@ fn airFloatCast(f: *Function, inst: Air.Inst.Index) !CValue {
57785810
5779 if (f.liveness.isUnused(inst)) {5811 if (f.liveness.isUnused(inst)) {
5780 try reap(f, inst, &.{ty_op.operand});5812 try reap(f, inst, &.{ty_op.operand});
5781 return CValue.none;5813 return .none;
5782 }5814 }
57835815
5784 const inst_ty = f.air.typeOfIndex(inst);5816 const inst_ty = f.air.typeOfIndex(inst);
...@@ -5826,7 +5858,7 @@ fn airPtrToInt(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5826,7 +5858,7 @@ fn airPtrToInt(f: *Function, inst: Air.Inst.Index) !CValue {
58265858
5827 if (f.liveness.isUnused(inst)) {5859 if (f.liveness.isUnused(inst)) {
5828 try reap(f, inst, &.{un_op});5860 try reap(f, inst, &.{un_op});
5829 return CValue.none;5861 return .none;
5830 }5862 }
58315863
5832 const operand = try f.resolveInst(un_op);5864 const operand = try f.resolveInst(un_op);
...@@ -5837,7 +5869,7 @@ fn airPtrToInt(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5837,7 +5869,7 @@ fn airPtrToInt(f: *Function, inst: Air.Inst.Index) !CValue {
5837 try f.writeCValue(writer, local, .Other);5869 try f.writeCValue(writer, local, .Other);
58385870
5839 try writer.writeAll(" = (");5871 try writer.writeAll(" = (");
5840 try f.renderTypecast(writer, inst_ty);5872 try f.renderType(writer, inst_ty);
5841 try writer.writeByte(')');5873 try writer.writeByte(')');
5842 try f.writeCValue(writer, operand, .Other);5874 try f.writeCValue(writer, operand, .Other);
5843 try writer.writeAll(";\n");5875 try writer.writeAll(";\n");
...@@ -5854,7 +5886,7 @@ fn airUnBuiltinCall(...@@ -5854,7 +5886,7 @@ fn airUnBuiltinCall(
58545886
5855 if (f.liveness.isUnused(inst)) {5887 if (f.liveness.isUnused(inst)) {
5856 try reap(f, inst, &.{ty_op.operand});5888 try reap(f, inst, &.{ty_op.operand});
5857 return CValue.none;5889 return .none;
5858 }5890 }
58595891
5860 const operand = try f.resolveInst(ty_op.operand);5892 const operand = try f.resolveInst(ty_op.operand);
...@@ -5886,7 +5918,7 @@ fn airBinBuiltinCall(...@@ -5886,7 +5918,7 @@ fn airBinBuiltinCall(
58865918
5887 if (f.liveness.isUnused(inst)) {5919 if (f.liveness.isUnused(inst)) {
5888 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });5920 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
5889 return CValue.none;5921 return .none;
5890 }5922 }
58915923
5892 const lhs = try f.resolveInst(bin_op.lhs);5924 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...@@ -5959,7 +5991,7 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue
5959 try writer.writeAll(";\n");5991 try writer.writeAll(";\n");
5960 try writer.writeAll("if (");5992 try writer.writeAll("if (");
5961 try writer.print("zig_cmpxchg_{s}((zig_atomic(", .{flavor});5993 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());
5963 try writer.writeByte(')');5995 try writer.writeByte(')');
5964 if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile");5996 if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile");
5965 try writer.writeAll(" *)");5997 try writer.writeAll(" *)");
...@@ -5988,7 +6020,7 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue...@@ -5988,7 +6020,7 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue
5988 try writer.writeAll(";\n");6020 try writer.writeAll(";\n");
5989 try f.writeCValue(writer, local, .Other);6021 try f.writeCValue(writer, local, .Other);
5990 try writer.print(".is_null = zig_cmpxchg_{s}((zig_atomic(", .{flavor});6022 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());
5992 try writer.writeByte(')');6024 try writer.writeByte(')');
5993 if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile");6025 if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile");
5994 try writer.writeAll(" *)");6026 try writer.writeAll(" *)");
...@@ -6009,7 +6041,7 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue...@@ -6009,7 +6041,7 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue
60096041
6010 if (f.liveness.isUnused(inst)) {6042 if (f.liveness.isUnused(inst)) {
6011 try freeLocal(f, inst, local.new_local, 0);6043 try freeLocal(f, inst, local.new_local, 0);
6012 return CValue.none;6044 return .none;
6013 }6045 }
60146046
6015 return local;6047 return local;
...@@ -6031,12 +6063,12 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6031,12 +6063,12 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue {
6031 switch (extra.op()) {6063 switch (extra.op()) {
6032 else => {6064 else => {
6033 try writer.writeAll("zig_atomic(");6065 try writer.writeAll("zig_atomic(");
6034 try f.renderTypecast(writer, ptr_ty.elemType());6066 try f.renderType(writer, ptr_ty.elemType());
6035 try writer.writeByte(')');6067 try writer.writeByte(')');
6036 },6068 },
6037 .Nand, .Min, .Max => {6069 .Nand, .Min, .Max => {
6038 // These are missing from stdatomic.h, so no atomic types for now.6070 // 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());
6040 },6072 },
6041 }6073 }
6042 if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile");6074 if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile");
...@@ -6052,7 +6084,7 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6052,7 +6084,7 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue {
60526084
6053 if (f.liveness.isUnused(inst)) {6085 if (f.liveness.isUnused(inst)) {
6054 try freeLocal(f, inst, local.new_local, 0);6086 try freeLocal(f, inst, local.new_local, 0);
6055 return CValue.none;6087 return .none;
6056 }6088 }
60576089
6058 return local;6090 return local;
...@@ -6064,7 +6096,7 @@ fn airAtomicLoad(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6064,7 +6096,7 @@ fn airAtomicLoad(f: *Function, inst: Air.Inst.Index) !CValue {
6064 try reap(f, inst, &.{atomic_load.ptr});6096 try reap(f, inst, &.{atomic_load.ptr});
6065 const ptr_ty = f.air.typeOf(atomic_load.ptr);6097 const ptr_ty = f.air.typeOf(atomic_load.ptr);
6066 if (!ptr_ty.isVolatilePtr() and f.liveness.isUnused(inst)) {6098 if (!ptr_ty.isVolatilePtr() and f.liveness.isUnused(inst)) {
6067 return CValue.none;6099 return .none;
6068 }6100 }
60696101
6070 const inst_ty = f.air.typeOfIndex(inst);6102 const inst_ty = f.air.typeOfIndex(inst);
...@@ -6073,7 +6105,7 @@ fn airAtomicLoad(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6073,7 +6105,7 @@ fn airAtomicLoad(f: *Function, inst: Air.Inst.Index) !CValue {
6073 try f.writeCValue(writer, local, .Other);6105 try f.writeCValue(writer, local, .Other);
60746106
6075 try writer.writeAll(" = zig_atomic_load((zig_atomic(");6107 try writer.writeAll(" = zig_atomic_load((zig_atomic(");
6076 try f.renderTypecast(writer, ptr_ty.elemType());6108 try f.renderType(writer, ptr_ty.elemType());
6077 try writer.writeByte(')');6109 try writer.writeByte(')');
6078 if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile");6110 if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile");
6079 try writer.writeAll(" *)");6111 try writer.writeAll(" *)");
...@@ -6096,7 +6128,7 @@ fn airAtomicStore(f: *Function, inst: Air.Inst.Index, order: [*:0]const u8) !CVa...@@ -6096,7 +6128,7 @@ fn airAtomicStore(f: *Function, inst: Air.Inst.Index, order: [*:0]const u8) !CVa
6096 const writer = f.object.writer();6128 const writer = f.object.writer();
60976129
6098 try writer.writeAll("zig_atomic_store((zig_atomic(");6130 try writer.writeAll("zig_atomic_store((zig_atomic(");
6099 try f.renderTypecast(writer, ptr_ty.elemType());6131 try f.renderType(writer, ptr_ty.elemType());
6100 try writer.writeByte(')');6132 try writer.writeByte(')');
6101 if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile");6133 if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile");
6102 try writer.writeAll(" *)");6134 try writer.writeAll(" *)");
...@@ -6107,7 +6139,7 @@ fn airAtomicStore(f: *Function, inst: Air.Inst.Index, order: [*:0]const u8) !CVa...@@ -6107,7 +6139,7 @@ fn airAtomicStore(f: *Function, inst: Air.Inst.Index, order: [*:0]const u8) !CVa
6107 try f.object.dg.renderTypeForBuiltinFnName(writer, ptr_ty.childType());6139 try f.object.dg.renderTypeForBuiltinFnName(writer, ptr_ty.childType());
6108 try writer.writeAll(");\n");6140 try writer.writeAll(");\n");
61096141
6110 return CValue.none;6142 return .none;
6111}6143}
61126144
6113fn airMemset(f: *Function, inst: Air.Inst.Index) !CValue {6145fn airMemset(f: *Function, inst: Air.Inst.Index) !CValue {
...@@ -6138,7 +6170,7 @@ fn airMemset(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6138,7 +6170,7 @@ fn airMemset(f: *Function, inst: Air.Inst.Index) !CValue {
6138 try writer.writeAll(" += ");6170 try writer.writeAll(" += ");
6139 try f.object.dg.renderValue(writer, Type.usize, Value.one, .Other);6171 try f.object.dg.renderValue(writer, Type.usize, Value.one, .Other);
6140 try writer.writeAll(") ((");6172 try writer.writeAll(") ((");
6141 try f.renderTypecast(writer, u8_ptr_ty);6173 try f.renderType(writer, u8_ptr_ty);
6142 try writer.writeByte(')');6174 try writer.writeByte(')');
6143 try f.writeCValue(writer, dest_ptr, .FunctionArgument);6175 try f.writeCValue(writer, dest_ptr, .FunctionArgument);
6144 try writer.writeAll(")[");6176 try writer.writeAll(")[");
...@@ -6150,7 +6182,7 @@ fn airMemset(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6150,7 +6182,7 @@ fn airMemset(f: *Function, inst: Air.Inst.Index) !CValue {
6150 try reap(f, inst, &.{ pl_op.operand, extra.lhs, extra.rhs });6182 try reap(f, inst, &.{ pl_op.operand, extra.lhs, extra.rhs });
6151 try freeLocal(f, inst, index.new_local, 0);6183 try freeLocal(f, inst, index.new_local, 0);
61526184
6153 return CValue.none;6185 return .none;
6154 }6186 }
61556187
6156 try reap(f, inst, &.{ pl_op.operand, extra.lhs, extra.rhs });6188 try reap(f, inst, &.{ pl_op.operand, extra.lhs, extra.rhs });
...@@ -6162,7 +6194,7 @@ fn airMemset(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6162,7 +6194,7 @@ fn airMemset(f: *Function, inst: Air.Inst.Index) !CValue {
6162 try f.writeCValue(writer, len, .FunctionArgument);6194 try f.writeCValue(writer, len, .FunctionArgument);
6163 try writer.writeAll(");\n");6195 try writer.writeAll(");\n");
61646196
6165 return CValue.none;6197 return .none;
6166}6198}
61676199
6168fn airMemcpy(f: *Function, inst: Air.Inst.Index) !CValue {6200fn airMemcpy(f: *Function, inst: Air.Inst.Index) !CValue {
...@@ -6182,7 +6214,7 @@ fn airMemcpy(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6182,7 +6214,7 @@ fn airMemcpy(f: *Function, inst: Air.Inst.Index) !CValue {
6182 try f.writeCValue(writer, len, .FunctionArgument);6214 try f.writeCValue(writer, len, .FunctionArgument);
6183 try writer.writeAll(");\n");6215 try writer.writeAll(");\n");
61846216
6185 return CValue.none;6217 return .none;
6186}6218}
61876219
6188fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {6220fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
...@@ -6195,7 +6227,7 @@ fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6195,7 +6227,7 @@ fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
6195 const union_ty = f.air.typeOf(bin_op.lhs).childType();6227 const union_ty = f.air.typeOf(bin_op.lhs).childType();
6196 const target = f.object.dg.module.getTarget();6228 const target = f.object.dg.module.getTarget();
6197 const layout = union_ty.unionGetLayout(target);6229 const layout = union_ty.unionGetLayout(target);
6198 if (layout.tag_size == 0) return CValue.none;6230 if (layout.tag_size == 0) return .none;
61996231
6200 try writer.writeByte('(');6232 try writer.writeByte('(');
6201 try f.writeCValue(writer, union_ptr, .Other);6233 try f.writeCValue(writer, union_ptr, .Other);
...@@ -6203,7 +6235,7 @@ fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6203,7 +6235,7 @@ fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
6203 try f.writeCValue(writer, new_tag, .Other);6235 try f.writeCValue(writer, new_tag, .Other);
6204 try writer.writeAll(";\n");6236 try writer.writeAll(";\n");
62056237
6206 return CValue.none;6238 return .none;
6207}6239}
62086240
6209fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {6241fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
...@@ -6211,7 +6243,7 @@ fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6211,7 +6243,7 @@ fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
62116243
6212 if (f.liveness.isUnused(inst)) {6244 if (f.liveness.isUnused(inst)) {
6213 try reap(f, inst, &.{ty_op.operand});6245 try reap(f, inst, &.{ty_op.operand});
6214 return CValue.none;6246 return .none;
6215 }6247 }
62166248
6217 const operand = try f.resolveInst(ty_op.operand);6249 const operand = try f.resolveInst(ty_op.operand);
...@@ -6221,7 +6253,7 @@ fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6221,7 +6253,7 @@ fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
62216253
6222 const target = f.object.dg.module.getTarget();6254 const target = f.object.dg.module.getTarget();
6223 const layout = un_ty.unionGetLayout(target);6255 const layout = un_ty.unionGetLayout(target);
6224 if (layout.tag_size == 0) return CValue.none;6256 if (layout.tag_size == 0) return .none;
62256257
6226 const inst_ty = f.air.typeOfIndex(inst);6258 const inst_ty = f.air.typeOfIndex(inst);
6227 const writer = f.object.writer();6259 const writer = f.object.writer();
...@@ -6239,7 +6271,7 @@ fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6239,7 +6271,7 @@ fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue {
62396271
6240 if (f.liveness.isUnused(inst)) {6272 if (f.liveness.isUnused(inst)) {
6241 try reap(f, inst, &.{un_op});6273 try reap(f, inst, &.{un_op});
6242 return CValue.none;6274 return .none;
6243 }6275 }
62446276
6245 const inst_ty = f.air.typeOfIndex(inst);6277 const inst_ty = f.air.typeOfIndex(inst);
...@@ -6250,7 +6282,9 @@ fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6250,7 +6282,9 @@ fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue {
6250 const writer = f.object.writer();6282 const writer = f.object.writer();
6251 const local = try f.allocLocal(inst, inst_ty);6283 const local = try f.allocLocal(inst, inst_ty);
6252 try f.writeCValue(writer, local, .Other);6284 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 });
6254 try f.writeCValue(writer, operand, .Other);6288 try f.writeCValue(writer, operand, .Other);
6255 try writer.writeAll(");\n");6289 try writer.writeAll(");\n");
62566290
...@@ -6262,7 +6296,7 @@ fn airErrorName(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6262,7 +6296,7 @@ fn airErrorName(f: *Function, inst: Air.Inst.Index) !CValue {
62626296
6263 if (f.liveness.isUnused(inst)) {6297 if (f.liveness.isUnused(inst)) {
6264 try reap(f, inst, &.{un_op});6298 try reap(f, inst, &.{un_op});
6265 return CValue.none;6299 return .none;
6266 }6300 }
62676301
6268 const writer = f.object.writer();6302 const writer = f.object.writer();
...@@ -6282,7 +6316,7 @@ fn airSplat(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6282,7 +6316,7 @@ fn airSplat(f: *Function, inst: Air.Inst.Index) !CValue {
6282 const ty_op = f.air.instructions.items(.data)[inst].ty_op;6316 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
6283 if (f.liveness.isUnused(inst)) {6317 if (f.liveness.isUnused(inst)) {
6284 try reap(f, inst, &.{ty_op.operand});6318 try reap(f, inst, &.{ty_op.operand});
6285 return CValue.none;6319 return .none;
6286 }6320 }
62876321
6288 const inst_ty = f.air.typeOfIndex(inst);6322 const inst_ty = f.air.typeOfIndex(inst);
...@@ -6298,13 +6332,13 @@ fn airSplat(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6298,13 +6332,13 @@ fn airSplat(f: *Function, inst: Air.Inst.Index) !CValue {
6298}6332}
62996333
6300fn airSelect(f: *Function, inst: Air.Inst.Index) !CValue {6334fn 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
6303 return f.fail("TODO: C backend: implement airSelect", .{});6337 return f.fail("TODO: C backend: implement airSelect", .{});
6304}6338}
63056339
6306fn airShuffle(f: *Function, inst: Air.Inst.Index) !CValue {6340fn 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
6309 return f.fail("TODO: C backend: implement airShuffle", .{});6343 return f.fail("TODO: C backend: implement airShuffle", .{});
6310}6344}
...@@ -6314,7 +6348,7 @@ fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6314,7 +6348,7 @@ fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue {
63146348
6315 if (f.liveness.isUnused(inst)) {6349 if (f.liveness.isUnused(inst)) {
6316 try reap(f, inst, &.{reduce.operand});6350 try reap(f, inst, &.{reduce.operand});
6317 return CValue.none;6351 return .none;
6318 }6352 }
63196353
6320 const target = f.object.dg.module.getTarget();6354 const target = f.object.dg.module.getTarget();
...@@ -6390,10 +6424,9 @@ fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6390,10 +6424,9 @@ fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue {
6390 //6424 //
6391 // Equivalent to:6425 // Equivalent to:
6392 // reduce: {6426 // reduce: {
6393 // var i: usize = 0;
6394 // var accum: T = init;6427 // var accum: T = init;
6395 // while (i < vec.len) : (i += 1) {6428 // for (vec) : (elem) {
6396 // accum = func(accum, vec[i]);6429 // accum = func(accum, elem);
6397 // }6430 // }
6398 // break :reduce accum;6431 // break :reduce accum;
6399 // }6432 // }
...@@ -6488,7 +6521,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6488,7 +6521,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
6488 }6521 }
6489 }6522 }
64906523
6491 if (f.liveness.isUnused(inst)) return CValue.none;6524 if (f.liveness.isUnused(inst)) return .none;
64926525
6493 const target = f.object.dg.module.getTarget();6526 const target = f.object.dg.module.getTarget();
64946527
...@@ -6514,7 +6547,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6514,7 +6547,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
6514 .Auto, .Extern => {6547 .Auto, .Extern => {
6515 try f.writeCValue(writer, local, .Other);6548 try f.writeCValue(writer, local, .Other);
6516 try writer.writeAll(" = (");6549 try writer.writeAll(" = (");
6517 try f.renderTypecast(writer, inst_ty);6550 try f.renderType(writer, inst_ty);
6518 try writer.writeAll(")");6551 try writer.writeAll(")");
6519 try writer.writeByte('{');6552 try writer.writeByte('{');
6520 var empty = true;6553 var empty = true;
...@@ -6533,7 +6566,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6533,7 +6566,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
65336566
6534 const element_ty = f.air.typeOf(element);6567 const element_ty = f.air.typeOf(element);
6535 try f.writeCValue(writer, switch (element_ty.zigTypeTag()) {6568 try f.writeCValue(writer, switch (element_ty.zigTypeTag()) {
6536 .Array => CValue{ .undef = element_ty },6569 .Array => .{ .undef = element_ty },
6537 else => resolved_element,6570 else => resolved_element,
6538 }, .Initializer);6571 }, .Initializer);
6539 empty = false;6572 empty = false;
...@@ -6557,7 +6590,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6557,7 +6590,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
6557 try writer.writeAll(", ");6590 try writer.writeAll(", ");
6558 try f.writeCValue(writer, resolved_element, .FunctionArgument);6591 try f.writeCValue(writer, resolved_element, .FunctionArgument);
6559 try writer.writeAll(", sizeof(");6592 try writer.writeAll(", sizeof(");
6560 try f.renderTypecast(writer, element_ty);6593 try f.renderType(writer, element_ty);
6561 try writer.writeAll("));\n");6594 try writer.writeAll("));\n");
6562 }6595 }
6563 },6596 },
...@@ -6602,11 +6635,11 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6602,11 +6635,11 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
6602 try f.renderIntCast(writer, inst_ty, element, field_ty, .FunctionArgument);6635 try f.renderIntCast(writer, inst_ty, element, field_ty, .FunctionArgument);
6603 } else {6636 } else {
6604 try writer.writeByte('(');6637 try writer.writeByte('(');
6605 try f.renderTypecast(writer, inst_ty);6638 try f.renderType(writer, inst_ty);
6606 try writer.writeByte(')');6639 try writer.writeByte(')');
6607 if (field_ty.isPtrAtRuntime()) {6640 if (field_ty.isPtrAtRuntime()) {
6608 try writer.writeByte('(');6641 try writer.writeByte('(');
6609 try f.renderTypecast(writer, switch (int_info.signedness) {6642 try f.renderType(writer, switch (int_info.signedness) {
6610 .unsigned => Type.usize,6643 .unsigned => Type.usize,
6611 .signed => Type.isize,6644 .signed => Type.isize,
6612 });6645 });
...@@ -6640,7 +6673,7 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6640,7 +6673,7 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {
66406673
6641 if (f.liveness.isUnused(inst)) {6674 if (f.liveness.isUnused(inst)) {
6642 try reap(f, inst, &.{extra.init});6675 try reap(f, inst, &.{extra.init});
6643 return CValue.none;6676 return .none;
6644 }6677 }
66456678
6646 const union_ty = f.air.typeOfIndex(inst);6679 const union_ty = f.air.typeOfIndex(inst);
...@@ -6660,7 +6693,7 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6660,7 +6693,7 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {
6660 return local;6693 return local;
6661 }6694 }
66626695
6663 if (union_ty.unionTagTypeSafety()) |tag_ty| {6696 const field: CValue = if (union_ty.unionTagTypeSafety()) |tag_ty| field: {
6664 const layout = union_ty.unionGetLayout(target);6697 const layout = union_ty.unionGetLayout(target);
6665 if (layout.tag_size != 0) {6698 if (layout.tag_size != 0) {
6666 const field_index = tag_ty.enumFieldIndex(field_name).?;6699 const field_index = tag_ty.enumFieldIndex(field_name).?;
...@@ -6677,18 +6710,13 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6677,18 +6710,13 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {
6677 try f.writeCValue(writer, local, .Other);6710 try f.writeCValue(writer, local, .Other);
6678 try writer.print(".tag = {}; ", .{try f.fmtIntLiteral(tag_ty, int_val)});6711 try writer.print(".tag = {}; ", .{try f.fmtIntLiteral(tag_ty, int_val)});
6679 }6712 }
6680 try f.writeCValue(writer, local, .Other);6713 break :field .{ .payload_identifier = field_name };
6681 try writer.print(".payload.{ } = ", .{fmtIdent(field_name)});6714 } else .{ .identifier = field_name };
6682 try f.writeCValue(writer, payload, .Other);
6683 try writer.writeAll(";\n");
6684 return local;
6685 }
66866715
6687 try f.writeCValue(writer, local, .Other);6716 try f.writeCValueMember(writer, local, field);
6688 try writer.print(".{ } = ", .{fmtIdent(field_name)});6717 try writer.writeAll(" = ");
6689 try f.writeCValue(writer, payload, .Other);6718 try f.writeCValue(writer, payload, .Other);
6690 try writer.writeAll(";\n");6719 try writer.writeAll(";\n");
6691
6692 return local;6720 return local;
6693}6721}
66946722
...@@ -6699,7 +6727,7 @@ fn airPrefetch(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6699,7 +6727,7 @@ fn airPrefetch(f: *Function, inst: Air.Inst.Index) !CValue {
6699 // The available prefetch intrinsics do not accept a cache argument; only6727 // The available prefetch intrinsics do not accept a cache argument; only
6700 // address, rw, and locality. So unless the cache is data, we do not lower6728 // address, rw, and locality. So unless the cache is data, we do not lower
6701 // this instruction.6729 // this instruction.
6702 .instruction => return CValue.none,6730 .instruction => return .none,
6703 }6731 }
6704 const ptr = try f.resolveInst(prefetch.ptr);6732 const ptr = try f.resolveInst(prefetch.ptr);
6705 try reap(f, inst, &.{prefetch.ptr});6733 try reap(f, inst, &.{prefetch.ptr});
...@@ -6709,11 +6737,11 @@ fn airPrefetch(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6709,11 +6737,11 @@ fn airPrefetch(f: *Function, inst: Air.Inst.Index) !CValue {
6709 try writer.print(", {d}, {d});\n", .{6737 try writer.print(", {d}, {d});\n", .{
6710 @enumToInt(prefetch.rw), prefetch.locality,6738 @enumToInt(prefetch.rw), prefetch.locality,
6711 });6739 });
6712 return CValue.none;6740 return .none;
6713}6741}
67146742
6715fn airWasmMemorySize(f: *Function, inst: Air.Inst.Index) !CValue {6743fn 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
6718 const pl_op = f.air.instructions.items(.data)[inst].pl_op;6746 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 {...@@ -6750,7 +6778,7 @@ fn airFloatNeg(f: *Function, inst: Air.Inst.Index) !CValue {
6750 const un_op = f.air.instructions.items(.data)[inst].un_op;6778 const un_op = f.air.instructions.items(.data)[inst].un_op;
6751 if (f.liveness.isUnused(inst)) {6779 if (f.liveness.isUnused(inst)) {
6752 try reap(f, inst, &.{un_op});6780 try reap(f, inst, &.{un_op});
6753 return CValue.none;6781 return .none;
6754 }6782 }
67556783
6756 const operand = try f.resolveInst(un_op);6784 const operand = try f.resolveInst(un_op);
...@@ -6772,7 +6800,7 @@ fn airUnFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CVal...@@ -6772,7 +6800,7 @@ fn airUnFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CVal
6772 const un_op = f.air.instructions.items(.data)[inst].un_op;6800 const un_op = f.air.instructions.items(.data)[inst].un_op;
6773 if (f.liveness.isUnused(inst)) {6801 if (f.liveness.isUnused(inst)) {
6774 try reap(f, inst, &.{un_op});6802 try reap(f, inst, &.{un_op});
6775 return CValue.none;6803 return .none;
6776 }6804 }
6777 const operand = try f.resolveInst(un_op);6805 const operand = try f.resolveInst(un_op);
6778 try reap(f, inst, &.{un_op});6806 try reap(f, inst, &.{un_op});
...@@ -6794,7 +6822,7 @@ fn airBinFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CVa...@@ -6794,7 +6822,7 @@ fn airBinFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CVa
6794 const bin_op = f.air.instructions.items(.data)[inst].bin_op;6822 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
6795 if (f.liveness.isUnused(inst)) {6823 if (f.liveness.isUnused(inst)) {
6796 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });6824 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
6797 return CValue.none;6825 return .none;
6798 }6826 }
6799 const lhs = try f.resolveInst(bin_op.lhs);6827 const lhs = try f.resolveInst(bin_op.lhs);
6800 const rhs = try f.resolveInst(bin_op.rhs);6828 const rhs = try f.resolveInst(bin_op.rhs);
...@@ -6821,7 +6849,7 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6821,7 +6849,7 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue {
6821 const bin_op = f.air.extraData(Air.Bin, pl_op.payload).data;6849 const bin_op = f.air.extraData(Air.Bin, pl_op.payload).data;
6822 if (f.liveness.isUnused(inst)) {6850 if (f.liveness.isUnused(inst)) {
6823 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs, pl_op.operand });6851 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs, pl_op.operand });
6824 return CValue.none;6852 return .none;
6825 }6853 }
6826 const inst_ty = f.air.typeOfIndex(inst);6854 const inst_ty = f.air.typeOfIndex(inst);
6827 const mulend1 = try f.resolveInst(bin_op.lhs);6855 const mulend1 = try f.resolveInst(bin_op.lhs);
...@@ -6843,6 +6871,81 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6843,6 +6871,81 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue {
6843 return local;6871 return local;
6844}6872}
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
6846fn toMemoryOrder(order: std.builtin.AtomicOrder) [:0]const u8 {6949fn toMemoryOrder(order: std.builtin.AtomicOrder) [:0]const u8 {
6847 return switch (order) {6950 return switch (order) {
6848 // Note: unordered is actually even less atomic than relaxed6951 // Note: unordered is actually even less atomic than relaxed
...@@ -7028,8 +7131,9 @@ fn stringLiteral(child_stream: anytype) StringLiteral(@TypeOf(child_stream)) {...@@ -7028,8 +7131,9 @@ fn stringLiteral(child_stream: anytype) StringLiteral(@TypeOf(child_stream)) {
7028 return .{ .counting_writer = std.io.countingWriter(child_stream) };7131 return .{ .counting_writer = std.io.countingWriter(child_stream) };
7029}7132}
70307133
7134const FormatStringContext = struct { str: []const u8, sentinel: ?u8 };
7031fn formatStringLiteral(7135fn formatStringLiteral(
7032 str: []const u8,7136 data: FormatStringContext,
7033 comptime fmt: []const u8,7137 comptime fmt: []const u8,
7034 _: std.fmt.FormatOptions,7138 _: std.fmt.FormatOptions,
7035 writer: anytype,7139 writer: anytype,
...@@ -7038,13 +7142,13 @@ fn formatStringLiteral(...@@ -7038,13 +7142,13 @@ fn formatStringLiteral(
70387142
7039 var literal = stringLiteral(writer);7143 var literal = stringLiteral(writer);
7040 try literal.start();7144 try literal.start();
7041 for (str) |c|7145 for (data.str) |c| try literal.writeChar(c);
7042 try literal.writeChar(c);7146 if (data.sentinel) |sentinel| if (sentinel != 0) try literal.writeChar(sentinel);
7043 try literal.end();7147 try literal.end();
7044}7148}
70457149
7046fn fmtStringLiteral(str: []const u8) std.fmt.Formatter(formatStringLiteral) {7150fn fmtStringLiteral(str: []const u8, sentinel: ?u8) std.fmt.Formatter(formatStringLiteral) {
7047 return .{ .data = str };7151 return .{ .data = .{ .str = str, .sentinel = sentinel } };
7048}7152}
70497153
7050fn undefPattern(comptime IntType: type) IntType {7154fn undefPattern(comptime IntType: type) IntType {
src/codegen/c/type.zig+141-147
...@@ -1056,7 +1056,7 @@ pub const CType = extern union {...@@ -1056,7 +1056,7 @@ pub const CType = extern union {
1056 }1056 }
1057 },1057 },
10581058
1059 .Struct, .Union => |zig_tag| if (ty.containerLayout() == .Packed) {1059 .Struct, .Union => |zig_ty_tag| if (ty.containerLayout() == .Packed) {
1060 if (ty.castTag(.@"struct")) |struct_obj| {1060 if (ty.castTag(.@"struct")) |struct_obj| {
1061 try self.initType(struct_obj.data.backing_int_ty, kind, lookup);1061 try self.initType(struct_obj.data.backing_int_ty, kind, lookup);
1062 } else {1062 } else {
...@@ -1068,9 +1068,13 @@ pub const CType = extern union {...@@ -1068,9 +1068,13 @@ pub const CType = extern union {
1068 }1068 }
1069 } else if (ty.isTupleOrAnonStruct()) {1069 } else if (ty.isTupleOrAnonStruct()) {
1070 if (lookup.isMutable()) {1070 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| {
1072 const field_ty = ty.structFieldType(field_i);1076 const field_ty = ty.structFieldType(field_i);
1073 if (ty.structFieldIsComptime(field_i) or1077 if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i)) or
1074 !field_ty.hasRuntimeBitsIgnoreComptime()) continue;1078 !field_ty.hasRuntimeBitsIgnoreComptime()) continue;
1075 _ = try lookup.typeToIndex(field_ty, switch (kind) {1079 _ = try lookup.typeToIndex(field_ty, switch (kind) {
1076 .forward, .forward_parameter => .forward,1080 .forward, .forward_parameter => .forward,
...@@ -1086,14 +1090,22 @@ pub const CType = extern union {...@@ -1086,14 +1090,22 @@ pub const CType = extern union {
1086 }1090 }
1087 }1091 }
1088 self.init(switch (kind) {1092 self.init(switch (kind) {
1089 .forward, .forward_parameter => .fwd_anon_struct,1093 .forward, .forward_parameter => switch (zig_ty_tag) {
1090 .complete, .parameter, .global => .anon_struct,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 },
1091 .payload => unreachable,1103 .payload => unreachable,
1092 });1104 });
1093 } else {1105 } else {
1094 const tag_ty = ty.unionTagTypeSafety();1106 const tag_ty = ty.unionTagTypeSafety();
1095 const is_tagged_union_wrapper = kind != .payload and tag_ty != null;1107 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;
1097 switch (kind) {1109 switch (kind) {
1098 .forward, .forward_parameter => {1110 .forward, .forward_parameter => {
1099 self.storage = .{ .fwd = .{1111 self.storage = .{ .fwd = .{
...@@ -1138,7 +1150,7 @@ pub const CType = extern union {...@@ -1138,7 +1150,7 @@ pub const CType = extern union {
1138 self.init(.void);1150 self.init(.void);
1139 } else {1151 } else {
1140 var is_packed = false;1152 var is_packed = false;
1141 for (0..switch (zig_tag) {1153 for (0..switch (zig_ty_tag) {
1142 .Struct => ty.structFieldCount(),1154 .Struct => ty.structFieldCount(),
1143 .Union => ty.unionFields().count(),1155 .Union => ty.unionFields().count(),
1144 else => unreachable,1156 else => unreachable,
...@@ -1181,10 +1193,10 @@ pub const CType = extern union {...@@ -1181,10 +1193,10 @@ pub const CType = extern union {
1181 }1193 }
1182 },1194 },
11831195
1184 .Array, .Vector => |zig_tag| {1196 .Array, .Vector => |zig_ty_tag| {
1185 switch (kind) {1197 switch (kind) {
1186 .forward, .complete, .global => {1198 .forward, .complete, .global => {
1187 const t: Tag = switch (zig_tag) {1199 const t: Tag = switch (zig_ty_tag) {
1188 .Array => .array,1200 .Array => .array,
1189 .Vector => .vector,1201 .Vector => .vector,
1190 else => unreachable,1202 else => unreachable,
...@@ -1296,19 +1308,21 @@ pub const CType = extern union {...@@ -1296,19 +1308,21 @@ pub const CType = extern union {
12961308
1297 .Fn => {1309 .Fn => {
1298 const info = ty.fnInfo();1310 const info = ty.fnInfo();
1299 if (lookup.isMutable()) {1311 if (!info.is_generic) {
1300 const param_kind: Kind = switch (kind) {1312 if (lookup.isMutable()) {
1301 .forward, .forward_parameter => .forward_parameter,1313 const param_kind: Kind = switch (kind) {
1302 .complete, .parameter, .global => .parameter,1314 .forward, .forward_parameter => .forward_parameter,
1303 .payload => unreachable,1315 .complete, .parameter, .global => .parameter,
1304 };1316 .payload => unreachable,
1305 _ = try lookup.typeToIndex(info.return_type, param_kind);1317 };
1306 for (info.param_types) |param_type| {1318 _ = try lookup.typeToIndex(info.return_type, param_kind);
1307 if (!param_type.hasRuntimeBitsIgnoreComptime()) continue;1319 for (info.param_types) |param_type| {
1308 _ = try lookup.typeToIndex(param_type, param_kind);1320 if (!param_type.hasRuntimeBitsIgnoreComptime()) continue;
1321 _ = try lookup.typeToIndex(param_type, param_kind);
1322 }
1309 }1323 }
1310 }1324 self.init(if (info.is_var_args) .varargs_function else .function);
1311 self.init(if (info.is_var_args) .varargs_function else .function);1325 } else self.init(.void);
1312 },1326 },
1313 }1327 }
1314 }1328 }
...@@ -1499,126 +1513,95 @@ pub const CType = extern union {...@@ -1499,126 +1513,95 @@ pub const CType = extern union {
1499 .@"union",1513 .@"union",
1500 .packed_struct,1514 .packed_struct,
1501 .packed_union,1515 .packed_union,
1502 => switch (ty.zigTypeTag()) {1516 => {
1503 .Struct => {1517 const zig_ty_tag = ty.zigTypeTag();
1504 const fields_len = ty.structFieldCount();1518 const fields_len = switch (zig_ty_tag) {
15051519 .Struct => ty.structFieldCount(),
1506 var c_fields_len: usize = 0;1520 .Union => ty.unionFields().count(),
1507 for (0..fields_len) |field_i| {1521 else => unreachable,
1508 const field_ty = ty.structFieldType(field_i);1522 };
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 },
15571523
1558 else => unreachable,1524 var c_fields_len: usize = 0;
1559 }1525 for (0..fields_len) |field_i| {
1560 },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 => {1532 const fields_pl = try arena.alloc(Payload.Fields.Field, c_fields_len);
1563 const union_fields = ty.unionFields();1533 var c_field_i: usize = 0;
1564 const fields_len = union_fields.count();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;1558 switch (t) {
1567 for (0..fields_len) |field_i| {1559 .fwd_anon_struct,
1568 const field_ty = ty.structFieldType(field_i);1560 .fwd_anon_union,
1569 if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue;1561 => {
1570 c_fields_len += 1;1562 const anon_pl = try arena.create(Payload.Fields);
1571 }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);1567 .unnamed_struct,
1574 var field_i: usize = 0;1568 .unnamed_union,
1575 var c_field_i: usize = 0;1569 .packed_unnamed_struct,
1576 var field_it = union_fields.iterator();1570 .packed_unnamed_union,
1577 while (field_it.next()) |field| {1571 => {
1578 defer field_i += 1;1572 const unnamed_pl = try arena.create(Payload.Unnamed);
1579 if (!field.value_ptr.ty.hasRuntimeBitsIgnoreComptime()) continue;1573 unnamed_pl.* = .{ .base = .{ .tag = t }, .data = .{
15801574 .fields = fields_pl,
1581 fields_pl[c_field_i] = .{1575 .owner_decl = ty.getOwnerDecl(),
1582 .name = try arena.dupeZ(u8, field.key_ptr.*),1576 .id = if (ty.unionTagTypeSafety()) |_| 0 else unreachable,
1583 .type = store.set.typeToIndex(field.value_ptr.ty, target, switch (kind) {1577 } };
1584 .forward, .forward_parameter => unreachable,1578 return initPayload(unnamed_pl);
1585 .complete, .parameter, .payload => .complete,1579 },
1586 .global => .global,
1587 }).?,
1588 .alignas = Payload.Fields.AlignAs.fieldAlign(ty, field_i, target),
1589 };
1590 c_field_i += 1;
1591 }
15921580
1593 switch (kind) {1581 .anon_struct,
1594 .forward, .forward_parameter => unreachable,1582 .anon_union,
1595 .complete, .parameter, .global => {1583 .@"struct",
1596 const union_pl = try arena.create(Payload.Aggregate);1584 .@"union",
1597 union_pl.* = .{ .base = .{ .tag = t }, .data = .{1585 .packed_struct,
1598 .fields = fields_pl,1586 .packed_union,
1599 .fwd_decl = store.set.typeToIndex(ty, target, .forward).?,1587 => {
1600 } };1588 const struct_pl = try arena.create(Payload.Aggregate);
1601 return initPayload(union_pl);1589 struct_pl.* = .{ .base = .{ .tag = t }, .data = .{
1602 },1590 .fields = fields_pl,
1603 .payload => if (ty.unionTagTypeSafety()) |_| {1591 .fwd_decl = store.set.typeToIndex(ty, target, .forward).?,
1604 const union_pl = try arena.create(Payload.Unnamed);1592 } };
1605 union_pl.* = .{ .base = .{ .tag = t }, .data = .{1593 return initPayload(struct_pl);
1606 .fields = fields_pl,1594 },
1607 .owner_decl = ty.getOwnerDecl(),
1608 .id = 0,
1609 } };
1610 return initPayload(union_pl);
1611 } else unreachable,
1612 }
1613 },
16141595
1615 else => unreachable,1596 else => unreachable,
1597 }
1616 },1598 },
16171599
1618 .function,1600 .function,
1619 .varargs_function,1601 .varargs_function,
1620 => {1602 => {
1621 const info = ty.fnInfo();1603 const info = ty.fnInfo();
1604 assert(!info.is_generic);
1622 const param_kind: Kind = switch (kind) {1605 const param_kind: Kind = switch (kind) {
1623 .forward, .forward_parameter => .forward_parameter,1606 .forward, .forward_parameter => .forward_parameter,
1624 .complete, .parameter, .global => .parameter,1607 .complete, .parameter, .global => .parameter,
...@@ -1707,14 +1690,19 @@ pub const CType = extern union {...@@ -1707,14 +1690,19 @@ pub const CType = extern union {
1707 ]u8 = undefined;1690 ]u8 = undefined;
1708 const c_fields = cty.cast(Payload.Fields).?.data;1691 const c_fields = cty.cast(Payload.Fields).?.data;
17091692
1693 const zig_ty_tag = ty.zigTypeTag();
1710 var c_field_i: usize = 0;1694 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| {
1712 const field_ty = ty.structFieldType(field_i);1700 const field_ty = ty.structFieldType(field_i);
1713 if (ty.structFieldIsComptime(field_i) or1701 if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i)) or
1714 !field_ty.hasRuntimeBitsIgnoreComptime()) continue;1702 !field_ty.hasRuntimeBitsIgnoreComptime()) continue;
17151703
1704 defer c_field_i += 1;
1716 const c_field = &c_fields[c_field_i];1705 const c_field = &c_fields[c_field_i];
1717 c_field_i += 1;
17181706
1719 if (!self.eqlRecurse(field_ty, c_field.type, switch (self.kind) {1707 if (!self.eqlRecurse(field_ty, c_field.type, switch (self.kind) {
1720 .forward, .forward_parameter => .forward,1708 .forward, .forward_parameter => .forward,
...@@ -1725,8 +1713,11 @@ pub const CType = extern union {...@@ -1725,8 +1713,11 @@ pub const CType = extern union {
1725 u8,1713 u8,
1726 if (ty.isSimpleTuple())1714 if (ty.isSimpleTuple())
1727 std.fmt.bufPrint(&name_buf, "f{}", .{field_i}) catch unreachable1715 std.fmt.bufPrint(&name_buf, "f{}", .{field_i}) catch unreachable
1728 else1716 else switch (zig_ty_tag) {
1729 ty.structFieldName(field_i),1717 .Struct => ty.structFieldName(field_i),
1718 .Union => ty.unionFields().keys()[field_i],
1719 else => unreachable,
1720 },
1730 mem.span(c_field.name),1721 mem.span(c_field.name),
1731 ) or Payload.Fields.AlignAs.fieldAlign(ty, field_i, target).@"align" !=1722 ) or Payload.Fields.AlignAs.fieldAlign(ty, field_i, target).@"align" !=
1732 c_field.alignas.@"align") return false;1723 c_field.alignas.@"align") return false;
...@@ -1764,6 +1755,7 @@ pub const CType = extern union {...@@ -1764,6 +1755,7 @@ pub const CType = extern union {
1764 if (ty.zigTypeTag() != .Fn) return false;1755 if (ty.zigTypeTag() != .Fn) return false;
17651756
1766 const info = ty.fnInfo();1757 const info = ty.fnInfo();
1758 assert(!info.is_generic);
1767 const data = cty.cast(Payload.Function).?.data;1759 const data = cty.cast(Payload.Function).?.data;
1768 const param_kind: Kind = switch (self.kind) {1760 const param_kind: Kind = switch (self.kind) {
1769 .forward, .forward_parameter => .forward_parameter,1761 .forward, .forward_parameter => .forward_parameter,
...@@ -1824,29 +1816,30 @@ pub const CType = extern union {...@@ -1824,29 +1816,30 @@ pub const CType = extern union {
1824 var name_buf: [1816 var name_buf: [
1825 std.fmt.count("f{}", .{std.math.maxInt(usize)})1817 std.fmt.count("f{}", .{std.math.maxInt(usize)})
1826 ]u8 = undefined;1818 ]u8 = undefined;
1819
1820 const zig_ty_tag = ty.zigTypeTag();
1827 for (0..switch (ty.zigTypeTag()) {1821 for (0..switch (ty.zigTypeTag()) {
1828 .Struct => ty.structFieldCount(),1822 .Struct => ty.structFieldCount(),
1829 .Union => ty.unionFields().count(),1823 .Union => ty.unionFields().count(),
1830 else => unreachable,1824 else => unreachable,
1831 }) |field_i| {1825 }) |field_i| {
1832 const field_ty = ty.structFieldType(field_i);1826 const field_ty = ty.structFieldType(field_i);
1833 if (ty.structFieldIsComptime(field_i) or1827 if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i)) or
1834 !field_ty.hasRuntimeBitsIgnoreComptime()) continue;1828 !field_ty.hasRuntimeBitsIgnoreComptime()) continue;
18351829
1836 self.updateHasherRecurse(1830 self.updateHasherRecurse(hasher, field_ty, switch (self.kind) {
1837 hasher,1831 .forward, .forward_parameter => .forward,
1838 ty.structFieldType(field_i),1832 .complete, .parameter => .complete,
1839 switch (self.kind) {1833 .global => .global,
1840 .forward, .forward_parameter => .forward,1834 .payload => unreachable,
1841 .complete, .parameter => .complete,1835 });
1842 .global => .global,
1843 .payload => unreachable,
1844 },
1845 );
1846 hasher.update(if (ty.isSimpleTuple())1836 hasher.update(if (ty.isSimpleTuple())
1847 std.fmt.bufPrint(&name_buf, "f{}", .{field_i}) catch unreachable1837 std.fmt.bufPrint(&name_buf, "f{}", .{field_i}) catch unreachable
1848 else1838 else switch (zig_ty_tag) {
1849 ty.structFieldName(field_i));1839 .Struct => ty.structFieldName(field_i),
1840 .Union => ty.unionFields().keys()[field_i],
1841 else => unreachable,
1842 });
1850 autoHash(1843 autoHash(
1851 hasher,1844 hasher,
1852 Payload.Fields.AlignAs.fieldAlign(ty, field_i, target).@"align",1845 Payload.Fields.AlignAs.fieldAlign(ty, field_i, target).@"align",
...@@ -1878,6 +1871,7 @@ pub const CType = extern union {...@@ -1878,6 +1871,7 @@ pub const CType = extern union {
1878 .varargs_function,1871 .varargs_function,
1879 => {1872 => {
1880 const info = ty.fnInfo();1873 const info = ty.fnInfo();
1874 assert(!info.is_generic);
1881 const param_kind: Kind = switch (self.kind) {1875 const param_kind: Kind = switch (self.kind) {
1882 .forward, .forward_parameter => .forward_parameter,1876 .forward, .forward_parameter => .forward_parameter,
1883 .complete, .parameter, .global => .parameter,1877 .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)...@@ -247,8 +247,8 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node)
247247
248 const abi_define = abiDefine(comp);248 const abi_define = abiDefine(comp);
249249
250 // Covers defines, zig.h, ctypes, asm, lazy fwd, lazy code.250 // Covers defines, zig.h, ctypes, asm, lazy fwd.
251 try f.all_buffers.ensureUnusedCapacity(gpa, 6);251 try f.all_buffers.ensureUnusedCapacity(gpa, 5);
252252
253 if (abi_define) |buf| f.appendBufAssumeCapacity(buf);253 if (abi_define) |buf| f.appendBufAssumeCapacity(buf);
254 f.appendBufAssumeCapacity(zig_h);254 f.appendBufAssumeCapacity(zig_h);
...@@ -263,8 +263,8 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node)...@@ -263,8 +263,8 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node)
263 f.appendBufAssumeCapacity(asm_buf.items);263 f.appendBufAssumeCapacity(asm_buf.items);
264 }264 }
265265
266 const lazy_indices = f.all_buffers.items.len;266 const lazy_index = f.all_buffers.items.len;
267 f.all_buffers.items.len += 2;267 f.all_buffers.items.len += 1;
268268
269 try self.flushErrDecls(&f.lazy_db);269 try self.flushErrDecls(&f.lazy_db);
270270
...@@ -297,6 +297,7 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node)...@@ -297,6 +297,7 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node)
297297
298 {298 {
299 // We need to flush lazy ctypes after flushing all decls but before flushing any decl ctypes.299 // 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.
300 assert(f.ctypes.count() == 0);301 assert(f.ctypes.count() == 0);
301 try self.flushCTypes(&f, .none, f.lazy_db.ctypes);302 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)...@@ -305,30 +306,22 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node)
305 try self.flushCTypes(&f, entry.key_ptr.toOptional(), entry.value_ptr.ctypes);306 try self.flushCTypes(&f, entry.key_ptr.toOptional(), entry.value_ptr.ctypes);
306 }307 }
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
322 f.all_buffers.items[ctypes_index] = .{309 f.all_buffers.items[ctypes_index] = .{
323 .iov_base = if (f.ctypes_buf.items.len > 0) f.ctypes_buf.items.ptr else "",310 .iov_base = if (f.ctypes_buf.items.len > 0) f.ctypes_buf.items.ptr else "",
324 .iov_len = f.ctypes_buf.items.len,311 .iov_len = f.ctypes_buf.items.len,
325 };312 };
326 f.file_size += f.ctypes_buf.items.len;313 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
328 // Now the code.321 // Now the code.
329 try f.all_buffers.ensureUnusedCapacity(gpa, decl_values.len);322 try f.all_buffers.ensureUnusedCapacity(gpa, 1 + decl_values.len);
330 for (decl_values) |decl|323 f.appendBufAssumeCapacity(f.lazy_db.code.items);
331 f.appendBufAssumeCapacity(decl.code.items);324 for (decl_values) |decl| f.appendBufAssumeCapacity(decl.code.items);
332325
333 const file = self.base.file.?;326 const file = self.base.file.?;
334 try file.setEndPos(f.file_size);327 try file.setEndPos(f.file_size);
src/target.zig+1
...@@ -723,6 +723,7 @@ pub fn supportsFunctionAlignment(target: std.Target) bool {...@@ -723,6 +723,7 @@ pub fn supportsFunctionAlignment(target: std.Target) bool {
723pub fn supportsTailCall(target: std.Target, backend: std.builtin.CompilerBackend) bool {723pub fn supportsTailCall(target: std.Target, backend: std.builtin.CompilerBackend) bool {
724 switch (backend) {724 switch (backend) {
725 .stage1, .stage2_llvm => return @import("codegen/llvm.zig").supportsTailCall(target),725 .stage1, .stage2_llvm => return @import("codegen/llvm.zig").supportsTailCall(target),
726 .stage2_c => return true,
726 else => return false,727 else => return false,
727 }728 }
728}729}
test/behavior/field_parent_ptr.zig-3
...@@ -48,7 +48,6 @@ fn testParentFieldPtrFirst(a: *const bool) !void {...@@ -48,7 +48,6 @@ fn testParentFieldPtrFirst(a: *const bool) !void {
48test "@fieldParentPtr untagged union" {48test "@fieldParentPtr untagged union" {
49 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;49 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
50 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO50 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
51 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
52 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO51 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
5352
54 try testFieldParentPtrUnion(&bar.c);53 try testFieldParentPtrUnion(&bar.c);
...@@ -75,7 +74,6 @@ fn testFieldParentPtrUnion(c: *const i32) !void {...@@ -75,7 +74,6 @@ fn testFieldParentPtrUnion(c: *const i32) !void {
75test "@fieldParentPtr tagged union" {74test "@fieldParentPtr tagged union" {
76 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;75 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
77 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO76 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
78 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
79 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO77 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
8078
81 try testFieldParentPtrTaggedUnion(&bar_tagged.c);79 try testFieldParentPtrTaggedUnion(&bar_tagged.c);
...@@ -102,7 +100,6 @@ fn testFieldParentPtrTaggedUnion(c: *const i32) !void {...@@ -102,7 +100,6 @@ fn testFieldParentPtrTaggedUnion(c: *const i32) !void {
102test "@fieldParentPtr extern union" {100test "@fieldParentPtr extern union" {
103 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;101 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
104 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO102 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
105 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
106 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO103 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
107104
108 try testFieldParentPtrExternUnion(&bar_extern.c);105 try testFieldParentPtrExternUnion(&bar_extern.c);
test/behavior/packed-struct.zig-1
...@@ -603,7 +603,6 @@ test "packed struct initialized in bitcast" {...@@ -603,7 +603,6 @@ test "packed struct initialized in bitcast" {
603test "pointer to container level packed struct field" {603test "pointer to container level packed struct field" {
604 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;604 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
605 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;605 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
606 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
607 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;606 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
608 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;607 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" {...@@ -507,7 +507,6 @@ test "ptrCast comptime known slice to C pointer" {
507}507}
508508
509test "ptrToInt on a generic function" {509test "ptrToInt on a generic function" {
510 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
511 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO510 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
512 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO511 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
513 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO512 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 {...@@ -96,10 +96,9 @@ fn doNothingWithFirstArg(args: anytype) void {
96test "simple variadic function" {96test "simple variadic function" {
97 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO97 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
98 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO98 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
99 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
100 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO99 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
101 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO100 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) {
103 // https://github.com/ziglang/zig/issues/14096102 // https://github.com/ziglang/zig/issues/14096
104 return error.SkipZigTest;103 return error.SkipZigTest;
105 }104 }
...@@ -112,6 +111,12 @@ test "simple variadic function" {...@@ -112,6 +111,12 @@ test "simple variadic function" {
112 return @cVaArg(&ap, c_int);111 return @cVaArg(&ap, c_int);
113 }112 }
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
115 fn add(count: c_int, ...) callconv(.C) c_int {120 fn add(count: c_int, ...) callconv(.C) c_int {
116 var ap = @cVaStart();121 var ap = @cVaStart();
117 defer @cVaEnd(&ap);122 defer @cVaEnd(&ap);
...@@ -124,8 +129,13 @@ test "simple variadic function" {...@@ -124,8 +129,13 @@ test "simple variadic function" {
124 }129 }
125 };130 };
126131
127 try std.testing.expectEqual(@as(c_int, 0), S.simple(@as(c_int, 0)));132 if (builtin.zig_backend != .stage2_c) {
128 try std.testing.expectEqual(@as(c_int, 1024), S.simple(@as(c_int, 1024)));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)));
129 try std.testing.expectEqual(@as(c_int, 0), S.add(0));139 try std.testing.expectEqual(@as(c_int, 0), S.add(0));
130 try std.testing.expectEqual(@as(c_int, 1), S.add(1, @as(c_int, 1)));140 try std.testing.expectEqual(@as(c_int, 1), S.add(1, @as(c_int, 1)));
131 try std.testing.expectEqual(@as(c_int, 3), S.add(2, @as(c_int, 1), @as(c_int, 2)));141 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" {...@@ -134,10 +144,9 @@ test "simple variadic function" {
134test "variadic functions" {144test "variadic functions" {
135 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO145 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
136 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO146 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
137 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
138 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO147 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
139 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO148 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) {
141 // https://github.com/ziglang/zig/issues/14096150 // https://github.com/ziglang/zig/issues/14096
142 return error.SkipZigTest;151 return error.SkipZigTest;
143 }152 }
...@@ -178,10 +187,9 @@ test "variadic functions" {...@@ -178,10 +187,9 @@ test "variadic functions" {
178test "copy VaList" {187test "copy VaList" {
179 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO188 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
180 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO189 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
181 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
182 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO190 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
183 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO191 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) {
185 // https://github.com/ziglang/zig/issues/14096193 // https://github.com/ziglang/zig/issues/14096
186 return error.SkipZigTest;194 return error.SkipZigTest;
187 }195 }