authorgravatar for paul.verigo@gmail.comPavel Verigo <paul.verigo@gmail.com> 2024-06-28 00:39:49+02:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2024-07-02 15:02:59+02:00
log1a951b49af90d04832ec7e928eb2f87630499d59
tree2516baefd77288eaf580522cc5a52425d188c078
parent5a9495002fb8de2b70462c40dd27938c2fef6271

stage2-wasm: not op for <= 128 bits ints


2 files changed, 85 insertions(+), 32 deletions(-)

src/arch/wasm/CodeGen.zig+35-18
...@@ -3729,32 +3729,49 @@ fn airNot(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -3729,32 +3729,49 @@ fn airNot(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3729 try func.addLabel(.local_set, not_tmp.local.value);3729 try func.addLabel(.local_set, not_tmp.local.value);
3730 break :result not_tmp;3730 break :result not_tmp;
3731 } else {3731 } else {
3732 const operand_bits = operand_ty.intInfo(mod).bits;3732 const int_info = operand_ty.intInfo(mod);
3733 const wasm_bits = toWasmBits(operand_bits) orelse {3733 const wasm_bits = toWasmBits(int_info.bits) orelse {
3734 return func.fail("TODO: Implement binary NOT for integer with bitsize '{d}'", .{operand_bits});3734 return func.fail("TODO: Implement binary NOT for {}", .{operand_ty.fmt(mod)});
3735 };3735 };
37363736
3737 switch (wasm_bits) {3737 switch (wasm_bits) {
3738 32 => {3738 32 => {
3739 const bin_op = try func.binOp(operand, .{ .imm32 = ~@as(u32, 0) }, operand_ty, .xor);3739 try func.emitWValue(operand);
3740 break :result try (try func.wrapOperand(bin_op, operand_ty)).toLocal(func, operand_ty);3740 try func.addImm32(switch (int_info.signedness) {
3741 .unsigned => ~@as(u32, 0) >> @intCast(32 - int_info.bits),
3742 .signed => ~@as(u32, 0),
3743 });
3744 try func.addTag(.i32_xor);
3745 break :result try @as(WValue, .stack).toLocal(func, operand_ty);
3741 },3746 },
3742 64 => {3747 64 => {
3743 const bin_op = try func.binOp(operand, .{ .imm64 = ~@as(u64, 0) }, operand_ty, .xor);3748 try func.emitWValue(operand);
3744 break :result try (try func.wrapOperand(bin_op, operand_ty)).toLocal(func, operand_ty);3749 try func.addImm64(switch (int_info.signedness) {
3750 .unsigned => ~@as(u64, 0) >> @intCast(64 - int_info.bits),
3751 .signed => ~@as(u64, 0),
3752 });
3753 try func.addTag(.i64_xor);
3754 break :result try @as(WValue, .stack).toLocal(func, operand_ty);
3745 },3755 },
3746 128 => {3756 128 => {
3747 const result_ptr = try func.allocStack(operand_ty);3757 const ptr = try func.allocStack(operand_ty);
3748 try func.emitWValue(result_ptr);3758
3749 const msb = try func.load(operand, Type.u64, 0);3759 try func.emitWValue(ptr);
3750 const msb_xor = try func.binOp(msb, .{ .imm64 = ~@as(u64, 0) }, Type.u64, .xor);3760 _ = try func.load(operand, Type.u64, 0);
3751 try func.store(.{ .stack = {} }, msb_xor, Type.u64, 0 + result_ptr.offset());3761 try func.addImm64(~@as(u64, 0));
37523762 try func.addTag(.i64_xor);
3753 try func.emitWValue(result_ptr);3763 try func.store(.stack, .stack, Type.u64, ptr.offset());
3754 const lsb = try func.load(operand, Type.u64, 8);3764
3755 const lsb_xor = try func.binOp(lsb, .{ .imm64 = ~@as(u64, 0) }, Type.u64, .xor);3765 try func.emitWValue(ptr);
3756 try func.store(result_ptr, lsb_xor, Type.u64, 8 + result_ptr.offset());3766 _ = try func.load(operand, Type.u64, 8);
3757 break :result result_ptr;3767 try func.addImm64(switch (int_info.signedness) {
3768 .unsigned => ~@as(u64, 0) >> @intCast(128 - int_info.bits),
3769 .signed => ~@as(u64, 0),
3770 });
3771 try func.addTag(.i64_xor);
3772 try func.store(.stack, .stack, Type.u64, ptr.offset() + 8);
3773
3774 break :result ptr;
3758 },3775 },
3759 else => unreachable,3776 else => unreachable,
3760 }3777 }
test/behavior/math.zig+50-14
...@@ -393,9 +393,39 @@ fn comptimeAdd(comptime a: comptime_int, comptime b: comptime_int) comptime_int...@@ -393,9 +393,39 @@ fn comptimeAdd(comptime a: comptime_int, comptime b: comptime_int) comptime_int
393 return a + b;393 return a + b;
394}394}
395395
396fn not(comptime T: type, a: T) T {
397 return ~a;
398}
399
396test "binary not" {400test "binary not" {
397 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;401 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
398402
403 try expect(not(u0, 0) == 0);
404 try expect(not(u1, 0) == 1);
405 try expect(not(u1, 1) == 0);
406 try expect(not(u5, 0b01001) == 0b10110);
407 try expect(not(u5, 0b10110) == 0b01001);
408 try expect(not(u16, 0b10101010_10101010) == 0b01010101_01010101);
409 try expect(not(u16, 0b01010101_01010101) == 0b10101010_10101010);
410 try expect(not(u32, 0xAAAA_3333) == 0x5555_CCCC);
411 try expect(not(u32, 0x5555_CCCC) == 0xAAAA_3333);
412 try expect(not(u35, 0x4_1111_FFFF) == 0x3_EEEE_0000);
413 try expect(not(u35, 0x3_EEEE_0000) == 0x4_1111_FFFF);
414 try expect(not(u48, 0x4567_89AB_CDEF) == 0xBA98_7654_3210);
415 try expect(not(u48, 0xBA98_7654_3210) == 0x4567_89AB_CDEF);
416 try expect(not(u64, 0x0123_4567_89AB_CDEF) == 0xFEDC_BA98_7654_3210);
417 try expect(not(u64, 0xFEDC_BA98_7654_3210) == 0x0123_4567_89AB_CDEF);
418
419 try expect(not(i0, 0) == 0);
420 try expect(not(i1, 0) == -1);
421 try expect(not(i1, -1) == 0);
422 try expect(not(i5, -2) == 1);
423 try expect(not(i5, 3) == -4);
424 try expect(not(i32, 0) == -1);
425 try expect(not(i32, -2147483648) == 2147483647);
426 try expect(not(i64, -1) == 0);
427 try expect(not(i64, 0) == -1);
428
399 try expect(comptime x: {429 try expect(comptime x: {
400 break :x ~@as(u16, 0b1010101010101010) == 0b0101010101010101;430 break :x ~@as(u16, 0b1010101010101010) == 0b0101010101010101;
401 });431 });
...@@ -405,34 +435,40 @@ test "binary not" {...@@ -405,34 +435,40 @@ test "binary not" {
405 try expect(comptime x: {435 try expect(comptime x: {
406 break :x ~@as(u0, 0) == 0;436 break :x ~@as(u0, 0) == 0;
407 });437 });
408 try testBinaryNot(0b1010101010101010);
409}438}
410439
411fn testBinaryNot(x: u16) !void {440test "binary not big int <= 128 bits" {
412 try expect(~x == 0b0101010101010101);
413}
414
415test "binary not 128-bit" {
416 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
417 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO441 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
418 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO442 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
419 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO443 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
420 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;444 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
421 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;445 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
422446
447 try expect(not(u65, 1) == 0x1_FFFFFFFF_FFFFFFFE);
448 try expect(not(u65, 0x1_FFFFFFFF_FFFFFFFE) == 1);
449
450 try expect(not(u96, 0x01234567_89ABCDEF_00000001) == 0xFEDCBA98_76543210_FFFFFFFE);
451 try expect(not(u96, 0xFEDCBA98_76543210_FFFFFFFE) == 0x01234567_89ABCDEF_00000001);
452
453 try expect(not(u128, 0xAAAAAAAA_AAAAAAAA_AAAAAAAA_AAAAAAAA) == 0x55555555_55555555_55555555_55555555);
454 try expect(not(u128, 0x55555555_55555555_55555555_55555555) == 0xAAAAAAAA_AAAAAAAA_AAAAAAAA_AAAAAAAA);
455
456 try expect(not(i65, -1) == 0);
457 try expect(not(i65, 0) == -1);
458 try expect(not(i65, -18446744073709551616) == 18446744073709551615);
459 try expect(not(i65, 18446744073709551615) == -18446744073709551616);
460
461 try expect(not(i128, -1) == 0);
462 try expect(not(i128, 0) == -1);
463 try expect(not(i128, -200) == 199);
464 try expect(not(i128, 199) == -200);
465
423 try expect(comptime x: {466 try expect(comptime x: {
424 break :x ~@as(u128, 0x55555555_55555555_55555555_55555555) == 0xaaaaaaaa_aaaaaaaa_aaaaaaaa_aaaaaaaa;467 break :x ~@as(u128, 0x55555555_55555555_55555555_55555555) == 0xaaaaaaaa_aaaaaaaa_aaaaaaaa_aaaaaaaa;
425 });468 });
426 try expect(comptime x: {469 try expect(comptime x: {
427 break :x ~@as(i128, 0x55555555_55555555_55555555_55555555) == @as(i128, @bitCast(@as(u128, 0xaaaaaaaa_aaaaaaaa_aaaaaaaa_aaaaaaaa)));470 break :x ~@as(i128, 0x55555555_55555555_55555555_55555555) == @as(i128, @bitCast(@as(u128, 0xaaaaaaaa_aaaaaaaa_aaaaaaaa_aaaaaaaa)));
428 });471 });
429
430 try testBinaryNot128(u128, 0xaaaaaaaa_aaaaaaaa_aaaaaaaa_aaaaaaaa);
431 try testBinaryNot128(i128, @as(i128, @bitCast(@as(u128, 0xaaaaaaaa_aaaaaaaa_aaaaaaaa_aaaaaaaa))));
432}
433
434fn testBinaryNot128(comptime Type: type, x: Type) !void {
435 try expect(~x == @as(Type, 0x55555555_55555555_55555555_55555555));
436}472}
437473
438test "division" {474test "division" {