| author | |
| committer | |
| log | 56d535dd24a16bcd827b54d151d6858a2c3ec3b5 |
| tree | 75e1206499fd0d8cc614b218ad8f3c1595c9a29e |
| parent | dc3176d6287955d2ecdaaa26f46f5577d5316d36 |
Additionally fixed a bug for shr on signed big ints2 files changed, 63 insertions(+), 67 deletions(-)
src/arch/wasm/CodeGen.zig+23-21| ... | ... | @@ -2669,8 +2669,14 @@ fn binOpBigInt(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) Inner |
| 2669 | 2669 | .signed => return func.callIntrinsic("__udivti3", &.{ ty.toIntern(), ty.toIntern() }, ty, &.{ lhs, rhs }), |
| 2670 | 2670 | .unsigned => return func.callIntrinsic("__divti3", &.{ ty.toIntern(), ty.toIntern() }, ty, &.{ lhs, rhs }), |
| 2671 | 2671 | }, |
| 2672 | .rem => return func.callIntrinsic("__umodti3", &.{ ty.toIntern(), ty.toIntern() }, ty, &.{ lhs, rhs }), | |
| 2673 | .shr => return func.callIntrinsic("__lshrti3", &.{ ty.toIntern(), .i32_type }, ty, &.{ lhs, rhs }), | |
| 2672 | .rem => switch (int_info.signedness) { | |
| 2673 | .signed => return func.callIntrinsic("__modti3", &.{ ty.toIntern(), ty.toIntern() }, ty, &.{ lhs, rhs }), | |
| 2674 | .unsigned => return func.callIntrinsic("__umodti3", &.{ ty.toIntern(), ty.toIntern() }, ty, &.{ lhs, rhs }), | |
| 2675 | }, | |
| 2676 | .shr => switch (int_info.signedness) { | |
| 2677 | .signed => return func.callIntrinsic("__ashrti3", &.{ ty.toIntern(), .i32_type }, ty, &.{ lhs, rhs }), | |
| 2678 | .unsigned => return func.callIntrinsic("__lshrti3", &.{ ty.toIntern(), .i32_type }, ty, &.{ lhs, rhs }), | |
| 2679 | }, | |
| 2674 | 2680 | .shl => return func.callIntrinsic("__ashlti3", &.{ ty.toIntern(), .i32_type }, ty, &.{ lhs, rhs }), |
| 2675 | 2681 | .@"and", .@"or", .xor => { |
| 2676 | 2682 | const result = try func.allocStack(ty); |
| ... | ... | @@ -6055,14 +6061,14 @@ fn airShlWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6055 | 6061 | |
| 6056 | 6062 | const lhs = try func.resolveInst(extra.lhs); |
| 6057 | 6063 | const rhs = try func.resolveInst(extra.rhs); |
| 6058 | const lhs_ty = func.typeOf(extra.lhs); | |
| 6064 | const ty = func.typeOf(extra.lhs); | |
| 6059 | 6065 | const rhs_ty = func.typeOf(extra.rhs); |
| 6060 | 6066 | |
| 6061 | if (lhs_ty.zigTypeTag(mod) == .Vector) { | |
| 6067 | if (ty.zigTypeTag(mod) == .Vector) { | |
| 6062 | 6068 | return func.fail("TODO: Implement overflow arithmetic for vectors", .{}); |
| 6063 | 6069 | } |
| 6064 | 6070 | |
| 6065 | const int_info = lhs_ty.intInfo(mod); | |
| 6071 | const int_info = ty.intInfo(mod); | |
| 6066 | 6072 | const wasm_bits = toWasmBits(int_info.bits) orelse { |
| 6067 | 6073 | return func.fail("TODO: Implement shl_with_overflow for integer bitsize: {d}", .{int_info.bits}); |
| 6068 | 6074 | }; |
| ... | ... | @@ -6070,32 +6076,28 @@ fn airShlWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6070 | 6076 | // Ensure rhs is coerced to lhs as they must have the same WebAssembly types |
| 6071 | 6077 | // before we can perform any binary operation. |
| 6072 | 6078 | const rhs_wasm_bits = toWasmBits(rhs_ty.intInfo(mod).bits).?; |
| 6073 | const rhs_final = if (wasm_bits != rhs_wasm_bits) blk: { | |
| 6074 | const rhs_casted = try func.intcast(rhs, rhs_ty, lhs_ty); | |
| 6075 | break :blk try rhs_casted.toLocal(func, lhs_ty); | |
| 6079 | // If wasm_bits == 128, compiler-rt expects i32 for shift | |
| 6080 | const rhs_final = if (wasm_bits != rhs_wasm_bits and wasm_bits == 64) blk: { | |
| 6081 | const rhs_casted = try func.intcast(rhs, rhs_ty, ty); | |
| 6082 | break :blk try rhs_casted.toLocal(func, ty); | |
| 6076 | 6083 | } else rhs; |
| 6077 | 6084 | |
| 6078 | var shl = try (try func.binOp(lhs, rhs_final, lhs_ty, .shl)).toLocal(func, lhs_ty); | |
| 6085 | var shl = try (try func.wrapBinOp(lhs, rhs_final, ty, .shl)).toLocal(func, ty); | |
| 6079 | 6086 | defer shl.free(func); |
| 6080 | var result = if (wasm_bits != int_info.bits) blk: { | |
| 6081 | break :blk try (try func.wrapOperand(shl, lhs_ty)).toLocal(func, lhs_ty); | |
| 6082 | } else shl; | |
| 6083 | defer result.free(func); // it's a no-op to free the same local twice (when wasm_bits == int_info.bits) | |
| 6084 | 6087 | |
| 6085 | 6088 | const overflow_bit = blk: { |
| 6086 | try func.emitWValue(lhs); | |
| 6087 | const shr = try func.binOp(result, rhs_final, lhs_ty, .shr); | |
| 6088 | break :blk try func.cmp(.stack, shr, lhs_ty, .neq); | |
| 6089 | const shr = try func.binOp(shl, rhs_final, ty, .shr); | |
| 6090 | break :blk try func.cmp(shr, lhs, ty, .neq); | |
| 6089 | 6091 | }; |
| 6090 | 6092 | var overflow_local = try overflow_bit.toLocal(func, Type.u1); |
| 6091 | 6093 | defer overflow_local.free(func); |
| 6092 | 6094 | |
| 6093 | const result_ptr = try func.allocStack(func.typeOfIndex(inst)); | |
| 6094 | try func.store(result_ptr, result, lhs_ty, 0); | |
| 6095 | const offset = @as(u32, @intCast(lhs_ty.abiSize(pt))); | |
| 6096 | try func.store(result_ptr, overflow_local, Type.u1, offset); | |
| 6095 | const result = try func.allocStack(func.typeOfIndex(inst)); | |
| 6096 | const offset: u32 = @intCast(ty.abiSize(pt)); | |
| 6097 | try func.store(result, shl, ty, 0); | |
| 6098 | try func.store(result, overflow_local, Type.u1, offset); | |
| 6097 | 6099 | |
| 6098 | return func.finishAir(inst, result_ptr, &.{ extra.lhs, extra.rhs }); | |
| 6100 | return func.finishAir(inst, result, &.{ extra.lhs, extra.rhs }); | |
| 6099 | 6101 | } |
| 6100 | 6102 | |
| 6101 | 6103 | fn airMulWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
test/behavior/math.zig+40-46| ... | ... | @@ -1345,62 +1345,56 @@ test "@subWithOverflow > 64 bits" { |
| 1345 | 1345 | try testSubWithOverflow(i128, maxInt(i128), -2, minInt(i128) + 1, 1); |
| 1346 | 1346 | } |
| 1347 | 1347 | |
| 1348 | fn testShlWithOverflow(comptime T: type, a: T, b: math.Log2Int(T), shl: T, bit: u1) !void { | |
| 1349 | const ov = @shlWithOverflow(a, b); | |
| 1350 | try expect(ov[0] == shl); | |
| 1351 | try expect(ov[1] == bit); | |
| 1352 | } | |
| 1353 | ||
| 1348 | 1354 | test "@shlWithOverflow" { |
| 1349 | 1355 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1350 | 1356 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1351 | 1357 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; |
| 1352 | 1358 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1353 | 1359 | |
| 1354 | { | |
| 1355 | var a: u4 = 2; | |
| 1356 | _ = &a; | |
| 1357 | var b: u2 = 1; | |
| 1358 | var ov = @shlWithOverflow(a, b); | |
| 1359 | try expect(ov[0] == 4); | |
| 1360 | try expect(ov[1] == 0); | |
| 1360 | try testShlWithOverflow(u4, 2, 1, 4, 0); | |
| 1361 | try testShlWithOverflow(u4, 2, 3, 0, 1); | |
| 1361 | 1362 | |
| 1362 | b = 3; | |
| 1363 | ov = @shlWithOverflow(a, b); | |
| 1364 | try expect(ov[0] == 0); | |
| 1365 | try expect(ov[1] == 1); | |
| 1366 | } | |
| 1363 | try testShlWithOverflow(i9, 127, 1, 254, 0); | |
| 1364 | try testShlWithOverflow(i9, 127, 2, -4, 1); | |
| 1367 | 1365 | |
| 1368 | { | |
| 1369 | var a: i9 = 127; | |
| 1370 | _ = &a; | |
| 1371 | var b: u4 = 1; | |
| 1372 | var ov = @shlWithOverflow(a, b); | |
| 1373 | try expect(ov[0] == 254); | |
| 1374 | try expect(ov[1] == 0); | |
| 1366 | try testShlWithOverflow(u16, 0b0010111111111111, 3, 0b0111111111111000, 1); | |
| 1367 | try testShlWithOverflow(u16, 0b0010111111111111, 2, 0b1011111111111100, 0); | |
| 1375 | 1368 | |
| 1376 | b = 2; | |
| 1377 | ov = @shlWithOverflow(a, b); | |
| 1378 | try expect(ov[0] == -4); | |
| 1379 | try expect(ov[1] == 1); | |
| 1380 | } | |
| 1369 | try testShlWithOverflow(u16, 0b0000_0000_0000_0011, 15, 0b1000_0000_0000_0000, 1); | |
| 1370 | try testShlWithOverflow(u16, 0b0000_0000_0000_0011, 14, 0b1100_0000_0000_0000, 0); | |
| 1371 | } | |
| 1381 | 1372 | |
| 1382 | { | |
| 1383 | const ov = @shlWithOverflow(@as(u16, 0b0010111111111111), 3); | |
| 1384 | try expect(ov[0] == 0b0111111111111000); | |
| 1385 | try expect(ov[1] == 1); | |
| 1386 | } | |
| 1387 | { | |
| 1388 | const ov = @shlWithOverflow(@as(u16, 0b0010111111111111), 2); | |
| 1389 | try expect(ov[0] == 0b1011111111111100); | |
| 1390 | try expect(ov[1] == 0); | |
| 1391 | } | |
| 1392 | { | |
| 1393 | var a: u16 = 0b0000_0000_0000_0011; | |
| 1394 | _ = &a; | |
| 1395 | var b: u4 = 15; | |
| 1396 | var ov = @shlWithOverflow(a, b); | |
| 1397 | try expect(ov[0] == 0b1000_0000_0000_0000); | |
| 1398 | try expect(ov[1] == 1); | |
| 1399 | b = 14; | |
| 1400 | ov = @shlWithOverflow(a, b); | |
| 1401 | try expect(ov[0] == 0b1100_0000_0000_0000); | |
| 1402 | try expect(ov[1] == 0); | |
| 1403 | } | |
| 1373 | test "@shlWithOverflow > 64 bits" { | |
| 1374 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1375 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | |
| 1376 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | |
| 1377 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | |
| 1378 | ||
| 1379 | try testShlWithOverflow(u65, 0x0_0100_0000_0000_0000, 7, 0x0_8000_0000_0000_0000, 0); | |
| 1380 | try testShlWithOverflow(u65, 0x0_0100_0000_0000_0000, 8, 0x1_0000_0000_0000_0000, 0); | |
| 1381 | try testShlWithOverflow(u65, 0x0_0100_0000_0000_0000, 9, 0, 1); | |
| 1382 | try testShlWithOverflow(u65, 0x0_0100_0000_0000_0000, 10, 0, 1); | |
| 1383 | ||
| 1384 | try testShlWithOverflow(u128, 0x0100_0000_0000_0000_0000000000000000, 6, 0x4000_0000_0000_0000_0000000000000000, 0); | |
| 1385 | try testShlWithOverflow(u128, 0x0100_0000_0000_0000_0000000000000000, 7, 0x8000_0000_0000_0000_0000000000000000, 0); | |
| 1386 | try testShlWithOverflow(u128, 0x0100_0000_0000_0000_0000000000000000, 8, 0, 1); | |
| 1387 | try testShlWithOverflow(u128, 0x0100_0000_0000_0000_0000000000000000, 9, 0, 1); | |
| 1388 | ||
| 1389 | try testShlWithOverflow(i65, 0x0_0100_0000_0000_0000, 7, 0x0_8000_0000_0000_0000, 0); | |
| 1390 | try testShlWithOverflow(i65, 0x0_0100_0000_0000_0000, 8, minInt(i65), 1); | |
| 1391 | try testShlWithOverflow(i65, 0x0_0100_0000_0000_0000, 9, 0, 1); | |
| 1392 | try testShlWithOverflow(i65, 0x0_0100_0000_0000_0000, 10, 0, 1); | |
| 1393 | ||
| 1394 | try testShlWithOverflow(i128, 0x0100_0000_0000_0000_0000000000000000, 6, 0x4000_0000_0000_0000_0000000000000000, 0); | |
| 1395 | try testShlWithOverflow(i128, 0x0100_0000_0000_0000_0000000000000000, 7, minInt(i128), 1); | |
| 1396 | try testShlWithOverflow(i128, 0x0100_0000_0000_0000_0000000000000000, 8, 0, 1); | |
| 1397 | try testShlWithOverflow(i128, 0x0100_0000_0000_0000_0000000000000000, 9, 0, 1); | |
| 1404 | 1398 | } |
| 1405 | 1399 | |
| 1406 | 1400 | test "overflow arithmetic with u0 values" { |