shift.zig (4845B) - Raw
1 const std = @import("std"); 2 const builtin = @import("builtin"); 3 const Log2Int = std.math.Log2Int; 4 const common = @import("common.zig"); 5 6 pub const panic = common.panic; 7 8 comptime { 9 // symbol compatibility with libgcc 10 @export(&__ashlsi3, .{ .name = "__ashlsi3", .linkage = common.linkage, .visibility = common.visibility }); 11 @export(&__ashrsi3, .{ .name = "__ashrsi3", .linkage = common.linkage, .visibility = common.visibility }); 12 @export(&__lshrsi3, .{ .name = "__lshrsi3", .linkage = common.linkage, .visibility = common.visibility }); 13 14 @export(&__ashlti3, .{ .name = "__ashlti3", .linkage = common.linkage, .visibility = common.visibility }); 15 @export(&__ashrti3, .{ .name = "__ashrti3", .linkage = common.linkage, .visibility = common.visibility }); 16 @export(&__lshrti3, .{ .name = "__lshrti3", .linkage = common.linkage, .visibility = common.visibility }); 17 18 if (common.want_aeabi) { 19 @export(&__aeabi_llsl, .{ .name = "__aeabi_llsl", .linkage = common.linkage, .visibility = common.visibility }); 20 @export(&__aeabi_lasr, .{ .name = "__aeabi_lasr", .linkage = common.linkage, .visibility = common.visibility }); 21 @export(&__aeabi_llsr, .{ .name = "__aeabi_llsr", .linkage = common.linkage, .visibility = common.visibility }); 22 } else { 23 @export(&__ashldi3, .{ .name = "__ashldi3", .linkage = common.linkage, .visibility = common.visibility }); 24 @export(&__ashrdi3, .{ .name = "__ashrdi3", .linkage = common.linkage, .visibility = common.visibility }); 25 @export(&__lshrdi3, .{ .name = "__lshrdi3", .linkage = common.linkage, .visibility = common.visibility }); 26 } 27 } 28 29 // Arithmetic shift left: shift in 0 from right to left 30 // Precondition: 0 <= b < bits_in_dword 31 inline fn ashlXi3(comptime T: type, a: T, b: i32) T { 32 const word_t = common.HalveInt(T, false); 33 34 const input = word_t{ .all = a }; 35 var output: word_t = undefined; 36 37 if (b >= word_t.bits) { 38 output.s.low = 0; 39 output.s.high = input.s.low << @intCast(b - word_t.bits); 40 } else if (b == 0) { 41 return a; 42 } else { 43 output.s.low = input.s.low << @intCast(b); 44 output.s.high = input.s.high << @intCast(b); 45 output.s.high |= input.s.low >> @intCast(word_t.bits - b); 46 } 47 48 return output.all; 49 } 50 51 // Arithmetic shift right: shift in 1 from left to right 52 // Precondition: 0 <= b < T.bit_count 53 inline fn ashrXi3(comptime T: type, a: T, b: i32) T { 54 const word_t = common.HalveInt(T, true); 55 56 const input = word_t{ .all = a }; 57 var output: word_t = undefined; 58 59 if (b >= word_t.bits) { 60 output.s.high = input.s.high >> (word_t.bits - 1); 61 output.s.low = input.s.high >> @intCast(b - word_t.bits); 62 } else if (b == 0) { 63 return a; 64 } else { 65 output.s.high = input.s.high >> @intCast(b); 66 output.s.low = input.s.high << @intCast(word_t.bits - b); 67 // Avoid sign-extension here 68 output.s.low |= @bitCast(@as(word_t.HalfTU, @bitCast(input.s.low)) >> @intCast(b)); 69 } 70 71 return output.all; 72 } 73 74 // Logical shift right: shift in 0 from left to right 75 // Precondition: 0 <= b < T.bit_count 76 inline fn lshrXi3(comptime T: type, a: T, b: i32) T { 77 const word_t = common.HalveInt(T, false); 78 79 const input = word_t{ .all = a }; 80 var output: word_t = undefined; 81 82 if (b >= word_t.bits) { 83 output.s.high = 0; 84 output.s.low = input.s.high >> @intCast(b - word_t.bits); 85 } else if (b == 0) { 86 return a; 87 } else { 88 output.s.high = input.s.high >> @intCast(b); 89 output.s.low = input.s.high << @intCast(word_t.bits - b); 90 output.s.low |= input.s.low >> @intCast(b); 91 } 92 93 return output.all; 94 } 95 96 pub fn __ashlsi3(a: i32, b: i32) callconv(.c) i32 { 97 return ashlXi3(i32, a, b); 98 } 99 100 pub fn __ashrsi3(a: i32, b: i32) callconv(.c) i32 { 101 return ashrXi3(i32, a, b); 102 } 103 104 pub fn __lshrsi3(a: i32, b: i32) callconv(.c) i32 { 105 return lshrXi3(i32, a, b); 106 } 107 108 pub fn __ashldi3(a: i64, b: i32) callconv(.c) i64 { 109 return ashlXi3(i64, a, b); 110 } 111 fn __aeabi_llsl(a: i64, b: i32) callconv(.{ .arm_aapcs = .{} }) i64 { 112 return ashlXi3(i64, a, b); 113 } 114 115 pub fn __ashlti3(a: i128, b: i32) callconv(.c) i128 { 116 return ashlXi3(i128, a, b); 117 } 118 119 pub fn __ashrdi3(a: i64, b: i32) callconv(.c) i64 { 120 return ashrXi3(i64, a, b); 121 } 122 fn __aeabi_lasr(a: i64, b: i32) callconv(.{ .arm_aapcs = .{} }) i64 { 123 return ashrXi3(i64, a, b); 124 } 125 126 pub fn __ashrti3(a: i128, b: i32) callconv(.c) i128 { 127 return ashrXi3(i128, a, b); 128 } 129 130 pub fn __lshrdi3(a: i64, b: i32) callconv(.c) i64 { 131 return lshrXi3(i64, a, b); 132 } 133 fn __aeabi_llsr(a: i64, b: i32) callconv(.{ .arm_aapcs = .{} }) i64 { 134 return lshrXi3(i64, a, b); 135 } 136 137 pub fn __lshrti3(a: i128, b: i32) callconv(.c) i128 { 138 return lshrXi3(i128, a, b); 139 } 140 141 test { 142 _ = @import("shift_test.zig"); 143 }