authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-01-25 16:51:57-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-01-25 16:51:57-05:00
logf2835c6a286c9e6bb033cbf04a2ed3463e206bf3
tree1a657f52b1ad7d6bee917e2246ad98505cdf69bd
parent366c76744429cb9c2fcd60abad191b7ef40ed5db
parent0682c9ac3351b1c7159fd123dc226188918579e6
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #10679 from Luukdegram/wasm-unions

Stage2: wasm - Implement unions

21 files changed, 211 insertions(+), 64 deletions(-)

src/arch/wasm/CodeGen.zig+118-46
...@@ -722,9 +722,9 @@ fn typeToValtype(ty: Type, target: std.Target) wasm.Valtype {...@@ -722,9 +722,9 @@ fn typeToValtype(ty: Type, target: std.Target) wasm.Valtype {
722 if (info.bits > 32 and info.bits <= 64) break :blk wasm.Valtype.i64;722 if (info.bits > 32 and info.bits <= 64) break :blk wasm.Valtype.i64;
723 break :blk wasm.Valtype.i32; // represented as pointer to stack723 break :blk wasm.Valtype.i32; // represented as pointer to stack
724 },724 },
725 .Enum => switch (ty.tag()) {725 .Enum => {
726 .enum_simple => wasm.Valtype.i32,726 var buf: Type.Payload.Bits = undefined;
727 else => typeToValtype(ty.cast(Type.Payload.EnumFull).?.data.tag_ty, target),727 return typeToValtype(ty.intTagType(&buf), target);
728 },728 },
729 else => wasm.Valtype.i32, // all represented as reference/immediate729 else => wasm.Valtype.i32, // all represented as reference/immediate
730 };730 };
...@@ -1033,14 +1033,21 @@ pub const DeclGen = struct {...@@ -1033,14 +1033,21 @@ pub const DeclGen = struct {
1033 return Result{ .appended = {} };1033 return Result{ .appended = {} };
1034 },1034 },
1035 .Enum => {1035 .Enum => {
1036 try writer.writeByteNTimes(0xaa, @intCast(usize, ty.abiSize(self.target())));1036 var int_buffer: Value.Payload.U64 = undefined;
1037 return Result{ .appended = {} };1037 const int_val = val.enumToInt(ty, &int_buffer);
1038 var buf: Type.Payload.Bits = undefined;
1039 const int_ty = ty.intTagType(&buf);
1040 return self.genTypedValue(int_ty, int_val, writer);
1038 },1041 },
1039 .Bool => {1042 .Bool => {
1040 try writer.writeByte(@boolToInt(val.toBool()));1043 try writer.writeByte(@boolToInt(val.toBool()));
1041 return Result{ .appended = {} };1044 return Result{ .appended = {} };
1042 },1045 },
1043 .Struct => {1046 .Struct => {
1047 const struct_ty = ty.castTag(.@"struct").?.data;
1048 if (struct_ty.layout == .Packed) {
1049 return self.fail("TODO: Packed structs for wasm", .{});
1050 }
1044 const field_vals = val.castTag(.@"struct").?.data;1051 const field_vals = val.castTag(.@"struct").?.data;
1045 for (field_vals) |field_val, index| {1052 for (field_vals) |field_val, index| {
1046 const field_ty = ty.structFieldType(index);1053 const field_ty = ty.structFieldType(index);
...@@ -1053,9 +1060,45 @@ pub const DeclGen = struct {...@@ -1053,9 +1060,45 @@ pub const DeclGen = struct {
1053 return Result{ .appended = {} };1060 return Result{ .appended = {} };
1054 },1061 },
1055 .Union => {1062 .Union => {
1056 // TODO: Implement Union declarations1063 const union_val = val.castTag(.@"union").?.data;
1057 try writer.writeByteNTimes(0xaa, @intCast(usize, ty.abiSize(self.target())));1064 const layout = ty.unionGetLayout(self.target());
1058 return Result{ .appended = {} };1065
1066 if (layout.payload_size == 0) {
1067 return self.genTypedValue(ty.unionTagType().?, union_val.tag, writer);
1068 }
1069
1070 // Check if we should store the tag first, in which case, do so now:
1071 if (layout.tag_align >= layout.payload_align) {
1072 switch (try self.genTypedValue(ty.unionTagType().?, union_val.tag, writer)) {
1073 .appended => {},
1074 .externally_managed => |payload| try writer.writeAll(payload),
1075 }
1076 }
1077
1078 const union_ty = ty.cast(Type.Payload.Union).?.data;
1079 const field_index = union_ty.tag_ty.enumTagFieldIndex(union_val.tag).?;
1080 assert(union_ty.haveFieldTypes());
1081 const field_ty = union_ty.fields.values()[field_index].ty;
1082 if (!field_ty.hasRuntimeBits()) {
1083 try writer.writeByteNTimes(0xaa, @intCast(usize, layout.payload_size));
1084 } else {
1085 switch (try self.genTypedValue(field_ty, union_val.val, writer)) {
1086 .appended => {},
1087 .externally_managed => |payload| try writer.writeAll(payload),
1088 }
1089
1090 // Unions have the size of the largest field, so we must pad
1091 // whenever the active field has a smaller size.
1092 const diff = layout.payload_size - field_ty.abiSize(self.target());
1093 if (diff > 0) {
1094 try writer.writeByteNTimes(0xaa, @intCast(usize, diff));
1095 }
1096 }
1097
1098 if (layout.tag_size == 0) {
1099 return Result{ .appended = {} };
1100 }
1101 return self.genTypedValue(union_ty.tag_ty, union_val.tag, writer);
1059 },1102 },
1060 .Pointer => switch (val.tag()) {1103 .Pointer => switch (val.tag()) {
1061 .variable => {1104 .variable => {
...@@ -1080,6 +1123,10 @@ pub const DeclGen = struct {...@@ -1080,6 +1123,10 @@ pub const DeclGen = struct {
1080 }1123 }
1081 return Result{ .appended = {} };1124 return Result{ .appended = {} };
1082 },1125 },
1126 .zero => {
1127 try writer.writeByteNTimes(0, @divExact(self.target().cpu.arch.ptrBitWidth(), 8));
1128 return Result{ .appended = {} };
1129 },
1083 else => return self.fail("TODO: Implement zig decl gen for pointer type value: '{s}'", .{@tagName(val.tag())}),1130 else => return self.fail("TODO: Implement zig decl gen for pointer type value: '{s}'", .{@tagName(val.tag())}),
1084 },1131 },
1085 .ErrorUnion => {1132 .ErrorUnion => {
...@@ -1334,7 +1381,7 @@ fn isByRef(ty: Type, target: std.Target) bool {...@@ -1334,7 +1381,7 @@ fn isByRef(ty: Type, target: std.Target) bool {
1334 },1381 },
1335 .Pointer => {1382 .Pointer => {
1336 // Slices act like struct and will be passed by reference1383 // Slices act like struct and will be passed by reference
1337 if (ty.isSlice()) return ty.hasRuntimeBits();1384 if (ty.isSlice()) return true;
1338 return false;1385 return false;
1339 },1386 },
1340 }1387 }
...@@ -1394,6 +1441,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {...@@ -1394,6 +1441,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
1394 .bit_or => self.airBinOp(inst, .@"or"),1441 .bit_or => self.airBinOp(inst, .@"or"),
1395 .bool_and => self.airBinOp(inst, .@"and"),1442 .bool_and => self.airBinOp(inst, .@"and"),
1396 .bool_or => self.airBinOp(inst, .@"or"),1443 .bool_or => self.airBinOp(inst, .@"or"),
1444 .rem => self.airBinOp(inst, .rem),
1397 .shl => self.airBinOp(inst, .shl),1445 .shl => self.airBinOp(inst, .shl),
1398 .shr => self.airBinOp(inst, .shr),1446 .shr => self.airBinOp(inst, .shr),
1399 .xor => self.airBinOp(inst, .xor),1447 .xor => self.airBinOp(inst, .xor),
...@@ -1419,6 +1467,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {...@@ -1419,6 +1467,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
1419 .dbg_stmt => WValue.none,1467 .dbg_stmt => WValue.none,
1420 .intcast => self.airIntcast(inst),1468 .intcast => self.airIntcast(inst),
1421 .float_to_int => self.airFloatToInt(inst),1469 .float_to_int => self.airFloatToInt(inst),
1470 .get_union_tag => self.airGetUnionTag(inst),
14221471
1423 .is_err => self.airIsErr(inst, .i32_ne),1472 .is_err => self.airIsErr(inst, .i32_ne),
1424 .is_non_err => self.airIsErr(inst, .i32_eq),1473 .is_non_err => self.airIsErr(inst, .i32_eq),
...@@ -1454,6 +1503,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {...@@ -1454,6 +1503,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
1454 .slice_ptr => self.airSlicePtr(inst),1503 .slice_ptr => self.airSlicePtr(inst),
1455 .store => self.airStore(inst),1504 .store => self.airStore(inst),
14561505
1506 .set_union_tag => self.airSetUnionTag(inst),
1457 .struct_field_ptr => self.airStructFieldPtr(inst),1507 .struct_field_ptr => self.airStructFieldPtr(inst),
1458 .struct_field_ptr_index_0 => self.airStructFieldPtrIndex(inst, 0),1508 .struct_field_ptr_index_0 => self.airStructFieldPtrIndex(inst, 0),
1459 .struct_field_ptr_index_1 => self.airStructFieldPtrIndex(inst, 1),1509 .struct_field_ptr_index_1 => self.airStructFieldPtrIndex(inst, 1),
...@@ -1477,7 +1527,6 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {...@@ -1477,7 +1527,6 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
1477 .div_float,1527 .div_float,
1478 .div_floor,1528 .div_floor,
1479 .div_exact,1529 .div_exact,
1480 .rem,
1481 .mod,1530 .mod,
1482 .max,1531 .max,
1483 .min,1532 .min,
...@@ -1494,8 +1543,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {...@@ -1494,8 +1543,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
1494 .fpext,1543 .fpext,
1495 .unwrap_errunion_payload_ptr,1544 .unwrap_errunion_payload_ptr,
1496 .unwrap_errunion_err_ptr,1545 .unwrap_errunion_err_ptr,
1497 .set_union_tag,1546
1498 .get_union_tag,
1499 .ptr_slice_len_ptr,1547 .ptr_slice_len_ptr,
1500 .ptr_slice_ptr_ptr,1548 .ptr_slice_ptr_ptr,
1501 .int_to_float,1549 .int_to_float,
...@@ -1518,7 +1566,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {...@@ -1518,7 +1566,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
1518 .sub_with_overflow,1566 .sub_with_overflow,
1519 .mul_with_overflow,1567 .mul_with_overflow,
1520 .shl_with_overflow,1568 .shl_with_overflow,
1521 => |tag| self.fail("TODO: Implement wasm inst: {s}", .{@tagName(tag)}),1569 => |tag| return self.fail("TODO: Implement wasm inst: {s}", .{@tagName(tag)}),
1522 };1570 };
1523}1571}
15241572
...@@ -1596,6 +1644,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -1596,6 +1644,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
1596 break :blk func.data.owner_decl;1644 break :blk func.data.owner_decl;
1597 } else if (func_val.castTag(.extern_fn)) |ext_fn| {1645 } else if (func_val.castTag(.extern_fn)) |ext_fn| {
1598 break :blk ext_fn.data;1646 break :blk ext_fn.data;
1647 } else if (func_val.castTag(.decl_ref)) |decl_ref| {
1648 break :blk decl_ref.data;
1599 }1649 }
1600 return self.fail("Expected a function, but instead found type '{s}'", .{func_val.tag()});1650 return self.fail("Expected a function, but instead found type '{s}'", .{func_val.tag()});
1601 };1651 };
...@@ -1697,7 +1747,7 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro...@@ -1697,7 +1747,7 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro
16971747
1698 return self.memCopy(ty, lhs, rhs);1748 return self.memCopy(ty, lhs, rhs);
1699 },1749 },
1700 .Struct, .Array => {1750 .Struct, .Array, .Union => {
1701 return try self.memCopy(ty, lhs, rhs);1751 return try self.memCopy(ty, lhs, rhs);
1702 },1752 },
1703 .Pointer => {1753 .Pointer => {
...@@ -1720,18 +1770,8 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro...@@ -1720,18 +1770,8 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro
1720 try self.emitWValue(lhs);1770 try self.emitWValue(lhs);
1721 try self.emitWValue(rhs);1771 try self.emitWValue(rhs);
1722 const valtype = typeToValtype(ty, self.target);1772 const valtype = typeToValtype(ty, self.target);
1723 // check if we should pass by pointer or value based on ABI size1773 const abi_size = @intCast(u8, ty.abiSize(self.target));
1724 // TODO: Implement a way to get ABI values from a given type,1774
1725 // that is portable across the backend, rather than copying logic.
1726 const abi_size = switch (ty.zigTypeTag()) {
1727 .Int,
1728 .Float,
1729 .ErrorSet,
1730 .Enum,
1731 .Bool,
1732 => @intCast(u8, ty.abiSize(self.target)),
1733 else => @as(u8, 4),
1734 };
1735 const opcode = buildOpcode(.{1775 const opcode = buildOpcode(.{
1736 .valtype1 = valtype,1776 .valtype1 = valtype,
1737 .width = abi_size * 8, // use bitsize instead of byte size1777 .width = abi_size * 8, // use bitsize instead of byte size
...@@ -1771,22 +1811,9 @@ fn load(self: *Self, operand: WValue, ty: Type, offset: u32) InnerError!WValue {...@@ -1771,22 +1811,9 @@ fn load(self: *Self, operand: WValue, ty: Type, offset: u32) InnerError!WValue {
1771 .unsigned1811 .unsigned
1772 else1812 else
1773 .signed;1813 .signed;
1774 // TODO: Implement a way to get ABI values from a given type,1814
1775 // that is portable across the backend, rather than copying logic.1815 // TODO: Revisit below to determine if optional zero-sized pointers should still have abi-size 4.
1776 const abi_size = switch (ty.zigTypeTag()) {1816 const abi_size = if (ty.isPtrLikeOptional()) @as(u8, 4) else @intCast(u8, ty.abiSize(self.target));
1777 .Int,
1778 .Float,
1779 .ErrorSet,
1780 .Enum,
1781 .Bool,
1782 .ErrorUnion,
1783 => @intCast(u8, ty.abiSize(self.target)),
1784 .Optional => blk: {
1785 if (ty.isPtrLikeOptional()) break :blk @intCast(u8, self.ptrSize());
1786 break :blk @intCast(u8, ty.abiSize(self.target));
1787 },
1788 else => @as(u8, 4),
1789 };
17901817
1791 const opcode = buildOpcode(.{1818 const opcode = buildOpcode(.{
1792 .valtype1 = typeToValtype(ty, self.target),1819 .valtype1 = typeToValtype(ty, self.target),
...@@ -1952,7 +1979,13 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue {...@@ -1952,7 +1979,13 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue {
1952 return WValue{ .imm32 = field_index.data };1979 return WValue{ .imm32 = field_index.data };
1953 }1980 }
1954 },1981 },
1955 else => unreachable,1982 .enum_numbered => {
1983 const index = field_index.data;
1984 const enum_data = ty.castTag(.enum_numbered).?.data;
1985 const enum_val = enum_data.values.keys()[index];
1986 return self.lowerConstant(enum_val, enum_data.tag_ty);
1987 },
1988 else => return self.fail("TODO: lowerConstant for enum tag: {}", .{ty.tag()}),
1956 }1989 }
1957 } else {1990 } else {
1958 var int_tag_buffer: Type.Payload.Bits = undefined;1991 var int_tag_buffer: Type.Payload.Bits = undefined;
...@@ -2724,7 +2757,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2724,7 +2757,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2724 const elem_size = elem_ty.abiSize(self.target);2757 const elem_size = elem_ty.abiSize(self.target);
27252758
2726 // load pointer onto stack2759 // load pointer onto stack
2727 const slice_ptr = try self.load(slice, slice_ty, 0);2760 const slice_ptr = try self.load(slice, Type.usize, 0);
2728 try self.addLabel(.local_get, slice_ptr.local);2761 try self.addLabel(.local_get, slice_ptr.local);
27292762
2730 // calculate index into slice2763 // calculate index into slice
...@@ -2746,14 +2779,13 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2746,14 +2779,13 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2746 if (self.liveness.isUnused(inst)) return WValue.none;2779 if (self.liveness.isUnused(inst)) return WValue.none;
2747 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;2780 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
2748 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;2781 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
2749 const slice_ty = self.air.typeOf(bin_op.lhs);
2750 const elem_ty = self.air.getRefType(ty_pl.ty).childType();2782 const elem_ty = self.air.getRefType(ty_pl.ty).childType();
2751 const elem_size = elem_ty.abiSize(self.target);2783 const elem_size = elem_ty.abiSize(self.target);
27522784
2753 const slice = try self.resolveInst(bin_op.lhs);2785 const slice = try self.resolveInst(bin_op.lhs);
2754 const index = try self.resolveInst(bin_op.rhs);2786 const index = try self.resolveInst(bin_op.rhs);
27552787
2756 const slice_ptr = try self.load(slice, slice_ty, 0);2788 const slice_ptr = try self.load(slice, Type.usize, 0);
2757 try self.addLabel(.local_get, slice_ptr.local);2789 try self.addLabel(.local_get, slice_ptr.local);
27582790
2759 // calculate index into slice2791 // calculate index into slice
...@@ -3177,3 +3209,43 @@ fn cmpBigInt(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.ma...@@ -3177,3 +3209,43 @@ fn cmpBigInt(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.ma
3177 try self.addLabel(.local_set, result.local);3209 try self.addLabel(.local_set, result.local);
3178 return result;3210 return result;
3179}3211}
3212
3213fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3214 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
3215 const un_ty = self.air.typeOf(bin_op.lhs).childType();
3216 const tag_ty = self.air.typeOf(bin_op.rhs);
3217 const layout = un_ty.unionGetLayout(self.target);
3218 if (layout.tag_size == 0) return WValue{ .none = {} };
3219 const union_ptr = try self.resolveInst(bin_op.lhs);
3220 const new_tag = try self.resolveInst(bin_op.rhs);
3221 if (layout.payload_size == 0) {
3222 try self.store(union_ptr, new_tag, tag_ty, 0);
3223 return WValue{ .none = {} };
3224 }
3225
3226 // when the tag alignment is smaller than the payload, the field will be stored
3227 // after the payload.
3228 const offset = if (layout.tag_align < layout.payload_align) blk: {
3229 break :blk @intCast(u32, layout.payload_size);
3230 } else @as(u32, 0);
3231 try self.store(union_ptr, new_tag, tag_ty, offset);
3232 return WValue{ .none = {} };
3233}
3234
3235fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3236 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };
3237
3238 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
3239 const un_ty = self.air.typeOf(ty_op.operand);
3240 const tag_ty = self.air.typeOfIndex(inst);
3241 const layout = un_ty.unionGetLayout(self.target);
3242 if (layout.tag_size == 0) return WValue{ .none = {} };
3243 const operand = try self.resolveInst(ty_op.operand);
3244
3245 // when the tag alignment is smaller than the payload, the field will be stored
3246 // after the payload.
3247 const offset = if (layout.tag_align < layout.payload_align) blk: {
3248 break :blk @intCast(u32, layout.payload_size);
3249 } else @as(u32, 0);
3250 return self.load(operand, tag_ty, offset);
3251}
src/arch/wasm/Emit.zig+4
...@@ -173,6 +173,10 @@ pub fn emitMir(emit: *Emit) InnerError!void {...@@ -173,6 +173,10 @@ pub fn emitMir(emit: *Emit) InnerError!void {
173 .i64_trunc_f32_u => try emit.emitTag(tag),173 .i64_trunc_f32_u => try emit.emitTag(tag),
174 .i64_trunc_f64_s => try emit.emitTag(tag),174 .i64_trunc_f64_s => try emit.emitTag(tag),
175 .i64_trunc_f64_u => try emit.emitTag(tag),175 .i64_trunc_f64_u => try emit.emitTag(tag),
176 .i32_rem_s => try emit.emitTag(tag),
177 .i32_rem_u => try emit.emitTag(tag),
178 .i64_rem_s => try emit.emitTag(tag),
179 .i64_rem_u => try emit.emitTag(tag),
176180
177 .extended => try emit.emitExtended(inst),181 .extended => try emit.emitExtended(inst),
178 }182 }
src/arch/wasm/Mir.zig+8
...@@ -327,6 +327,10 @@ pub const Inst = struct {...@@ -327,6 +327,10 @@ pub const Inst = struct {
327 /// Uses `tag`327 /// Uses `tag`
328 i32_div_u = 0x6E,328 i32_div_u = 0x6E,
329 /// Uses `tag`329 /// Uses `tag`
330 i32_rem_s = 0x6F,
331 /// Uses `tag`
332 i32_rem_u = 0x70,
333 /// Uses `tag`
330 i32_and = 0x71,334 i32_and = 0x71,
331 /// Uses `tag`335 /// Uses `tag`
332 i32_or = 0x72,336 i32_or = 0x72,
...@@ -349,6 +353,10 @@ pub const Inst = struct {...@@ -349,6 +353,10 @@ pub const Inst = struct {
349 /// Uses `tag`353 /// Uses `tag`
350 i64_div_u = 0x80,354 i64_div_u = 0x80,
351 /// Uses `tag`355 /// Uses `tag`
356 i64_rem_s = 0x81,
357 /// Uses `tag`
358 i64_rem_u = 0x82,
359 /// Uses `tag`
352 i64_and = 0x83,360 i64_and = 0x83,
353 /// Uses `tag`361 /// Uses `tag`
354 i64_or = 0x84,362 i64_or = 0x84,
test/behavior.zig+17-17
...@@ -3,18 +3,34 @@ const builtin = @import("builtin");...@@ -3,18 +3,34 @@ const builtin = @import("builtin");
3test {3test {
4 // Tests that pass for stage1, llvm backend, C backend, wasm backend, arm backend and x86_64 backend.4 // Tests that pass for stage1, llvm backend, C backend, wasm backend, arm backend and x86_64 backend.
5 _ = @import("behavior/align.zig");5 _ = @import("behavior/align.zig");
6 _ = @import("behavior/alignof.zig");
6 _ = @import("behavior/array.zig");7 _ = @import("behavior/array.zig");
8 _ = @import("behavior/bit_shifting.zig");
7 _ = @import("behavior/bool.zig");9 _ = @import("behavior/bool.zig");
10 _ = @import("behavior/bugs/394.zig");
8 _ = @import("behavior/bugs/655.zig");11 _ = @import("behavior/bugs/655.zig");
12 _ = @import("behavior/bugs/656.zig");
9 _ = @import("behavior/bugs/679.zig");13 _ = @import("behavior/bugs/679.zig");
10 _ = @import("behavior/bugs/1111.zig");14 _ = @import("behavior/bugs/1111.zig");
15 _ = @import("behavior/bugs/1277.zig");
16 _ = @import("behavior/bugs/1310.zig");
17 _ = @import("behavior/bugs/1381.zig");
18 _ = @import("behavior/bugs/1500.zig");
19 _ = @import("behavior/bugs/1735.zig");
20 _ = @import("behavior/bugs/2006.zig");
11 _ = @import("behavior/bugs/2346.zig");21 _ = @import("behavior/bugs/2346.zig");
22 _ = @import("behavior/bugs/3112.zig");
23 _ = @import("behavior/bugs/3367.zig");
12 _ = @import("behavior/bugs/6850.zig");24 _ = @import("behavior/bugs/6850.zig");
25 _ = @import("behavior/bugs/7250.zig");
13 _ = @import("behavior/cast.zig");26 _ = @import("behavior/cast.zig");
14 _ = @import("behavior/comptime_memory.zig");27 _ = @import("behavior/comptime_memory.zig");
15 _ = @import("behavior/fn_in_struct_in_comptime.zig");28 _ = @import("behavior/fn_in_struct_in_comptime.zig");
29 _ = @import("behavior/generics_llvm.zig");
16 _ = @import("behavior/hasdecl.zig");30 _ = @import("behavior/hasdecl.zig");
17 _ = @import("behavior/hasfield.zig");31 _ = @import("behavior/hasfield.zig");
32 _ = @import("behavior/namespace_depends_on_compile_var.zig");
33 _ = @import("behavior/optional_llvm.zig");
18 _ = @import("behavior/prefetch.zig");34 _ = @import("behavior/prefetch.zig");
19 _ = @import("behavior/pub_enum.zig");35 _ = @import("behavior/pub_enum.zig");
20 _ = @import("behavior/slice_sentinel_comptime.zig");36 _ = @import("behavior/slice_sentinel_comptime.zig");
...@@ -60,6 +76,7 @@ test {...@@ -60,6 +76,7 @@ test {
60 _ = @import("behavior/type_info.zig");76 _ = @import("behavior/type_info.zig");
61 _ = @import("behavior/undefined.zig");77 _ = @import("behavior/undefined.zig");
62 _ = @import("behavior/underscore.zig");78 _ = @import("behavior/underscore.zig");
79 _ = @import("behavior/union.zig");
63 _ = @import("behavior/usingnamespace.zig");80 _ = @import("behavior/usingnamespace.zig");
64 _ = @import("behavior/void.zig");81 _ = @import("behavior/void.zig");
65 _ = @import("behavior/while.zig");82 _ = @import("behavior/while.zig");
...@@ -68,30 +85,16 @@ test {...@@ -68,30 +85,16 @@ test {
68 // Tests that pass for stage1, llvm backend, C backend85 // Tests that pass for stage1, llvm backend, C backend
69 _ = @import("behavior/cast_int.zig");86 _ = @import("behavior/cast_int.zig");
70 _ = @import("behavior/int128.zig");87 _ = @import("behavior/int128.zig");
71 _ = @import("behavior/union.zig");
72 _ = @import("behavior/translate_c_macros.zig");88 _ = @import("behavior/translate_c_macros.zig");
7389
74 if (builtin.zig_backend != .stage2_c) {90 if (builtin.zig_backend != .stage2_c) {
75 // Tests that pass for stage1 and the llvm backend.91 // Tests that pass for stage1 and the llvm backend.
76 _ = @import("behavior/alignof.zig");
77 _ = @import("behavior/array_llvm.zig");92 _ = @import("behavior/array_llvm.zig");
78 _ = @import("behavior/atomics.zig");93 _ = @import("behavior/atomics.zig");
79 _ = @import("behavior/basic_llvm.zig");94 _ = @import("behavior/basic_llvm.zig");
80 _ = @import("behavior/bit_shifting.zig");
81 _ = @import("behavior/bugs/394.zig");
82 _ = @import("behavior/bugs/656.zig");
83 _ = @import("behavior/bugs/1277.zig");
84 _ = @import("behavior/bugs/1310.zig");
85 _ = @import("behavior/bugs/1381.zig");
86 _ = @import("behavior/bugs/1500.zig");
87 _ = @import("behavior/bugs/1735.zig");
88 _ = @import("behavior/bugs/1741.zig");95 _ = @import("behavior/bugs/1741.zig");
89 _ = @import("behavior/bugs/2006.zig");
90 _ = @import("behavior/bugs/2578.zig");96 _ = @import("behavior/bugs/2578.zig");
91 _ = @import("behavior/bugs/3007.zig");97 _ = @import("behavior/bugs/3007.zig");
92 _ = @import("behavior/bugs/3112.zig");
93 _ = @import("behavior/bugs/3367.zig");
94 _ = @import("behavior/bugs/7250.zig");
95 _ = @import("behavior/bugs/9584.zig");98 _ = @import("behavior/bugs/9584.zig");
96 _ = @import("behavior/cast_llvm.zig");99 _ = @import("behavior/cast_llvm.zig");
97 _ = @import("behavior/enum_llvm.zig");100 _ = @import("behavior/enum_llvm.zig");
...@@ -99,13 +102,10 @@ test {...@@ -99,13 +102,10 @@ test {
99 _ = @import("behavior/eval.zig");102 _ = @import("behavior/eval.zig");
100 _ = @import("behavior/floatop.zig");103 _ = @import("behavior/floatop.zig");
101 _ = @import("behavior/fn.zig");104 _ = @import("behavior/fn.zig");
102 _ = @import("behavior/generics_llvm.zig");
103 _ = @import("behavior/math.zig");105 _ = @import("behavior/math.zig");
104 _ = @import("behavior/maximum_minimum.zig");106 _ = @import("behavior/maximum_minimum.zig");
105 _ = @import("behavior/merge_error_sets.zig");107 _ = @import("behavior/merge_error_sets.zig");
106 _ = @import("behavior/namespace_depends_on_compile_var.zig");
107 _ = @import("behavior/null_llvm.zig");108 _ = @import("behavior/null_llvm.zig");
108 _ = @import("behavior/optional_llvm.zig");
109 _ = @import("behavior/popcount.zig");109 _ = @import("behavior/popcount.zig");
110 _ = @import("behavior/saturating_arithmetic.zig");110 _ = @import("behavior/saturating_arithmetic.zig");
111 _ = @import("behavior/sizeof_and_typeof.zig");111 _ = @import("behavior/sizeof_and_typeof.zig");
test/behavior/alignof.zig+6
...@@ -11,6 +11,9 @@ const Foo = struct {...@@ -11,6 +11,9 @@ const Foo = struct {
11};11};
1212
13test "@alignOf(T) before referencing T" {13test "@alignOf(T) before referencing T" {
14 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
15 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
16 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
14 comptime try expect(@alignOf(Foo) != maxInt(usize));17 comptime try expect(@alignOf(Foo) != maxInt(usize));
15 if (native_arch == .x86_64) {18 if (native_arch == .x86_64) {
16 comptime try expect(@alignOf(Foo) == 4);19 comptime try expect(@alignOf(Foo) == 4);
...@@ -18,6 +21,9 @@ test "@alignOf(T) before referencing T" {...@@ -18,6 +21,9 @@ test "@alignOf(T) before referencing T" {
18}21}
1922
20test "comparison of @alignOf(T) against zero" {23test "comparison of @alignOf(T) against zero" {
24 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
25 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
26 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
21 {27 {
22 const T = struct { x: u32 };28 const T = struct { x: u32 };
23 try expect(!(@alignOf(T) == 0));29 try expect(!(@alignOf(T) == 0));
test/behavior/bit_shifting.zig+4
...@@ -1,5 +1,6 @@...@@ -1,5 +1,6 @@
1const std = @import("std");1const std = @import("std");
2const expect = std.testing.expect;2const expect = std.testing.expect;
3const builtin = @import("builtin");
34
4fn ShardedTable(comptime Key: type, comptime mask_bit_count: comptime_int, comptime V: type) type {5fn ShardedTable(comptime Key: type, comptime mask_bit_count: comptime_int, comptime V: type) type {
5 const key_bits = @typeInfo(Key).Int.bits;6 const key_bits = @typeInfo(Key).Int.bits;
...@@ -60,6 +61,9 @@ fn ShardedTable(comptime Key: type, comptime mask_bit_count: comptime_int, compt...@@ -60,6 +61,9 @@ fn ShardedTable(comptime Key: type, comptime mask_bit_count: comptime_int, compt
60}61}
6162
62test "sharded table" {63test "sharded table" {
64 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
65 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
66 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
63 // realistic 16-way sharding67 // realistic 16-way sharding
64 try testShardedTable(u32, 4, 8);68 try testShardedTable(u32, 4, 8);
6569
test/behavior/bugs/1277.zig+3
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1const std = @import("std");1const std = @import("std");
2const builtin = @import("builtin");
23
3const S = struct {4const S = struct {
4 f: ?fn () i32,5 f: ?fn () i32,
...@@ -11,5 +12,7 @@ fn f() i32 {...@@ -11,5 +12,7 @@ fn f() i32 {
11}12}
1213
13test "don't emit an LLVM global for a const function when it's in an optional in a struct" {14test "don't emit an LLVM global for a const function when it's in an optional in a struct" {
15 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
16 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
14 try std.testing.expect(s.f.?() == 1234);17 try std.testing.expect(s.f.?() == 1234);
15}18}
test/behavior/bugs/1310.zig+3
...@@ -1,5 +1,6 @@...@@ -1,5 +1,6 @@
1const std = @import("std");1const std = @import("std");
2const expect = std.testing.expect;2const expect = std.testing.expect;
3const builtin = @import("builtin");
34
4pub const VM = ?[*]const struct_InvocationTable_;5pub const VM = ?[*]const struct_InvocationTable_;
5pub const struct_InvocationTable_ = extern struct {6pub const struct_InvocationTable_ = extern struct {
...@@ -22,5 +23,7 @@ fn agent_callback(_vm: [*]VM, options: [*]u8) callconv(.C) i32 {...@@ -22,5 +23,7 @@ fn agent_callback(_vm: [*]VM, options: [*]u8) callconv(.C) i32 {
22}23}
2324
24test "fixed" {25test "fixed" {
26 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
27 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
25 try expect(agent_callback(undefined, undefined) == 11);28 try expect(agent_callback(undefined, undefined) == 11);
26}29}
test/behavior/bugs/1381.zig+3
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1const std = @import("std");1const std = @import("std");
2const builtin = @import("builtin");
23
3const B = union(enum) {4const B = union(enum) {
4 D: u8,5 D: u8,
...@@ -11,6 +12,8 @@ const A = union(enum) {...@@ -11,6 +12,8 @@ const A = union(enum) {
11};12};
1213
13test "union that needs padding bytes inside an array" {14test "union that needs padding bytes inside an array" {
15 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
16 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
14 var as = [_]A{17 var as = [_]A{
15 A{ .B = B{ .D = 1 } },18 A{ .B = B{ .D = 1 } },
16 A{ .B = B{ .D = 1 } },19 A{ .B = B{ .D = 1 } },
test/behavior/bugs/1500.zig+4
...@@ -1,3 +1,4 @@...@@ -1,3 +1,4 @@
1const builtin = @import("builtin");
1const A = struct {2const A = struct {
2 b: B,3 b: B,
3};4};
...@@ -5,6 +6,9 @@ const A = struct {...@@ -5,6 +6,9 @@ const A = struct {
5const B = *const fn (A) void;6const B = *const fn (A) void;
67
7test "allow these dependencies" {8test "allow these dependencies" {
9 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
10 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
11 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
8 var a: A = undefined;12 var a: A = undefined;
9 var b: B = undefined;13 var b: B = undefined;
10 if (false) {14 if (false) {
test/behavior/bugs/1735.zig+4
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1const std = @import("std");1const std = @import("std");
2const builtin = @import("builtin");
23
3const mystruct = struct {4const mystruct = struct {
4 pending: ?listofstructs,5 pending: ?listofstructs,
...@@ -41,6 +42,9 @@ const a = struct {...@@ -41,6 +42,9 @@ const a = struct {
41};42};
4243
43test "initialization" {44test "initialization" {
45 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
46 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
47 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
44 var t = a.init();48 var t = a.init();
45 try std.testing.expect(t.foo.len == 0);49 try std.testing.expect(t.foo.len == 0);
46}50}
test/behavior/bugs/2006.zig+4
...@@ -1,10 +1,14 @@...@@ -1,10 +1,14 @@
1const std = @import("std");1const std = @import("std");
2const expect = std.testing.expect;2const expect = std.testing.expect;
3const builtin = @import("builtin");
34
4const S = struct {5const S = struct {
5 p: *S,6 p: *S,
6};7};
7test "bug 2006" {8test "bug 2006" {
9 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
10 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
11 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
8 var a: S = undefined;12 var a: S = undefined;
9 a = S{ .p = undefined };13 a = S{ .p = undefined };
10 try expect(@sizeOf(S) != 0);14 try expect(@sizeOf(S) != 0);
test/behavior/bugs/3112.zig+3-1
...@@ -13,7 +13,9 @@ fn prev(p: ?State) void {...@@ -13,7 +13,9 @@ fn prev(p: ?State) void {
1313
14test "zig test crash" {14test "zig test crash" {
15 if (builtin.zig_backend == .stage1) return error.SkipZigTest;15 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
1616 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
17 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
18 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
17 var global: State = undefined;19 var global: State = undefined;
18 global.enter = prev;20 global.enter = prev;
19 global.enter(null);21 global.enter(null);
test/behavior/bugs/3367.zig+4
...@@ -1,3 +1,4 @@...@@ -1,3 +1,4 @@
1const builtin = @import("builtin");
1const Foo = struct {2const Foo = struct {
2 usingnamespace Mixin;3 usingnamespace Mixin;
3};4};
...@@ -9,6 +10,9 @@ const Mixin = struct {...@@ -9,6 +10,9 @@ const Mixin = struct {
9};10};
1011
11test "container member access usingnamespace decls" {12test "container member access usingnamespace decls" {
13 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
14 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
15 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
12 var foo = Foo{};16 var foo = Foo{};
13 foo.two();17 foo.two();
14}18}
test/behavior/bugs/394.zig+3
...@@ -8,8 +8,11 @@ const S = struct {...@@ -8,8 +8,11 @@ const S = struct {
8};8};
99
10const expect = @import("std").testing.expect;10const expect = @import("std").testing.expect;
11const builtin = @import("builtin");
1112
12test "bug 394 fixed" {13test "bug 394 fixed" {
14 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
15 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
13 const x = S{16 const x = S{
14 .x = 3,17 .x = 3,
15 .y = E{ .B = 1 },18 .y = E{ .B = 1 },
test/behavior/bugs/656.zig+3
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1const expect = @import("std").testing.expect;1const expect = @import("std").testing.expect;
2const builtin = @import("builtin");
23
3const PrefixOp = union(enum) {4const PrefixOp = union(enum) {
4 Return,5 Return,
...@@ -10,6 +11,8 @@ const Value = struct {...@@ -10,6 +11,8 @@ const Value = struct {
10};11};
1112
12test "optional if after an if in a switch prong of a switch with 2 prongs in an else" {13test "optional if after an if in a switch prong of a switch with 2 prongs in an else" {
14 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
15 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
13 try foo(false, true);16 try foo(false, true);
14}17}
1518
test/behavior/bugs/7250.zig+4
...@@ -1,3 +1,4 @@...@@ -1,3 +1,4 @@
1const builtin = @import("builtin");
1const nrfx_uart_t = extern struct {2const nrfx_uart_t = extern struct {
2 p_reg: [*c]u32,3 p_reg: [*c]u32,
3 drv_inst_idx: u8,4 drv_inst_idx: u8,
...@@ -13,5 +14,8 @@ threadlocal var g_uart0 = nrfx_uart_t{...@@ -13,5 +14,8 @@ threadlocal var g_uart0 = nrfx_uart_t{
13};14};
1415
15test "reference a global threadlocal variable" {16test "reference a global threadlocal variable" {
17 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
18 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
19 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
16 _ = nrfx_uart_rx(&g_uart0);20 _ = nrfx_uart_rx(&g_uart0);
17}21}
test/behavior/generics_llvm.zig+7
...@@ -1,5 +1,6 @@...@@ -1,5 +1,6 @@
1const std = @import("std");1const std = @import("std");
2const expect = std.testing.expect;2const expect = std.testing.expect;
3const builtin = @import("builtin");
34
4const foos = [_]fn (anytype) bool{5const foos = [_]fn (anytype) bool{
5 foo1,6 foo1,
...@@ -14,11 +15,17 @@ fn foo2(arg: anytype) bool {...@@ -14,11 +15,17 @@ fn foo2(arg: anytype) bool {
14}15}
1516
16test "array of generic fns" {17test "array of generic fns" {
18 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
19 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
20 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
17 try expect(foos[0](true));21 try expect(foos[0](true));
18 try expect(!foos[1](true));22 try expect(!foos[1](true));
19}23}
2024
21test "generic struct" {25test "generic struct" {
26 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
27 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
28 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
22 var a1 = GenNode(i32){29 var a1 = GenNode(i32){
23 .value = 13,30 .value = 13,
24 .next = null,31 .next = null,
test/behavior/namespace_depends_on_compile_var.zig+3
...@@ -3,6 +3,9 @@ const builtin = @import("builtin");...@@ -3,6 +3,9 @@ const builtin = @import("builtin");
3const expect = std.testing.expect;3const expect = std.testing.expect;
44
5test "namespace depends on compile var" {5test "namespace depends on compile var" {
6 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
7 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
8 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
6 if (some_namespace.a_bool) {9 if (some_namespace.a_bool) {
7 try expect(some_namespace.a_bool);10 try expect(some_namespace.a_bool);
8 } else {11 } else {
test/behavior/optional_llvm.zig+4
...@@ -2,8 +2,12 @@ const std = @import("std");...@@ -2,8 +2,12 @@ const std = @import("std");
2const testing = std.testing;2const testing = std.testing;
3const expect = testing.expect;3const expect = testing.expect;
4const expectEqual = testing.expectEqual;4const expectEqual = testing.expectEqual;
5const builtin = @import("builtin");
56
6test "self-referential struct through a slice of optional" {7test "self-referential struct through a slice of optional" {
8 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
9 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
10 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
7 const S = struct {11 const S = struct {
8 const Node = struct {12 const Node = struct {
9 children: []?Node,13 children: []?Node,
test/behavior/union.zig+2
...@@ -362,6 +362,8 @@ pub const FooUnion = union(enum) {...@@ -362,6 +362,8 @@ pub const FooUnion = union(enum) {
362var glbl_array: [2]FooUnion = undefined;362var glbl_array: [2]FooUnion = undefined;
363363
364test "initialize global array of union" {364test "initialize global array of union" {
365 if (@import("builtin").zig_backend == .stage2_wasm) return error.SkipZigTest;
366
365 glbl_array[1] = FooUnion{ .U1 = 2 };367 glbl_array[1] = FooUnion{ .U1 = 2 };
366 glbl_array[0] = FooUnion{ .U0 = 1 };368 glbl_array[0] = FooUnion{ .U0 = 1 };
367 try expect(glbl_array[0].U0 == 1);369 try expect(glbl_array[0].U0 == 1);