authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2022-10-24 10:42:41-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2022-10-25 05:11:29-04:00
logab468d57e3af5d158dfbe0229cc451ce62dd80dc
treed628f8800d7a102182f85cfc6bc17154ed154497
parent15df64ade8e460141d6485340ca0f88d21f03c47

cbe: implement packed structs

Sometimes you have to break a test to make progress :)

7 files changed, 724 insertions(+), 323 deletions(-)

lib/include/zig.h+48-47
......@@ -316,19 +316,28 @@ zig_extern_c void *memset (void *, int, zig_usize);
316316#define zig_maxInt(Type, bits) zig_shr_##Type(zig_maxInt_##Type, (zig_bitSizeOf(zig_##Type) - bits))
317317#define zig_minInt(Type, bits) zig_not_##Type(zig_maxInt(Type, bits), bits)
318318
319#define zig_int_operator(Type, RhsType, operation, operator) \
320 static inline zig_##Type zig_##operation##_##Type(zig_##Type lhs, zig_##RhsType rhs) { \
321 return lhs operator rhs; \
322 }
323#define zig_int_operators(w) \
324 zig_int_operator(u##w, u##w, and, &) \
325 zig_int_operator(i##w, i##w, and, &) \
326 zig_int_operator(u##w, u##w, or, |) \
327 zig_int_operator(i##w, i##w, or, |) \
328 zig_int_operator(u##w, u##w, xor, ^) \
329 zig_int_operator(i##w, i##w, xor, ^) \
330 zig_int_operator(u##w, u8, shl, <<) \
331 zig_int_operator(i##w, u8, shl, <<) \
332 zig_int_operator(u##w, u8, shr, >>) \
333 zig_int_operator(u##w, u##w, div_floor, /) \
334 zig_int_operator(u##w, u##w, mod, %)
335zig_int_operators(8)
336zig_int_operators(16)
337zig_int_operators(32)
338zig_int_operators(64)
339
319340#define zig_int_helpers(w) \
320 static inline zig_u##w zig_shl_u##w(zig_u##w lhs, zig_u8 rhs) { \
321 return lhs << rhs; \
322 } \
323\
324 static inline zig_i##w zig_shl_i##w(zig_i##w lhs, zig_u8 rhs) { \
325 return lhs << rhs; \
326 } \
327\
328 static inline zig_u##w zig_shr_u##w(zig_u##w lhs, zig_u8 rhs) { \
329 return lhs >> rhs; \
330 } \
331\
332341 static inline zig_i##w zig_shr_i##w(zig_i##w lhs, zig_u8 rhs) { \
333342 zig_i##w sign_mask = lhs < zig_as_i##w(0) ? zig_as_i##w(-1) : zig_as_i##w(0); \
334343 return ((lhs ^ sign_mask) >> rhs) ^ sign_mask; \
......@@ -351,18 +360,10 @@ zig_extern_c void *memset (void *, int, zig_usize);
351360 return (val & zig_as_u##w(1) << (bits - zig_as_u8(1))) != 0 \
352361 ? val | zig_minInt(i##w, bits) : val & zig_maxInt(i##w, bits); \
353362 } \
354\
355 static inline zig_u##w zig_div_floor_u##w(zig_u##w lhs, zig_u##w rhs) { \
356 return lhs / rhs; \
357 } \
358363\
359364 static inline zig_i##w zig_div_floor_i##w(zig_i##w lhs, zig_i##w rhs) { \
360365 return lhs / rhs - (((lhs ^ rhs) & (lhs % rhs)) < zig_as_i##w(0)); \
361366 } \
362\
363 static inline zig_u##w zig_mod_u##w(zig_u##w lhs, zig_u##w rhs) { \
364 return lhs % rhs; \
365 } \
366367\
367368 static inline zig_i##w zig_mod_i##w(zig_i##w lhs, zig_i##w rhs) { \
368369 zig_i##w rem = lhs % rhs; \
......@@ -969,12 +970,12 @@ typedef signed __int128 zig_i128;
969970#define zig_lo_i128(val) ((zig_u64)((val) >> 0))
970971#define zig_bitcast_u128(val) ((zig_u128)(val))
971972#define zig_bitcast_i128(val) ((zig_i128)(val))
972#define zig_cmp_int128(ZigType, CType) \
973 static inline zig_i8 zig_cmp_##ZigType(CType lhs, CType rhs) { \
973#define zig_cmp_int128(Type) \
974 static inline zig_i8 zig_cmp_##Type(zig_##Type lhs, zig_##Type rhs) { \
974975 return (lhs > rhs) - (lhs < rhs); \
975976 }
976#define zig_bit_int128(ZigType, CType, operation, operator) \
977 static inline CType zig_##operation##_##ZigType(CType lhs, CType rhs) { \
977#define zig_bit_int128(Type, operation, operator) \
978 static inline zig_##Type zig_##operation##_##Type(zig_##Type lhs, zig_##Type rhs) { \
978979 return lhs operator rhs; \
979980 }
980981
......@@ -996,15 +997,15 @@ typedef struct { zig_align(16) zig_i64 hi; zig_u64 lo; } zig_i128;
996997#define zig_lo_i128(val) ((val).lo)
997998#define zig_bitcast_u128(val) zig_as_u128((zig_u64)(val).hi, (val).lo)
998999#define zig_bitcast_i128(val) zig_as_i128((zig_i64)(val).hi, (val).lo)
999#define zig_cmp_int128(ZigType, CType) \
1000 static inline zig_c_int zig_cmp_##ZigType(CType lhs, CType rhs) { \
1000#define zig_cmp_int128(Type) \
1001 static inline zig_i8 zig_cmp_##Type(zig_##Type lhs, zig_##Type rhs) { \
10011002 return (lhs.hi == rhs.hi) \
10021003 ? (lhs.lo > rhs.lo) - (lhs.lo < rhs.lo) \
10031004 : (lhs.hi > rhs.hi) - (lhs.hi < rhs.hi); \
10041005 }
1005#define zig_bit_int128(ZigType, CType, operation, operator) \
1006 static inline CType zig_##operation##_##ZigType(CType lhs, CType rhs) { \
1007 return (CType){ .hi = lhs.hi operator rhs.hi, .lo = lhs.lo operator rhs.lo }; \
1006#define zig_bit_int128(Type, operation, operator) \
1007 static inline zig_##Type zig_##operation##_##Type(zig_##Type lhs, zig_##Type rhs) { \
1008 return (zig_##Type){ .hi = lhs.hi operator rhs.hi, .lo = lhs.lo operator rhs.lo }; \
10081009 }
10091010
10101011#endif /* zig_has_int128 */
......@@ -1014,17 +1015,17 @@ typedef struct { zig_align(16) zig_i64 hi; zig_u64 lo; } zig_i128;
10141015#define zig_minInt_i128 zig_as_i128(zig_minInt_i64, zig_minInt_u64)
10151016#define zig_maxInt_i128 zig_as_i128(zig_maxInt_i64, zig_maxInt_u64)
10161017
1017zig_cmp_int128(u128, zig_u128)
1018zig_cmp_int128(i128, zig_i128)
1018zig_cmp_int128(u128)
1019zig_cmp_int128(i128)
10191020
1020zig_bit_int128(u128, zig_u128, and, &)
1021zig_bit_int128(i128, zig_i128, and, &)
1021zig_bit_int128(u128, and, &)
1022zig_bit_int128(i128, and, &)
10221023
1023zig_bit_int128(u128, zig_u128, or, |)
1024zig_bit_int128(i128, zig_i128, or, |)
1024zig_bit_int128(u128, or, |)
1025zig_bit_int128(i128, or, |)
10251026
1026zig_bit_int128(u128, zig_u128, xor, ^)
1027zig_bit_int128(i128, zig_i128, xor, ^)
1027zig_bit_int128(u128, xor, ^)
1028zig_bit_int128(i128, xor, ^)
10281029
10291030static inline zig_u128 zig_shr_u128(zig_u128 lhs, zig_u8 rhs);
10301031
......@@ -1164,7 +1165,7 @@ static inline zig_i128 zig_mod_i128(zig_i128 lhs, zig_i128 rhs) {
11641165#define zig_mod_u128 zig_rem_u128
11651166
11661167static inline zig_i128 zig_shr_i128(zig_i128 lhs, zig_u8 rhs) {
1167 zig_i128 sign_mask = zig_cmp_i128(lhs, zig_as_i128(0, 0)) < 0 ? zig_as_i128(-1, UINT64_MAX) : zig_as_i128(0, 0);
1168 zig_i128 sign_mask = zig_cmp_i128(lhs, zig_as_i128(0, 0)) < zig_as_i8(0) ? zig_as_i128(-1, UINT64_MAX) : zig_as_i128(0, 0);
11681169 return zig_xor_i128(zig_bitcast_i128(zig_shr_u128(zig_bitcast_u128(zig_xor_i128(lhs, sign_mask)), rhs)), sign_mask);
11691170}
11701171
......@@ -1218,8 +1219,8 @@ static inline zig_bool zig_shlo_u128(zig_u128 *res, zig_u128 lhs, zig_u8 rhs, zi
12181219static inline zig_bool zig_shlo_i128(zig_i128 *res, zig_i128 lhs, zig_u8 rhs, zig_u8 bits) {
12191220 *res = zig_shlw_i128(lhs, rhs, bits);
12201221 zig_i128 mask = zig_bitcast_i128(zig_shl_u128(zig_maxInt_u128, bits - rhs - zig_as_u8(1)));
1221 return zig_cmp_i128(zig_and_i128(lhs, mask), zig_as_i128(0, 0)) != 0 &&
1222 zig_cmp_i128(zig_and_i128(lhs, mask), mask) != 0;
1222 return zig_cmp_i128(zig_and_i128(lhs, mask), zig_as_i128(0, 0)) != zig_as_i8(0) &&
1223 zig_cmp_i128(zig_and_i128(lhs, mask), mask) != zig_as_i8(0);
12231224}
12241225
12251226static inline zig_bool zig_addo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, zig_u8 bits) {
......@@ -1316,15 +1317,15 @@ static inline zig_bool zig_subo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs)
13161317
13171318static inline zig_u128 zig_shls_u128(zig_u128 lhs, zig_u128 rhs, zig_u8 bits) {
13181319 zig_u128 res;
1319 if (zig_cmp_u128(rhs, zig_as_u128(0, bits)) >= 0)
1320 return zig_cmp_u128(lhs, zig_as_u128(0, 0)) != 0 ? zig_maxInt(u128, bits) : lhs;
1320 if (zig_cmp_u128(rhs, zig_as_u128(0, bits)) >= zig_as_i8(0))
1321 return zig_cmp_u128(lhs, zig_as_u128(0, 0)) != zig_as_i8(0) ? zig_maxInt(u128, bits) : lhs;
13211322 return zig_shlo_u128(&res, lhs, (zig_u8)rhs, bits) ? zig_maxInt(u128, bits) : res;
13221323}
13231324
13241325static inline zig_i128 zig_shls_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) {
13251326 zig_i128 res;
1326 if (zig_cmp_u128(zig_bitcast_u128(rhs), zig_as_u128(0, bits)) < 0 && !zig_shlo_i128(&res, lhs, rhs, bits)) return res;
1327 return zig_cmp_i128(lhs, zig_as_i128(0, 0)) < 0 ? zig_minInt(i128, bits) : zig_maxInt(i128, bits);
1327 if (zig_cmp_u128(zig_bitcast_u128(rhs), zig_as_u128(0, bits)) < zig_as_i8(0) && !zig_shlo_i128(&res, lhs, rhs, bits)) return res;
1328 return zig_cmp_i128(lhs, zig_as_i128(0, 0)) < zig_as_i8(0) ? zig_minInt(i128, bits) : zig_maxInt(i128, bits);
13281329}
13291330
13301331static inline zig_u128 zig_adds_u128(zig_u128 lhs, zig_u128 rhs, zig_u8 bits) {
......@@ -1335,7 +1336,7 @@ static inline zig_u128 zig_adds_u128(zig_u128 lhs, zig_u128 rhs, zig_u8 bits) {
13351336static inline zig_i128 zig_adds_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) {
13361337 zig_i128 res;
13371338 if (!zig_addo_i128(&res, lhs, rhs, bits)) return res;
1338 return zig_cmp_i128(res, zig_as_i128(0, 0)) >= 0 ? zig_minInt(i128, bits) : zig_maxInt(i128, bits);
1339 return zig_cmp_i128(res, zig_as_i128(0, 0)) >= zig_as_i8(0) ? zig_minInt(i128, bits) : zig_maxInt(i128, bits);
13391340}
13401341
13411342static inline zig_u128 zig_subs_u128(zig_u128 lhs, zig_u128 rhs, zig_u8 bits) {
......@@ -1346,7 +1347,7 @@ static inline zig_u128 zig_subs_u128(zig_u128 lhs, zig_u128 rhs, zig_u8 bits) {
13461347static inline zig_i128 zig_subs_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) {
13471348 zig_i128 res;
13481349 if (!zig_subo_i128(&res, lhs, rhs, bits)) return res;
1349 return zig_cmp_i128(res, zig_as_i128(0, 0)) >= 0 ? zig_minInt(i128, bits) : zig_maxInt(i128, bits);
1350 return zig_cmp_i128(res, zig_as_i128(0, 0)) >= zig_as_i8(0) ? zig_minInt(i128, bits) : zig_maxInt(i128, bits);
13501351}
13511352
13521353static inline zig_u128 zig_muls_u128(zig_u128 lhs, zig_u128 rhs, zig_u8 bits) {
......@@ -1357,7 +1358,7 @@ static inline zig_u128 zig_muls_u128(zig_u128 lhs, zig_u128 rhs, zig_u8 bits) {
13571358static inline zig_i128 zig_muls_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) {
13581359 zig_i128 res;
13591360 if (!zig_mulo_i128(&res, lhs, rhs, bits)) return res;
1360 return zig_cmp_i128(zig_xor_i128(lhs, rhs), zig_as_i128(0, 0)) < 0 ? zig_minInt(i128, bits) : zig_maxInt(i128, bits);
1361 return zig_cmp_i128(zig_xor_i128(lhs, rhs), zig_as_i128(0, 0)) < zig_as_i8(0) ? zig_minInt(i128, bits) : zig_maxInt(i128, bits);
13611362}
13621363
13631364static inline zig_u8 zig_clz_u128(zig_u128 val, zig_u8 bits) {
src/codegen/c.zig+675-268
......@@ -18,7 +18,7 @@ const Air = @import("../Air.zig");
1818const Liveness = @import("../Liveness.zig");
1919const CType = @import("../type.zig").CType;
2020
21const Mutability = enum { Const, Mut };
21const Mutability = enum { Const, ConstArgument, Mut };
2222const BigInt = std.math.big.int;
2323
2424pub const CValue = union(enum) {
......@@ -254,24 +254,20 @@ pub const Function = struct {
254254
255255 const val = f.air.value(inst).?;
256256 const ty = f.air.typeOf(inst);
257 switch (ty.zigTypeTag()) {
258 .Array => {
259 const writer = f.object.code_header.writer();
260 const decl_c_value = f.allocLocalValue();
261 gop.value_ptr.* = decl_c_value;
262 try writer.writeAll("static ");
263 try f.object.dg.renderTypeAndName(writer, ty, decl_c_value, .Const, 0, .Complete);
264 try writer.writeAll(" = ");
265 try f.object.dg.renderValue(writer, ty, val, .Initializer);
266 try writer.writeAll(";\n ");
267 return decl_c_value;
268 },
269 else => {
270 const result = CValue{ .constant = inst };
271 gop.value_ptr.* = result;
272 return result;
273 },
274 }
257
258 const result = if (lowersToArray(ty, f.object.dg.module.getTarget())) result: {
259 const writer = f.object.code_header.writer();
260 const decl_c_value = f.allocLocalValue();
261 try writer.writeAll("static ");
262 try f.object.dg.renderTypeAndName(writer, ty, decl_c_value, .Const, 0, .Complete);
263 try writer.writeAll(" = ");
264 try f.object.dg.renderValue(writer, ty, val, .Initializer);
265 try writer.writeAll(";\n ");
266 break :result decl_c_value;
267 } else CValue{ .constant = inst };
268
269 gop.value_ptr.* = result;
270 return result;
275271 }
276272
277273 fn wantSafety(f: *Function) bool {
......@@ -374,7 +370,7 @@ pub const Function = struct {
374370
375371 fn renderTypeForBuiltinFnName(f: *Function, writer: anytype, ty: Type) !void {
376372 const target = f.object.dg.module.getTarget();
377 const c_bits = if (ty.isInt()) c_bits: {
373 const c_bits = if (ty.isAbiInt()) c_bits: {
378374 const int_info = ty.intInfo(target);
379375 try writer.writeByte(signAbbrev(int_info.signedness));
380376 break :c_bits toCIntBits(int_info.bits) orelse
......@@ -393,21 +389,21 @@ pub const Function = struct {
393389 switch (info) {
394390 .None => {},
395391 .Range => {
396 var arena = std.heap.ArenaAllocator.init(f.object.dg.module.gpa);
392 var arena = std.heap.ArenaAllocator.init(f.object.dg.gpa);
397393 defer arena.deinit();
398394
399 const expected_contents = union { u: Value.Payload.U64, i: Value.Payload.I64 };
400 var stack align(@alignOf(expected_contents)) =
401 std.heap.stackFallback(@sizeOf(expected_contents), arena.allocator());
395 const ExpectedContents = union { u: Value.Payload.U64, i: Value.Payload.I64 };
396 var stack align(@alignOf(ExpectedContents)) =
397 std.heap.stackFallback(@sizeOf(ExpectedContents), arena.allocator());
402398
403399 const int_info = ty.intInfo(target);
404400 if (int_info.signedness == .signed) {
405401 const min_val = try ty.minInt(stack.get(), target);
406 try writer.print(", {x}", .{try f.fmtIntLiteral(ty, min_val)});
402 try writer.print(", {x}", .{try f.object.dg.fmtIntLiteral(ty, min_val)});
407403 }
408404
409405 const max_val = try ty.maxInt(stack.get(), target);
410 try writer.print(", {x}", .{try f.fmtIntLiteral(ty, max_val)});
406 try writer.print(", {x}", .{try f.object.dg.fmtIntLiteral(ty, max_val)});
411407 },
412408 .Bits => {
413409 var bits_pl = Value.Payload.U64{
......@@ -415,7 +411,7 @@ pub const Function = struct {
415411 .data = ty.bitSize(target),
416412 };
417413 const bits_val = Value.initPayload(&bits_pl.base);
418 try writer.print(", {}", .{try f.fmtIntLiteral(Type.u8, bits_val)});
414 try writer.print(", {}", .{try f.object.dg.fmtIntLiteral(Type.u8, bits_val)});
419415 },
420416 }
421417 }
......@@ -471,7 +467,7 @@ pub const DeclGen = struct {
471467 @setCold(true);
472468 const src = LazySrcLoc.nodeOffset(0);
473469 const src_loc = src.toSrcLoc(dg.decl);
474 dg.error_msg = try Module.ErrorMsg.create(dg.module.gpa, src_loc, format, args);
470 dg.error_msg = try Module.ErrorMsg.create(dg.gpa, src_loc, format, args);
475471 return error.AnalysisFail;
476472 }
477473
......@@ -559,14 +555,55 @@ pub const DeclGen = struct {
559555 try dg.renderDeclValue(writer, ptr_ty, ptr_val, decl_index);
560556 },
561557 .field_ptr => {
558 const ptr_info = ptr_ty.ptrInfo();
562559 const field_ptr = ptr_val.castTag(.field_ptr).?.data;
563560 const container_ty = field_ptr.container_ty;
564561 const index = field_ptr.field_index;
562
563 var container_ptr_ty_pl: Type.Payload.ElemType = .{
564 .base = .{ .tag = .c_mut_pointer },
565 .data = field_ptr.container_ty,
566 };
567 const container_ptr_ty = Type.initPayload(&container_ptr_ty_pl.base);
568
565569 const FieldInfo = struct { name: []const u8, ty: Type };
566570 const field_info: FieldInfo = switch (container_ty.zigTypeTag()) {
567 .Struct => FieldInfo{
568 .name = container_ty.structFields().keys()[index],
569 .ty = container_ty.structFields().values()[index].ty,
571 .Struct => switch (container_ty.containerLayout()) {
572 .Auto, .Extern => FieldInfo{
573 .name = container_ty.structFields().keys()[index],
574 .ty = container_ty.structFields().values()[index].ty,
575 },
576 .Packed => if (ptr_info.data.host_size == 0) {
577 const target = dg.module.getTarget();
578
579 const byte_offset = container_ty.packedStructFieldByteOffset(index, target);
580 var byte_offset_pl = Value.Payload.U64{
581 .base = .{ .tag = .int_u64 },
582 .data = byte_offset,
583 };
584 const byte_offset_val = Value.initPayload(&byte_offset_pl.base);
585
586 var ptr_u8_pl = ptr_info;
587 ptr_u8_pl.data.pointee_type = Type.u8;
588 const ptr_u8_ty = Type.initPayload(&ptr_u8_pl.base);
589
590 try writer.writeAll("&((");
591 try dg.renderTypecast(writer, ptr_u8_ty);
592 try writer.writeByte(')');
593 try dg.renderParentPtr(writer, field_ptr.container_ptr, container_ptr_ty);
594 return writer.print(")[{}]", .{try dg.fmtIntLiteral(Type.usize, byte_offset_val)});
595 } else {
596 var host_pl = Type.Payload.Bits{
597 .base = .{ .tag = .int_unsigned },
598 .data = ptr_info.data.host_size * 8,
599 };
600 const host_ty = Type.initPayload(&host_pl.base);
601
602 try writer.writeByte('(');
603 try dg.renderTypecast(writer, ptr_ty);
604 try writer.writeByte(')');
605 return dg.renderParentPtr(writer, field_ptr.container_ptr, host_ty);
606 },
570607 },
571608 .Union => FieldInfo{
572609 .name = container_ty.unionFields().keys()[index],
......@@ -582,20 +619,16 @@ pub const DeclGen = struct {
582619 },
583620 else => unreachable,
584621 };
585 var container_ptr_ty_pl: Type.Payload.ElemType = .{
586 .base = .{ .tag = .c_mut_pointer },
587 .data = field_ptr.container_ty,
588 };
589 const container_ptr_ty = Type.initPayload(&container_ptr_ty_pl.base);
590622
591623 if (field_info.ty.hasRuntimeBitsIgnoreComptime()) {
592624 try writer.writeAll("&(");
593625 try dg.renderParentPtr(writer, field_ptr.container_ptr, container_ptr_ty);
594 if (field_ptr.container_ty.tag() == .union_tagged or field_ptr.container_ty.tag() == .union_safety_tagged) {
595 try writer.print(")->payload.{ }", .{fmtIdent(field_info.name)});
596 } else {
597 try writer.print(")->{ }", .{fmtIdent(field_info.name)});
626 try writer.writeAll(")->");
627 switch (field_ptr.container_ty.tag()) {
628 .union_tagged, .union_safety_tagged => try writer.writeAll("payload."),
629 else => {},
598630 }
631 try writer.print("{ }", .{fmtIdent(field_info.name)});
599632 } else {
600633 try dg.renderParentPtr(writer, field_ptr.container_ptr, field_info.ty);
601634 }
......@@ -694,25 +727,28 @@ pub const DeclGen = struct {
694727 try dg.renderValue(writer, Type.bool, val, .Initializer);
695728 return writer.writeAll(" }");
696729 },
697 .Struct => {
698 if (location != .Initializer) {
699 try writer.writeByte('(');
700 try dg.renderTypecast(writer, ty);
701 try writer.writeByte(')');
702 }
730 .Struct => switch (ty.containerLayout()) {
731 .Auto, .Extern => {
732 if (location != .Initializer) {
733 try writer.writeByte('(');
734 try dg.renderTypecast(writer, ty);
735 try writer.writeByte(')');
736 }
703737
704 try writer.writeByte('{');
705 var empty = true;
706 for (ty.structFields().values()) |field| {
707 if (!field.ty.hasRuntimeBits()) continue;
738 try writer.writeByte('{');
739 var empty = true;
740 for (ty.structFields().values()) |field| {
741 if (!field.ty.hasRuntimeBits()) continue;
708742
709 if (!empty) try writer.writeByte(',');
710 try dg.renderValue(writer, field.ty, val, .Initializer);
743 if (!empty) try writer.writeByte(',');
744 try dg.renderValue(writer, field.ty, val, .Initializer);
711745
712 empty = false;
713 }
714 if (empty) try writer.print("{x}", .{try dg.fmtIntLiteral(Type.u8, Value.undef)});
715 return writer.writeByte('}');
746 empty = false;
747 }
748 if (empty) try writer.print("{x}", .{try dg.fmtIntLiteral(Type.u8, Value.undef)});
749 return writer.writeByte('}');
750 },
751 .Packed => return writer.print("{x}", .{try dg.fmtIntLiteral(ty, Value.undef)}),
716752 },
717753 .Union => {
718754 if (location != .Initializer) {
......@@ -898,7 +934,7 @@ pub const DeclGen = struct {
898934 },
899935 else => {
900936 // Fall back to generic implementation.
901 var arena = std.heap.ArenaAllocator.init(dg.module.gpa);
937 var arena = std.heap.ArenaAllocator.init(dg.gpa);
902938 defer arena.deinit();
903939 const arena_allocator = arena.allocator();
904940
......@@ -1024,28 +1060,63 @@ pub const DeclGen = struct {
10241060 },
10251061 else => unreachable,
10261062 },
1027 .Struct => {
1028 const field_vals = val.castTag(.aggregate).?.data;
1063 .Struct => switch (ty.containerLayout()) {
1064 .Auto, .Extern => {
1065 const field_vals = val.castTag(.aggregate).?.data;
10291066
1030 if (location != .Initializer) {
1031 try writer.writeByte('(');
1032 try dg.renderTypecast(writer, ty);
1033 try writer.writeByte(')');
1034 }
1067 if (location != .Initializer) {
1068 try writer.writeByte('(');
1069 try dg.renderTypecast(writer, ty);
1070 try writer.writeByte(')');
1071 }
10351072
1036 try writer.writeByte('{');
1037 var empty = true;
1038 for (field_vals) |field_val, field_index| {
1039 const field_ty = ty.structFieldType(field_index);
1040 if (!field_ty.hasRuntimeBits()) continue;
1073 try writer.writeByte('{');
1074 var empty = true;
1075 for (field_vals) |field_val, field_index| {
1076 const field_ty = ty.structFieldType(field_index);
1077 if (!field_ty.hasRuntimeBits()) continue;
10411078
1042 if (!empty) try writer.writeByte(',');
1043 try dg.renderValue(writer, field_ty, field_val, .Initializer);
1079 if (!empty) try writer.writeByte(',');
1080 try dg.renderValue(writer, field_ty, field_val, .Initializer);
10441081
1045 empty = false;
1046 }
1047 if (empty) try writer.print("{}", .{try dg.fmtIntLiteral(Type.u8, Value.zero)});
1048 try writer.writeByte('}');
1082 empty = false;
1083 }
1084 if (empty) try writer.print("{}", .{try dg.fmtIntLiteral(Type.u8, Value.zero)});
1085 try writer.writeByte('}');
1086 },
1087 .Packed => {
1088 const field_vals = val.castTag(.aggregate).?.data;
1089 const int_info = ty.intInfo(target);
1090
1091 var bit_offset_ty_pl = Type.Payload.Bits{
1092 .base = .{ .tag = .int_unsigned },
1093 .data = Type.smallestUnsignedBits(int_info.bits - 1),
1094 };
1095 const bit_offset_ty = Type.initPayload(&bit_offset_ty_pl.base);
1096
1097 var bit_offset_val_pl: Value.Payload.U64 = .{ .base = .{ .tag = .int_u64 }, .data = 0 };
1098 const bit_offset_val = Value.initPayload(&bit_offset_val_pl.base);
1099
1100 try writer.writeByte('(');
1101 var empty = true;
1102 for (field_vals) |field_val, index| {
1103 const field_ty = ty.structFieldType(index);
1104 if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue;
1105
1106 if (!empty) try writer.writeAll(" | ");
1107 try writer.writeByte('(');
1108 try dg.renderTypecast(writer, ty);
1109 try writer.writeByte(')');
1110 try dg.renderValue(writer, field_ty, field_val, .Other);
1111 try writer.writeAll(" << ");
1112 try dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument);
1113
1114 bit_offset_val_pl.data += field_ty.bitSize(target);
1115 empty = false;
1116 }
1117 if (empty) try dg.renderValue(writer, ty, Value.undef, .Initializer);
1118 try writer.writeByte(')');
1119 },
10491120 },
10501121 .Union => {
10511122 const union_obj = val.castTag(.@"union").?.data;
......@@ -1103,11 +1174,12 @@ pub const DeclGen = struct {
11031174 if (fn_info.cc == .Naked) try w.writeAll("zig_naked ");
11041175 if (dg.decl.val.castTag(.function)) |func_payload|
11051176 if (func_payload.data.is_cold) try w.writeAll("zig_cold ");
1106 const ret_ty = fn_info.return_type;
1107 try dg.renderType(w, if (ret_ty.tag() == .noreturn or ret_ty.hasRuntimeBitsIgnoreComptime())
1108 ret_ty
1109 else
1110 Type.void, kind);
1177
1178 const target = dg.module.getTarget();
1179 var ret_buf: LowerFnRetTyBuffer = undefined;
1180 const ret_ty = lowerFnRetTy(fn_info.return_type, &ret_buf, target);
1181
1182 try dg.renderType(w, ret_ty, kind);
11111183 try w.writeByte(' ');
11121184 try dg.renderDeclName(w, dg.decl_index);
11131185 try w.writeByte('(');
......@@ -1117,7 +1189,7 @@ pub const DeclGen = struct {
11171189 if (!param_type.hasRuntimeBitsIgnoreComptime()) continue;
11181190 if (index > 0) try w.writeAll(", ");
11191191 const name = CValue{ .arg = index };
1120 try dg.renderTypeAndName(w, param_type, name, .Const, 0, kind);
1192 try dg.renderTypeAndName(w, param_type, name, .ConstArgument, 0, kind);
11211193 index += 1;
11221194 }
11231195
......@@ -1137,10 +1209,13 @@ pub const DeclGen = struct {
11371209
11381210 const fn_info = t.fnInfo();
11391211
1212 const target = dg.module.getTarget();
1213 var ret_buf: LowerFnRetTyBuffer = undefined;
1214 const ret_ty = lowerFnRetTy(fn_info.return_type, &ret_buf, target);
1215
11401216 try bw.writeAll("typedef ");
1141 try dg.renderType(bw, fn_info.return_type, .Forward);
1217 try dg.renderType(bw, ret_ty, .Forward);
11421218 try bw.writeAll(" (*");
1143
11441219 const name_begin = buffer.items.len;
11451220 try bw.print("zig_F_{}", .{typeToCIdentifier(t, dg.module)});
11461221 const name_end = buffer.items.len;
......@@ -1315,8 +1390,12 @@ pub const DeclGen = struct {
13151390 const val = fields.values[i];
13161391 if (val.tag() != .unreachable_value) continue;
13171392
1318 const field_name = try std.fmt.allocPrint(dg.typedefs.allocator, "field_{d}", .{i});
1319 defer dg.typedefs.allocator.free(field_name);
1393 var field_name_buf: []const u8 = &.{};
1394 defer dg.typedefs.allocator.free(field_name_buf);
1395 const field_name = if (t.isTuple()) field_name: {
1396 field_name_buf = try std.fmt.allocPrint(dg.typedefs.allocator, "field_{d}", .{i});
1397 break :field_name field_name_buf;
1398 } else t.structFieldName(i);
13201399
13211400 try buffer.append(' ');
13221401 try dg.renderTypeAndName(buffer.writer(), field_ty, .{ .identifier = field_name }, .Mut, 0, .Complete);
......@@ -1463,7 +1542,10 @@ pub const DeclGen = struct {
14631542 try bw.print(" zig_A_{}_{d}", .{ typeToCIdentifier(info.elem_type, dg.module), info.len });
14641543 const name_end = buffer.items.len;
14651544
1466 try bw.print("[{d}];\n", .{if (info.len > 0) info.len else 1});
1545 const c_len = if (info.len > 0) info.len else 1;
1546 var c_len_pl: Value.Payload.U64 = .{ .base = .{ .tag = .int_u64 }, .data = c_len };
1547 const c_len_val = Value.initPayload(&c_len_pl.base);
1548 try bw.print("[{}];\n", .{try dg.fmtIntLiteral(Type.usize, c_len_val)});
14671549
14681550 const rendered = buffer.toOwnedSlice();
14691551 errdefer dg.typedefs.allocator.free(rendered);
......@@ -1487,7 +1569,7 @@ pub const DeclGen = struct {
14871569 try dg.renderTypeAndName(bw, child_type, .{ .identifier = "payload" }, .Mut, 0, .Complete);
14881570 try bw.writeAll(";\n ");
14891571 try dg.renderTypeAndName(bw, Type.bool, .{ .identifier = "is_null" }, .Mut, 0, .Complete);
1490 try bw.writeAll("; } ");
1572 try bw.writeAll(";\n} ");
14911573 const name_begin = buffer.items.len;
14921574 try bw.print("zig_Q_{}", .{typeToCIdentifier(child_type, dg.module)});
14931575 const name_end = buffer.items.len;
......@@ -1566,18 +1648,29 @@ pub const DeclGen = struct {
15661648 try w.writeAll("zig_");
15671649 try t.print(w, dg.module);
15681650 } else {
1569 const info = t.intInfo(target);
1570 const c_bits = toCIntBits(info.bits) orelse
1571 return dg.fail("TODO: C backend: implement integer types larger than 128 bits", .{});
1572 try w.print("zig_{c}{d}", .{ signAbbrev(info.signedness), c_bits });
1651 const int_info = t.intInfo(target);
1652 if (toCIntBits(int_info.bits)) |c_bits|
1653 return w.print("zig_{c}{d}", .{ signAbbrev(int_info.signedness), c_bits })
1654 else if (loweredArrayInfo(t, target)) |array_info| {
1655 assert(array_info.sentinel == null);
1656 var array_pl = Type.Payload.Array{
1657 .base = .{ .tag = .array },
1658 .data = .{ .len = array_info.len, .elem_type = array_info.elem_type },
1659 };
1660 const array_ty = Type.initPayload(&array_pl.base);
1661
1662 return dg.renderType(w, array_ty, kind);
1663 } else return dg.fail("C backend: Unable to lower unnamed integer type {}", .{
1664 t.fmt(dg.module),
1665 });
15731666 }
15741667 },
15751668 .Pointer => {
1576 const child_ty = t.childType();
1577 if (t.isSlice()) {
1669 const ptr_info = t.ptrInfo().data;
1670 if (ptr_info.size == .Slice) {
15781671 var slice_pl = Type.Payload.ElemType{
15791672 .base = .{ .tag = if (t.ptrIsMutable()) .mut_slice else .const_slice },
1580 .data = child_ty,
1673 .data = ptr_info.pointee_type,
15811674 };
15821675 const slice_ty = Type.initPayload(&slice_pl.base);
15831676
......@@ -1587,14 +1680,22 @@ pub const DeclGen = struct {
15871680 return w.writeAll(name);
15881681 }
15891682
1590 if (child_ty.zigTypeTag() == .Fn) {
1591 const name = dg.getTypedefName(child_ty) orelse
1592 try dg.renderPtrToFnTypedef(child_ty);
1683 if (ptr_info.pointee_type.zigTypeTag() == .Fn) {
1684 const name = dg.getTypedefName(ptr_info.pointee_type) orelse
1685 try dg.renderPtrToFnTypedef(ptr_info.pointee_type);
15931686
15941687 return w.writeAll(name);
15951688 }
15961689
1597 if (t.isCPtr() and child_ty.eql(Type.u8, dg.module) and
1690 if (ptr_info.host_size != 0) {
1691 var host_pl = Type.Payload.Bits{
1692 .base = .{ .tag = .int_unsigned },
1693 .data = ptr_info.host_size * 8,
1694 };
1695 const host_ty = Type.initPayload(&host_pl.base);
1696
1697 try dg.renderType(w, host_ty, .Forward);
1698 } else if (t.isCPtr() and ptr_info.pointee_type.eql(Type.u8, dg.module) and
15981699 (dg.decl.val.tag() == .extern_fn or
15991700 std.mem.eql(u8, std.mem.span(dg.decl.name), "main")))
16001701 {
......@@ -1603,9 +1704,9 @@ pub const DeclGen = struct {
16031704 // u8 and i8 produce unsigned char and signed char respectively,
16041705 // which in C are (not very usefully) different than char.
16051706 try w.writeAll("char");
1606 } else try dg.renderType(w, switch (child_ty.tag()) {
1707 } else try dg.renderType(w, switch (ptr_info.pointee_type.tag()) {
16071708 .anyopaque => Type.void,
1608 else => child_ty,
1709 else => ptr_info.pointee_type,
16091710 }, .Forward);
16101711 if (t.isConstPtr()) try w.writeAll(" const");
16111712 if (t.isVolatilePtr()) try w.writeAll(" volatile");
......@@ -1654,7 +1755,9 @@ pub const DeclGen = struct {
16541755
16551756 return w.writeAll(name);
16561757 },
1657 .Struct, .Union => |tag| if (kind == .Complete or t.isTupleOrAnonStruct()) {
1758 .Struct, .Union => |tag| if (tag == .Struct and t.containerLayout() == .Packed)
1759 try dg.renderType(w, t.castTag(.@"struct").?.data.backing_int_ty, kind)
1760 else if (kind == .Complete or t.isTupleOrAnonStruct()) {
16581761 const name = dg.getTypedefName(t) orelse switch (tag) {
16591762 .Struct => if (t.isTupleOrAnonStruct())
16601763 try dg.renderTupleTypedef(t)
......@@ -1664,7 +1767,7 @@ pub const DeclGen = struct {
16641767 else => unreachable,
16651768 };
16661769
1667 return w.writeAll(name);
1770 try w.writeAll(name);
16681771 } else {
16691772 var ptr_pl = Type.Payload.ElemType{
16701773 .base = .{ .tag = .single_const_pointer },
......@@ -1675,7 +1778,7 @@ pub const DeclGen = struct {
16751778 const name = dg.getTypedefName(ptr_ty) orelse
16761779 try dg.renderFwdTypedef(ptr_ty);
16771780
1678 return w.writeAll(name);
1781 try w.writeAll(name);
16791782 },
16801783 .Enum => {
16811784 // For enums, we simply use the integer tag type.
......@@ -1751,24 +1854,32 @@ pub const DeclGen = struct {
17511854 ) error{ OutOfMemory, AnalysisFail }!void {
17521855 var suffix = std.ArrayList(u8).init(dg.gpa);
17531856 defer suffix.deinit();
1857 const suffix_writer = suffix.writer();
17541858
17551859 // Any top-level array types are rendered here as a suffix, which
17561860 // avoids creating typedefs for every array type
1861 const target = dg.module.getTarget();
17571862 var render_ty = ty;
1758 while (render_ty.zigTypeTag() == .Array) {
1759 const sentinel_bit = @boolToInt(render_ty.sentinel() != null);
1760 const c_len = render_ty.arrayLen() + sentinel_bit;
1761 try suffix.writer().print("[{d}]", .{c_len});
1762 render_ty = render_ty.elemType();
1863 var depth: u32 = 0;
1864 while (loweredArrayInfo(render_ty, target)) |array_info| {
1865 const c_len = array_info.len + @boolToInt(array_info.sentinel != null);
1866 var c_len_pl: Value.Payload.U64 = .{ .base = .{ .tag = .int_u64 }, .data = c_len };
1867 const c_len_val = Value.initPayload(&c_len_pl.base);
1868
1869 try suffix_writer.writeByte('[');
1870 if (mutability == .ConstArgument and depth == 0) try suffix_writer.writeAll("static const ");
1871 try suffix.writer().print("{}]", .{try dg.fmtIntLiteral(Type.usize, c_len_val)});
1872 render_ty = array_info.elem_type;
1873 depth += 1;
17631874 }
17641875
1765 if (alignment != 0 and alignment > ty.abiAlignment(dg.module.getTarget())) {
1876 if (alignment != 0 and alignment > ty.abiAlignment(target)) {
17661877 try w.print("zig_align({}) ", .{alignment});
17671878 }
17681879 try dg.renderType(w, render_ty, kind);
17691880
17701881 const const_prefix = switch (mutability) {
1771 .Const => "const ",
1882 .Const, .ConstArgument => "const ",
17721883 .Mut => "",
17731884 };
17741885 try w.print(" {s}", .{const_prefix});
......@@ -1935,7 +2046,7 @@ pub const DeclGen = struct {
19352046 } else if (decl.isExtern()) {
19362047 return writer.writeAll(mem.sliceTo(decl.name, 0));
19372048 } else {
1938 const gpa = dg.module.gpa;
2049 const gpa = dg.gpa;
19392050 const name = try decl.getFullyQualifiedName(dg.module);
19402051 defer gpa.free(name);
19412052 return writer.print("{ }", .{fmtIdent(name)});
......@@ -2298,8 +2409,8 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
22982409 .trunc => try airTrunc(f, inst),
22992410 .bool_to_int => try airBoolToInt(f, inst),
23002411 .load => try airLoad(f, inst),
2301 .ret => try airRet(f, inst),
2302 .ret_load => try airRetLoad(f, inst),
2412 .ret => try airRet(f, inst, false),
2413 .ret_load => try airRet(f, inst, true),
23032414 .store => try airStore(f, inst),
23042415 .loop => try airLoop(f, inst),
23052416 .cond_br => try airCondBr(f, inst),
......@@ -2588,14 +2699,15 @@ fn airArg(f: *Function) CValue {
25882699
25892700fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
25902701 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
2591 const is_volatile = f.air.typeOf(ty_op.operand).isVolatilePtr();
2702 const ptr_info = f.air.typeOf(ty_op.operand).ptrInfo().data;
25922703
25932704 const inst_ty = f.air.typeOfIndex(inst);
25942705 if (!inst_ty.hasRuntimeBitsIgnoreComptime() or
2595 !is_volatile and f.liveness.isUnused(inst))
2706 !ptr_info.@"volatile" and f.liveness.isUnused(inst))
25962707 return CValue.none;
25972708
2598 const is_array = inst_ty.zigTypeTag() == .Array;
2709 const target = f.object.dg.module.getTarget();
2710 const is_array = lowersToArray(inst_ty, target);
25992711 const operand = try f.resolveInst(ty_op.operand);
26002712 const writer = f.object.writer();
26012713
......@@ -2612,26 +2724,88 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
26122724 try f.writeCValue(writer, operand, .FunctionArgument);
26132725 try writer.writeAll(", sizeof(");
26142726 try f.renderTypecast(writer, inst_ty);
2615 try writer.writeAll("));\n");
2727 try writer.writeAll("))");
2728 } else if (ptr_info.host_size != 0) {
2729 var host_pl = Type.Payload.Bits{
2730 .base = .{ .tag = .int_unsigned },
2731 .data = ptr_info.host_size * 8,
2732 };
2733 const host_ty = Type.initPayload(&host_pl.base);
2734
2735 var bit_offset_ty_pl = Type.Payload.Bits{
2736 .base = .{ .tag = .int_unsigned },
2737 .data = Type.smallestUnsignedBits(host_pl.data - 1),
2738 };
2739 const bit_offset_ty = Type.initPayload(&bit_offset_ty_pl.base);
2740
2741 var bit_offset_val_pl: Value.Payload.U64 = .{
2742 .base = .{ .tag = .int_u64 },
2743 .data = ptr_info.bit_offset,
2744 };
2745 const bit_offset_val = Value.initPayload(&bit_offset_val_pl.base);
2746
2747 var field_pl = Type.Payload.Bits{
2748 .base = .{ .tag = .int_unsigned },
2749 .data = @intCast(u16, inst_ty.bitSize(target)),
2750 };
2751 const field_ty = Type.initPayload(&field_pl.base);
2752
2753 try writer.writeAll(" = (");
2754 try f.renderTypecast(writer, inst_ty);
2755 try writer.writeAll(")zig_wrap_");
2756 try f.renderTypeForBuiltinFnName(writer, field_ty);
2757 try writer.writeAll("((");
2758 try f.renderTypecast(writer, field_ty);
2759 try writer.writeAll(")zig_shr_");
2760 try f.renderTypeForBuiltinFnName(writer, host_ty);
2761 try writer.writeByte('(');
2762 try f.writeCValueDeref(writer, operand);
2763 try writer.print(", {})", .{try f.fmtIntLiteral(bit_offset_ty, bit_offset_val)});
2764 try f.renderBuiltinInfo(writer, field_ty, .Bits);
2765 try writer.writeByte(')');
26162766 } else {
26172767 try writer.writeAll(" = ");
26182768 try f.writeCValueDeref(writer, operand);
2619 try writer.writeAll(";\n");
26202769 }
2770 try writer.writeAll(";\n");
26212771 return local;
26222772}
26232773
2624fn airRet(f: *Function, inst: Air.Inst.Index) !CValue {
2774fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue {
26252775 const un_op = f.air.instructions.items(.data)[inst].un_op;
26262776 const writer = f.object.writer();
2627 const ret_ty = f.air.typeOf(un_op);
2628 if (ret_ty.isFnOrHasRuntimeBitsIgnoreComptime()) {
2777 const target = f.object.dg.module.getTarget();
2778 const op_ty = f.air.typeOf(un_op);
2779 const ret_ty = if (is_ptr) op_ty.childType() else op_ty;
2780 var lowered_ret_buf: LowerFnRetTyBuffer = undefined;
2781 const lowered_ret_ty = lowerFnRetTy(ret_ty, &lowered_ret_buf, target);
2782
2783 if (lowered_ret_ty.hasRuntimeBitsIgnoreComptime()) {
2784 var deref = is_ptr;
26292785 const operand = try f.resolveInst(un_op);
2786 const ret_val = if (lowersToArray(ret_ty, target)) ret_val: {
2787 const array_local = try f.allocLocal(lowered_ret_ty, .Mut);
2788 try writer.writeAll(";\n");
2789 try writer.writeAll("memcpy(");
2790 try f.writeCValueMember(writer, array_local, .{ .identifier = "array" });
2791 try writer.writeAll(", ");
2792 if (deref)
2793 try f.writeCValueDeref(writer, operand)
2794 else
2795 try f.writeCValue(writer, operand, .FunctionArgument);
2796 deref = false;
2797 try writer.writeAll(", sizeof(");
2798 try f.renderTypecast(writer, ret_ty);
2799 try writer.writeAll("));\n");
2800 break :ret_val array_local;
2801 } else operand;
2802
26302803 try writer.writeAll("return ");
2631 try f.writeCValue(writer, operand, .Other);
2804 if (deref)
2805 try f.writeCValueDeref(writer, ret_val)
2806 else
2807 try f.writeCValue(writer, ret_val, .Other);
26322808 try writer.writeAll(";\n");
2633 } else if (ret_ty.isError()) {
2634 try writer.writeAll("return 0;");
26352809 } else if (f.object.dg.decl.ty.fnCallingConvention() != .Naked) {
26362810 // Not even allowed to return void in a naked function.
26372811 try writer.writeAll("return;\n");
......@@ -2639,24 +2813,6 @@ fn airRet(f: *Function, inst: Air.Inst.Index) !CValue {
26392813 return CValue.none;
26402814}
26412815
2642fn airRetLoad(f: *Function, inst: Air.Inst.Index) !CValue {
2643 const un_op = f.air.instructions.items(.data)[inst].un_op;
2644 const writer = f.object.writer();
2645 const ptr_ty = f.air.typeOf(un_op);
2646 const ret_ty = ptr_ty.childType();
2647 if (ret_ty.isFnOrHasRuntimeBitsIgnoreComptime()) {
2648 const ptr = try f.resolveInst(un_op);
2649 try writer.writeAll("return *");
2650 try f.writeCValue(writer, ptr, .Other);
2651 try writer.writeAll(";\n");
2652 } else if (ret_ty.isError()) {
2653 try writer.writeAll("return 0;\n");
2654 } else {
2655 try writer.writeAll("return;\n");
2656 }
2657 return CValue.none;
2658}
2659
26602816fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue {
26612817 if (f.liveness.isUnused(inst))
26622818 return CValue.none;
......@@ -2696,12 +2852,12 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {
26962852 try writer.writeAll(";\n");
26972853 } else switch (dest_int_info.signedness) {
26982854 .unsigned => {
2699 var arena = std.heap.ArenaAllocator.init(f.object.dg.module.gpa);
2855 var arena = std.heap.ArenaAllocator.init(f.object.dg.gpa);
27002856 defer arena.deinit();
27012857
2702 const expected_contents = union { u: Value.Payload.U64, i: Value.Payload.I64 };
2703 var stack align(@alignOf(expected_contents)) =
2704 std.heap.stackFallback(@sizeOf(expected_contents), arena.allocator());
2858 const ExpectedContents = union { u: Value.Payload.U64, i: Value.Payload.I64 };
2859 var stack align(@alignOf(ExpectedContents)) =
2860 std.heap.stackFallback(@sizeOf(ExpectedContents), arena.allocator());
27052861
27062862 const mask_val = try inst_ty.maxInt(stack.get(), target);
27072863
......@@ -2756,10 +2912,11 @@ fn airStoreUndefined(f: *Function, lhs_child_ty: Type, dest_ptr: CValue) !CValue
27562912fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {
27572913 // *a = b;
27582914 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
2759 const lhs_child_ty = f.air.typeOf(bin_op.lhs).childType();
2760 if (!lhs_child_ty.hasRuntimeBitsIgnoreComptime()) return CValue.none;
2915 const ptr_info = f.air.typeOf(bin_op.lhs).ptrInfo().data;
2916 if (!ptr_info.pointee_type.hasRuntimeBitsIgnoreComptime()) return CValue.none;
27612917
2762 const dest_ptr = try f.resolveInst(bin_op.lhs);
2918 const ptr_val = try f.resolveInst(bin_op.lhs);
2919 const src_ty = f.air.typeOf(bin_op.rhs);
27632920 const src_val = try f.resolveInst(bin_op.rhs);
27642921
27652922 // TODO Sema should emit a different instruction when the store should
......@@ -2767,20 +2924,20 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {
27672924 const src_val_is_undefined =
27682925 if (f.air.value(bin_op.rhs)) |v| v.isUndefDeep() else false;
27692926 if (src_val_is_undefined)
2770 return try airStoreUndefined(f, lhs_child_ty, dest_ptr);
2927 return try airStoreUndefined(f, ptr_info.pointee_type, ptr_val);
27712928
2929 const target = f.object.dg.module.getTarget();
27722930 const writer = f.object.writer();
2773 if (lhs_child_ty.zigTypeTag() == .Array) {
2931 if (lowersToArray(ptr_info.pointee_type, target)) {
27742932 // For this memcpy to safely work we need the rhs to have the same
27752933 // underlying type as the lhs (i.e. they must both be arrays of the same underlying type).
2776 const rhs_type = f.air.typeOf(bin_op.rhs);
2777 assert(rhs_type.eql(lhs_child_ty, f.object.dg.module));
2934 assert(src_ty.eql(ptr_info.pointee_type, f.object.dg.module));
27782935
27792936 // If the source is a constant, writeCValue will emit a brace initialization
27802937 // so work around this by initializing into new local.
27812938 // TODO this should be done by manually initializing elements of the dest array
27822939 const array_src = if (src_val == .constant) blk: {
2783 const new_local = try f.allocLocal(rhs_type, .Const);
2940 const new_local = try f.allocLocal(src_ty, .Const);
27842941 try writer.writeAll(" = ");
27852942 try f.writeCValue(writer, src_val, .Initializer);
27862943 try writer.writeAll(";\n");
......@@ -2789,18 +2946,69 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {
27892946 } else src_val;
27902947
27912948 try writer.writeAll("memcpy(");
2792 try f.writeCValue(writer, dest_ptr, .FunctionArgument);
2949 try f.writeCValue(writer, ptr_val, .FunctionArgument);
27932950 try writer.writeAll(", ");
27942951 try f.writeCValue(writer, array_src, .FunctionArgument);
27952952 try writer.writeAll(", sizeof(");
2796 try f.renderTypecast(writer, lhs_child_ty);
2797 try writer.writeAll("));\n");
2953 try f.renderTypecast(writer, src_ty);
2954 try writer.writeAll("))");
2955 } else if (ptr_info.host_size != 0) {
2956 const host_bits = ptr_info.host_size * 8;
2957 var host_pl = Type.Payload.Bits{ .base = .{ .tag = .int_unsigned }, .data = host_bits };
2958 const host_ty = Type.initPayload(&host_pl.base);
2959
2960 var bit_offset_ty_pl = Type.Payload.Bits{
2961 .base = .{ .tag = .int_unsigned },
2962 .data = Type.smallestUnsignedBits(host_bits - 1),
2963 };
2964 const bit_offset_ty = Type.initPayload(&bit_offset_ty_pl.base);
2965
2966 var bit_offset_val_pl: Value.Payload.U64 = .{
2967 .base = .{ .tag = .int_u64 },
2968 .data = ptr_info.bit_offset,
2969 };
2970 const bit_offset_val = Value.initPayload(&bit_offset_val_pl.base);
2971
2972 const src_bits = src_ty.bitSize(target);
2973
2974 const Limb = std.math.big.Limb;
2975 const ExpectedContents = [BigInt.Managed.default_capacity]Limb;
2976 var stack align(@alignOf(ExpectedContents)) =
2977 std.heap.stackFallback(@sizeOf(ExpectedContents), f.object.dg.gpa);
2978
2979 var mask = try BigInt.Managed.initCapacity(stack.get(), BigInt.calcTwosCompLimbCount(host_bits));
2980 defer mask.deinit();
2981
2982 try mask.setTwosCompIntLimit(.max, .unsigned, @intCast(usize, src_bits));
2983 try mask.shiftLeft(&mask, ptr_info.bit_offset);
2984 try mask.bitNotWrap(&mask, .unsigned, host_bits);
2985
2986 var mask_pl = Value.Payload.BigInt{
2987 .base = .{ .tag = .int_big_positive },
2988 .data = mask.limbs[0..mask.len()],
2989 };
2990 const mask_val = Value.initPayload(&mask_pl.base);
2991
2992 try f.writeCValueDeref(writer, ptr_val);
2993 try writer.writeAll(" = zig_or_");
2994 try f.renderTypeForBuiltinFnName(writer, host_ty);
2995 try writer.writeAll("(zig_and_");
2996 try f.renderTypeForBuiltinFnName(writer, host_ty);
2997 try writer.writeByte('(');
2998 try f.writeCValueDeref(writer, ptr_val);
2999 try writer.print(", {x}), zig_shl_", .{try f.fmtIntLiteral(host_ty, mask_val)});
3000 try f.renderTypeForBuiltinFnName(writer, host_ty);
3001 try writer.writeAll("((");
3002 try f.renderTypecast(writer, host_ty);
3003 try writer.writeByte(')');
3004 try f.writeCValue(writer, src_val, .Other);
3005 try writer.print(", {}))", .{try f.fmtIntLiteral(bit_offset_ty, bit_offset_val)});
27983006 } else {
2799 try f.writeCValueDeref(writer, dest_ptr);
3007 try f.writeCValueDeref(writer, ptr_val);
28003008 try writer.writeAll(" = ");
28013009 try f.writeCValue(writer, src_val, .Other);
2802 try writer.writeAll(";\n");
28033010 }
3011 try writer.writeAll(";\n");
28043012 return CValue.none;
28053013}
28063014
......@@ -2959,7 +3167,9 @@ fn airEquality(
29593167 }
29603168
29613169 try f.writeCValue(writer, lhs, .Other);
3170 try writer.writeByte(' ');
29623171 try writer.writeAll(eq_op_str);
3172 try writer.writeByte(' ');
29633173 try f.writeCValue(writer, rhs, .Other);
29643174 try writer.writeAll(";\n");
29653175
......@@ -3079,17 +3289,22 @@ fn airCall(
30793289 };
30803290 const writer = f.object.writer();
30813291
3082 const result_local: CValue = r: {
3083 if (!loweredFnRetTyHasBits(fn_ty)) {
3084 break :r .none;
3085 } else if (f.liveness.isUnused(inst)) {
3086 try writer.print("(void)", .{});
3087 break :r .none;
3088 } else {
3089 const local = try f.allocLocal(fn_ty.fnReturnType(), .Const);
3090 try writer.writeAll(" = ");
3091 break :r local;
3092 }
3292 const target = f.object.dg.module.getTarget();
3293 const ret_ty = fn_ty.fnReturnType();
3294 var lowered_ret_buf: LowerFnRetTyBuffer = undefined;
3295 const lowered_ret_ty = lowerFnRetTy(ret_ty, &lowered_ret_buf, target);
3296
3297 const result_local: CValue = if (!lowered_ret_ty.hasRuntimeBitsIgnoreComptime())
3298 .none
3299 else if (f.liveness.isUnused(inst)) r: {
3300 try writer.writeByte('(');
3301 try f.renderTypecast(writer, Type.void);
3302 try writer.writeByte(')');
3303 break :r .none;
3304 } else r: {
3305 const local = try f.allocLocal(lowered_ret_ty, .Const);
3306 try writer.writeAll(" = ");
3307 break :r local;
30933308 };
30943309
30953310 var is_extern = false;
......@@ -3138,7 +3353,19 @@ fn airCall(
31383353 args_written += 1;
31393354 }
31403355 try writer.writeAll(");\n");
3141 return result_local;
3356
3357 if (result_local == .none or !lowersToArray(ret_ty, target)) return result_local;
3358
3359 const array_local = try f.allocLocal(ret_ty, .Mut);
3360 try writer.writeAll(";\n");
3361 try writer.writeAll("memcpy(");
3362 try f.writeCValue(writer, array_local, .FunctionArgument);
3363 try writer.writeAll(", ");
3364 try f.writeCValueMember(writer, result_local, .{ .identifier = "array" });
3365 try writer.writeAll(", sizeof(");
3366 try f.renderTypecast(writer, ret_ty);
3367 try writer.writeAll("));\n");
3368 return array_local;
31423369}
31433370
31443371fn airDbgStmt(f: *Function, inst: Air.Inst.Index) !CValue {
......@@ -3263,7 +3490,8 @@ fn lowerTry(
32633490 }
32643491 }
32653492
3266 const is_array = payload_ty.zigTypeTag() == .Array;
3493 const target = f.object.dg.module.getTarget();
3494 const is_array = lowersToArray(payload_ty, target);
32673495 const local = try f.allocLocal(result_ty, if (is_array) .Mut else .Const);
32683496 if (is_array) {
32693497 try writer.writeAll(";\n");
......@@ -3814,51 +4042,74 @@ fn airFieldParentPtr(f: *Function, inst: Air.Inst.Index) !CValue {
38144042
38154043fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struct_ptr: CValue, index: u32) !CValue {
38164044 const writer = f.object.writer();
4045 const field_ptr_ty = f.air.typeOfIndex(inst);
4046 const field_ptr_info = field_ptr_ty.ptrInfo();
38174047 const struct_ty = struct_ptr_ty.elemType();
3818 var field_name: []const u8 = undefined;
3819 var field_val_ty: Type = undefined;
4048 const field_ty = struct_ty.structFieldType(index);
38204049
3821 var field_name_buf: []const u8 = "";
4050 // Ensure complete type definition is visible before accessing fields.
4051 try f.renderType(std.io.null_writer, struct_ty);
4052
4053 const local = try f.allocLocal(field_ptr_ty, .Const);
4054 try writer.writeAll(" = (");
4055 try f.renderTypecast(writer, field_ptr_ty);
4056 try writer.writeByte(')');
4057
4058 const extra_name: ?[]const u8 = switch (struct_ty.tag()) {
4059 .union_tagged, .union_safety_tagged => "payload",
4060 else => null,
4061 };
4062
4063 var field_name_buf: []const u8 = &.{};
38224064 defer f.object.dg.gpa.free(field_name_buf);
3823 switch (struct_ty.tag()) {
3824 .@"struct" => {
3825 const fields = struct_ty.structFields();
3826 field_name = fields.keys()[index];
3827 field_val_ty = fields.values()[index].ty;
3828 },
3829 .@"union", .union_safety_tagged, .union_tagged => {
3830 const fields = struct_ty.unionFields();
3831 field_name = fields.keys()[index];
3832 field_val_ty = fields.values()[index].ty;
4065 const field_name: ?[]const u8 = switch (struct_ty.tag()) {
4066 .@"struct" => switch (struct_ty.containerLayout()) {
4067 .Auto, .Extern => struct_ty.structFieldName(index),
4068 .Packed => if (field_ptr_info.data.host_size == 0) {
4069 const target = f.object.dg.module.getTarget();
4070
4071 const byte_offset = struct_ty.packedStructFieldByteOffset(index, target);
4072 var byte_offset_pl = Value.Payload.U64{
4073 .base = .{ .tag = .int_u64 },
4074 .data = byte_offset,
4075 };
4076 const byte_offset_val = Value.initPayload(&byte_offset_pl.base);
4077
4078 var ptr_u8_pl = field_ptr_info;
4079 ptr_u8_pl.data.pointee_type = Type.u8;
4080 const ptr_u8_ty = Type.initPayload(&ptr_u8_pl.base);
4081
4082 try writer.writeAll("&((");
4083 try f.renderTypecast(writer, ptr_u8_ty);
4084 try writer.writeByte(')');
4085 try f.writeCValue(writer, struct_ptr, .Other);
4086 try writer.print(")[{}];\n", .{try f.fmtIntLiteral(Type.usize, byte_offset_val)});
4087 return local;
4088 } else null,
38334089 },
3834 .tuple, .anon_struct => {
4090 .@"union", .union_safety_tagged, .union_tagged => struct_ty.unionFields().keys()[index],
4091 .tuple, .anon_struct => |tag| field_name: {
38354092 const tuple = struct_ty.tupleFields();
38364093 if (tuple.values[index].tag() != .unreachable_value) return CValue.none;
38374094
4095 if (tag == .anon_struct) break :field_name struct_ty.structFieldName(index);
4096
38384097 field_name_buf = try std.fmt.allocPrint(f.object.dg.gpa, "field_{d}", .{index});
3839 field_name = field_name_buf;
3840 field_val_ty = tuple.types[index];
4098 break :field_name field_name_buf;
38414099 },
38424100 else => unreachable,
3843 }
3844 const payload = if (struct_ty.tag() == .union_tagged or struct_ty.tag() == .union_safety_tagged) "payload." else "";
3845
3846 // Ensure complete type definition is visible before accessing fields.
3847 try f.renderType(std.io.null_writer, struct_ty);
4101 };
38484102
3849 const inst_ty = f.air.typeOfIndex(inst);
3850 const local = try f.allocLocal(inst_ty, .Const);
3851 if (field_val_ty.hasRuntimeBitsIgnoreComptime()) {
3852 try writer.writeAll(" = &");
3853 try f.writeCValueDeref(writer, struct_ptr);
3854 try writer.print(".{s}{ };\n", .{ payload, fmtIdent(field_name) });
3855 } else {
3856 try writer.writeAll(" = (");
3857 try f.renderTypecast(writer, inst_ty);
3858 try writer.writeByte(')');
3859 try f.writeCValue(writer, struct_ptr, .Other);
3860 try writer.writeAll(";\n");
3861 }
4103 if (field_ty.hasRuntimeBitsIgnoreComptime()) {
4104 try writer.writeByte('&');
4105 if (extra_name orelse field_name) |name|
4106 try f.writeCValueDerefMember(writer, struct_ptr, .{ .identifier = name })
4107 else
4108 try f.writeCValueDeref(writer, struct_ptr);
4109 if (extra_name) |_| if (field_name) |name|
4110 try writer.print(".{ }", .{fmtIdent(name)});
4111 } else try f.writeCValue(writer, struct_ptr, .Other);
4112 try writer.writeAll(";\n");
38624113 return local;
38634114}
38644115
......@@ -3868,18 +4119,84 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
38684119
38694120 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
38704121 const extra = f.air.extraData(Air.StructField, ty_pl.payload).data;
3871 const writer = f.object.writer();
4122 const inst_ty = f.air.typeOfIndex(inst);
4123 const target = f.object.dg.module.getTarget();
38724124 const struct_byval = try f.resolveInst(extra.struct_operand);
38734125 const struct_ty = f.air.typeOf(extra.struct_operand);
4126 const writer = f.object.writer();
4127
4128 // Ensure complete type definition is visible before accessing fields.
4129 try f.renderType(std.io.null_writer, struct_ty);
4130
38744131 var field_name_buf: []const u8 = "";
38754132 defer f.object.dg.gpa.free(field_name_buf);
38764133 const field_name = switch (struct_ty.tag()) {
3877 .@"struct" => struct_ty.structFields().keys()[extra.field_index],
4134 .@"struct" => switch (struct_ty.containerLayout()) {
4135 .Auto, .Extern => struct_ty.structFieldName(extra.field_index),
4136 .Packed => {
4137 const struct_obj = struct_ty.castTag(.@"struct").?.data;
4138 const int_info = struct_ty.intInfo(target);
4139
4140 var bit_offset_ty_pl = Type.Payload.Bits{
4141 .base = .{ .tag = .int_unsigned },
4142 .data = Type.smallestUnsignedBits(int_info.bits - 1),
4143 };
4144 const bit_offset_ty = Type.initPayload(&bit_offset_ty_pl.base);
4145
4146 var bit_offset_val_pl: Value.Payload.U64 = .{
4147 .base = .{ .tag = .int_u64 },
4148 .data = struct_obj.packedFieldBitOffset(target, extra.field_index),
4149 };
4150 const bit_offset_val = Value.initPayload(&bit_offset_val_pl.base);
4151
4152 const field_int_signedness = if (inst_ty.isAbiInt())
4153 inst_ty.intInfo(target).signedness
4154 else
4155 .unsigned;
4156 var field_int_pl = Type.Payload.Bits{
4157 .base = .{ .tag = switch (field_int_signedness) {
4158 .unsigned => .int_unsigned,
4159 .signed => .int_signed,
4160 } },
4161 .data = @intCast(u16, inst_ty.bitSize(target)),
4162 };
4163 const field_int_ty = Type.initPayload(&field_int_pl.base);
4164
4165 const temp_local = try f.allocLocal(field_int_ty, .Const);
4166 try writer.writeAll(" = zig_wrap_");
4167 try f.renderTypeForBuiltinFnName(writer, field_int_ty);
4168 try writer.writeAll("((");
4169 try f.renderTypecast(writer, field_int_ty);
4170 try writer.writeAll(")zig_shr_");
4171 try f.renderTypeForBuiltinFnName(writer, struct_ty);
4172 try writer.writeByte('(');
4173 try f.writeCValue(writer, struct_byval, .Other);
4174 try writer.writeAll(", ");
4175 try f.object.dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument);
4176 try writer.writeByte(')');
4177 try f.renderBuiltinInfo(writer, field_int_ty, .Bits);
4178 try writer.writeAll(");\n");
4179 if (inst_ty.eql(field_int_ty, f.object.dg.module)) return temp_local;
4180
4181 const local = try f.allocLocal(inst_ty, .Mut);
4182 try writer.writeAll(";\n");
4183 try writer.writeAll("memcpy(");
4184 try f.writeCValue(writer, .{ .local_ref = local.local }, .FunctionArgument);
4185 try writer.writeAll(", ");
4186 try f.writeCValue(writer, .{ .local_ref = temp_local.local }, .FunctionArgument);
4187 try writer.writeAll(", sizeof(");
4188 try f.renderTypecast(writer, inst_ty);
4189 try writer.writeAll("));\n");
4190 return local;
4191 },
4192 },
38784193 .@"union", .union_safety_tagged, .union_tagged => struct_ty.unionFields().keys()[extra.field_index],
3879 .tuple, .anon_struct => blk: {
4194 .tuple, .anon_struct => |tag| blk: {
38804195 const tuple = struct_ty.tupleFields();
38814196 if (tuple.values[extra.field_index].tag() != .unreachable_value) return CValue.none;
38824197
4198 if (tag == .anon_struct) break :blk struct_ty.structFieldName(extra.field_index);
4199
38834200 field_name_buf = try std.fmt.allocPrint(f.object.dg.gpa, "field_{d}", .{extra.field_index});
38844201 break :blk field_name_buf;
38854202 },
......@@ -3887,13 +4204,8 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
38874204 };
38884205 const payload = if (struct_ty.tag() == .union_tagged or struct_ty.tag() == .union_safety_tagged) "payload." else "";
38894206
3890 // Ensure complete type definition is visible before accessing fields.
3891 try f.renderType(std.io.null_writer, struct_ty);
3892
3893 const inst_ty = f.air.typeOfIndex(inst);
3894 const is_array = inst_ty.zigTypeTag() == .Array;
4207 const is_array = lowersToArray(inst_ty, target);
38954208 const local = try f.allocLocal(inst_ty, if (is_array) .Mut else .Const);
3896
38974209 if (is_array) {
38984210 try writer.writeAll(";\n");
38994211 try writer.writeAll("memcpy(");
......@@ -4067,7 +4379,8 @@ fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {
40674379 const inst_ty = f.air.typeOfIndex(inst);
40684380 const payload_ty = inst_ty.errorUnionPayload();
40694381 const error_ty = inst_ty.errorUnionSet();
4070 const is_array = payload_ty.zigTypeTag() == .Array;
4382 const target = f.object.dg.module.getTarget();
4383 const is_array = lowersToArray(payload_ty, target);
40714384 const local = try f.allocLocal(inst_ty, if (is_array) .Mut else .Const);
40724385 try writer.writeAll(" = { .payload = ");
40734386 try f.writeCValue(writer, if (is_array) CValue{ .undef = payload_ty } else operand, .Initializer);
......@@ -4141,7 +4454,7 @@ fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue {
41414454 } else {
41424455 try writer.writeAll("&(");
41434456 try f.writeCValueDeref(writer, operand);
4144 try writer.writeAll(")[0]");
4457 try writer.print(")[{}]", .{try f.fmtIntLiteral(Type.usize, Value.zero)});
41454458 }
41464459
41474460 var len_pl: Value.Payload.U64 = .{ .base = .{ .tag = .int_u64 }, .data = array_len };
......@@ -4571,16 +4884,18 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
45714884 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
45724885 const len = @intCast(usize, inst_ty.arrayLen());
45734886 const elements = @ptrCast([]const Air.Inst.Ref, f.air.extra[ty_pl.payload..][0..len]);
4887 const target = f.object.dg.module.getTarget();
45744888 const mutability: Mutability = for (elements) |element| {
4575 if (f.air.typeOf(element).zigTypeTag() == .Array) break .Mut;
4889 if (lowersToArray(f.air.typeOf(element), target)) break .Mut;
45764890 } else .Const;
45774891
45784892 const writer = f.object.writer();
45794893 const local = try f.allocLocal(inst_ty, mutability);
4580 try writer.writeAll(" = {");
4894 try writer.writeAll(" = ");
45814895 switch (inst_ty.zigTypeTag()) {
45824896 .Array => {
45834897 const elem_ty = inst_ty.childType();
4898 try writer.writeByte('{');
45844899 var empty = true;
45854900 for (elements) |element| {
45864901 if (!empty) try writer.writeAll(", ");
......@@ -4595,49 +4910,99 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
45954910 if (empty) try writer.print("{}", .{try f.fmtIntLiteral(Type.u8, Value.zero)});
45964911 try writer.writeAll("};\n");
45974912 },
4598 .Struct => {
4599 var empty = true;
4600 for (elements) |element, index| {
4601 if (inst_ty.structFieldValueComptime(index)) |_| continue;
4913 .Struct => switch (inst_ty.containerLayout()) {
4914 .Auto, .Extern => {
4915 try writer.writeByte('{');
4916 var empty = true;
4917 for (elements) |element, index| {
4918 if (inst_ty.structFieldValueComptime(index)) |_| continue;
46024919
4603 if (!empty) try writer.writeAll(", ");
4604 if (!inst_ty.isTupleOrAnonStruct()) {
4605 try writer.print(".{ } = ", .{fmtIdent(inst_ty.structFieldName(index))});
4920 if (!empty) try writer.writeAll(", ");
4921 if (!inst_ty.isTupleOrAnonStruct()) {
4922 try writer.print(".{ } = ", .{fmtIdent(inst_ty.structFieldName(index))});
4923 }
4924
4925 const element_ty = f.air.typeOf(element);
4926 try f.writeCValue(writer, switch (element_ty.zigTypeTag()) {
4927 .Array => CValue{ .undef = element_ty },
4928 else => try f.resolveInst(element),
4929 }, .Initializer);
4930 empty = false;
4931 }
4932 if (empty) try writer.print("{}", .{try f.fmtIntLiteral(Type.u8, Value.zero)});
4933 try writer.writeAll("};\n");
4934
4935 for (elements) |element, index| {
4936 if (inst_ty.structFieldValueComptime(index)) |_| continue;
4937
4938 const element_ty = f.air.typeOf(element);
4939 if (element_ty.zigTypeTag() != .Array) continue;
4940
4941 var field_name_buf: []u8 = &.{};
4942 defer f.object.dg.gpa.free(field_name_buf);
4943 const field_name = if (inst_ty.isTuple()) field_name: {
4944 field_name_buf = try std.fmt.allocPrint(f.object.dg.gpa, "field_{d}", .{index});
4945 break :field_name field_name_buf;
4946 } else inst_ty.structFieldName(index);
4947
4948 try writer.writeAll(";\n");
4949 try writer.writeAll("memcpy(");
4950 try f.writeCValue(writer, local, .Other);
4951 try writer.print(".{ }, ", .{fmtIdent(field_name)});
4952 try f.writeCValue(writer, try f.resolveInst(element), .FunctionArgument);
4953 try writer.writeAll(", sizeof(");
4954 try f.renderTypecast(writer, element_ty);
4955 try writer.writeAll("));\n");
46064956 }
4957 },
4958 .Packed => {
4959 const int_info = inst_ty.intInfo(target);
46074960
4608 const element_ty = f.air.typeOf(element);
4609 try f.writeCValue(writer, switch (element_ty.zigTypeTag()) {
4610 .Array => CValue{ .undef = element_ty },
4611 else => try f.resolveInst(element),
4612 }, .Initializer);
4613 empty = false;
4614 }
4615 if (empty) try writer.print("{}", .{try f.fmtIntLiteral(Type.u8, Value.zero)});
4616 try writer.writeAll("};\n");
4961 var bit_offset_ty_pl = Type.Payload.Bits{
4962 .base = .{ .tag = .int_unsigned },
4963 .data = Type.smallestUnsignedBits(int_info.bits - 1),
4964 };
4965 const bit_offset_ty = Type.initPayload(&bit_offset_ty_pl.base);
46174966
4618 for (elements) |element, index| {
4619 if (inst_ty.structFieldValueComptime(index)) |_| continue;
4967 var bit_offset_val_pl: Value.Payload.U64 = .{ .base = .{ .tag = .int_u64 }, .data = 0 };
4968 const bit_offset_val = Value.initPayload(&bit_offset_val_pl.base);
46204969
4621 const element_ty = f.air.typeOf(element);
4622 if (element_ty.zigTypeTag() != .Array) continue;
4970 var empty = true;
4971 for (elements) |_, index| {
4972 const field_ty = inst_ty.structFieldType(index);
4973 if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue;
46234974
4624 var field_name_storage: ?[]u8 = null;
4625 defer if (field_name_storage) |storage| f.object.dg.gpa.free(storage);
4626 const field_name = if (inst_ty.isTupleOrAnonStruct()) field_name: {
4627 const name = try std.fmt.allocPrint(f.object.dg.gpa, "field_{d}", .{index});
4628 field_name_storage = name;
4629 break :field_name name;
4630 } else inst_ty.structFieldName(index);
4975 if (!empty) {
4976 try writer.writeAll("zig_or_");
4977 try f.renderTypeForBuiltinFnName(writer, inst_ty);
4978 try writer.writeByte('(');
4979 }
4980 empty = false;
4981 }
4982 empty = true;
4983 for (elements) |element, index| {
4984 const field_ty = inst_ty.structFieldType(index);
4985 if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue;
4986
4987 if (!empty) try writer.writeAll(", ");
4988 try writer.writeAll("zig_shlw_");
4989 try f.renderTypeForBuiltinFnName(writer, inst_ty);
4990 try writer.writeAll("((");
4991 try f.renderTypecast(writer, inst_ty);
4992 try writer.writeByte(')');
4993 try f.writeCValue(writer, try f.resolveInst(element), .Other);
4994 try writer.writeAll(", ");
4995 try f.object.dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument);
4996 try f.renderBuiltinInfo(writer, inst_ty, .Bits);
4997 try writer.writeByte(')');
4998 if (!empty) try writer.writeByte(')');
46314999
5000 bit_offset_val_pl.data += field_ty.bitSize(target);
5001 empty = false;
5002 }
5003 if (empty) try f.writeCValue(writer, .{ .undef = inst_ty }, .Initializer);
46325004 try writer.writeAll(";\n");
4633 try writer.writeAll("memcpy(");
4634 try f.writeCValue(writer, local, .Other);
4635 try writer.print(".{ }, ", .{fmtIdent(field_name)});
4636 try f.writeCValue(writer, try f.resolveInst(element), .FunctionArgument);
4637 try writer.writeAll(", sizeof(");
4638 try f.renderTypecast(writer, element_ty);
4639 try writer.writeAll("));\n");
4640 }
5005 },
46415006 },
46425007 .Vector => return f.fail("TODO: C backend: implement airAggregateInit for vectors", .{}),
46435008 else => unreachable,
......@@ -4947,7 +5312,7 @@ fn formatIntLiteral(
49475312 const int_info = data.ty.intInfo(target);
49485313
49495314 const Limb = std.math.big.Limb;
4950 const expected_contents = struct {
5315 const ExpectedContents = struct {
49515316 const base = 10;
49525317 const limbs_count_128 = BigInt.calcTwosCompLimbCount(128);
49535318 const expected_needed_limbs_count = BigInt.calcToStringLimbsBufferLen(limbs_count_128, base);
......@@ -4959,8 +5324,8 @@ fn formatIntLiteral(
49595324 undef_limbs: [limbs_count_128]Limb,
49605325 wrap_limbs: [limbs_count_128]Limb,
49615326 };
4962 var stack align(@alignOf(expected_contents)) =
4963 std.heap.stackFallback(@sizeOf(expected_contents), data.mod.gpa);
5327 var stack align(@alignOf(ExpectedContents)) =
5328 std.heap.stackFallback(@sizeOf(ExpectedContents), data.mod.gpa);
49645329 const allocator = stack.get();
49655330
49665331 var undef_limbs: []Limb = &.{};
......@@ -5092,18 +5457,60 @@ fn formatIntLiteral(
50925457 }
50935458}
50945459
5095fn loweredFnRetTyHasBits(fn_ty: Type) bool {
5096 const ret_ty = fn_ty.fnReturnType();
5097 if (ret_ty.hasRuntimeBitsIgnoreComptime()) {
5098 return true;
5099 }
5100 if (ret_ty.isError()) {
5101 return true;
5102 }
5103 return false;
5104}
5105
51065460fn isByRef(ty: Type) bool {
51075461 _ = ty;
51085462 return false;
51095463}
5464
5465const LowerFnRetTyBuffer = struct {
5466 const names = [1][]const u8{"array"};
5467 types: [1]Type,
5468 values: [1]Value,
5469 payload: Type.Payload.AnonStruct,
5470};
5471fn lowerFnRetTy(ret_ty: Type, buffer: *LowerFnRetTyBuffer, target: std.Target) Type {
5472 if (ret_ty.zigTypeTag() == .NoReturn) return Type.initTag(.noreturn);
5473
5474 if (lowersToArray(ret_ty, target)) {
5475 buffer.types = [1]Type{ret_ty};
5476 buffer.values = [1]Value{Value.initTag(.unreachable_value)};
5477 buffer.payload = .{ .data = .{
5478 .names = &LowerFnRetTyBuffer.names,
5479 .types = &buffer.types,
5480 .values = &buffer.values,
5481 } };
5482 return Type.initPayload(&buffer.payload.base);
5483 }
5484
5485 return if (ret_ty.hasRuntimeBitsIgnoreComptime()) ret_ty else Type.void;
5486}
5487
5488fn lowersToArray(ty: Type, target: std.Target) bool {
5489 return switch (ty.zigTypeTag()) {
5490 .Array => return true,
5491 else => return ty.isAbiInt() and toCIntBits(@intCast(u32, ty.bitSize(target))) == null,
5492 };
5493}
5494
5495fn loweredArrayInfo(ty: Type, target: std.Target) ?Type.ArrayInfo {
5496 if (!lowersToArray(ty, target)) return null;
5497
5498 switch (ty.zigTypeTag()) {
5499 .Array => return ty.arrayInfo(),
5500 else => {
5501 const abi_size = ty.abiSize(target);
5502 const abi_align = ty.abiAlignment(target);
5503 return Type.ArrayInfo{
5504 .elem_type = switch (abi_align) {
5505 1 => Type.u8,
5506 2 => Type.u16,
5507 4 => Type.u32,
5508 8 => Type.u64,
5509 16 => Type.initTag(.u128),
5510 else => unreachable,
5511 },
5512 .len = @divExact(abi_size, abi_align),
5513 };
5514 },
5515 }
5516}
test/behavior/bitcast.zig-2
......@@ -108,7 +108,6 @@ test "@bitCast packed structs at runtime and comptime" {
108108 return error.SkipZigTest;
109109 }
110110 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
111 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
112111 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
113112 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
114113 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
......@@ -167,7 +166,6 @@ test "@bitCast extern structs at runtime and comptime" {
167166
168167test "bitcast packed struct to integer and back" {
169168 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
170 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
171169 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
172170 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
173171 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
test/behavior/eval.zig-2
......@@ -718,7 +718,6 @@ test "*align(1) u16 is the same as *align(1:0:2) u16" {
718718}
719719
720720test "array concatenation of function calls" {
721 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
722721 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
723722 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
724723
......@@ -727,7 +726,6 @@ test "array concatenation of function calls" {
727726}
728727
729728test "array multiplication of function calls" {
730 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
731729 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
732730 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
733731
test/behavior/packed-struct.zig+1-1
......@@ -414,7 +414,6 @@ test "load pointer from packed struct" {
414414}
415415
416416test "@ptrToInt on a packed struct field" {
417 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
418417 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
419418 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
420419 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
......@@ -448,6 +447,7 @@ test "optional pointer in packed struct" {
448447}
449448
450449test "nested packed struct field access test" {
450 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
451451 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
452452 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
453453 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
test/behavior/struct.zig-2
......@@ -505,7 +505,6 @@ test "packed struct fields are ordered from LSB to MSB" {
505505 }
506506 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
507507 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
508 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
509508 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
510509 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
511510 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -1301,7 +1300,6 @@ test "packed struct aggregate init" {
13011300 }
13021301 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
13031302 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1304 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
13051303 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
13061304 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
13071305 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/undefined.zig-1
......@@ -15,7 +15,6 @@ const static_array = initStaticArray();
1515test "init static array to undefined" {
1616 // This test causes `initStaticArray()` to be codegen'd, and the
1717 // C backend does not yet support returning arrays, so it fails
18 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1918 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
2019 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2120