authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-01-10 23:43:06+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-01-10 23:43:06+01:00
logada8e171373017cfd2a92267797c473c02aba130
tree306e5444aae35e32cccd6828e00152f02ff8594f
parent97c6d4fb3e78815d08cd61c63fcce57ab08b55ea
parentbf46aee878aa3ac6824047038ed887744da3e259
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #10565 from Luukdegram/wasm-cast

Stage2: wasm - Implement optional equality, casts and more

6 files changed, 264 insertions(+), 73 deletions(-)

src/arch/wasm/CodeGen.zig+211-60
...@@ -597,7 +597,8 @@ fn resolveInst(self: Self, ref: Air.Inst.Ref) WValue {...@@ -597,7 +597,8 @@ fn resolveInst(self: Self, ref: Air.Inst.Ref) WValue {
597 };597 };
598598
599 const inst_type = self.air.typeOfIndex(inst_index);599 const inst_type = self.air.typeOfIndex(inst_index);
600 if (!inst_type.hasCodeGenBits()) return .none;600 // It's allowed to have 0-bit integers
601 if (!inst_type.hasCodeGenBits() and !inst_type.isInt()) return WValue{ .none = {} };
601602
602 if (self.air.instructions.items(.tag)[inst_index] == .constant) {603 if (self.air.instructions.items(.tag)[inst_index] == .constant) {
603 const ty_pl = self.air.instructions.items(.data)[inst_index].ty_pl;604 const ty_pl = self.air.instructions.items(.data)[inst_index].ty_pl;
...@@ -689,7 +690,7 @@ fn typeToValtype(self: *Self, ty: Type) InnerError!wasm.Valtype {...@@ -689,7 +690,7 @@ fn typeToValtype(self: *Self, ty: Type) InnerError!wasm.Valtype {
689 const info = ty.intInfo(self.target);690 const info = ty.intInfo(self.target);
690 if (info.bits <= 32) break :blk wasm.Valtype.i32;691 if (info.bits <= 32) break :blk wasm.Valtype.i32;
691 if (info.bits > 32 and info.bits <= 64) break :blk wasm.Valtype.i64;692 if (info.bits > 32 and info.bits <= 64) break :blk wasm.Valtype.i64;
692 return self.fail("Integer bit size not supported by wasm: '{d}'", .{info.bits});693 break :blk wasm.Valtype.i32; // represented as pointer to stack
693 },694 },
694 .Enum => switch (ty.tag()) {695 .Enum => switch (ty.tag()) {
695 .enum_simple => wasm.Valtype.i32,696 .enum_simple => wasm.Valtype.i32,
...@@ -752,7 +753,7 @@ fn genFunctype(self: *Self, fn_ty: Type) !wasm.Type {...@@ -752,7 +753,7 @@ fn genFunctype(self: *Self, fn_ty: Type) !wasm.Type {
752 defer returns.deinit();753 defer returns.deinit();
753 const return_type = fn_ty.fnReturnType();754 const return_type = fn_ty.fnReturnType();
754755
755 const want_sret = isByRef(return_type);756 const want_sret = self.isByRef(return_type);
756757
757 if (want_sret) {758 if (want_sret) {
758 try params.append(try self.typeToValtype(Type.usize));759 try params.append(try self.typeToValtype(Type.usize));
...@@ -900,17 +901,6 @@ fn genTypedValue(self: *Self, ty: Type, val: Value) InnerError!Result {...@@ -900,17 +901,6 @@ fn genTypedValue(self: *Self, ty: Type, val: Value) InnerError!Result {
900 .Array => switch (val.tag()) {901 .Array => switch (val.tag()) {
901 .bytes => {902 .bytes => {
902 const payload = val.castTag(.bytes).?;903 const payload = val.castTag(.bytes).?;
903 if (ty.sentinel()) |sentinel| {
904 try self.code.appendSlice(payload.data);
905
906 switch (try self.genTypedValue(ty.childType(), sentinel)) {
907 .appended => return Result.appended,
908 .externally_managed => |data| {
909 try self.code.appendSlice(data);
910 return Result.appended;
911 },
912 }
913 }
914 return Result{ .externally_managed = payload.data };904 return Result{ .externally_managed = payload.data };
915 },905 },
916 .array => {906 .array => {
...@@ -1094,7 +1084,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) InnerError!CallWValu...@@ -1094,7 +1084,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) InnerError!CallWValu
1094 const ret_ty = fn_ty.fnReturnType();1084 const ret_ty = fn_ty.fnReturnType();
1095 // Check if we store the result as a pointer to the stack rather than1085 // Check if we store the result as a pointer to the stack rather than
1096 // by value1086 // by value
1097 if (isByRef(ret_ty)) {1087 if (self.isByRef(ret_ty)) {
1098 // the sret arg will be passed as first argument, therefore we1088 // the sret arg will be passed as first argument, therefore we
1099 // set the `return_value` before allocating locals for regular args.1089 // set the `return_value` before allocating locals for regular args.
1100 result.return_value = .{ .local = self.local_index };1090 result.return_value = .{ .local = self.local_index };
...@@ -1219,7 +1209,7 @@ fn ptrSize(self: *const Self) u16 {...@@ -1219,7 +1209,7 @@ fn ptrSize(self: *const Self) u16 {
12191209
1220/// For a given `Type`, will return true when the type will be passed1210/// For a given `Type`, will return true when the type will be passed
1221/// by reference, rather than by value.1211/// by reference, rather than by value.
1222fn isByRef(ty: Type) bool {1212fn isByRef(self: Self, ty: Type) bool {
1223 switch (ty.zigTypeTag()) {1213 switch (ty.zigTypeTag()) {
1224 .Type,1214 .Type,
1225 .ComptimeInt,1215 .ComptimeInt,
...@@ -1234,7 +1224,6 @@ fn isByRef(ty: Type) bool {...@@ -1234,7 +1224,6 @@ fn isByRef(ty: Type) bool {
1234 .NoReturn,1224 .NoReturn,
1235 .Void,1225 .Void,
1236 .Bool,1226 .Bool,
1237 .Int,
1238 .Float,1227 .Float,
1239 .ErrorSet,1228 .ErrorSet,
1240 .Fn,1229 .Fn,
...@@ -1248,6 +1237,7 @@ fn isByRef(ty: Type) bool {...@@ -1248,6 +1237,7 @@ fn isByRef(ty: Type) bool {
1248 .Frame,1237 .Frame,
1249 .Union,1238 .Union,
1250 => return ty.hasCodeGenBits(),1239 => return ty.hasCodeGenBits(),
1240 .Int => return if (ty.intInfo(self.target).bits > 64) true else false,
1251 .ErrorUnion => {1241 .ErrorUnion => {
1252 const has_tag = ty.errorUnionSet().hasCodeGenBits();1242 const has_tag = ty.errorUnionSet().hasCodeGenBits();
1253 const has_pl = ty.errorUnionPayload().hasCodeGenBits();1243 const has_pl = ty.errorUnionPayload().hasCodeGenBits();
...@@ -1318,6 +1308,8 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {...@@ -1318,6 +1308,8 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
1318 .bit_or => self.airBinOp(inst, .@"or"),1308 .bit_or => self.airBinOp(inst, .@"or"),
1319 .bool_and => self.airBinOp(inst, .@"and"),1309 .bool_and => self.airBinOp(inst, .@"and"),
1320 .bool_or => self.airBinOp(inst, .@"or"),1310 .bool_or => self.airBinOp(inst, .@"or"),
1311 .shl => self.airBinOp(inst, .shl),
1312 .shr => self.airBinOp(inst, .shr),
1321 .xor => self.airBinOp(inst, .xor),1313 .xor => self.airBinOp(inst, .xor),
13221314
1323 .cmp_eq => self.airCmp(inst, .eq),1315 .cmp_eq => self.airCmp(inst, .eq),
...@@ -1341,6 +1333,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {...@@ -1341,6 +1333,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
1341 .constant => unreachable,1333 .constant => unreachable,
1342 .dbg_stmt => WValue.none,1334 .dbg_stmt => WValue.none,
1343 .intcast => self.airIntcast(inst),1335 .intcast => self.airIntcast(inst),
1336 .float_to_int => self.airFloatToInt(inst),
13441337
1345 .is_err => self.airIsErr(inst, .i32_ne),1338 .is_err => self.airIsErr(inst, .i32_ne),
1346 .is_non_err => self.airIsErr(inst, .i32_eq),1339 .is_non_err => self.airIsErr(inst, .i32_eq),
...@@ -1417,17 +1410,16 @@ fn airRet(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -1417,17 +1410,16 @@ fn airRet(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
14171410
1418fn airRetPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {1411fn airRetPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
1419 const child_type = self.air.typeOfIndex(inst).childType();1412 const child_type = self.air.typeOfIndex(inst).childType();
1413 if (child_type.abiSize(self.target) == 0) return WValue{ .none = {} };
1414
1415 if (self.isByRef(child_type)) {
1416 return self.return_value;
1417 }
14201418
1421 // Initialize the stack1419 // Initialize the stack
1422 if (self.initial_stack_value == .none) {1420 if (self.initial_stack_value == .none) {
1423 try self.initializeStack();1421 try self.initializeStack();
1424 }1422 }
1425
1426 if (child_type.abiSize(self.target) == 0) return WValue{ .none = {} };
1427
1428 if (isByRef(child_type)) {
1429 return self.return_value;
1430 }
1431 return self.allocStack(child_type);1423 return self.allocStack(child_type);
1432}1424}
14331425
...@@ -1437,7 +1429,7 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -1437,7 +1429,7 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
1437 const ret_ty = self.air.typeOf(un_op).childType();1429 const ret_ty = self.air.typeOf(un_op).childType();
1438 if (!ret_ty.hasCodeGenBits()) return WValue.none;1430 if (!ret_ty.hasCodeGenBits()) return WValue.none;
14391431
1440 if (!isByRef(ret_ty)) {1432 if (!self.isByRef(ret_ty)) {
1441 const result = try self.load(operand, ret_ty, 0);1433 const result = try self.load(operand, ret_ty, 0);
1442 try self.emitWValue(result);1434 try self.emitWValue(result);
1443 }1435 }
...@@ -1459,7 +1451,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -1459,7 +1451,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
1459 else => unreachable,1451 else => unreachable,
1460 };1452 };
1461 const ret_ty = fn_ty.fnReturnType();1453 const ret_ty = fn_ty.fnReturnType();
1462 const first_param_sret = isByRef(ret_ty);1454 const first_param_sret = self.isByRef(ret_ty);
14631455
1464 const target: ?*Decl = blk: {1456 const target: ?*Decl = blk: {
1465 const func_val = self.air.value(pl_op.operand) orelse break :blk null;1457 const func_val = self.air.value(pl_op.operand) orelse break :blk null;
...@@ -1487,7 +1479,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -1487,7 +1479,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
14871479
1488 // If we need to pass by reference, but the argument is a constant,1480 // If we need to pass by reference, but the argument is a constant,
1489 // we must first lower it before passing it.1481 // we must first lower it before passing it.
1490 if (isByRef(arg_ty) and arg_val == .constant) {1482 if (self.isByRef(arg_ty) and arg_val == .constant) {
1491 const arg_local = try self.allocStack(arg_ty);1483 const arg_local = try self.allocStack(arg_ty);
1492 try self.store(arg_local, arg_val, arg_ty, 0);1484 try self.store(arg_local, arg_val, arg_ty, 0);
1493 try self.emitWValue(arg_local);1485 try self.emitWValue(arg_local);
...@@ -1599,7 +1591,12 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro...@@ -1599,7 +1591,12 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro
1599 if (payload_ty.hasCodeGenBits()) {1591 if (payload_ty.hasCodeGenBits()) {
1600 const payload_local = try self.allocLocal(payload_ty);1592 const payload_local = try self.allocLocal(payload_ty);
1601 try self.addLabel(.local_set, payload_local.local);1593 try self.addLabel(.local_set, payload_local.local);
1602 try self.store(lhs, payload_local, payload_ty, payload_offset);1594 if (self.isByRef(payload_ty)) {
1595 const ptr = try self.buildPointerOffset(lhs, payload_offset, .new);
1596 try self.store(ptr, payload_local, payload_ty, 0);
1597 } else {
1598 try self.store(lhs, payload_local, payload_ty, payload_offset);
1599 }
1603 }1600 }
1604 try self.addLabel(.local_set, tag_local.local);1601 try self.addLabel(.local_set, tag_local.local);
16051602
...@@ -1616,7 +1613,7 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro...@@ -1616,7 +1613,7 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro
1616 // Load values from `rhs` stack position and store in `lhs` instead1613 // Load values from `rhs` stack position and store in `lhs` instead
1617 const tag_local = try self.load(rhs, tag_ty, 0);1614 const tag_local = try self.load(rhs, tag_ty, 0);
1618 if (payload_ty.hasCodeGenBits()) {1615 if (payload_ty.hasCodeGenBits()) {
1619 if (isByRef(payload_ty)) {1616 if (self.isByRef(payload_ty)) {
1620 const payload_ptr = try self.buildPointerOffset(rhs, payload_offset, .new);1617 const payload_ptr = try self.buildPointerOffset(rhs, payload_offset, .new);
1621 const lhs_payload_ptr = try self.buildPointerOffset(lhs, payload_offset, .new);1618 const lhs_payload_ptr = try self.buildPointerOffset(lhs, payload_offset, .new);
1622 try self.store(lhs_payload_ptr, payload_ptr, payload_ty, 0);1619 try self.store(lhs_payload_ptr, payload_ptr, payload_ty, 0);
...@@ -1649,12 +1646,13 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro...@@ -1649,12 +1646,13 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro
1649 }1646 }
1650 },1647 },
1651 .Struct, .Array => {1648 .Struct, .Array => {
1652 if (rhs == .constant) {1649 const final_rhs = if (rhs == .constant) blk: {
1650 const tmp = try self.allocLocal(Type.usize);
1653 try self.emitWValue(rhs);1651 try self.emitWValue(rhs);
1654 try self.addLabel(.local_set, lhs.local);1652 try self.addLabel(.local_set, tmp.local);
1655 return;1653 break :blk tmp;
1656 }1654 } else rhs;
1657 return try self.memCopy(ty, lhs, rhs);1655 return try self.memCopy(ty, lhs, final_rhs);
1658 },1656 },
1659 .Pointer => {1657 .Pointer => {
1660 if (ty.isSlice() and rhs == .constant) {1658 if (ty.isSlice() and rhs == .constant) {
...@@ -1665,10 +1663,20 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro...@@ -1665,10 +1663,20 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro
1665 const ptr_local = try self.allocLocal(Type.usize);1663 const ptr_local = try self.allocLocal(Type.usize);
1666 const len_offset = self.ptrSize();1664 const len_offset = self.ptrSize();
1667 if (val.castTag(.decl_ref)) |decl| {1665 if (val.castTag(.decl_ref)) |decl| {
1668 // for decl references we also need to retrieve the length and the original decl's pointer1666 const decl_ty: Type = decl.data.ty;
1669 try self.addMemArg(.i32_load, .{ .offset = 0, .alignment = self.ptrSize() });1667 if (decl_ty.isSlice()) {
1670 try self.addLabel(.memory_address, decl.data.link.wasm.sym_index);1668 // for decl references we also need to retrieve the length and the original decl's pointer
1671 try self.addMemArg(.i32_load, .{ .offset = len_offset, .alignment = self.ptrSize() });1669 try self.addMemArg(.i32_load, .{ .offset = 0, .alignment = self.ptrSize() });
1670 try self.addLabel(.memory_address, decl.data.link.wasm.sym_index);
1671 try self.addMemArg(.i32_load, .{ .offset = len_offset, .alignment = self.ptrSize() });
1672 } else if (decl_ty.zigTypeTag() == .Array) {
1673 const len = decl_ty.arrayLen();
1674 switch (self.ptrSize()) {
1675 4 => try self.addImm32(@bitCast(i32, @intCast(u32, len))),
1676 8 => try self.addImm64(len),
1677 else => unreachable,
1678 }
1679 } else return self.fail("Wasm todo: Implement storing slices for decl_ref with type: {}", .{decl_ty});
1672 }1680 }
1673 try self.addLabel(.local_set, len_local.local);1681 try self.addLabel(.local_set, len_local.local);
1674 try self.addLabel(.local_set, ptr_local.local);1682 try self.addLabel(.local_set, ptr_local.local);
...@@ -1677,15 +1685,23 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro...@@ -1677,15 +1685,23 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro
1677 return;1685 return;
1678 } else if (ty.isSlice()) {1686 } else if (ty.isSlice()) {
1679 // store pointer first1687 // store pointer first
1680 const ptr_local = try self.load(rhs, Type.@"usize", 0);1688 const ptr_local = try self.load(rhs, Type.usize, 0);
1681 try self.store(lhs, ptr_local, Type.@"usize", 0);1689 try self.store(lhs, ptr_local, Type.usize, 0);
16821690
1683 // retrieve length from rhs, and store that alongside lhs as well1691 // retrieve length from rhs, and store that alongside lhs as well
1684 const len_local = try self.load(rhs, Type.@"usize", 4);1692 const len_local = try self.load(rhs, Type.usize, self.ptrSize());
1685 try self.store(lhs, len_local, Type.@"usize", 4);1693 try self.store(lhs, len_local, Type.usize, self.ptrSize());
1686 return;1694 return;
1687 }1695 }
1688 },1696 },
1697 .Int => if (ty.intInfo(self.target).bits > 64) {
1698 if (rhs == .constant) {
1699 try self.emitWValue(rhs);
1700 try self.addLabel(.local_set, lhs.local);
1701 return;
1702 }
1703 return try self.memCopy(ty, lhs, rhs);
1704 },
1689 else => {},1705 else => {},
1690 }1706 }
1691 try self.emitWValue(lhs);1707 try self.emitWValue(lhs);
...@@ -1723,7 +1739,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -1723,7 +1739,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
17231739
1724 if (!ty.hasCodeGenBits()) return WValue{ .none = {} };1740 if (!ty.hasCodeGenBits()) return WValue{ .none = {} };
17251741
1726 if (isByRef(ty)) {1742 if (self.isByRef(ty)) {
1727 const new_local = try self.allocStack(ty);1743 const new_local = try self.allocStack(ty);
1728 try self.store(new_local, operand, ty, 0);1744 try self.store(new_local, operand, ty, 0);
1729 return new_local;1745 return new_local;
...@@ -1787,9 +1803,16 @@ fn airArg(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -1787,9 +1803,16 @@ fn airArg(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
1787}1803}
17881804
1789fn airBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue {1805fn airBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue {
1806 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };
1807
1790 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1808 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1791 const lhs = self.resolveInst(bin_op.lhs);1809 const lhs = self.resolveInst(bin_op.lhs);
1792 const rhs = self.resolveInst(bin_op.rhs);1810 const rhs = self.resolveInst(bin_op.rhs);
1811 const operand_ty = self.air.typeOfIndex(inst);
1812
1813 if (self.isByRef(operand_ty)) {
1814 return self.fail("TODO: Implement binary operation for type: {}", .{operand_ty});
1815 }
17931816
1794 try self.emitWValue(lhs);1817 try self.emitWValue(lhs);
1795 try self.emitWValue(rhs);1818 try self.emitWValue(rhs);
...@@ -1865,16 +1888,36 @@ fn emitConstant(self: *Self, val: Value, ty: Type) InnerError!void {...@@ -1865,16 +1888,36 @@ fn emitConstant(self: *Self, val: Value, ty: Type) InnerError!void {
1865 // write constant1888 // write constant
1866 switch (int_info.signedness) {1889 switch (int_info.signedness) {
1867 .signed => switch (int_info.bits) {1890 .signed => switch (int_info.bits) {
1868 0...32 => try self.addImm32(@intCast(i32, val.toSignedInt())),1891 0...32 => return try self.addImm32(@intCast(i32, val.toSignedInt())),
1869 33...64 => try self.addImm64(@bitCast(u64, val.toSignedInt())),1892 33...64 => return try self.addImm64(@bitCast(u64, val.toSignedInt())),
1893 65...128 => {},
1870 else => |bits| return self.fail("Wasm todo: emitConstant for integer with {d} bits", .{bits}),1894 else => |bits| return self.fail("Wasm todo: emitConstant for integer with {d} bits", .{bits}),
1871 },1895 },
1872 .unsigned => switch (int_info.bits) {1896 .unsigned => switch (int_info.bits) {
1873 0...32 => try self.addImm32(@bitCast(i32, @intCast(u32, val.toUnsignedInt()))),1897 0...32 => return try self.addImm32(@bitCast(i32, @intCast(u32, val.toUnsignedInt()))),
1874 33...64 => try self.addImm64(val.toUnsignedInt()),1898 33...64 => return try self.addImm64(val.toUnsignedInt()),
1899 65...128 => {},
1875 else => |bits| return self.fail("Wasm TODO: emitConstant for integer with {d} bits", .{bits}),1900 else => |bits| return self.fail("Wasm TODO: emitConstant for integer with {d} bits", .{bits}),
1876 },1901 },
1877 }1902 }
1903 const result = try self.allocStack(ty);
1904 var space: Value.BigIntSpace = undefined;
1905 const bigint = val.toBigInt(&space);
1906 if (bigint.limbs.len == 1 and bigint.limbs[0] == 0) {
1907 try self.addLabel(.local_get, result.local);
1908 return;
1909 }
1910 if (@sizeOf(usize) != @sizeOf(u64)) {
1911 return self.fail("Wasm todo: Implement big integers for 32bit compiler", .{});
1912 }
1913
1914 for (bigint.limbs) |_, index| {
1915 const limb = bigint.limbs[bigint.limbs.len - index - 1];
1916 try self.addLabel(.local_get, result.local);
1917 try self.addImm64(limb);
1918 try self.addMemArg(.i64_store, .{ .offset = @intCast(u32, index * 8), .alignment = 8 });
1919 }
1920 try self.addLabel(.local_get, result.local);
1878 },1921 },
1879 .Bool => try self.addImm32(@intCast(i32, val.toSignedInt())),1922 .Bool => try self.addImm32(@intCast(i32, val.toSignedInt())),
1880 .Float => {1923 .Float => {
...@@ -2233,9 +2276,6 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: std.math.CompareOperator) Inner...@@ -2233,9 +2276,6 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: std.math.CompareOperator) Inner
2233 const rhs = self.resolveInst(bin_op.rhs);2276 const rhs = self.resolveInst(bin_op.rhs);
2234 const operand_ty = self.air.typeOf(bin_op.lhs);2277 const operand_ty = self.air.typeOf(bin_op.lhs);
22352278
2236 try self.emitWValue(lhs);
2237 try self.emitWValue(rhs);
2238
2239 if (operand_ty.zigTypeTag() == .Optional and !operand_ty.isPtrLikeOptional()) {2279 if (operand_ty.zigTypeTag() == .Optional and !operand_ty.isPtrLikeOptional()) {
2240 var buf: Type.Payload.ElemType = undefined;2280 var buf: Type.Payload.ElemType = undefined;
2241 const payload_ty = operand_ty.optionalChild(&buf);2281 const payload_ty = operand_ty.optionalChild(&buf);
...@@ -2243,10 +2283,15 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: std.math.CompareOperator) Inner...@@ -2243,10 +2283,15 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: std.math.CompareOperator) Inner
2243 // When we hit this case, we must check the value of optionals2283 // When we hit this case, we must check the value of optionals
2244 // that are not pointers. This means first checking against non-null for2284 // that are not pointers. This means first checking against non-null for
2245 // both lhs and rhs, as well as checking the payload are matching of lhs and rhs2285 // both lhs and rhs, as well as checking the payload are matching of lhs and rhs
2246 return self.fail("TODO: Implement airCmp for comparing optionals", .{});2286 return self.cmpOptionals(lhs, rhs, operand_ty, op);
2247 }2287 }
2288 } else if (self.isByRef(operand_ty)) {
2289 return self.cmpBigInt(lhs, rhs, operand_ty, op);
2248 }2290 }
22492291
2292 try self.emitWValue(lhs);
2293 try self.emitWValue(rhs);
2294
2250 const signedness: std.builtin.Signedness = blk: {2295 const signedness: std.builtin.Signedness = blk: {
2251 // by default we tell the operand type is unsigned (i.e. bools and enum values)2296 // by default we tell the operand type is unsigned (i.e. bools and enum values)
2252 if (operand_ty.zigTypeTag() != .Int) break :blk .unsigned;2297 if (operand_ty.zigTypeTag() != .Int) break :blk .unsigned;
...@@ -2390,7 +2435,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2390,7 +2435,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2390 return self.fail("Field type '{}' too big to fit into stack frame", .{field_ty});2435 return self.fail("Field type '{}' too big to fit into stack frame", .{field_ty});
2391 };2436 };
23922437
2393 if (isByRef(field_ty)) {2438 if (self.isByRef(field_ty)) {
2394 return WValue{ .local_with_offset = .{ .local = operand.local, .offset = offset } };2439 return WValue{ .local_with_offset = .{ .local = operand.local, .offset = offset } };
2395 }2440 }
23962441
...@@ -2573,13 +2618,16 @@ fn airIsErr(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerError!W...@@ -2573,13 +2618,16 @@ fn airIsErr(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerError!W
2573}2618}
25742619
2575fn airUnwrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {2620fn airUnwrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2576 if (self.liveness.isUnused(inst)) return WValue.none;2621 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };
2577 const ty_op = self.air.instructions.items(.data)[inst].ty_op;2622 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2578 const operand = self.resolveInst(ty_op.operand);2623 const operand = self.resolveInst(ty_op.operand);
2579 const err_ty = self.air.typeOf(ty_op.operand);2624 const err_ty = self.air.typeOf(ty_op.operand);
2580 const payload_ty = err_ty.errorUnionPayload();2625 const payload_ty = err_ty.errorUnionPayload();
2581 if (!payload_ty.hasCodeGenBits()) return WValue.none;2626 if (!payload_ty.hasCodeGenBits()) return WValue{ .none = {} };
2582 const offset = @intCast(u32, err_ty.errorUnionSet().abiSize(self.target));2627 const offset = @intCast(u32, err_ty.errorUnionSet().abiSize(self.target));
2628 if (self.isByRef(payload_ty)) {
2629 return self.buildPointerOffset(operand, offset, .new);
2630 }
2583 return try self.load(operand, payload_ty, offset);2631 return try self.load(operand, payload_ty, offset);
2584}2632}
25852633
...@@ -2632,6 +2680,8 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2632,6 +2680,8 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2632}2680}
26332681
2634fn airIntcast(self: *Self, inst: Air.Inst.Index) InnerError!WValue {2682fn airIntcast(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2683 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };
2684
2635 const ty_op = self.air.instructions.items(.data)[inst].ty_op;2685 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2636 const ty = self.air.getRefType(ty_op.ty);2686 const ty = self.air.getRefType(ty_op.ty);
2637 const operand = self.resolveInst(ty_op.operand);2687 const operand = self.resolveInst(ty_op.operand);
...@@ -2656,7 +2706,8 @@ fn airIntcast(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2656,7 +2706,8 @@ fn airIntcast(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2656 .signed => .i64_extend_i32_s,2706 .signed => .i64_extend_i32_s,
2657 .unsigned => .i64_extend_i32_u,2707 .unsigned => .i64_extend_i32_u,
2658 });2708 });
2659 }2709 } else unreachable;
2710
2660 const result = try self.allocLocal(ty);2711 const result = try self.allocLocal(ty);
2661 try self.addLabel(.local_set, result.local);2712 try self.addLabel(.local_set, result.local);
2662 return result;2713 return result;
...@@ -2668,12 +2719,16 @@ fn airIsNull(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode, op_kind: en...@@ -2668,12 +2719,16 @@ fn airIsNull(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode, op_kind: en
26682719
2669 const op_ty = self.air.typeOf(un_op);2720 const op_ty = self.air.typeOf(un_op);
2670 const optional_ty = if (op_kind == .ptr) op_ty.childType() else op_ty;2721 const optional_ty = if (op_kind == .ptr) op_ty.childType() else op_ty;
2722 return self.isNull(operand, optional_ty, opcode);
2723}
2724
2725fn isNull(self: *Self, operand: WValue, optional_ty: Type, opcode: wasm.Opcode) InnerError!WValue {
2671 try self.emitWValue(operand);2726 try self.emitWValue(operand);
2672 if (!optional_ty.isPtrLikeOptional()) {2727 if (!optional_ty.isPtrLikeOptional()) {
2673 var buf: Type.Payload.ElemType = undefined;2728 var buf: Type.Payload.ElemType = undefined;
2674 const payload_ty = optional_ty.optionalChild(&buf);2729 const payload_ty = optional_ty.optionalChild(&buf);
2675 // When payload is zero-bits, we can treat operand as a value, rather than a2730 // When payload is zero-bits, we can treat operand as a value, rather than
2676 // stack value2731 // a pointer to the stack value
2677 if (payload_ty.hasCodeGenBits()) {2732 if (payload_ty.hasCodeGenBits()) {
2678 try self.addMemArg(.i32_load8_u, .{ .offset = 0, .alignment = 1 });2733 try self.addMemArg(.i32_load8_u, .{ .offset = 0, .alignment = 1 });
2679 }2734 }
...@@ -2699,7 +2754,7 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2699,7 +2754,7 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
26992754
2700 const offset = opt_ty.abiSize(self.target) - payload_ty.abiSize(self.target);2755 const offset = opt_ty.abiSize(self.target) - payload_ty.abiSize(self.target);
27012756
2702 if (isByRef(payload_ty)) {2757 if (self.isByRef(payload_ty)) {
2703 return self.buildPointerOffset(operand, offset, .new);2758 return self.buildPointerOffset(operand, offset, .new);
2704 }2759 }
27052760
...@@ -2830,7 +2885,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2830,7 +2885,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2830 const result = try self.allocLocal(elem_ty);2885 const result = try self.allocLocal(elem_ty);
2831 try self.addLabel(.local_set, result.local);2886 try self.addLabel(.local_set, result.local);
28322887
2833 if (isByRef(elem_ty)) {2888 if (self.isByRef(elem_ty)) {
2834 return result;2889 return result;
2835 }2890 }
2836 return try self.load(result, elem_ty, 0);2891 return try self.load(result, elem_ty, 0);
...@@ -2991,7 +3046,7 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2991,7 +3046,7 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
29913046
2992 const result = try self.allocLocal(elem_ty);3047 const result = try self.allocLocal(elem_ty);
2993 try self.addLabel(.local_set, result.local);3048 try self.addLabel(.local_set, result.local);
2994 if (isByRef(elem_ty)) {3049 if (self.isByRef(elem_ty)) {
2995 return result;3050 return result;
2996 }3051 }
2997 return try self.load(result, elem_ty, 0);3052 return try self.load(result, elem_ty, 0);
...@@ -3141,8 +3196,104 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -3141,8 +3196,104 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3141 const result = try self.allocLocal(elem_ty);3196 const result = try self.allocLocal(elem_ty);
3142 try self.addLabel(.local_set, result.local);3197 try self.addLabel(.local_set, result.local);
31433198
3144 if (isByRef(elem_ty)) {3199 if (self.isByRef(elem_ty)) {
3145 return result;3200 return result;
3146 }3201 }
3147 return try self.load(result, elem_ty, 0);3202 return try self.load(result, elem_ty, 0);
3148}3203}
3204
3205fn airFloatToInt(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3206 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };
3207
3208 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
3209 const operand = self.resolveInst(ty_op.operand);
3210 const dest_ty = self.air.typeOfIndex(inst);
3211 const op_ty = self.air.typeOf(ty_op.operand);
3212
3213 try self.emitWValue(operand);
3214 const op = buildOpcode(.{
3215 .op = .trunc,
3216 .valtype1 = try self.typeToValtype(dest_ty),
3217 .valtype2 = try self.typeToValtype(op_ty),
3218 .signedness = if (dest_ty.isSignedInt()) .signed else .unsigned,
3219 });
3220 try self.addTag(Mir.Inst.Tag.fromOpcode(op));
3221
3222 const result = try self.allocLocal(dest_ty);
3223 try self.addLabel(.local_set, result.local);
3224 return result;
3225}
3226
3227fn cmpOptionals(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.math.CompareOperator) InnerError!WValue {
3228 assert(operand_ty.hasCodeGenBits());
3229 assert(op == .eq or op == .neq);
3230 var buf: Type.Payload.ElemType = undefined;
3231 const payload_ty = operand_ty.optionalChild(&buf);
3232 const offset = @intCast(u32, operand_ty.abiSize(self.target) - payload_ty.abiSize(self.target));
3233
3234 const lhs_is_null = try self.isNull(lhs, operand_ty, .i32_eq);
3235 const rhs_is_null = try self.isNull(rhs, operand_ty, .i32_eq);
3236
3237 // We store the final result in here that will be validated
3238 // if the optional is truly equal.
3239 const result = try self.allocLocal(Type.initTag(.i32));
3240
3241 try self.startBlock(.block, wasm.block_empty);
3242 try self.emitWValue(lhs_is_null);
3243 try self.emitWValue(rhs_is_null);
3244 try self.addTag(.i32_ne); // inverse so we can exit early
3245 try self.addLabel(.br_if, 0);
3246
3247 const lhs_pl = try self.load(lhs, payload_ty, offset);
3248 const rhs_pl = try self.load(rhs, payload_ty, offset);
3249
3250 try self.emitWValue(lhs_pl);
3251 try self.emitWValue(rhs_pl);
3252 const opcode = buildOpcode(.{ .op = .ne, .valtype1 = try self.typeToValtype(payload_ty) });
3253 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));
3254 try self.addLabel(.br_if, 0);
3255
3256 try self.addImm32(1);
3257 try self.addLabel(.local_set, result.local);
3258 try self.endBlock();
3259
3260 try self.emitWValue(result);
3261 try self.addImm32(0);
3262 try self.addTag(if (op == .eq) .i32_ne else .i32_eq);
3263 try self.addLabel(.local_set, result.local);
3264 return result;
3265}
3266
3267/// Compares big integers by checking both its high bits and low bits.
3268/// TODO: Lower this to compiler_rt call
3269fn cmpBigInt(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.math.CompareOperator) InnerError!WValue {
3270 if (operand_ty.intInfo(self.target).bits > 128) {
3271 return self.fail("TODO: Support cmpBigInt for integer bitsize: '{d}'", .{operand_ty.intInfo(self.target).bits});
3272 }
3273
3274 const result = try self.allocLocal(Type.initTag(.i32));
3275 {
3276 try self.startBlock(.block, wasm.block_empty);
3277 const lhs_high_bit = try self.load(lhs, Type.initTag(.u64), 0);
3278 const lhs_low_bit = try self.load(lhs, Type.initTag(.u64), 8);
3279 const rhs_high_bit = try self.load(rhs, Type.initTag(.u64), 0);
3280 const rhs_low_bit = try self.load(rhs, Type.initTag(.u64), 8);
3281 try self.emitWValue(lhs_high_bit);
3282 try self.emitWValue(rhs_high_bit);
3283 try self.addTag(.i64_ne);
3284 try self.addLabel(.br_if, 0);
3285 try self.emitWValue(lhs_low_bit);
3286 try self.emitWValue(rhs_low_bit);
3287 try self.addTag(.i64_ne);
3288 try self.addLabel(.br_if, 0);
3289 try self.addImm32(1);
3290 try self.addLabel(.local_set, result.local);
3291 try self.endBlock();
3292 }
3293
3294 try self.emitWValue(result);
3295 try self.addImm32(0);
3296 try self.addTag(if (op == .eq) .i32_ne else .i32_eq);
3297 try self.addLabel(.local_set, result.local);
3298 return result;
3299}
src/arch/wasm/Emit.zig+12
...@@ -161,6 +161,18 @@ pub fn emitMir(emit: *Emit) InnerError!void {...@@ -161,6 +161,18 @@ pub fn emitMir(emit: *Emit) InnerError!void {
161 .i64_extend8_s => try emit.emitTag(tag),161 .i64_extend8_s => try emit.emitTag(tag),
162 .i64_extend16_s => try emit.emitTag(tag),162 .i64_extend16_s => try emit.emitTag(tag),
163 .i64_extend32_s => try emit.emitTag(tag),163 .i64_extend32_s => try emit.emitTag(tag),
164 .i32_reinterpret_f32 => try emit.emitTag(tag),
165 .i64_reinterpret_f64 => try emit.emitTag(tag),
166 .f32_reinterpret_i32 => try emit.emitTag(tag),
167 .f64_reinterpret_i64 => try emit.emitTag(tag),
168 .i32_trunc_f32_s => try emit.emitTag(tag),
169 .i32_trunc_f32_u => try emit.emitTag(tag),
170 .i32_trunc_f64_s => try emit.emitTag(tag),
171 .i32_trunc_f64_u => try emit.emitTag(tag),
172 .i64_trunc_f32_s => try emit.emitTag(tag),
173 .i64_trunc_f32_u => try emit.emitTag(tag),
174 .i64_trunc_f64_s => try emit.emitTag(tag),
175 .i64_trunc_f64_u => try emit.emitTag(tag),
164176
165 .extended => try emit.emitExtended(inst),177 .extended => try emit.emitExtended(inst),
166 }178 }
src/arch/wasm/Mir.zig+24
...@@ -363,10 +363,34 @@ pub const Inst = struct {...@@ -363,10 +363,34 @@ pub const Inst = struct {
363 /// Uses `tag`363 /// Uses `tag`
364 i32_wrap_i64 = 0xA7,364 i32_wrap_i64 = 0xA7,
365 /// Uses `tag`365 /// Uses `tag`
366 i32_trunc_f32_s = 0xA8,
367 /// Uses `tag`
368 i32_trunc_f32_u = 0xA9,
369 /// Uses `tag`
370 i32_trunc_f64_s = 0xAA,
371 /// Uses `tag`
372 i32_trunc_f64_u = 0xAB,
373 /// Uses `tag`
366 i64_extend_i32_s = 0xAC,374 i64_extend_i32_s = 0xAC,
367 /// Uses `tag`375 /// Uses `tag`
368 i64_extend_i32_u = 0xAD,376 i64_extend_i32_u = 0xAD,
369 /// Uses `tag`377 /// Uses `tag`
378 i64_trunc_f32_s = 0xAE,
379 /// Uses `tag`
380 i64_trunc_f32_u = 0xAF,
381 /// Uses `tag`
382 i64_trunc_f64_s = 0xB0,
383 /// Uses `tag`
384 i64_trunc_f64_u = 0xB1,
385 /// Uses `tag`
386 i32_reinterpret_f32 = 0xBC,
387 /// Uses `tag`
388 i64_reinterpret_f64 = 0xBD,
389 /// Uses `tag`
390 f32_reinterpret_i32 = 0xBE,
391 /// Uses `tag`
392 f64_reinterpret_i64 = 0xBF,
393 /// Uses `tag`
370 i32_extend8_s = 0xC0,394 i32_extend8_s = 0xC0,
371 /// Uses `tag`395 /// Uses `tag`
372 i32_extend16_s = 0xC1,396 i32_extend16_s = 0xC1,
test/behavior.zig+7-6
...@@ -20,8 +20,8 @@ test {...@@ -20,8 +20,8 @@ test {
2020
21 if (builtin.zig_backend != .stage2_arm and builtin.zig_backend != .stage2_x86_64) {21 if (builtin.zig_backend != .stage2_arm and builtin.zig_backend != .stage2_x86_64) {
22 // Tests that pass for stage1, llvm backend, C backend, wasm backend.22 // Tests that pass for stage1, llvm backend, C backend, wasm backend.
23 _ = @import("behavior/align.zig");
23 _ = @import("behavior/array.zig");24 _ = @import("behavior/array.zig");
24 _ = @import("behavior/bugs/3586.zig");
25 _ = @import("behavior/basic.zig");25 _ = @import("behavior/basic.zig");
26 _ = @import("behavior/bitcast.zig");26 _ = @import("behavior/bitcast.zig");
27 _ = @import("behavior/bugs/624.zig");27 _ = @import("behavior/bugs/624.zig");
...@@ -31,12 +31,14 @@ test {...@@ -31,12 +31,14 @@ test {
31 _ = @import("behavior/bugs/2692.zig");31 _ = @import("behavior/bugs/2692.zig");
32 _ = @import("behavior/bugs/2889.zig");32 _ = @import("behavior/bugs/2889.zig");
33 _ = @import("behavior/bugs/3046.zig");33 _ = @import("behavior/bugs/3046.zig");
34 _ = @import("behavior/bugs/3586.zig");
34 _ = @import("behavior/bugs/4560.zig");35 _ = @import("behavior/bugs/4560.zig");
35 _ = @import("behavior/bugs/4769_a.zig");36 _ = @import("behavior/bugs/4769_a.zig");
36 _ = @import("behavior/bugs/4769_b.zig");37 _ = @import("behavior/bugs/4769_b.zig");
37 _ = @import("behavior/bugs/4954.zig");38 _ = @import("behavior/bugs/4954.zig");
38 _ = @import("behavior/byval_arg_var.zig");39 _ = @import("behavior/byval_arg_var.zig");
39 _ = @import("behavior/call.zig");40 _ = @import("behavior/call.zig");
41 _ = @import("behavior/cast.zig");
40 _ = @import("behavior/defer.zig");42 _ = @import("behavior/defer.zig");
41 _ = @import("behavior/enum.zig");43 _ = @import("behavior/enum.zig");
42 _ = @import("behavior/error.zig");44 _ = @import("behavior/error.zig");
...@@ -48,12 +50,15 @@ test {...@@ -48,12 +50,15 @@ test {
48 _ = @import("behavior/inttoptr.zig");50 _ = @import("behavior/inttoptr.zig");
49 _ = @import("behavior/member_func.zig");51 _ = @import("behavior/member_func.zig");
50 _ = @import("behavior/null.zig");52 _ = @import("behavior/null.zig");
53 _ = @import("behavior/optional.zig");
51 _ = @import("behavior/pointers.zig");54 _ = @import("behavior/pointers.zig");
52 _ = @import("behavior/ptrcast.zig");55 _ = @import("behavior/ptrcast.zig");
53 _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig");56 _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig");
57 _ = @import("behavior/src.zig");
54 _ = @import("behavior/struct.zig");58 _ = @import("behavior/struct.zig");
55 _ = @import("behavior/this.zig");59 _ = @import("behavior/this.zig");
56 _ = @import("behavior/truncate.zig");60 _ = @import("behavior/truncate.zig");
61 _ = @import("behavior/try.zig");
57 _ = @import("behavior/undefined.zig");62 _ = @import("behavior/undefined.zig");
58 _ = @import("behavior/underscore.zig");63 _ = @import("behavior/underscore.zig");
59 _ = @import("behavior/usingnamespace.zig");64 _ = @import("behavior/usingnamespace.zig");
...@@ -62,13 +67,9 @@ test {...@@ -62,13 +67,9 @@ test {
6267
63 if (builtin.zig_backend != .stage2_wasm) {68 if (builtin.zig_backend != .stage2_wasm) {
64 // Tests that pass for stage1, llvm backend, C backend69 // Tests that pass for stage1, llvm backend, C backend
65 _ = @import("behavior/align.zig");70 _ = @import("behavior/cast_int.zig");
66 _ = @import("behavior/cast.zig");
67 _ = @import("behavior/int128.zig");71 _ = @import("behavior/int128.zig");
68 _ = @import("behavior/optional.zig");
69 _ = @import("behavior/translate_c_macros.zig");72 _ = @import("behavior/translate_c_macros.zig");
70 _ = @import("behavior/try.zig");
71 _ = @import("behavior/src.zig");
7273
73 if (builtin.zig_backend != .stage2_c) {74 if (builtin.zig_backend != .stage2_c) {
74 // Tests that pass for stage1 and the llvm backend.75 // Tests that pass for stage1 and the llvm backend.
test/behavior/cast.zig-7
...@@ -43,13 +43,6 @@ fn testResolveUndefWithInt(b: bool, x: i32) !void {...@@ -43,13 +43,6 @@ fn testResolveUndefWithInt(b: bool, x: i32) !void {
43 }43 }
44}44}
4545
46test "@intCast i32 to u7" {
47 var x: u128 = maxInt(u128);
48 var y: i32 = 120;
49 var z = x >> @intCast(u7, y);
50 try expect(z == 0xff);
51}
52
53test "@intCast to comptime_int" {46test "@intCast to comptime_int" {
54 try expect(@intCast(comptime_int, 0) == 0);47 try expect(@intCast(comptime_int, 0) == 0);
55}48}
test/behavior/cast_int.zig created+10
...@@ -0,0 +1,10 @@
1const std = @import("std");
2const expect = std.testing.expect;
3const maxInt = std.math.maxInt;
4
5test "@intCast i32 to u7" {
6 var x: u128 = maxInt(u128);
7 var y: i32 = 120;
8 var z = x >> @intCast(u7, y);
9 try expect(z == 0xff);
10}