authorgravatar for gethwilliams@googlemail.comGethDW <gethwilliams@googlemail.com> 2022-10-18 12:05:48+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-10-18 14:05:48+03:00
logedc842ff18e19d8c07cde1199f72903356fbf77f
treef7596acbb448018d28a9b19042142d48c53ef124
parent759f72fcfe56ec103d9bb93c2423e37fe3ba1162
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

stage2: implement packedStuctToInt for more types


2 files changed, 89 insertions(+), 9 deletions(-)

src/value.zig+64-9
......@@ -1300,16 +1300,16 @@ pub const Value = extern union {
13001300 for (fields) |field, i| {
13011301 const field_val = field_vals[i];
13021302 const field_bigint_const = switch (field.ty.zigTypeTag()) {
1303 .Float => switch (field.ty.floatBits(target)) {
1304 16 => bitcastFloatToBigInt(f16, field_val.toFloat(f16), &field_buf),
1305 32 => bitcastFloatToBigInt(f32, field_val.toFloat(f32), &field_buf),
1306 64 => bitcastFloatToBigInt(f64, field_val.toFloat(f64), &field_buf),
1307 80 => bitcastFloatToBigInt(f80, field_val.toFloat(f80), &field_buf),
1308 128 => bitcastFloatToBigInt(f128, field_val.toFloat(f128), &field_buf),
1309 else => unreachable,
1303 .Void => continue,
1304 .Float => floatToBigInt(field_val, field.ty, target, &field_buf),
1305 .Int, .Bool => intOrBoolToBigInt(field_val, field.ty, target, &field_buf, &field_space),
1306 .Struct => switch (field.ty.containerLayout()) {
1307 .Auto, .Extern => unreachable, // Sema should have error'd before this.
1308 .Packed => packedStructToInt(field_val, field.ty, target, &field_buf),
13101309 },
1311 .Int, .Bool => field_val.toBigInt(&field_space, target),
1312 .Struct => packedStructToInt(field_val, field.ty, target, &field_buf),
1310 .Vector => vectorToBigInt(field_val, field.ty, target, &field_buf),
1311 .Enum => enumToBigInt(field_val, field.ty, target, &field_space),
1312 .Union => unreachable, // TODO: packed structs support packed unions
13131313 else => unreachable,
13141314 };
13151315 var field_bigint = BigIntMutable.init(&field_buf2, 0);
......@@ -1320,6 +1320,61 @@ pub const Value = extern union {
13201320 return bigint.toConst();
13211321 }
13221322
1323 fn intOrBoolToBigInt(val: Value, ty: Type, target: Target, buf: []std.math.big.Limb, space: *BigIntSpace) BigIntConst {
1324 const big_int_const = val.toBigInt(space, target);
1325 if (big_int_const.positive) return big_int_const;
1326
1327 var big_int = BigIntMutable.init(buf, 0);
1328 big_int.bitNotWrap(big_int_const.negate(), .unsigned, @intCast(u32, ty.bitSize(target)));
1329 big_int.addScalar(big_int.toConst(), 1);
1330 return big_int.toConst();
1331 }
1332
1333 fn vectorToBigInt(val: Value, ty: Type, target: Target, buf: []std.math.big.Limb) BigIntConst {
1334 const endian = target.cpu.arch.endian();
1335 var vec_bitint = BigIntMutable.init(buf, 0);
1336 const vec_len = @intCast(usize, ty.arrayLen());
1337 const elem_ty = ty.childType();
1338 const elem_size = @intCast(usize, elem_ty.bitSize(target));
1339
1340 var elem_buf: [16]std.math.big.Limb = undefined;
1341 var elem_space: BigIntSpace = undefined;
1342 var elem_buf2: [16]std.math.big.Limb = undefined;
1343
1344 var elem_i: usize = 0;
1345 while (elem_i < vec_len) : (elem_i += 1) {
1346 const elem_i_target = if (endian == .Big) vec_len - elem_i - 1 else elem_i;
1347 const elem_val = val.indexVectorlike(elem_i_target);
1348 const elem_bigint_const = switch (elem_ty.zigTypeTag()) {
1349 .Int, .Bool => intOrBoolToBigInt(elem_val, elem_ty, target, &elem_buf, &elem_space),
1350 .Float => floatToBigInt(elem_val, elem_ty, target, &elem_buf),
1351 .Pointer => unreachable, // TODO
1352 else => unreachable, // Sema should not let this happen
1353 };
1354 var elem_bitint = BigIntMutable.init(&elem_buf2, 0);
1355 elem_bitint.shiftLeft(elem_bigint_const, elem_size * elem_i);
1356 vec_bitint.bitOr(vec_bitint.toConst(), elem_bitint.toConst());
1357 }
1358 return vec_bitint.toConst();
1359 }
1360
1361 fn enumToBigInt(val: Value, ty: Type, target: Target, space: *BigIntSpace) BigIntConst {
1362 var enum_buf: Payload.U64 = undefined;
1363 const int_val = val.enumToInt(ty, &enum_buf);
1364 return int_val.toBigInt(space, target);
1365 }
1366
1367 fn floatToBigInt(val: Value, ty: Type, target: Target, buf: []std.math.big.Limb) BigIntConst {
1368 return switch (ty.floatBits(target)) {
1369 16 => bitcastFloatToBigInt(f16, val.toFloat(f16), buf),
1370 32 => bitcastFloatToBigInt(f32, val.toFloat(f32), buf),
1371 64 => bitcastFloatToBigInt(f64, val.toFloat(f64), buf),
1372 80 => bitcastFloatToBigInt(f80, val.toFloat(f80), buf),
1373 128 => bitcastFloatToBigInt(f128, val.toFloat(f128), buf),
1374 else => unreachable,
1375 };
1376 }
1377
13231378 fn bitcastFloatToBigInt(comptime F: type, f: F, buf: []std.math.big.Limb) BigIntConst {
13241379 const Int = @Type(.{ .Int = .{
13251380 .signedness = .unsigned,
test/behavior/bitcast.zig+25
......@@ -282,3 +282,28 @@ test "@bitCast packed struct of floats" {
282282 try S.doTheTest();
283283 comptime try S.doTheTest();
284284}
285
286test "comptime @bitCast packed struct to int" {
287 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
288 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
289 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
290 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
291 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
292
293 const S = packed struct {
294 @"void": void = {},
295 uint: u8 = 13,
296 uint_bit_aligned: u3 = 2,
297 iint_pos: i4 = 1,
298 iint_neg4: i3 = -4,
299 iint_neg2: i3 = -2,
300 float: f32 = 3.14,
301 @"enum": enum(u2) { A, B = 1, C, D } = .B,
302 vectorb: @Vector(3, bool) = .{ true, false, true },
303 vectori: @Vector(2, u8) = .{ 127, 42 },
304 vectorf: @Vector(2, f16) = .{ 3.14, 2.71 },
305 };
306 const Int = @typeInfo(S).Struct.backing_integer.?;
307 var s: S = .{};
308 try expectEqual(@bitCast(Int, s), comptime @bitCast(Int, S{}));
309}