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);...@@ -316,19 +316,28 @@ zig_extern_c void *memset (void *, int, zig_usize);
316#define zig_maxInt(Type, bits) zig_shr_##Type(zig_maxInt_##Type, (zig_bitSizeOf(zig_##Type) - bits))316#define zig_maxInt(Type, bits) zig_shr_##Type(zig_maxInt_##Type, (zig_bitSizeOf(zig_##Type) - bits))
317#define zig_minInt(Type, bits) zig_not_##Type(zig_maxInt(Type, bits), bits)317#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
319#define zig_int_helpers(w) \340#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\
332 static inline zig_i##w zig_shr_i##w(zig_i##w lhs, zig_u8 rhs) { \341 static inline zig_i##w zig_shr_i##w(zig_i##w lhs, zig_u8 rhs) { \
333 zig_i##w sign_mask = lhs < zig_as_i##w(0) ? zig_as_i##w(-1) : zig_as_i##w(0); \342 zig_i##w sign_mask = lhs < zig_as_i##w(0) ? zig_as_i##w(-1) : zig_as_i##w(0); \
334 return ((lhs ^ sign_mask) >> rhs) ^ sign_mask; \343 return ((lhs ^ sign_mask) >> rhs) ^ sign_mask; \
...@@ -351,18 +360,10 @@ zig_extern_c void *memset (void *, int, zig_usize);...@@ -351,18 +360,10 @@ zig_extern_c void *memset (void *, int, zig_usize);
351 return (val & zig_as_u##w(1) << (bits - zig_as_u8(1))) != 0 \360 return (val & zig_as_u##w(1) << (bits - zig_as_u8(1))) != 0 \
352 ? val | zig_minInt(i##w, bits) : val & zig_maxInt(i##w, bits); \361 ? val | zig_minInt(i##w, bits) : val & zig_maxInt(i##w, bits); \
353 } \362 } \
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 } \
358\363\
359 static inline zig_i##w zig_div_floor_i##w(zig_i##w lhs, zig_i##w rhs) { \364 static inline zig_i##w zig_div_floor_i##w(zig_i##w lhs, zig_i##w rhs) { \
360 return lhs / rhs - (((lhs ^ rhs) & (lhs % rhs)) < zig_as_i##w(0)); \365 return lhs / rhs - (((lhs ^ rhs) & (lhs % rhs)) < zig_as_i##w(0)); \
361 } \366 } \
362\
363 static inline zig_u##w zig_mod_u##w(zig_u##w lhs, zig_u##w rhs) { \
364 return lhs % rhs; \
365 } \
366\367\
367 static inline zig_i##w zig_mod_i##w(zig_i##w lhs, zig_i##w rhs) { \368 static inline zig_i##w zig_mod_i##w(zig_i##w lhs, zig_i##w rhs) { \
368 zig_i##w rem = lhs % rhs; \369 zig_i##w rem = lhs % rhs; \
...@@ -969,12 +970,12 @@ typedef signed __int128 zig_i128;...@@ -969,12 +970,12 @@ typedef signed __int128 zig_i128;
969#define zig_lo_i128(val) ((zig_u64)((val) >> 0))970#define zig_lo_i128(val) ((zig_u64)((val) >> 0))
970#define zig_bitcast_u128(val) ((zig_u128)(val))971#define zig_bitcast_u128(val) ((zig_u128)(val))
971#define zig_bitcast_i128(val) ((zig_i128)(val))972#define zig_bitcast_i128(val) ((zig_i128)(val))
972#define zig_cmp_int128(ZigType, CType) \973#define zig_cmp_int128(Type) \
973 static inline zig_i8 zig_cmp_##ZigType(CType lhs, CType rhs) { \974 static inline zig_i8 zig_cmp_##Type(zig_##Type lhs, zig_##Type rhs) { \
974 return (lhs > rhs) - (lhs < rhs); \975 return (lhs > rhs) - (lhs < rhs); \
975 }976 }
976#define zig_bit_int128(ZigType, CType, operation, operator) \977#define zig_bit_int128(Type, operation, operator) \
977 static inline CType zig_##operation##_##ZigType(CType lhs, CType rhs) { \978 static inline zig_##Type zig_##operation##_##Type(zig_##Type lhs, zig_##Type rhs) { \
978 return lhs operator rhs; \979 return lhs operator rhs; \
979 }980 }
980981
...@@ -996,15 +997,15 @@ typedef struct { zig_align(16) zig_i64 hi; zig_u64 lo; } zig_i128;...@@ -996,15 +997,15 @@ typedef struct { zig_align(16) zig_i64 hi; zig_u64 lo; } zig_i128;
996#define zig_lo_i128(val) ((val).lo)997#define zig_lo_i128(val) ((val).lo)
997#define zig_bitcast_u128(val) zig_as_u128((zig_u64)(val).hi, (val).lo)998#define zig_bitcast_u128(val) zig_as_u128((zig_u64)(val).hi, (val).lo)
998#define zig_bitcast_i128(val) zig_as_i128((zig_i64)(val).hi, (val).lo)999#define zig_bitcast_i128(val) zig_as_i128((zig_i64)(val).hi, (val).lo)
999#define zig_cmp_int128(ZigType, CType) \1000#define zig_cmp_int128(Type) \
1000 static inline zig_c_int zig_cmp_##ZigType(CType lhs, CType rhs) { \1001 static inline zig_i8 zig_cmp_##Type(zig_##Type lhs, zig_##Type rhs) { \
1001 return (lhs.hi == rhs.hi) \1002 return (lhs.hi == rhs.hi) \
1002 ? (lhs.lo > rhs.lo) - (lhs.lo < rhs.lo) \1003 ? (lhs.lo > rhs.lo) - (lhs.lo < rhs.lo) \
1003 : (lhs.hi > rhs.hi) - (lhs.hi < rhs.hi); \1004 : (lhs.hi > rhs.hi) - (lhs.hi < rhs.hi); \
1004 }1005 }
1005#define zig_bit_int128(ZigType, CType, operation, operator) \1006#define zig_bit_int128(Type, operation, operator) \
1006 static inline CType zig_##operation##_##ZigType(CType lhs, CType rhs) { \1007 static inline zig_##Type zig_##operation##_##Type(zig_##Type lhs, zig_##Type rhs) { \
1007 return (CType){ .hi = lhs.hi operator rhs.hi, .lo = lhs.lo operator rhs.lo }; \1008 return (zig_##Type){ .hi = lhs.hi operator rhs.hi, .lo = lhs.lo operator rhs.lo }; \
1008 }1009 }
10091010
1010#endif /* zig_has_int128 */1011#endif /* zig_has_int128 */
...@@ -1014,17 +1015,17 @@ typedef struct { zig_align(16) zig_i64 hi; zig_u64 lo; } zig_i128;...@@ -1014,17 +1015,17 @@ typedef struct { zig_align(16) zig_i64 hi; zig_u64 lo; } zig_i128;
1014#define zig_minInt_i128 zig_as_i128(zig_minInt_i64, zig_minInt_u64)1015#define zig_minInt_i128 zig_as_i128(zig_minInt_i64, zig_minInt_u64)
1015#define zig_maxInt_i128 zig_as_i128(zig_maxInt_i64, zig_maxInt_u64)1016#define zig_maxInt_i128 zig_as_i128(zig_maxInt_i64, zig_maxInt_u64)
10161017
1017zig_cmp_int128(u128, zig_u128)1018zig_cmp_int128(u128)
1018zig_cmp_int128(i128, zig_i128)1019zig_cmp_int128(i128)
10191020
1020zig_bit_int128(u128, zig_u128, and, &)1021zig_bit_int128(u128, and, &)
1021zig_bit_int128(i128, zig_i128, and, &)1022zig_bit_int128(i128, and, &)
10221023
1023zig_bit_int128(u128, zig_u128, or, |)1024zig_bit_int128(u128, or, |)
1024zig_bit_int128(i128, zig_i128, or, |)1025zig_bit_int128(i128, or, |)
10251026
1026zig_bit_int128(u128, zig_u128, xor, ^)1027zig_bit_int128(u128, xor, ^)
1027zig_bit_int128(i128, zig_i128, xor, ^)1028zig_bit_int128(i128, xor, ^)
10281029
1029static inline zig_u128 zig_shr_u128(zig_u128 lhs, zig_u8 rhs);1030static 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) {...@@ -1164,7 +1165,7 @@ static inline zig_i128 zig_mod_i128(zig_i128 lhs, zig_i128 rhs) {
1164#define zig_mod_u128 zig_rem_u1281165#define zig_mod_u128 zig_rem_u128
11651166
1166static inline zig_i128 zig_shr_i128(zig_i128 lhs, zig_u8 rhs) {1167static 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);
1168 return zig_xor_i128(zig_bitcast_i128(zig_shr_u128(zig_bitcast_u128(zig_xor_i128(lhs, sign_mask)), rhs)), sign_mask);1169 return zig_xor_i128(zig_bitcast_i128(zig_shr_u128(zig_bitcast_u128(zig_xor_i128(lhs, sign_mask)), rhs)), sign_mask);
1169}1170}
11701171
...@@ -1218,8 +1219,8 @@ static inline zig_bool zig_shlo_u128(zig_u128 *res, zig_u128 lhs, zig_u8 rhs, zi...@@ -1218,8 +1219,8 @@ static inline zig_bool zig_shlo_u128(zig_u128 *res, zig_u128 lhs, zig_u8 rhs, zi
1218static inline zig_bool zig_shlo_i128(zig_i128 *res, zig_i128 lhs, zig_u8 rhs, zig_u8 bits) {1219static inline zig_bool zig_shlo_i128(zig_i128 *res, zig_i128 lhs, zig_u8 rhs, zig_u8 bits) {
1219 *res = zig_shlw_i128(lhs, rhs, bits);1220 *res = zig_shlw_i128(lhs, rhs, bits);
1220 zig_i128 mask = zig_bitcast_i128(zig_shl_u128(zig_maxInt_u128, bits - rhs - zig_as_u8(1)));1221 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 return zig_cmp_i128(zig_and_i128(lhs, mask), zig_as_i128(0, 0)) != zig_as_i8(0) &&
1222 zig_cmp_i128(zig_and_i128(lhs, mask), mask) != 0;1223 zig_cmp_i128(zig_and_i128(lhs, mask), mask) != zig_as_i8(0);
1223}1224}
12241225
1225static inline zig_bool zig_addo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, zig_u8 bits) {1226static 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)...@@ -1316,15 +1317,15 @@ static inline zig_bool zig_subo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs)
13161317
1317static inline zig_u128 zig_shls_u128(zig_u128 lhs, zig_u128 rhs, zig_u8 bits) {1318static inline zig_u128 zig_shls_u128(zig_u128 lhs, zig_u128 rhs, zig_u8 bits) {
1318 zig_u128 res;1319 zig_u128 res;
1319 if (zig_cmp_u128(rhs, zig_as_u128(0, bits)) >= 0)1320 if (zig_cmp_u128(rhs, zig_as_u128(0, bits)) >= zig_as_i8(0))
1320 return zig_cmp_u128(lhs, zig_as_u128(0, 0)) != 0 ? zig_maxInt(u128, bits) : lhs;1321 return zig_cmp_u128(lhs, zig_as_u128(0, 0)) != zig_as_i8(0) ? zig_maxInt(u128, bits) : lhs;
1321 return zig_shlo_u128(&res, lhs, (zig_u8)rhs, bits) ? zig_maxInt(u128, bits) : res;1322 return zig_shlo_u128(&res, lhs, (zig_u8)rhs, bits) ? zig_maxInt(u128, bits) : res;
1322}1323}
13231324
1324static inline zig_i128 zig_shls_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) {1325static inline zig_i128 zig_shls_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) {
1325 zig_i128 res;1326 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 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;
1327 return zig_cmp_i128(lhs, zig_as_i128(0, 0)) < 0 ? zig_minInt(i128, bits) : zig_maxInt(i128, bits);1328 return zig_cmp_i128(lhs, zig_as_i128(0, 0)) < zig_as_i8(0) ? zig_minInt(i128, bits) : zig_maxInt(i128, bits);
1328}1329}
13291330
1330static inline zig_u128 zig_adds_u128(zig_u128 lhs, zig_u128 rhs, zig_u8 bits) {1331static 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) {...@@ -1335,7 +1336,7 @@ static inline zig_u128 zig_adds_u128(zig_u128 lhs, zig_u128 rhs, zig_u8 bits) {
1335static inline zig_i128 zig_adds_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) {1336static inline zig_i128 zig_adds_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) {
1336 zig_i128 res;1337 zig_i128 res;
1337 if (!zig_addo_i128(&res, lhs, rhs, bits)) return res;1338 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);
1339}1340}
13401341
1341static inline zig_u128 zig_subs_u128(zig_u128 lhs, zig_u128 rhs, zig_u8 bits) {1342static 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) {...@@ -1346,7 +1347,7 @@ static inline zig_u128 zig_subs_u128(zig_u128 lhs, zig_u128 rhs, zig_u8 bits) {
1346static inline zig_i128 zig_subs_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) {1347static inline zig_i128 zig_subs_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) {
1347 zig_i128 res;1348 zig_i128 res;
1348 if (!zig_subo_i128(&res, lhs, rhs, bits)) return res;1349 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);
1350}1351}
13511352
1352static inline zig_u128 zig_muls_u128(zig_u128 lhs, zig_u128 rhs, zig_u8 bits) {1353static 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) {...@@ -1357,7 +1358,7 @@ static inline zig_u128 zig_muls_u128(zig_u128 lhs, zig_u128 rhs, zig_u8 bits) {
1357static inline zig_i128 zig_muls_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) {1358static inline zig_i128 zig_muls_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) {
1358 zig_i128 res;1359 zig_i128 res;
1359 if (!zig_mulo_i128(&res, lhs, rhs, bits)) return res;1360 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);
1361}1362}
13621363
1363static inline zig_u8 zig_clz_u128(zig_u128 val, zig_u8 bits) {1364static 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");...@@ -18,7 +18,7 @@ const Air = @import("../Air.zig");
18const Liveness = @import("../Liveness.zig");18const Liveness = @import("../Liveness.zig");
19const CType = @import("../type.zig").CType;19const CType = @import("../type.zig").CType;
2020
21const Mutability = enum { Const, Mut };21const Mutability = enum { Const, ConstArgument, Mut };
22const BigInt = std.math.big.int;22const BigInt = std.math.big.int;
2323
24pub const CValue = union(enum) {24pub const CValue = union(enum) {
...@@ -254,24 +254,20 @@ pub const Function = struct {...@@ -254,24 +254,20 @@ pub const Function = struct {
254254
255 const val = f.air.value(inst).?;255 const val = f.air.value(inst).?;
256 const ty = f.air.typeOf(inst);256 const ty = f.air.typeOf(inst);
257 switch (ty.zigTypeTag()) {257
258 .Array => {258 const result = if (lowersToArray(ty, f.object.dg.module.getTarget())) result: {
259 const writer = f.object.code_header.writer();259 const writer = f.object.code_header.writer();
260 const decl_c_value = f.allocLocalValue();260 const decl_c_value = f.allocLocalValue();
261 gop.value_ptr.* = decl_c_value;261 try writer.writeAll("static ");
262 try writer.writeAll("static ");262 try f.object.dg.renderTypeAndName(writer, ty, decl_c_value, .Const, 0, .Complete);
263 try f.object.dg.renderTypeAndName(writer, ty, decl_c_value, .Const, 0, .Complete);263 try writer.writeAll(" = ");
264 try writer.writeAll(" = ");264 try f.object.dg.renderValue(writer, ty, val, .Initializer);
265 try f.object.dg.renderValue(writer, ty, val, .Initializer);265 try writer.writeAll(";\n ");
266 try writer.writeAll(";\n ");266 break :result decl_c_value;
267 return decl_c_value;267 } else CValue{ .constant = inst };
268 },268
269 else => {269 gop.value_ptr.* = result;
270 const result = CValue{ .constant = inst };270 return result;
271 gop.value_ptr.* = result;
272 return result;
273 },
274 }
275 }271 }
276272
277 fn wantSafety(f: *Function) bool {273 fn wantSafety(f: *Function) bool {
...@@ -374,7 +370,7 @@ pub const Function = struct {...@@ -374,7 +370,7 @@ pub const Function = struct {
374370
375 fn renderTypeForBuiltinFnName(f: *Function, writer: anytype, ty: Type) !void {371 fn renderTypeForBuiltinFnName(f: *Function, writer: anytype, ty: Type) !void {
376 const target = f.object.dg.module.getTarget();372 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: {
378 const int_info = ty.intInfo(target);374 const int_info = ty.intInfo(target);
379 try writer.writeByte(signAbbrev(int_info.signedness));375 try writer.writeByte(signAbbrev(int_info.signedness));
380 break :c_bits toCIntBits(int_info.bits) orelse376 break :c_bits toCIntBits(int_info.bits) orelse
...@@ -393,21 +389,21 @@ pub const Function = struct {...@@ -393,21 +389,21 @@ pub const Function = struct {
393 switch (info) {389 switch (info) {
394 .None => {},390 .None => {},
395 .Range => {391 .Range => {
396 var arena = std.heap.ArenaAllocator.init(f.object.dg.module.gpa);392 var arena = std.heap.ArenaAllocator.init(f.object.dg.gpa);
397 defer arena.deinit();393 defer arena.deinit();
398394
399 const expected_contents = union { u: Value.Payload.U64, i: Value.Payload.I64 };395 const ExpectedContents = union { u: Value.Payload.U64, i: Value.Payload.I64 };
400 var stack align(@alignOf(expected_contents)) =396 var stack align(@alignOf(ExpectedContents)) =
401 std.heap.stackFallback(@sizeOf(expected_contents), arena.allocator());397 std.heap.stackFallback(@sizeOf(ExpectedContents), arena.allocator());
402398
403 const int_info = ty.intInfo(target);399 const int_info = ty.intInfo(target);
404 if (int_info.signedness == .signed) {400 if (int_info.signedness == .signed) {
405 const min_val = try ty.minInt(stack.get(), target);401 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)});
407 }403 }
408404
409 const max_val = try ty.maxInt(stack.get(), target);405 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)});
411 },407 },
412 .Bits => {408 .Bits => {
413 var bits_pl = Value.Payload.U64{409 var bits_pl = Value.Payload.U64{
...@@ -415,7 +411,7 @@ pub const Function = struct {...@@ -415,7 +411,7 @@ pub const Function = struct {
415 .data = ty.bitSize(target),411 .data = ty.bitSize(target),
416 };412 };
417 const bits_val = Value.initPayload(&bits_pl.base);413 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)});
419 },415 },
420 }416 }
421 }417 }
...@@ -471,7 +467,7 @@ pub const DeclGen = struct {...@@ -471,7 +467,7 @@ pub const DeclGen = struct {
471 @setCold(true);467 @setCold(true);
472 const src = LazySrcLoc.nodeOffset(0);468 const src = LazySrcLoc.nodeOffset(0);
473 const src_loc = src.toSrcLoc(dg.decl);469 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);
475 return error.AnalysisFail;471 return error.AnalysisFail;
476 }472 }
477473
...@@ -559,14 +555,55 @@ pub const DeclGen = struct {...@@ -559,14 +555,55 @@ pub const DeclGen = struct {
559 try dg.renderDeclValue(writer, ptr_ty, ptr_val, decl_index);555 try dg.renderDeclValue(writer, ptr_ty, ptr_val, decl_index);
560 },556 },
561 .field_ptr => {557 .field_ptr => {
558 const ptr_info = ptr_ty.ptrInfo();
562 const field_ptr = ptr_val.castTag(.field_ptr).?.data;559 const field_ptr = ptr_val.castTag(.field_ptr).?.data;
563 const container_ty = field_ptr.container_ty;560 const container_ty = field_ptr.container_ty;
564 const index = field_ptr.field_index;561 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
565 const FieldInfo = struct { name: []const u8, ty: Type };569 const FieldInfo = struct { name: []const u8, ty: Type };
566 const field_info: FieldInfo = switch (container_ty.zigTypeTag()) {570 const field_info: FieldInfo = switch (container_ty.zigTypeTag()) {
567 .Struct => FieldInfo{571 .Struct => switch (container_ty.containerLayout()) {
568 .name = container_ty.structFields().keys()[index],572 .Auto, .Extern => FieldInfo{
569 .ty = container_ty.structFields().values()[index].ty,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 },
570 },607 },
571 .Union => FieldInfo{608 .Union => FieldInfo{
572 .name = container_ty.unionFields().keys()[index],609 .name = container_ty.unionFields().keys()[index],
...@@ -582,20 +619,16 @@ pub const DeclGen = struct {...@@ -582,20 +619,16 @@ pub const DeclGen = struct {
582 },619 },
583 else => unreachable,620 else => unreachable,
584 };621 };
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
591 if (field_info.ty.hasRuntimeBitsIgnoreComptime()) {623 if (field_info.ty.hasRuntimeBitsIgnoreComptime()) {
592 try writer.writeAll("&(");624 try writer.writeAll("&(");
593 try dg.renderParentPtr(writer, field_ptr.container_ptr, container_ptr_ty);625 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) {626 try writer.writeAll(")->");
595 try writer.print(")->payload.{ }", .{fmtIdent(field_info.name)});627 switch (field_ptr.container_ty.tag()) {
596 } else {628 .union_tagged, .union_safety_tagged => try writer.writeAll("payload."),
597 try writer.print(")->{ }", .{fmtIdent(field_info.name)});629 else => {},
598 }630 }
631 try writer.print("{ }", .{fmtIdent(field_info.name)});
599 } else {632 } else {
600 try dg.renderParentPtr(writer, field_ptr.container_ptr, field_info.ty);633 try dg.renderParentPtr(writer, field_ptr.container_ptr, field_info.ty);
601 }634 }
...@@ -694,25 +727,28 @@ pub const DeclGen = struct {...@@ -694,25 +727,28 @@ pub const DeclGen = struct {
694 try dg.renderValue(writer, Type.bool, val, .Initializer);727 try dg.renderValue(writer, Type.bool, val, .Initializer);
695 return writer.writeAll(" }");728 return writer.writeAll(" }");
696 },729 },
697 .Struct => {730 .Struct => switch (ty.containerLayout()) {
698 if (location != .Initializer) {731 .Auto, .Extern => {
699 try writer.writeByte('(');732 if (location != .Initializer) {
700 try dg.renderTypecast(writer, ty);733 try writer.writeByte('(');
701 try writer.writeByte(')');734 try dg.renderTypecast(writer, ty);
702 }735 try writer.writeByte(')');
736 }
703737
704 try writer.writeByte('{');738 try writer.writeByte('{');
705 var empty = true;739 var empty = true;
706 for (ty.structFields().values()) |field| {740 for (ty.structFields().values()) |field| {
707 if (!field.ty.hasRuntimeBits()) continue;741 if (!field.ty.hasRuntimeBits()) continue;
708742
709 if (!empty) try writer.writeByte(',');743 if (!empty) try writer.writeByte(',');
710 try dg.renderValue(writer, field.ty, val, .Initializer);744 try dg.renderValue(writer, field.ty, val, .Initializer);
711745
712 empty = false;746 empty = false;
713 }747 }
714 if (empty) try writer.print("{x}", .{try dg.fmtIntLiteral(Type.u8, Value.undef)});748 if (empty) try writer.print("{x}", .{try dg.fmtIntLiteral(Type.u8, Value.undef)});
715 return writer.writeByte('}');749 return writer.writeByte('}');
750 },
751 .Packed => return writer.print("{x}", .{try dg.fmtIntLiteral(ty, Value.undef)}),
716 },752 },
717 .Union => {753 .Union => {
718 if (location != .Initializer) {754 if (location != .Initializer) {
...@@ -898,7 +934,7 @@ pub const DeclGen = struct {...@@ -898,7 +934,7 @@ pub const DeclGen = struct {
898 },934 },
899 else => {935 else => {
900 // Fall back to generic implementation.936 // Fall back to generic implementation.
901 var arena = std.heap.ArenaAllocator.init(dg.module.gpa);937 var arena = std.heap.ArenaAllocator.init(dg.gpa);
902 defer arena.deinit();938 defer arena.deinit();
903 const arena_allocator = arena.allocator();939 const arena_allocator = arena.allocator();
904940
...@@ -1024,28 +1060,63 @@ pub const DeclGen = struct {...@@ -1024,28 +1060,63 @@ pub const DeclGen = struct {
1024 },1060 },
1025 else => unreachable,1061 else => unreachable,
1026 },1062 },
1027 .Struct => {1063 .Struct => switch (ty.containerLayout()) {
1028 const field_vals = val.castTag(.aggregate).?.data;1064 .Auto, .Extern => {
1065 const field_vals = val.castTag(.aggregate).?.data;
10291066
1030 if (location != .Initializer) {1067 if (location != .Initializer) {
1031 try writer.writeByte('(');1068 try writer.writeByte('(');
1032 try dg.renderTypecast(writer, ty);1069 try dg.renderTypecast(writer, ty);
1033 try writer.writeByte(')');1070 try writer.writeByte(')');
1034 }1071 }
10351072
1036 try writer.writeByte('{');1073 try writer.writeByte('{');
1037 var empty = true;1074 var empty = true;
1038 for (field_vals) |field_val, field_index| {1075 for (field_vals) |field_val, field_index| {
1039 const field_ty = ty.structFieldType(field_index);1076 const field_ty = ty.structFieldType(field_index);
1040 if (!field_ty.hasRuntimeBits()) continue;1077 if (!field_ty.hasRuntimeBits()) continue;
10411078
1042 if (!empty) try writer.writeByte(',');1079 if (!empty) try writer.writeByte(',');
1043 try dg.renderValue(writer, field_ty, field_val, .Initializer);1080 try dg.renderValue(writer, field_ty, field_val, .Initializer);
10441081
1045 empty = false;1082 empty = false;
1046 }1083 }
1047 if (empty) try writer.print("{}", .{try dg.fmtIntLiteral(Type.u8, Value.zero)});1084 if (empty) try writer.print("{}", .{try dg.fmtIntLiteral(Type.u8, Value.zero)});
1048 try writer.writeByte('}');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 },
1049 },1120 },
1050 .Union => {1121 .Union => {
1051 const union_obj = val.castTag(.@"union").?.data;1122 const union_obj = val.castTag(.@"union").?.data;
...@@ -1103,11 +1174,12 @@ pub const DeclGen = struct {...@@ -1103,11 +1174,12 @@ pub const DeclGen = struct {
1103 if (fn_info.cc == .Naked) try w.writeAll("zig_naked ");1174 if (fn_info.cc == .Naked) try w.writeAll("zig_naked ");
1104 if (dg.decl.val.castTag(.function)) |func_payload|1175 if (dg.decl.val.castTag(.function)) |func_payload|
1105 if (func_payload.data.is_cold) try w.writeAll("zig_cold ");1176 if (func_payload.data.is_cold) try w.writeAll("zig_cold ");
1106 const ret_ty = fn_info.return_type;1177
1107 try dg.renderType(w, if (ret_ty.tag() == .noreturn or ret_ty.hasRuntimeBitsIgnoreComptime())1178 const target = dg.module.getTarget();
1108 ret_ty1179 var ret_buf: LowerFnRetTyBuffer = undefined;
1109 else1180 const ret_ty = lowerFnRetTy(fn_info.return_type, &ret_buf, target);
1110 Type.void, kind);1181
1182 try dg.renderType(w, ret_ty, kind);
1111 try w.writeByte(' ');1183 try w.writeByte(' ');
1112 try dg.renderDeclName(w, dg.decl_index);1184 try dg.renderDeclName(w, dg.decl_index);
1113 try w.writeByte('(');1185 try w.writeByte('(');
...@@ -1117,7 +1189,7 @@ pub const DeclGen = struct {...@@ -1117,7 +1189,7 @@ pub const DeclGen = struct {
1117 if (!param_type.hasRuntimeBitsIgnoreComptime()) continue;1189 if (!param_type.hasRuntimeBitsIgnoreComptime()) continue;
1118 if (index > 0) try w.writeAll(", ");1190 if (index > 0) try w.writeAll(", ");
1119 const name = CValue{ .arg = index };1191 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);
1121 index += 1;1193 index += 1;
1122 }1194 }
11231195
...@@ -1137,10 +1209,13 @@ pub const DeclGen = struct {...@@ -1137,10 +1209,13 @@ pub const DeclGen = struct {
11371209
1138 const fn_info = t.fnInfo();1210 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
1140 try bw.writeAll("typedef ");1216 try bw.writeAll("typedef ");
1141 try dg.renderType(bw, fn_info.return_type, .Forward);1217 try dg.renderType(bw, ret_ty, .Forward);
1142 try bw.writeAll(" (*");1218 try bw.writeAll(" (*");
1143
1144 const name_begin = buffer.items.len;1219 const name_begin = buffer.items.len;
1145 try bw.print("zig_F_{}", .{typeToCIdentifier(t, dg.module)});1220 try bw.print("zig_F_{}", .{typeToCIdentifier(t, dg.module)});
1146 const name_end = buffer.items.len;1221 const name_end = buffer.items.len;
...@@ -1315,8 +1390,12 @@ pub const DeclGen = struct {...@@ -1315,8 +1390,12 @@ pub const DeclGen = struct {
1315 const val = fields.values[i];1390 const val = fields.values[i];
1316 if (val.tag() != .unreachable_value) continue;1391 if (val.tag() != .unreachable_value) continue;
13171392
1318 const field_name = try std.fmt.allocPrint(dg.typedefs.allocator, "field_{d}", .{i});1393 var field_name_buf: []const u8 = &.{};
1319 defer dg.typedefs.allocator.free(field_name);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
1321 try buffer.append(' ');1400 try buffer.append(' ');
1322 try dg.renderTypeAndName(buffer.writer(), field_ty, .{ .identifier = field_name }, .Mut, 0, .Complete);1401 try dg.renderTypeAndName(buffer.writer(), field_ty, .{ .identifier = field_name }, .Mut, 0, .Complete);
...@@ -1463,7 +1542,10 @@ pub const DeclGen = struct {...@@ -1463,7 +1542,10 @@ pub const DeclGen = struct {
1463 try bw.print(" zig_A_{}_{d}", .{ typeToCIdentifier(info.elem_type, dg.module), info.len });1542 try bw.print(" zig_A_{}_{d}", .{ typeToCIdentifier(info.elem_type, dg.module), info.len });
1464 const name_end = buffer.items.len;1543 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
1468 const rendered = buffer.toOwnedSlice();1550 const rendered = buffer.toOwnedSlice();
1469 errdefer dg.typedefs.allocator.free(rendered);1551 errdefer dg.typedefs.allocator.free(rendered);
...@@ -1487,7 +1569,7 @@ pub const DeclGen = struct {...@@ -1487,7 +1569,7 @@ pub const DeclGen = struct {
1487 try dg.renderTypeAndName(bw, child_type, .{ .identifier = "payload" }, .Mut, 0, .Complete);1569 try dg.renderTypeAndName(bw, child_type, .{ .identifier = "payload" }, .Mut, 0, .Complete);
1488 try bw.writeAll(";\n ");1570 try bw.writeAll(";\n ");
1489 try dg.renderTypeAndName(bw, Type.bool, .{ .identifier = "is_null" }, .Mut, 0, .Complete);1571 try dg.renderTypeAndName(bw, Type.bool, .{ .identifier = "is_null" }, .Mut, 0, .Complete);
1490 try bw.writeAll("; } ");1572 try bw.writeAll(";\n} ");
1491 const name_begin = buffer.items.len;1573 const name_begin = buffer.items.len;
1492 try bw.print("zig_Q_{}", .{typeToCIdentifier(child_type, dg.module)});1574 try bw.print("zig_Q_{}", .{typeToCIdentifier(child_type, dg.module)});
1493 const name_end = buffer.items.len;1575 const name_end = buffer.items.len;
...@@ -1566,18 +1648,29 @@ pub const DeclGen = struct {...@@ -1566,18 +1648,29 @@ pub const DeclGen = struct {
1566 try w.writeAll("zig_");1648 try w.writeAll("zig_");
1567 try t.print(w, dg.module);1649 try t.print(w, dg.module);
1568 } else {1650 } else {
1569 const info = t.intInfo(target);1651 const int_info = t.intInfo(target);
1570 const c_bits = toCIntBits(info.bits) orelse1652 if (toCIntBits(int_info.bits)) |c_bits|
1571 return dg.fail("TODO: C backend: implement integer types larger than 128 bits", .{});1653 return w.print("zig_{c}{d}", .{ signAbbrev(int_info.signedness), c_bits })
1572 try w.print("zig_{c}{d}", .{ signAbbrev(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 });
1573 }1666 }
1574 },1667 },
1575 .Pointer => {1668 .Pointer => {
1576 const child_ty = t.childType();1669 const ptr_info = t.ptrInfo().data;
1577 if (t.isSlice()) {1670 if (ptr_info.size == .Slice) {
1578 var slice_pl = Type.Payload.ElemType{1671 var slice_pl = Type.Payload.ElemType{
1579 .base = .{ .tag = if (t.ptrIsMutable()) .mut_slice else .const_slice },1672 .base = .{ .tag = if (t.ptrIsMutable()) .mut_slice else .const_slice },
1580 .data = child_ty,1673 .data = ptr_info.pointee_type,
1581 };1674 };
1582 const slice_ty = Type.initPayload(&slice_pl.base);1675 const slice_ty = Type.initPayload(&slice_pl.base);
15831676
...@@ -1587,14 +1680,22 @@ pub const DeclGen = struct {...@@ -1587,14 +1680,22 @@ pub const DeclGen = struct {
1587 return w.writeAll(name);1680 return w.writeAll(name);
1588 }1681 }
15891682
1590 if (child_ty.zigTypeTag() == .Fn) {1683 if (ptr_info.pointee_type.zigTypeTag() == .Fn) {
1591 const name = dg.getTypedefName(child_ty) orelse1684 const name = dg.getTypedefName(ptr_info.pointee_type) orelse
1592 try dg.renderPtrToFnTypedef(child_ty);1685 try dg.renderPtrToFnTypedef(ptr_info.pointee_type);
15931686
1594 return w.writeAll(name);1687 return w.writeAll(name);
1595 }1688 }
15961689
1597 if (t.isCPtr() and child_ty.eql(Type.u8, dg.module) and1690 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
1598 (dg.decl.val.tag() == .extern_fn or1699 (dg.decl.val.tag() == .extern_fn or
1599 std.mem.eql(u8, std.mem.span(dg.decl.name), "main")))1700 std.mem.eql(u8, std.mem.span(dg.decl.name), "main")))
1600 {1701 {
...@@ -1603,9 +1704,9 @@ pub const DeclGen = struct {...@@ -1603,9 +1704,9 @@ pub const DeclGen = struct {
1603 // u8 and i8 produce unsigned char and signed char respectively,1704 // u8 and i8 produce unsigned char and signed char respectively,
1604 // which in C are (not very usefully) different than char.1705 // which in C are (not very usefully) different than char.
1605 try w.writeAll("char");1706 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()) {
1607 .anyopaque => Type.void,1708 .anyopaque => Type.void,
1608 else => child_ty,1709 else => ptr_info.pointee_type,
1609 }, .Forward);1710 }, .Forward);
1610 if (t.isConstPtr()) try w.writeAll(" const");1711 if (t.isConstPtr()) try w.writeAll(" const");
1611 if (t.isVolatilePtr()) try w.writeAll(" volatile");1712 if (t.isVolatilePtr()) try w.writeAll(" volatile");
...@@ -1654,7 +1755,9 @@ pub const DeclGen = struct {...@@ -1654,7 +1755,9 @@ pub const DeclGen = struct {
16541755
1655 return w.writeAll(name);1756 return w.writeAll(name);
1656 },1757 },
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()) {
1658 const name = dg.getTypedefName(t) orelse switch (tag) {1761 const name = dg.getTypedefName(t) orelse switch (tag) {
1659 .Struct => if (t.isTupleOrAnonStruct())1762 .Struct => if (t.isTupleOrAnonStruct())
1660 try dg.renderTupleTypedef(t)1763 try dg.renderTupleTypedef(t)
...@@ -1664,7 +1767,7 @@ pub const DeclGen = struct {...@@ -1664,7 +1767,7 @@ pub const DeclGen = struct {
1664 else => unreachable,1767 else => unreachable,
1665 };1768 };
16661769
1667 return w.writeAll(name);1770 try w.writeAll(name);
1668 } else {1771 } else {
1669 var ptr_pl = Type.Payload.ElemType{1772 var ptr_pl = Type.Payload.ElemType{
1670 .base = .{ .tag = .single_const_pointer },1773 .base = .{ .tag = .single_const_pointer },
...@@ -1675,7 +1778,7 @@ pub const DeclGen = struct {...@@ -1675,7 +1778,7 @@ pub const DeclGen = struct {
1675 const name = dg.getTypedefName(ptr_ty) orelse1778 const name = dg.getTypedefName(ptr_ty) orelse
1676 try dg.renderFwdTypedef(ptr_ty);1779 try dg.renderFwdTypedef(ptr_ty);
16771780
1678 return w.writeAll(name);1781 try w.writeAll(name);
1679 },1782 },
1680 .Enum => {1783 .Enum => {
1681 // For enums, we simply use the integer tag type.1784 // For enums, we simply use the integer tag type.
...@@ -1751,24 +1854,32 @@ pub const DeclGen = struct {...@@ -1751,24 +1854,32 @@ pub const DeclGen = struct {
1751 ) error{ OutOfMemory, AnalysisFail }!void {1854 ) error{ OutOfMemory, AnalysisFail }!void {
1752 var suffix = std.ArrayList(u8).init(dg.gpa);1855 var suffix = std.ArrayList(u8).init(dg.gpa);
1753 defer suffix.deinit();1856 defer suffix.deinit();
1857 const suffix_writer = suffix.writer();
17541858
1755 // Any top-level array types are rendered here as a suffix, which1859 // Any top-level array types are rendered here as a suffix, which
1756 // avoids creating typedefs for every array type1860 // avoids creating typedefs for every array type
1861 const target = dg.module.getTarget();
1757 var render_ty = ty;1862 var render_ty = ty;
1758 while (render_ty.zigTypeTag() == .Array) {1863 var depth: u32 = 0;
1759 const sentinel_bit = @boolToInt(render_ty.sentinel() != null);1864 while (loweredArrayInfo(render_ty, target)) |array_info| {
1760 const c_len = render_ty.arrayLen() + sentinel_bit;1865 const c_len = array_info.len + @boolToInt(array_info.sentinel != null);
1761 try suffix.writer().print("[{d}]", .{c_len});1866 var c_len_pl: Value.Payload.U64 = .{ .base = .{ .tag = .int_u64 }, .data = c_len };
1762 render_ty = render_ty.elemType();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;
1763 }1874 }
17641875
1765 if (alignment != 0 and alignment > ty.abiAlignment(dg.module.getTarget())) {1876 if (alignment != 0 and alignment > ty.abiAlignment(target)) {
1766 try w.print("zig_align({}) ", .{alignment});1877 try w.print("zig_align({}) ", .{alignment});
1767 }1878 }
1768 try dg.renderType(w, render_ty, kind);1879 try dg.renderType(w, render_ty, kind);
17691880
1770 const const_prefix = switch (mutability) {1881 const const_prefix = switch (mutability) {
1771 .Const => "const ",1882 .Const, .ConstArgument => "const ",
1772 .Mut => "",1883 .Mut => "",
1773 };1884 };
1774 try w.print(" {s}", .{const_prefix});1885 try w.print(" {s}", .{const_prefix});
...@@ -1935,7 +2046,7 @@ pub const DeclGen = struct {...@@ -1935,7 +2046,7 @@ pub const DeclGen = struct {
1935 } else if (decl.isExtern()) {2046 } else if (decl.isExtern()) {
1936 return writer.writeAll(mem.sliceTo(decl.name, 0));2047 return writer.writeAll(mem.sliceTo(decl.name, 0));
1937 } else {2048 } else {
1938 const gpa = dg.module.gpa;2049 const gpa = dg.gpa;
1939 const name = try decl.getFullyQualifiedName(dg.module);2050 const name = try decl.getFullyQualifiedName(dg.module);
1940 defer gpa.free(name);2051 defer gpa.free(name);
1941 return writer.print("{ }", .{fmtIdent(name)});2052 return writer.print("{ }", .{fmtIdent(name)});
...@@ -2298,8 +2409,8 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO...@@ -2298,8 +2409,8 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
2298 .trunc => try airTrunc(f, inst),2409 .trunc => try airTrunc(f, inst),
2299 .bool_to_int => try airBoolToInt(f, inst),2410 .bool_to_int => try airBoolToInt(f, inst),
2300 .load => try airLoad(f, inst),2411 .load => try airLoad(f, inst),
2301 .ret => try airRet(f, inst),2412 .ret => try airRet(f, inst, false),
2302 .ret_load => try airRetLoad(f, inst),2413 .ret_load => try airRet(f, inst, true),
2303 .store => try airStore(f, inst),2414 .store => try airStore(f, inst),
2304 .loop => try airLoop(f, inst),2415 .loop => try airLoop(f, inst),
2305 .cond_br => try airCondBr(f, inst),2416 .cond_br => try airCondBr(f, inst),
...@@ -2588,14 +2699,15 @@ fn airArg(f: *Function) CValue {...@@ -2588,14 +2699,15 @@ fn airArg(f: *Function) CValue {
25882699
2589fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {2700fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
2590 const ty_op = f.air.instructions.items(.data)[inst].ty_op;2701 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
2593 const inst_ty = f.air.typeOfIndex(inst);2704 const inst_ty = f.air.typeOfIndex(inst);
2594 if (!inst_ty.hasRuntimeBitsIgnoreComptime() or2705 if (!inst_ty.hasRuntimeBitsIgnoreComptime() or
2595 !is_volatile and f.liveness.isUnused(inst))2706 !ptr_info.@"volatile" and f.liveness.isUnused(inst))
2596 return CValue.none;2707 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);
2599 const operand = try f.resolveInst(ty_op.operand);2711 const operand = try f.resolveInst(ty_op.operand);
2600 const writer = f.object.writer();2712 const writer = f.object.writer();
26012713
...@@ -2612,26 +2724,88 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -2612,26 +2724,88 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
2612 try f.writeCValue(writer, operand, .FunctionArgument);2724 try f.writeCValue(writer, operand, .FunctionArgument);
2613 try writer.writeAll(", sizeof(");2725 try writer.writeAll(", sizeof(");
2614 try f.renderTypecast(writer, inst_ty);2726 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(')');
2616 } else {2766 } else {
2617 try writer.writeAll(" = ");2767 try writer.writeAll(" = ");
2618 try f.writeCValueDeref(writer, operand);2768 try f.writeCValueDeref(writer, operand);
2619 try writer.writeAll(";\n");
2620 }2769 }
2770 try writer.writeAll(";\n");
2621 return local;2771 return local;
2622}2772}
26232773
2624fn airRet(f: *Function, inst: Air.Inst.Index) !CValue {2774fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue {
2625 const un_op = f.air.instructions.items(.data)[inst].un_op;2775 const un_op = f.air.instructions.items(.data)[inst].un_op;
2626 const writer = f.object.writer();2776 const writer = f.object.writer();
2627 const ret_ty = f.air.typeOf(un_op);2777 const target = f.object.dg.module.getTarget();
2628 if (ret_ty.isFnOrHasRuntimeBitsIgnoreComptime()) {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;
2629 const operand = try f.resolveInst(un_op);2785 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
2630 try writer.writeAll("return ");2803 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);
2632 try writer.writeAll(";\n");2808 try writer.writeAll(";\n");
2633 } else if (ret_ty.isError()) {
2634 try writer.writeAll("return 0;");
2635 } else if (f.object.dg.decl.ty.fnCallingConvention() != .Naked) {2809 } else if (f.object.dg.decl.ty.fnCallingConvention() != .Naked) {
2636 // Not even allowed to return void in a naked function.2810 // Not even allowed to return void in a naked function.
2637 try writer.writeAll("return;\n");2811 try writer.writeAll("return;\n");
...@@ -2639,24 +2813,6 @@ fn airRet(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -2639,24 +2813,6 @@ fn airRet(f: *Function, inst: Air.Inst.Index) !CValue {
2639 return CValue.none;2813 return CValue.none;
2640}2814}
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
2660fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue {2816fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue {
2661 if (f.liveness.isUnused(inst))2817 if (f.liveness.isUnused(inst))
2662 return CValue.none;2818 return CValue.none;
...@@ -2696,12 +2852,12 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -2696,12 +2852,12 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {
2696 try writer.writeAll(";\n");2852 try writer.writeAll(";\n");
2697 } else switch (dest_int_info.signedness) {2853 } else switch (dest_int_info.signedness) {
2698 .unsigned => {2854 .unsigned => {
2699 var arena = std.heap.ArenaAllocator.init(f.object.dg.module.gpa);2855 var arena = std.heap.ArenaAllocator.init(f.object.dg.gpa);
2700 defer arena.deinit();2856 defer arena.deinit();
27012857
2702 const expected_contents = union { u: Value.Payload.U64, i: Value.Payload.I64 };2858 const ExpectedContents = union { u: Value.Payload.U64, i: Value.Payload.I64 };
2703 var stack align(@alignOf(expected_contents)) =2859 var stack align(@alignOf(ExpectedContents)) =
2704 std.heap.stackFallback(@sizeOf(expected_contents), arena.allocator());2860 std.heap.stackFallback(@sizeOf(ExpectedContents), arena.allocator());
27052861
2706 const mask_val = try inst_ty.maxInt(stack.get(), target);2862 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...@@ -2756,10 +2912,11 @@ fn airStoreUndefined(f: *Function, lhs_child_ty: Type, dest_ptr: CValue) !CValue
2756fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {2912fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {
2757 // *a = b;2913 // *a = b;
2758 const bin_op = f.air.instructions.items(.data)[inst].bin_op;2914 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
2759 const lhs_child_ty = f.air.typeOf(bin_op.lhs).childType();2915 const ptr_info = f.air.typeOf(bin_op.lhs).ptrInfo().data;
2760 if (!lhs_child_ty.hasRuntimeBitsIgnoreComptime()) return CValue.none;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);
2763 const src_val = try f.resolveInst(bin_op.rhs);2920 const src_val = try f.resolveInst(bin_op.rhs);
27642921
2765 // TODO Sema should emit a different instruction when the store should2922 // TODO Sema should emit a different instruction when the store should
...@@ -2767,20 +2924,20 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -2767,20 +2924,20 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {
2767 const src_val_is_undefined =2924 const src_val_is_undefined =
2768 if (f.air.value(bin_op.rhs)) |v| v.isUndefDeep() else false;2925 if (f.air.value(bin_op.rhs)) |v| v.isUndefDeep() else false;
2769 if (src_val_is_undefined)2926 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();
2772 const writer = f.object.writer();2930 const writer = f.object.writer();
2773 if (lhs_child_ty.zigTypeTag() == .Array) {2931 if (lowersToArray(ptr_info.pointee_type, target)) {
2774 // For this memcpy to safely work we need the rhs to have the same2932 // For this memcpy to safely work we need the rhs to have the same
2775 // underlying type as the lhs (i.e. they must both be arrays of the same underlying type).2933 // 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);2934 assert(src_ty.eql(ptr_info.pointee_type, f.object.dg.module));
2777 assert(rhs_type.eql(lhs_child_ty, f.object.dg.module));
27782935
2779 // If the source is a constant, writeCValue will emit a brace initialization2936 // If the source is a constant, writeCValue will emit a brace initialization
2780 // so work around this by initializing into new local.2937 // so work around this by initializing into new local.
2781 // TODO this should be done by manually initializing elements of the dest array2938 // TODO this should be done by manually initializing elements of the dest array
2782 const array_src = if (src_val == .constant) blk: {2939 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);
2784 try writer.writeAll(" = ");2941 try writer.writeAll(" = ");
2785 try f.writeCValue(writer, src_val, .Initializer);2942 try f.writeCValue(writer, src_val, .Initializer);
2786 try writer.writeAll(";\n");2943 try writer.writeAll(";\n");
...@@ -2789,18 +2946,69 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -2789,18 +2946,69 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {
2789 } else src_val;2946 } else src_val;
27902947
2791 try writer.writeAll("memcpy(");2948 try writer.writeAll("memcpy(");
2792 try f.writeCValue(writer, dest_ptr, .FunctionArgument);2949 try f.writeCValue(writer, ptr_val, .FunctionArgument);
2793 try writer.writeAll(", ");2950 try writer.writeAll(", ");
2794 try f.writeCValue(writer, array_src, .FunctionArgument);2951 try f.writeCValue(writer, array_src, .FunctionArgument);
2795 try writer.writeAll(", sizeof(");2952 try writer.writeAll(", sizeof(");
2796 try f.renderTypecast(writer, lhs_child_ty);2953 try f.renderTypecast(writer, src_ty);
2797 try writer.writeAll("));\n");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)});
2798 } else {3006 } else {
2799 try f.writeCValueDeref(writer, dest_ptr);3007 try f.writeCValueDeref(writer, ptr_val);
2800 try writer.writeAll(" = ");3008 try writer.writeAll(" = ");
2801 try f.writeCValue(writer, src_val, .Other);3009 try f.writeCValue(writer, src_val, .Other);
2802 try writer.writeAll(";\n");
2803 }3010 }
3011 try writer.writeAll(";\n");
2804 return CValue.none;3012 return CValue.none;
2805}3013}
28063014
...@@ -2959,7 +3167,9 @@ fn airEquality(...@@ -2959,7 +3167,9 @@ fn airEquality(
2959 }3167 }
29603168
2961 try f.writeCValue(writer, lhs, .Other);3169 try f.writeCValue(writer, lhs, .Other);
3170 try writer.writeByte(' ');
2962 try writer.writeAll(eq_op_str);3171 try writer.writeAll(eq_op_str);
3172 try writer.writeByte(' ');
2963 try f.writeCValue(writer, rhs, .Other);3173 try f.writeCValue(writer, rhs, .Other);
2964 try writer.writeAll(";\n");3174 try writer.writeAll(";\n");
29653175
...@@ -3079,17 +3289,22 @@ fn airCall(...@@ -3079,17 +3289,22 @@ fn airCall(
3079 };3289 };
3080 const writer = f.object.writer();3290 const writer = f.object.writer();
30813291
3082 const result_local: CValue = r: {3292 const target = f.object.dg.module.getTarget();
3083 if (!loweredFnRetTyHasBits(fn_ty)) {3293 const ret_ty = fn_ty.fnReturnType();
3084 break :r .none;3294 var lowered_ret_buf: LowerFnRetTyBuffer = undefined;
3085 } else if (f.liveness.isUnused(inst)) {3295 const lowered_ret_ty = lowerFnRetTy(ret_ty, &lowered_ret_buf, target);
3086 try writer.print("(void)", .{});3296
3087 break :r .none;3297 const result_local: CValue = if (!lowered_ret_ty.hasRuntimeBitsIgnoreComptime())
3088 } else {3298 .none
3089 const local = try f.allocLocal(fn_ty.fnReturnType(), .Const);3299 else if (f.liveness.isUnused(inst)) r: {
3090 try writer.writeAll(" = ");3300 try writer.writeByte('(');
3091 break :r local;3301 try f.renderTypecast(writer, Type.void);
3092 }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;
3093 };3308 };
30943309
3095 var is_extern = false;3310 var is_extern = false;
...@@ -3138,7 +3353,19 @@ fn airCall(...@@ -3138,7 +3353,19 @@ fn airCall(
3138 args_written += 1;3353 args_written += 1;
3139 }3354 }
3140 try writer.writeAll(");\n");3355 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;
3142}3369}
31433370
3144fn airDbgStmt(f: *Function, inst: Air.Inst.Index) !CValue {3371fn airDbgStmt(f: *Function, inst: Air.Inst.Index) !CValue {
...@@ -3263,7 +3490,8 @@ fn lowerTry(...@@ -3263,7 +3490,8 @@ fn lowerTry(
3263 }3490 }
3264 }3491 }
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);
3267 const local = try f.allocLocal(result_ty, if (is_array) .Mut else .Const);3495 const local = try f.allocLocal(result_ty, if (is_array) .Mut else .Const);
3268 if (is_array) {3496 if (is_array) {
3269 try writer.writeAll(";\n");3497 try writer.writeAll(";\n");
...@@ -3814,51 +4042,74 @@ fn airFieldParentPtr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3814,51 +4042,74 @@ fn airFieldParentPtr(f: *Function, inst: Air.Inst.Index) !CValue {
38144042
3815fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struct_ptr: CValue, index: u32) !CValue {4043fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struct_ptr: CValue, index: u32) !CValue {
3816 const writer = f.object.writer();4044 const writer = f.object.writer();
4045 const field_ptr_ty = f.air.typeOfIndex(inst);
4046 const field_ptr_info = field_ptr_ty.ptrInfo();
3817 const struct_ty = struct_ptr_ty.elemType();4047 const struct_ty = struct_ptr_ty.elemType();
3818 var field_name: []const u8 = undefined;4048 const field_ty = struct_ty.structFieldType(index);
3819 var field_val_ty: Type = undefined;
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 = &.{};
3822 defer f.object.dg.gpa.free(field_name_buf);4064 defer f.object.dg.gpa.free(field_name_buf);
3823 switch (struct_ty.tag()) {4065 const field_name: ?[]const u8 = switch (struct_ty.tag()) {
3824 .@"struct" => {4066 .@"struct" => switch (struct_ty.containerLayout()) {
3825 const fields = struct_ty.structFields();4067 .Auto, .Extern => struct_ty.structFieldName(index),
3826 field_name = fields.keys()[index];4068 .Packed => if (field_ptr_info.data.host_size == 0) {
3827 field_val_ty = fields.values()[index].ty;4069 const target = f.object.dg.module.getTarget();
3828 },4070
3829 .@"union", .union_safety_tagged, .union_tagged => {4071 const byte_offset = struct_ty.packedStructFieldByteOffset(index, target);
3830 const fields = struct_ty.unionFields();4072 var byte_offset_pl = Value.Payload.U64{
3831 field_name = fields.keys()[index];4073 .base = .{ .tag = .int_u64 },
3832 field_val_ty = fields.values()[index].ty;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,
3833 },4089 },
3834 .tuple, .anon_struct => {4090 .@"union", .union_safety_tagged, .union_tagged => struct_ty.unionFields().keys()[index],
4091 .tuple, .anon_struct => |tag| field_name: {
3835 const tuple = struct_ty.tupleFields();4092 const tuple = struct_ty.tupleFields();
3836 if (tuple.values[index].tag() != .unreachable_value) return CValue.none;4093 if (tuple.values[index].tag() != .unreachable_value) return CValue.none;
38374094
4095 if (tag == .anon_struct) break :field_name struct_ty.structFieldName(index);
4096
3838 field_name_buf = try std.fmt.allocPrint(f.object.dg.gpa, "field_{d}", .{index});4097 field_name_buf = try std.fmt.allocPrint(f.object.dg.gpa, "field_{d}", .{index});
3839 field_name = field_name_buf;4098 break :field_name field_name_buf;
3840 field_val_ty = tuple.types[index];
3841 },4099 },
3842 else => unreachable,4100 else => unreachable,
3843 }4101 };
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);
38484102
3849 const inst_ty = f.air.typeOfIndex(inst);4103 if (field_ty.hasRuntimeBitsIgnoreComptime()) {
3850 const local = try f.allocLocal(inst_ty, .Const);4104 try writer.writeByte('&');
3851 if (field_val_ty.hasRuntimeBitsIgnoreComptime()) {4105 if (extra_name orelse field_name) |name|
3852 try writer.writeAll(" = &");4106 try f.writeCValueDerefMember(writer, struct_ptr, .{ .identifier = name })
3853 try f.writeCValueDeref(writer, struct_ptr);4107 else
3854 try writer.print(".{s}{ };\n", .{ payload, fmtIdent(field_name) });4108 try f.writeCValueDeref(writer, struct_ptr);
3855 } else {4109 if (extra_name) |_| if (field_name) |name|
3856 try writer.writeAll(" = (");4110 try writer.print(".{ }", .{fmtIdent(name)});
3857 try f.renderTypecast(writer, inst_ty);4111 } else try f.writeCValue(writer, struct_ptr, .Other);
3858 try writer.writeByte(')');4112 try writer.writeAll(";\n");
3859 try f.writeCValue(writer, struct_ptr, .Other);
3860 try writer.writeAll(";\n");
3861 }
3862 return local;4113 return local;
3863}4114}
38644115
...@@ -3868,18 +4119,84 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3868,18 +4119,84 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
38684119
3869 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;4120 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
3870 const extra = f.air.extraData(Air.StructField, ty_pl.payload).data;4121 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();
3872 const struct_byval = try f.resolveInst(extra.struct_operand);4124 const struct_byval = try f.resolveInst(extra.struct_operand);
3873 const struct_ty = f.air.typeOf(extra.struct_operand);4125 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
3874 var field_name_buf: []const u8 = "";4131 var field_name_buf: []const u8 = "";
3875 defer f.object.dg.gpa.free(field_name_buf);4132 defer f.object.dg.gpa.free(field_name_buf);
3876 const field_name = switch (struct_ty.tag()) {4133 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 },
3878 .@"union", .union_safety_tagged, .union_tagged => struct_ty.unionFields().keys()[extra.field_index],4193 .@"union", .union_safety_tagged, .union_tagged => struct_ty.unionFields().keys()[extra.field_index],
3879 .tuple, .anon_struct => blk: {4194 .tuple, .anon_struct => |tag| blk: {
3880 const tuple = struct_ty.tupleFields();4195 const tuple = struct_ty.tupleFields();
3881 if (tuple.values[extra.field_index].tag() != .unreachable_value) return CValue.none;4196 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
3883 field_name_buf = try std.fmt.allocPrint(f.object.dg.gpa, "field_{d}", .{extra.field_index});4200 field_name_buf = try std.fmt.allocPrint(f.object.dg.gpa, "field_{d}", .{extra.field_index});
3884 break :blk field_name_buf;4201 break :blk field_name_buf;
3885 },4202 },
...@@ -3887,13 +4204,8 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3887,13 +4204,8 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
3887 };4204 };
3888 const payload = if (struct_ty.tag() == .union_tagged or struct_ty.tag() == .union_safety_tagged) "payload." else "";4205 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.4207 const is_array = lowersToArray(inst_ty, target);
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;
3895 const local = try f.allocLocal(inst_ty, if (is_array) .Mut else .Const);4208 const local = try f.allocLocal(inst_ty, if (is_array) .Mut else .Const);
3896
3897 if (is_array) {4209 if (is_array) {
3898 try writer.writeAll(";\n");4210 try writer.writeAll(";\n");
3899 try writer.writeAll("memcpy(");4211 try writer.writeAll("memcpy(");
...@@ -4067,7 +4379,8 @@ fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4067,7 +4379,8 @@ fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {
4067 const inst_ty = f.air.typeOfIndex(inst);4379 const inst_ty = f.air.typeOfIndex(inst);
4068 const payload_ty = inst_ty.errorUnionPayload();4380 const payload_ty = inst_ty.errorUnionPayload();
4069 const error_ty = inst_ty.errorUnionSet();4381 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);
4071 const local = try f.allocLocal(inst_ty, if (is_array) .Mut else .Const);4384 const local = try f.allocLocal(inst_ty, if (is_array) .Mut else .Const);
4072 try writer.writeAll(" = { .payload = ");4385 try writer.writeAll(" = { .payload = ");
4073 try f.writeCValue(writer, if (is_array) CValue{ .undef = payload_ty } else operand, .Initializer);4386 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 {...@@ -4141,7 +4454,7 @@ fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue {
4141 } else {4454 } else {
4142 try writer.writeAll("&(");4455 try writer.writeAll("&(");
4143 try f.writeCValueDeref(writer, operand);4456 try f.writeCValueDeref(writer, operand);
4144 try writer.writeAll(")[0]");4457 try writer.print(")[{}]", .{try f.fmtIntLiteral(Type.usize, Value.zero)});
4145 }4458 }
41464459
4147 var len_pl: Value.Payload.U64 = .{ .base = .{ .tag = .int_u64 }, .data = array_len };4460 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 {...@@ -4571,16 +4884,18 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
4571 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;4884 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
4572 const len = @intCast(usize, inst_ty.arrayLen());4885 const len = @intCast(usize, inst_ty.arrayLen());
4573 const elements = @ptrCast([]const Air.Inst.Ref, f.air.extra[ty_pl.payload..][0..len]);4886 const elements = @ptrCast([]const Air.Inst.Ref, f.air.extra[ty_pl.payload..][0..len]);
4887 const target = f.object.dg.module.getTarget();
4574 const mutability: Mutability = for (elements) |element| {4888 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;
4576 } else .Const;4890 } else .Const;
45774891
4578 const writer = f.object.writer();4892 const writer = f.object.writer();
4579 const local = try f.allocLocal(inst_ty, mutability);4893 const local = try f.allocLocal(inst_ty, mutability);
4580 try writer.writeAll(" = {");4894 try writer.writeAll(" = ");
4581 switch (inst_ty.zigTypeTag()) {4895 switch (inst_ty.zigTypeTag()) {
4582 .Array => {4896 .Array => {
4583 const elem_ty = inst_ty.childType();4897 const elem_ty = inst_ty.childType();
4898 try writer.writeByte('{');
4584 var empty = true;4899 var empty = true;
4585 for (elements) |element| {4900 for (elements) |element| {
4586 if (!empty) try writer.writeAll(", ");4901 if (!empty) try writer.writeAll(", ");
...@@ -4595,49 +4910,99 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4595,49 +4910,99 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
4595 if (empty) try writer.print("{}", .{try f.fmtIntLiteral(Type.u8, Value.zero)});4910 if (empty) try writer.print("{}", .{try f.fmtIntLiteral(Type.u8, Value.zero)});
4596 try writer.writeAll("};\n");4911 try writer.writeAll("};\n");
4597 },4912 },
4598 .Struct => {4913 .Struct => switch (inst_ty.containerLayout()) {
4599 var empty = true;4914 .Auto, .Extern => {
4600 for (elements) |element, index| {4915 try writer.writeByte('{');
4601 if (inst_ty.structFieldValueComptime(index)) |_| continue;4916 var empty = true;
4917 for (elements) |element, index| {
4918 if (inst_ty.structFieldValueComptime(index)) |_| continue;
46024919
4603 if (!empty) try writer.writeAll(", ");4920 if (!empty) try writer.writeAll(", ");
4604 if (!inst_ty.isTupleOrAnonStruct()) {4921 if (!inst_ty.isTupleOrAnonStruct()) {
4605 try writer.print(".{ } = ", .{fmtIdent(inst_ty.structFieldName(index))});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");
4606 }4956 }
4957 },
4958 .Packed => {
4959 const int_info = inst_ty.intInfo(target);
46074960
4608 const element_ty = f.air.typeOf(element);4961 var bit_offset_ty_pl = Type.Payload.Bits{
4609 try f.writeCValue(writer, switch (element_ty.zigTypeTag()) {4962 .base = .{ .tag = .int_unsigned },
4610 .Array => CValue{ .undef = element_ty },4963 .data = Type.smallestUnsignedBits(int_info.bits - 1),
4611 else => try f.resolveInst(element),4964 };
4612 }, .Initializer);4965 const bit_offset_ty = Type.initPayload(&bit_offset_ty_pl.base);
4613 empty = false;
4614 }
4615 if (empty) try writer.print("{}", .{try f.fmtIntLiteral(Type.u8, Value.zero)});
4616 try writer.writeAll("};\n");
46174966
4618 for (elements) |element, index| {4967 var bit_offset_val_pl: Value.Payload.U64 = .{ .base = .{ .tag = .int_u64 }, .data = 0 };
4619 if (inst_ty.structFieldValueComptime(index)) |_| continue;4968 const bit_offset_val = Value.initPayload(&bit_offset_val_pl.base);
46204969
4621 const element_ty = f.air.typeOf(element);4970 var empty = true;
4622 if (element_ty.zigTypeTag() != .Array) continue;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;4975 if (!empty) {
4625 defer if (field_name_storage) |storage| f.object.dg.gpa.free(storage);4976 try writer.writeAll("zig_or_");
4626 const field_name = if (inst_ty.isTupleOrAnonStruct()) field_name: {4977 try f.renderTypeForBuiltinFnName(writer, inst_ty);
4627 const name = try std.fmt.allocPrint(f.object.dg.gpa, "field_{d}", .{index});4978 try writer.writeByte('(');
4628 field_name_storage = name;4979 }
4629 break :field_name name;4980 empty = false;
4630 } else inst_ty.structFieldName(index);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);
4632 try writer.writeAll(";\n");5004 try writer.writeAll(";\n");
4633 try writer.writeAll("memcpy(");5005 },
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 }
4641 },5006 },
4642 .Vector => return f.fail("TODO: C backend: implement airAggregateInit for vectors", .{}),5007 .Vector => return f.fail("TODO: C backend: implement airAggregateInit for vectors", .{}),
4643 else => unreachable,5008 else => unreachable,
...@@ -4947,7 +5312,7 @@ fn formatIntLiteral(...@@ -4947,7 +5312,7 @@ fn formatIntLiteral(
4947 const int_info = data.ty.intInfo(target);5312 const int_info = data.ty.intInfo(target);
49485313
4949 const Limb = std.math.big.Limb;5314 const Limb = std.math.big.Limb;
4950 const expected_contents = struct {5315 const ExpectedContents = struct {
4951 const base = 10;5316 const base = 10;
4952 const limbs_count_128 = BigInt.calcTwosCompLimbCount(128);5317 const limbs_count_128 = BigInt.calcTwosCompLimbCount(128);
4953 const expected_needed_limbs_count = BigInt.calcToStringLimbsBufferLen(limbs_count_128, base);5318 const expected_needed_limbs_count = BigInt.calcToStringLimbsBufferLen(limbs_count_128, base);
...@@ -4959,8 +5324,8 @@ fn formatIntLiteral(...@@ -4959,8 +5324,8 @@ fn formatIntLiteral(
4959 undef_limbs: [limbs_count_128]Limb,5324 undef_limbs: [limbs_count_128]Limb,
4960 wrap_limbs: [limbs_count_128]Limb,5325 wrap_limbs: [limbs_count_128]Limb,
4961 };5326 };
4962 var stack align(@alignOf(expected_contents)) =5327 var stack align(@alignOf(ExpectedContents)) =
4963 std.heap.stackFallback(@sizeOf(expected_contents), data.mod.gpa);5328 std.heap.stackFallback(@sizeOf(ExpectedContents), data.mod.gpa);
4964 const allocator = stack.get();5329 const allocator = stack.get();
49655330
4966 var undef_limbs: []Limb = &.{};5331 var undef_limbs: []Limb = &.{};
...@@ -5092,18 +5457,60 @@ fn formatIntLiteral(...@@ -5092,18 +5457,60 @@ fn formatIntLiteral(
5092 }5457 }
5093}5458}
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
5106fn isByRef(ty: Type) bool {5460fn isByRef(ty: Type) bool {
5107 _ = ty;5461 _ = ty;
5108 return false;5462 return false;
5109}5463}
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" {...@@ -108,7 +108,6 @@ test "@bitCast packed structs at runtime and comptime" {
108 return error.SkipZigTest;108 return error.SkipZigTest;
109 }109 }
110 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;110 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
111 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
112 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;111 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
113 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;112 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
114 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;113 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
...@@ -167,7 +166,6 @@ test "@bitCast extern structs at runtime and comptime" {...@@ -167,7 +166,6 @@ test "@bitCast extern structs at runtime and comptime" {
167166
168test "bitcast packed struct to integer and back" {167test "bitcast packed struct to integer and back" {
169 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;168 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
170 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
171 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;169 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
172 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;170 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
173 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;171 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" {...@@ -718,7 +718,6 @@ test "*align(1) u16 is the same as *align(1:0:2) u16" {
718}718}
719719
720test "array concatenation of function calls" {720test "array concatenation of function calls" {
721 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
722 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;721 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
723 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;722 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
724723
...@@ -727,7 +726,6 @@ test "array concatenation of function calls" {...@@ -727,7 +726,6 @@ test "array concatenation of function calls" {
727}726}
728727
729test "array multiplication of function calls" {728test "array multiplication of function calls" {
730 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
731 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;729 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
732 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;730 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" {...@@ -414,7 +414,6 @@ test "load pointer from packed struct" {
414}414}
415415
416test "@ptrToInt on a packed struct field" {416test "@ptrToInt on a packed struct field" {
417 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
418 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;417 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
419 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;418 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
420 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;419 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
...@@ -448,6 +447,7 @@ test "optional pointer in packed struct" {...@@ -448,6 +447,7 @@ test "optional pointer in packed struct" {
448}447}
449448
450test "nested packed struct field access test" {449test "nested packed struct field access test" {
450 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
451 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO451 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
452 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO452 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
453 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO453 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" {...@@ -505,7 +505,6 @@ test "packed struct fields are ordered from LSB to MSB" {
505 }505 }
506 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO506 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
507 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO507 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
508 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
509 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO508 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
510 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO509 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
511 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO510 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -1301,7 +1300,6 @@ test "packed struct aggregate init" {...@@ -1301,7 +1300,6 @@ test "packed struct aggregate init" {
1301 }1300 }
1302 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1301 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1303 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO1302 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1304 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
1305 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1303 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1306 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1304 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1307 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1305 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/undefined.zig-1
...@@ -15,7 +15,6 @@ const static_array = initStaticArray();...@@ -15,7 +15,6 @@ const static_array = initStaticArray();
15test "init static array to undefined" {15test "init static array to undefined" {
16 // This test causes `initStaticArray()` to be codegen'd, and the16 // This test causes `initStaticArray()` to be codegen'd, and the
17 // C backend does not yet support returning arrays, so it fails17 // C backend does not yet support returning arrays, so it fails
18 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
19 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;18 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
20 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;19 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2120