| author | |
| committer | |
| log | f2835c6a286c9e6bb033cbf04a2ed3463e206bf3 |
| tree | 1a657f52b1ad7d6bee917e2246ad98505cdf69bd |
| parent | 366c76744429cb9c2fcd60abad191b7ef40ed5db |
| parent | 0682c9ac3351b1c7159fd123dc226188918579e6 |
| signature |
Stage2: wasm - Implement unions21 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 | 722 | if (info.bits > 32 and info.bits <= 64) break :blk wasm.Valtype.i64; |
| 723 | 723 | break :blk wasm.Valtype.i32; // represented as pointer to stack |
| 724 | 724 | }, |
| 725 | .Enum => switch (ty.tag()) { | |
| 726 | .enum_simple => wasm.Valtype.i32, | |
| 727 | else => typeToValtype(ty.cast(Type.Payload.EnumFull).?.data.tag_ty, target), | |
| 725 | .Enum => { | |
| 726 | var buf: Type.Payload.Bits = undefined; | |
| 727 | return typeToValtype(ty.intTagType(&buf), target); | |
| 728 | 728 | }, |
| 729 | 729 | else => wasm.Valtype.i32, // all represented as reference/immediate |
| 730 | 730 | }; |
| ... | ... | @@ -1033,14 +1033,21 @@ pub const DeclGen = struct { |
| 1033 | 1033 | return Result{ .appended = {} }; |
| 1034 | 1034 | }, |
| 1035 | 1035 | .Enum => { |
| 1036 | try writer.writeByteNTimes(0xaa, @intCast(usize, ty.abiSize(self.target()))); | |
| 1037 | return Result{ .appended = {} }; | |
| 1036 | var int_buffer: Value.Payload.U64 = undefined; | |
| 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 | 1042 | .Bool => { |
| 1040 | 1043 | try writer.writeByte(@boolToInt(val.toBool())); |
| 1041 | 1044 | return Result{ .appended = {} }; |
| 1042 | 1045 | }, |
| 1043 | 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 | 1051 | const field_vals = val.castTag(.@"struct").?.data; |
| 1045 | 1052 | for (field_vals) |field_val, index| { |
| 1046 | 1053 | const field_ty = ty.structFieldType(index); |
| ... | ... | @@ -1053,9 +1060,45 @@ pub const DeclGen = struct { |
| 1053 | 1060 | return Result{ .appended = {} }; |
| 1054 | 1061 | }, |
| 1055 | 1062 | .Union => { |
| 1056 | // TODO: Implement Union declarations | |
| 1057 | try writer.writeByteNTimes(0xaa, @intCast(usize, ty.abiSize(self.target()))); | |
| 1058 | return Result{ .appended = {} }; | |
| 1063 | const union_val = val.castTag(.@"union").?.data; | |
| 1064 | const layout = ty.unionGetLayout(self.target()); | |
| 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 | 1103 | .Pointer => switch (val.tag()) { |
| 1061 | 1104 | .variable => { |
| ... | ... | @@ -1080,6 +1123,10 @@ pub const DeclGen = struct { |
| 1080 | 1123 | } |
| 1081 | 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 | 1130 | else => return self.fail("TODO: Implement zig decl gen for pointer type value: '{s}'", .{@tagName(val.tag())}), |
| 1084 | 1131 | }, |
| 1085 | 1132 | .ErrorUnion => { |
| ... | ... | @@ -1334,7 +1381,7 @@ fn isByRef(ty: Type, target: std.Target) bool { |
| 1334 | 1381 | }, |
| 1335 | 1382 | .Pointer => { |
| 1336 | 1383 | // Slices act like struct and will be passed by reference |
| 1337 | if (ty.isSlice()) return ty.hasRuntimeBits(); | |
| 1384 | if (ty.isSlice()) return true; | |
| 1338 | 1385 | return false; |
| 1339 | 1386 | }, |
| 1340 | 1387 | } |
| ... | ... | @@ -1394,6 +1441,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue { |
| 1394 | 1441 | .bit_or => self.airBinOp(inst, .@"or"), |
| 1395 | 1442 | .bool_and => self.airBinOp(inst, .@"and"), |
| 1396 | 1443 | .bool_or => self.airBinOp(inst, .@"or"), |
| 1444 | .rem => self.airBinOp(inst, .rem), | |
| 1397 | 1445 | .shl => self.airBinOp(inst, .shl), |
| 1398 | 1446 | .shr => self.airBinOp(inst, .shr), |
| 1399 | 1447 | .xor => self.airBinOp(inst, .xor), |
| ... | ... | @@ -1419,6 +1467,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue { |
| 1419 | 1467 | .dbg_stmt => WValue.none, |
| 1420 | 1468 | .intcast => self.airIntcast(inst), |
| 1421 | 1469 | .float_to_int => self.airFloatToInt(inst), |
| 1470 | .get_union_tag => self.airGetUnionTag(inst), | |
| 1422 | 1471 | |
| 1423 | 1472 | .is_err => self.airIsErr(inst, .i32_ne), |
| 1424 | 1473 | .is_non_err => self.airIsErr(inst, .i32_eq), |
| ... | ... | @@ -1454,6 +1503,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue { |
| 1454 | 1503 | .slice_ptr => self.airSlicePtr(inst), |
| 1455 | 1504 | .store => self.airStore(inst), |
| 1456 | 1505 | |
| 1506 | .set_union_tag => self.airSetUnionTag(inst), | |
| 1457 | 1507 | .struct_field_ptr => self.airStructFieldPtr(inst), |
| 1458 | 1508 | .struct_field_ptr_index_0 => self.airStructFieldPtrIndex(inst, 0), |
| 1459 | 1509 | .struct_field_ptr_index_1 => self.airStructFieldPtrIndex(inst, 1), |
| ... | ... | @@ -1477,7 +1527,6 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue { |
| 1477 | 1527 | .div_float, |
| 1478 | 1528 | .div_floor, |
| 1479 | 1529 | .div_exact, |
| 1480 | .rem, | |
| 1481 | 1530 | .mod, |
| 1482 | 1531 | .max, |
| 1483 | 1532 | .min, |
| ... | ... | @@ -1494,8 +1543,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue { |
| 1494 | 1543 | .fpext, |
| 1495 | 1544 | .unwrap_errunion_payload_ptr, |
| 1496 | 1545 | .unwrap_errunion_err_ptr, |
| 1497 | .set_union_tag, | |
| 1498 | .get_union_tag, | |
| 1546 | ||
| 1499 | 1547 | .ptr_slice_len_ptr, |
| 1500 | 1548 | .ptr_slice_ptr_ptr, |
| 1501 | 1549 | .int_to_float, |
| ... | ... | @@ -1518,7 +1566,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue { |
| 1518 | 1566 | .sub_with_overflow, |
| 1519 | 1567 | .mul_with_overflow, |
| 1520 | 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 | } |
| 1524 | 1572 | |
| ... | ... | @@ -1596,6 +1644,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 1596 | 1644 | break :blk func.data.owner_decl; |
| 1597 | 1645 | } else if (func_val.castTag(.extern_fn)) |ext_fn| { |
| 1598 | 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 | 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 | 1747 | |
| 1698 | 1748 | return self.memCopy(ty, lhs, rhs); |
| 1699 | 1749 | }, |
| 1700 | .Struct, .Array => { | |
| 1750 | .Struct, .Array, .Union => { | |
| 1701 | 1751 | return try self.memCopy(ty, lhs, rhs); |
| 1702 | 1752 | }, |
| 1703 | 1753 | .Pointer => { |
| ... | ... | @@ -1720,18 +1770,8 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro |
| 1720 | 1770 | try self.emitWValue(lhs); |
| 1721 | 1771 | try self.emitWValue(rhs); |
| 1722 | 1772 | const valtype = typeToValtype(ty, self.target); |
| 1723 | // check if we should pass by pointer or value based on ABI size | |
| 1724 | // TODO: Implement a way to get ABI values from a given type, | |
| 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 | }; | |
| 1773 | const abi_size = @intCast(u8, ty.abiSize(self.target)); | |
| 1774 | ||
| 1735 | 1775 | const opcode = buildOpcode(.{ |
| 1736 | 1776 | .valtype1 = valtype, |
| 1737 | 1777 | .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 | 1811 | .unsigned |
| 1772 | 1812 | else |
| 1773 | 1813 | .signed; |
| 1774 | // TODO: Implement a way to get ABI values from a given type, | |
| 1775 | // that is portable across the backend, rather than copying logic. | |
| 1776 | const abi_size = switch (ty.zigTypeTag()) { | |
| 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 | }; | |
| 1814 | ||
| 1815 | // TODO: Revisit below to determine if optional zero-sized pointers should still have abi-size 4. | |
| 1816 | const abi_size = if (ty.isPtrLikeOptional()) @as(u8, 4) else @intCast(u8, ty.abiSize(self.target)); | |
| 1790 | 1817 | |
| 1791 | 1818 | const opcode = buildOpcode(.{ |
| 1792 | 1819 | .valtype1 = typeToValtype(ty, self.target), |
| ... | ... | @@ -1952,7 +1979,13 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue { |
| 1952 | 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 | 1990 | } else { |
| 1958 | 1991 | var int_tag_buffer: Type.Payload.Bits = undefined; |
| ... | ... | @@ -2724,7 +2757,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 2724 | 2757 | const elem_size = elem_ty.abiSize(self.target); |
| 2725 | 2758 | |
| 2726 | 2759 | // 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 | 2761 | try self.addLabel(.local_get, slice_ptr.local); |
| 2729 | 2762 | |
| 2730 | 2763 | // calculate index into slice |
| ... | ... | @@ -2746,14 +2779,13 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 2746 | 2779 | if (self.liveness.isUnused(inst)) return WValue.none; |
| 2747 | 2780 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 2748 | 2781 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 2749 | const slice_ty = self.air.typeOf(bin_op.lhs); | |
| 2750 | 2782 | const elem_ty = self.air.getRefType(ty_pl.ty).childType(); |
| 2751 | 2783 | const elem_size = elem_ty.abiSize(self.target); |
| 2752 | 2784 | |
| 2753 | 2785 | const slice = try self.resolveInst(bin_op.lhs); |
| 2754 | 2786 | const index = try self.resolveInst(bin_op.rhs); |
| 2755 | 2787 | |
| 2756 | const slice_ptr = try self.load(slice, slice_ty, 0); | |
| 2788 | const slice_ptr = try self.load(slice, Type.usize, 0); | |
| 2757 | 2789 | try self.addLabel(.local_get, slice_ptr.local); |
| 2758 | 2790 | |
| 2759 | 2791 | // calculate index into slice |
| ... | ... | @@ -3177,3 +3209,43 @@ fn cmpBigInt(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.ma |
| 3177 | 3209 | try self.addLabel(.local_set, result.local); |
| 3178 | 3210 | return result; |
| 3179 | 3211 | } |
| 3212 | ||
| 3213 | fn 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 | ||
| 3235 | fn 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 | 173 | .i64_trunc_f32_u => try emit.emitTag(tag), |
| 174 | 174 | .i64_trunc_f64_s => try emit.emitTag(tag), |
| 175 | 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), | |
| 176 | 180 | |
| 177 | 181 | .extended => try emit.emitExtended(inst), |
| 178 | 182 | } |
src/arch/wasm/Mir.zig+8| ... | ... | @@ -327,6 +327,10 @@ pub const Inst = struct { |
| 327 | 327 | /// Uses `tag` |
| 328 | 328 | i32_div_u = 0x6E, |
| 329 | 329 | /// Uses `tag` |
| 330 | i32_rem_s = 0x6F, | |
| 331 | /// Uses `tag` | |
| 332 | i32_rem_u = 0x70, | |
| 333 | /// Uses `tag` | |
| 330 | 334 | i32_and = 0x71, |
| 331 | 335 | /// Uses `tag` |
| 332 | 336 | i32_or = 0x72, |
| ... | ... | @@ -349,6 +353,10 @@ pub const Inst = struct { |
| 349 | 353 | /// Uses `tag` |
| 350 | 354 | i64_div_u = 0x80, |
| 351 | 355 | /// Uses `tag` |
| 356 | i64_rem_s = 0x81, | |
| 357 | /// Uses `tag` | |
| 358 | i64_rem_u = 0x82, | |
| 359 | /// Uses `tag` | |
| 352 | 360 | i64_and = 0x83, |
| 353 | 361 | /// Uses `tag` |
| 354 | 362 | i64_or = 0x84, |
test/behavior.zig+17-17| ... | ... | @@ -3,18 +3,34 @@ const builtin = @import("builtin"); |
| 3 | 3 | test { |
| 4 | 4 | // Tests that pass for stage1, llvm backend, C backend, wasm backend, arm backend and x86_64 backend. |
| 5 | 5 | _ = @import("behavior/align.zig"); |
| 6 | _ = @import("behavior/alignof.zig"); | |
| 6 | 7 | _ = @import("behavior/array.zig"); |
| 8 | _ = @import("behavior/bit_shifting.zig"); | |
| 7 | 9 | _ = @import("behavior/bool.zig"); |
| 10 | _ = @import("behavior/bugs/394.zig"); | |
| 8 | 11 | _ = @import("behavior/bugs/655.zig"); |
| 12 | _ = @import("behavior/bugs/656.zig"); | |
| 9 | 13 | _ = @import("behavior/bugs/679.zig"); |
| 10 | 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 | 21 | _ = @import("behavior/bugs/2346.zig"); |
| 22 | _ = @import("behavior/bugs/3112.zig"); | |
| 23 | _ = @import("behavior/bugs/3367.zig"); | |
| 12 | 24 | _ = @import("behavior/bugs/6850.zig"); |
| 25 | _ = @import("behavior/bugs/7250.zig"); | |
| 13 | 26 | _ = @import("behavior/cast.zig"); |
| 14 | 27 | _ = @import("behavior/comptime_memory.zig"); |
| 15 | 28 | _ = @import("behavior/fn_in_struct_in_comptime.zig"); |
| 29 | _ = @import("behavior/generics_llvm.zig"); | |
| 16 | 30 | _ = @import("behavior/hasdecl.zig"); |
| 17 | 31 | _ = @import("behavior/hasfield.zig"); |
| 32 | _ = @import("behavior/namespace_depends_on_compile_var.zig"); | |
| 33 | _ = @import("behavior/optional_llvm.zig"); | |
| 18 | 34 | _ = @import("behavior/prefetch.zig"); |
| 19 | 35 | _ = @import("behavior/pub_enum.zig"); |
| 20 | 36 | _ = @import("behavior/slice_sentinel_comptime.zig"); |
| ... | ... | @@ -60,6 +76,7 @@ test { |
| 60 | 76 | _ = @import("behavior/type_info.zig"); |
| 61 | 77 | _ = @import("behavior/undefined.zig"); |
| 62 | 78 | _ = @import("behavior/underscore.zig"); |
| 79 | _ = @import("behavior/union.zig"); | |
| 63 | 80 | _ = @import("behavior/usingnamespace.zig"); |
| 64 | 81 | _ = @import("behavior/void.zig"); |
| 65 | 82 | _ = @import("behavior/while.zig"); |
| ... | ... | @@ -68,30 +85,16 @@ test { |
| 68 | 85 | // Tests that pass for stage1, llvm backend, C backend |
| 69 | 86 | _ = @import("behavior/cast_int.zig"); |
| 70 | 87 | _ = @import("behavior/int128.zig"); |
| 71 | _ = @import("behavior/union.zig"); | |
| 72 | 88 | _ = @import("behavior/translate_c_macros.zig"); |
| 73 | 89 | |
| 74 | 90 | if (builtin.zig_backend != .stage2_c) { |
| 75 | 91 | // Tests that pass for stage1 and the llvm backend. |
| 76 | _ = @import("behavior/alignof.zig"); | |
| 77 | 92 | _ = @import("behavior/array_llvm.zig"); |
| 78 | 93 | _ = @import("behavior/atomics.zig"); |
| 79 | 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 | 95 | _ = @import("behavior/bugs/1741.zig"); |
| 89 | _ = @import("behavior/bugs/2006.zig"); | |
| 90 | 96 | _ = @import("behavior/bugs/2578.zig"); |
| 91 | 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 | 98 | _ = @import("behavior/bugs/9584.zig"); |
| 96 | 99 | _ = @import("behavior/cast_llvm.zig"); |
| 97 | 100 | _ = @import("behavior/enum_llvm.zig"); |
| ... | ... | @@ -99,13 +102,10 @@ test { |
| 99 | 102 | _ = @import("behavior/eval.zig"); |
| 100 | 103 | _ = @import("behavior/floatop.zig"); |
| 101 | 104 | _ = @import("behavior/fn.zig"); |
| 102 | _ = @import("behavior/generics_llvm.zig"); | |
| 103 | 105 | _ = @import("behavior/math.zig"); |
| 104 | 106 | _ = @import("behavior/maximum_minimum.zig"); |
| 105 | 107 | _ = @import("behavior/merge_error_sets.zig"); |
| 106 | _ = @import("behavior/namespace_depends_on_compile_var.zig"); | |
| 107 | 108 | _ = @import("behavior/null_llvm.zig"); |
| 108 | _ = @import("behavior/optional_llvm.zig"); | |
| 109 | 109 | _ = @import("behavior/popcount.zig"); |
| 110 | 110 | _ = @import("behavior/saturating_arithmetic.zig"); |
| 111 | 111 | _ = @import("behavior/sizeof_and_typeof.zig"); |
test/behavior/alignof.zig+6| ... | ... | @@ -11,6 +11,9 @@ const Foo = struct { |
| 11 | 11 | }; |
| 12 | 12 | |
| 13 | 13 | test "@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 | 17 | comptime try expect(@alignOf(Foo) != maxInt(usize)); |
| 15 | 18 | if (native_arch == .x86_64) { |
| 16 | 19 | comptime try expect(@alignOf(Foo) == 4); |
| ... | ... | @@ -18,6 +21,9 @@ test "@alignOf(T) before referencing T" { |
| 18 | 21 | } |
| 19 | 22 | |
| 20 | 23 | test "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 | 28 | const T = struct { x: u32 }; |
| 23 | 29 | try expect(!(@alignOf(T) == 0)); |
test/behavior/bit_shifting.zig+4| ... | ... | @@ -1,5 +1,6 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | 2 | const expect = std.testing.expect; |
| 3 | const builtin = @import("builtin"); | |
| 3 | 4 | |
| 4 | 5 | fn ShardedTable(comptime Key: type, comptime mask_bit_count: comptime_int, comptime V: type) type { |
| 5 | 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 | 61 | } |
| 61 | 62 | |
| 62 | 63 | test "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 | 67 | // realistic 16-way sharding |
| 64 | 68 | try testShardedTable(u32, 4, 8); |
| 65 | 69 |
test/behavior/bugs/1277.zig+3| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | const builtin = @import("builtin"); | |
| 2 | 3 | |
| 3 | 4 | const S = struct { |
| 4 | 5 | f: ?fn () i32, |
| ... | ... | @@ -11,5 +12,7 @@ fn f() i32 { |
| 11 | 12 | } |
| 12 | 13 | |
| 13 | 14 | test "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 | 17 | try std.testing.expect(s.f.?() == 1234); |
| 15 | 18 | } |
test/behavior/bugs/1310.zig+3| ... | ... | @@ -1,5 +1,6 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | 2 | const expect = std.testing.expect; |
| 3 | const builtin = @import("builtin"); | |
| 3 | 4 | |
| 4 | 5 | pub const VM = ?[*]const struct_InvocationTable_; |
| 5 | 6 | pub const struct_InvocationTable_ = extern struct { |
| ... | ... | @@ -22,5 +23,7 @@ fn agent_callback(_vm: [*]VM, options: [*]u8) callconv(.C) i32 { |
| 22 | 23 | } |
| 23 | 24 | |
| 24 | 25 | test "fixed" { |
| 26 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 27 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | |
| 25 | 28 | try expect(agent_callback(undefined, undefined) == 11); |
| 26 | 29 | } |
test/behavior/bugs/1381.zig+3| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | const builtin = @import("builtin"); | |
| 2 | 3 | |
| 3 | 4 | const B = union(enum) { |
| 4 | 5 | D: u8, |
| ... | ... | @@ -11,6 +12,8 @@ const A = union(enum) { |
| 11 | 12 | }; |
| 12 | 13 | |
| 13 | 14 | test "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 | 17 | var as = [_]A{ |
| 15 | 18 | A{ .B = B{ .D = 1 } }, |
| 16 | 19 | A{ .B = B{ .D = 1 } }, |
test/behavior/bugs/1500.zig+4| ... | ... | @@ -1,3 +1,4 @@ |
| 1 | const builtin = @import("builtin"); | |
| 1 | 2 | const A = struct { |
| 2 | 3 | b: B, |
| 3 | 4 | }; |
| ... | ... | @@ -5,6 +6,9 @@ const A = struct { |
| 5 | 6 | const B = *const fn (A) void; |
| 6 | 7 | |
| 7 | 8 | test "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 | 12 | var a: A = undefined; |
| 9 | 13 | var b: B = undefined; |
| 10 | 14 | if (false) { |
test/behavior/bugs/1735.zig+4| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | const builtin = @import("builtin"); | |
| 2 | 3 | |
| 3 | 4 | const mystruct = struct { |
| 4 | 5 | pending: ?listofstructs, |
| ... | ... | @@ -41,6 +42,9 @@ const a = struct { |
| 41 | 42 | }; |
| 42 | 43 | |
| 43 | 44 | test "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 | 48 | var t = a.init(); |
| 45 | 49 | try std.testing.expect(t.foo.len == 0); |
| 46 | 50 | } |
test/behavior/bugs/2006.zig+4| ... | ... | @@ -1,10 +1,14 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | 2 | const expect = std.testing.expect; |
| 3 | const builtin = @import("builtin"); | |
| 3 | 4 | |
| 4 | 5 | const S = struct { |
| 5 | 6 | p: *S, |
| 6 | 7 | }; |
| 7 | 8 | test "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 | 12 | var a: S = undefined; |
| 9 | 13 | a = S{ .p = undefined }; |
| 10 | 14 | try expect(@sizeOf(S) != 0); |
test/behavior/bugs/3112.zig+3-1| ... | ... | @@ -13,7 +13,9 @@ fn prev(p: ?State) void { |
| 13 | 13 | |
| 14 | 14 | test "zig test crash" { |
| 15 | 15 | if (builtin.zig_backend == .stage1) return error.SkipZigTest; |
| 16 | ||
| 16 | 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 | 19 | var global: State = undefined; |
| 18 | 20 | global.enter = prev; |
| 19 | 21 | global.enter(null); |
test/behavior/bugs/3367.zig+4| ... | ... | @@ -1,3 +1,4 @@ |
| 1 | const builtin = @import("builtin"); | |
| 1 | 2 | const Foo = struct { |
| 2 | 3 | usingnamespace Mixin; |
| 3 | 4 | }; |
| ... | ... | @@ -9,6 +10,9 @@ const Mixin = struct { |
| 9 | 10 | }; |
| 10 | 11 | |
| 11 | 12 | test "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 | 16 | var foo = Foo{}; |
| 13 | 17 | foo.two(); |
| 14 | 18 | } |
test/behavior/bugs/394.zig+3| ... | ... | @@ -8,8 +8,11 @@ const S = struct { |
| 8 | 8 | }; |
| 9 | 9 | |
| 10 | 10 | const expect = @import("std").testing.expect; |
| 11 | const builtin = @import("builtin"); | |
| 11 | 12 | |
| 12 | 13 | test "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 | 16 | const x = S{ |
| 14 | 17 | .x = 3, |
| 15 | 18 | .y = E{ .B = 1 }, |
test/behavior/bugs/656.zig+3| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | const expect = @import("std").testing.expect; |
| 2 | const builtin = @import("builtin"); | |
| 2 | 3 | |
| 3 | 4 | const PrefixOp = union(enum) { |
| 4 | 5 | Return, |
| ... | ... | @@ -10,6 +11,8 @@ const Value = struct { |
| 10 | 11 | }; |
| 11 | 12 | |
| 12 | 13 | test "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 | 16 | try foo(false, true); |
| 14 | 17 | } |
| 15 | 18 |
test/behavior/bugs/7250.zig+4| ... | ... | @@ -1,3 +1,4 @@ |
| 1 | const builtin = @import("builtin"); | |
| 1 | 2 | const nrfx_uart_t = extern struct { |
| 2 | 3 | p_reg: [*c]u32, |
| 3 | 4 | drv_inst_idx: u8, |
| ... | ... | @@ -13,5 +14,8 @@ threadlocal var g_uart0 = nrfx_uart_t{ |
| 13 | 14 | }; |
| 14 | 15 | |
| 15 | 16 | test "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 | 20 | _ = nrfx_uart_rx(&g_uart0); |
| 17 | 21 | } |
test/behavior/generics_llvm.zig+7| ... | ... | @@ -1,5 +1,6 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | 2 | const expect = std.testing.expect; |
| 3 | const builtin = @import("builtin"); | |
| 3 | 4 | |
| 4 | 5 | const foos = [_]fn (anytype) bool{ |
| 5 | 6 | foo1, |
| ... | ... | @@ -14,11 +15,17 @@ fn foo2(arg: anytype) bool { |
| 14 | 15 | } |
| 15 | 16 | |
| 16 | 17 | test "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 | 21 | try expect(foos[0](true)); |
| 18 | 22 | try expect(!foos[1](true)); |
| 19 | 23 | } |
| 20 | 24 | |
| 21 | 25 | test "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 | 29 | var a1 = GenNode(i32){ |
| 23 | 30 | .value = 13, |
| 24 | 31 | .next = null, |
test/behavior/namespace_depends_on_compile_var.zig+3| ... | ... | @@ -3,6 +3,9 @@ const builtin = @import("builtin"); |
| 3 | 3 | const expect = std.testing.expect; |
| 4 | 4 | |
| 5 | 5 | test "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 | 9 | if (some_namespace.a_bool) { |
| 7 | 10 | try expect(some_namespace.a_bool); |
| 8 | 11 | } else { |
test/behavior/optional_llvm.zig+4| ... | ... | @@ -2,8 +2,12 @@ const std = @import("std"); |
| 2 | 2 | const testing = std.testing; |
| 3 | 3 | const expect = testing.expect; |
| 4 | 4 | const expectEqual = testing.expectEqual; |
| 5 | const builtin = @import("builtin"); | |
| 5 | 6 | |
| 6 | 7 | test "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 | 11 | const S = struct { |
| 8 | 12 | const Node = struct { |
| 9 | 13 | children: []?Node, |
test/behavior/union.zig+2| ... | ... | @@ -362,6 +362,8 @@ pub const FooUnion = union(enum) { |
| 362 | 362 | var glbl_array: [2]FooUnion = undefined; |
| 363 | 363 | |
| 364 | 364 | test "initialize global array of union" { |
| 365 | if (@import("builtin").zig_backend == .stage2_wasm) return error.SkipZigTest; | |
| 366 | ||
| 365 | 367 | glbl_array[1] = FooUnion{ .U1 = 2 }; |
| 366 | 368 | glbl_array[0] = FooUnion{ .U0 = 1 }; |
| 367 | 369 | try expect(glbl_array[0].U0 == 1); |