| ... | @@ -598,6 +598,8 @@ test "shr" { | ... | @@ -598,6 +598,8 @@ test "shr" { |
| 598 | pub fn rotr(comptime T: type, x: T, r: anytype) T { | 598 | pub fn rotr(comptime T: type, x: T, r: anytype) T { |
| 599 | if (@typeInfo(T) == .Vector) { | 599 | if (@typeInfo(T) == .Vector) { |
| 600 | const C = @typeInfo(T).Vector.child; | 600 | const C = @typeInfo(T).Vector.child; |
| | 601 | if (C == u0) return 0; |
| | 602 | |
| 601 | if (@typeInfo(C).Int.signedness == .signed) { | 603 | if (@typeInfo(C).Int.signedness == .signed) { |
| 602 | @compileError("cannot rotate signed integers"); | 604 | @compileError("cannot rotate signed integers"); |
| 603 | } | 605 | } |
| ... | @@ -606,8 +608,15 @@ pub fn rotr(comptime T: type, x: T, r: anytype) T { | ... | @@ -606,8 +608,15 @@ pub fn rotr(comptime T: type, x: T, r: anytype) T { |
| 606 | } else if (@typeInfo(T).Int.signedness == .signed) { | 608 | } else if (@typeInfo(T).Int.signedness == .signed) { |
| 607 | @compileError("cannot rotate signed integer"); | 609 | @compileError("cannot rotate signed integer"); |
| 608 | } else { | 610 | } else { |
| 609 | const ar = @intCast(Log2Int(T), @mod(r, @typeInfo(T).Int.bits)); | 611 | if (T == u0) return 0; |
| 610 | return x >> ar | x << (1 +% ~ar); | 612 | |
| | 613 | if (isPowerOfTwo(@typeInfo(T).Int.bits)) { |
| | 614 | const ar = @intCast(Log2Int(T), @mod(r, @typeInfo(T).Int.bits)); |
| | 615 | return x >> ar | x << (1 +% ~ar); |
| | 616 | } else { |
| | 617 | const ar = @mod(r, @typeInfo(T).Int.bits); |
| | 618 | return shr(T, x, ar) | shl(T, x, @typeInfo(T).Int.bits - ar); |
| | 619 | } |
| 611 | } | 620 | } |
| 612 | } | 621 | } |
| 613 | | 622 | |
| ... | @@ -618,6 +627,9 @@ test "rotr" { | ... | @@ -618,6 +627,9 @@ test "rotr" { |
| 618 | // https://github.com/ziglang/zig/issues/12012 | 627 | // https://github.com/ziglang/zig/issues/12012 |
| 619 | return error.SkipZigTest; | 628 | return error.SkipZigTest; |
| 620 | } | 629 | } |
| | 630 | try testing.expect(rotr(u0, 0b0, @as(usize, 3)) == 0b0); |
| | 631 | try testing.expect(rotr(u5, 0b00001, @as(usize, 0)) == 0b00001); |
| | 632 | try testing.expect(rotr(u6, 0b000001, @as(usize, 7)) == 0b100000); |
| 621 | try testing.expect(rotr(u8, 0b00000001, @as(usize, 0)) == 0b00000001); | 633 | try testing.expect(rotr(u8, 0b00000001, @as(usize, 0)) == 0b00000001); |
| 622 | try testing.expect(rotr(u8, 0b00000001, @as(usize, 9)) == 0b10000000); | 634 | try testing.expect(rotr(u8, 0b00000001, @as(usize, 9)) == 0b10000000); |
| 623 | try testing.expect(rotr(u8, 0b00000001, @as(usize, 8)) == 0b00000001); | 635 | try testing.expect(rotr(u8, 0b00000001, @as(usize, 8)) == 0b00000001); |
| ... | @@ -632,6 +644,8 @@ test "rotr" { | ... | @@ -632,6 +644,8 @@ test "rotr" { |
| 632 | pub fn rotl(comptime T: type, x: T, r: anytype) T { | 644 | pub fn rotl(comptime T: type, x: T, r: anytype) T { |
| 633 | if (@typeInfo(T) == .Vector) { | 645 | if (@typeInfo(T) == .Vector) { |
| 634 | const C = @typeInfo(T).Vector.child; | 646 | const C = @typeInfo(T).Vector.child; |
| | 647 | if (C == u0) return 0; |
| | 648 | |
| 635 | if (@typeInfo(C).Int.signedness == .signed) { | 649 | if (@typeInfo(C).Int.signedness == .signed) { |
| 636 | @compileError("cannot rotate signed integers"); | 650 | @compileError("cannot rotate signed integers"); |
| 637 | } | 651 | } |
| ... | @@ -640,8 +654,15 @@ pub fn rotl(comptime T: type, x: T, r: anytype) T { | ... | @@ -640,8 +654,15 @@ pub fn rotl(comptime T: type, x: T, r: anytype) T { |
| 640 | } else if (@typeInfo(T).Int.signedness == .signed) { | 654 | } else if (@typeInfo(T).Int.signedness == .signed) { |
| 641 | @compileError("cannot rotate signed integer"); | 655 | @compileError("cannot rotate signed integer"); |
| 642 | } else { | 656 | } else { |
| 643 | const ar = @intCast(Log2Int(T), @mod(r, @typeInfo(T).Int.bits)); | 657 | if (T == u0) return 0; |
| 644 | return x << ar | x >> 1 +% ~ar; | 658 | |
| | 659 | if (isPowerOfTwo(@typeInfo(T).Int.bits)) { |
| | 660 | const ar = @intCast(Log2Int(T), @mod(r, @typeInfo(T).Int.bits)); |
| | 661 | return x << ar | x >> 1 +% ~ar; |
| | 662 | } else { |
| | 663 | const ar = @mod(r, @typeInfo(T).Int.bits); |
| | 664 | return shl(T, x, ar) | shr(T, x, @typeInfo(T).Int.bits - ar); |
| | 665 | } |
| 645 | } | 666 | } |
| 646 | } | 667 | } |
| 647 | | 668 | |
| ... | @@ -652,6 +673,9 @@ test "rotl" { | ... | @@ -652,6 +673,9 @@ test "rotl" { |
| 652 | // https://github.com/ziglang/zig/issues/12012 | 673 | // https://github.com/ziglang/zig/issues/12012 |
| 653 | return error.SkipZigTest; | 674 | return error.SkipZigTest; |
| 654 | } | 675 | } |
| | 676 | try testing.expect(rotl(u0, 0b0, @as(usize, 3)) == 0b0); |
| | 677 | try testing.expect(rotl(u5, 0b00001, @as(usize, 0)) == 0b00001); |
| | 678 | try testing.expect(rotl(u6, 0b000001, @as(usize, 7)) == 0b000010); |
| 655 | try testing.expect(rotl(u8, 0b00000001, @as(usize, 0)) == 0b00000001); | 679 | try testing.expect(rotl(u8, 0b00000001, @as(usize, 0)) == 0b00000001); |
| 656 | try testing.expect(rotl(u8, 0b00000001, @as(usize, 9)) == 0b00000010); | 680 | try testing.expect(rotl(u8, 0b00000001, @as(usize, 9)) == 0b00000010); |
| 657 | try testing.expect(rotl(u8, 0b00000001, @as(usize, 8)) == 0b00000001); | 681 | try testing.expect(rotl(u8, 0b00000001, @as(usize, 8)) == 0b00000001); |