2020-03-30 10:55:21 +01:00
|
|
|
const std = @import("std");
|
|
|
|
const Log2Int = std.math.Log2Int;
|
2021-10-05 07:47:27 +01:00
|
|
|
const native_endian = @import("builtin").cpu.arch.endian();
|
2020-03-30 10:55:21 +01:00
|
|
|
|
|
|
|
fn Dwords(comptime T: type, comptime signed_half: bool) type {
|
|
|
|
return extern union {
|
2020-09-03 16:09:55 +01:00
|
|
|
pub const bits = @divExact(@typeInfo(T).Int.bits, 2);
|
2020-10-17 13:09:59 +01:00
|
|
|
pub const HalfTU = std.meta.Int(.unsigned, bits);
|
|
|
|
pub const HalfTS = std.meta.Int(.signed, bits);
|
2020-03-30 10:55:21 +01:00
|
|
|
pub const HalfT = if (signed_half) HalfTS else HalfTU;
|
|
|
|
|
|
|
|
all: T,
|
2021-04-13 00:43:50 +01:00
|
|
|
s: if (native_endian == .Little)
|
2020-03-30 10:55:21 +01:00
|
|
|
struct { low: HalfT, high: HalfT }
|
|
|
|
else
|
|
|
|
struct { high: HalfT, low: HalfT },
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
// Arithmetic shift left
|
|
|
|
// Precondition: 0 <= b < bits_in_dword
|
2022-01-02 02:49:34 +00:00
|
|
|
pub inline fn ashlXi3(comptime T: type, a: T, b: i32) T {
|
2020-03-30 10:55:21 +01:00
|
|
|
const dwords = Dwords(T, false);
|
|
|
|
const S = Log2Int(dwords.HalfT);
|
|
|
|
|
|
|
|
const input = dwords{ .all = a };
|
|
|
|
var output: dwords = undefined;
|
|
|
|
|
2020-09-03 16:09:55 +01:00
|
|
|
if (b >= dwords.bits) {
|
2020-03-30 10:55:21 +01:00
|
|
|
output.s.low = 0;
|
2020-09-03 16:09:55 +01:00
|
|
|
output.s.high = input.s.low << @intCast(S, b - dwords.bits);
|
2020-03-30 10:55:21 +01:00
|
|
|
} else if (b == 0) {
|
|
|
|
return a;
|
|
|
|
} else {
|
|
|
|
output.s.low = input.s.low << @intCast(S, b);
|
|
|
|
output.s.high = input.s.high << @intCast(S, b);
|
2020-09-03 16:09:55 +01:00
|
|
|
output.s.high |= input.s.low >> @intCast(S, dwords.bits - b);
|
2020-03-30 10:55:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return output.all;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Arithmetic shift right
|
|
|
|
// Precondition: 0 <= b < T.bit_count
|
2022-01-02 02:49:34 +00:00
|
|
|
pub inline fn ashrXi3(comptime T: type, a: T, b: i32) T {
|
2020-03-30 10:55:21 +01:00
|
|
|
const dwords = Dwords(T, true);
|
|
|
|
const S = Log2Int(dwords.HalfT);
|
|
|
|
|
|
|
|
const input = dwords{ .all = a };
|
|
|
|
var output: dwords = undefined;
|
|
|
|
|
2020-09-03 16:09:55 +01:00
|
|
|
if (b >= dwords.bits) {
|
|
|
|
output.s.high = input.s.high >> (dwords.bits - 1);
|
|
|
|
output.s.low = input.s.high >> @intCast(S, b - dwords.bits);
|
2020-03-30 10:55:21 +01:00
|
|
|
} else if (b == 0) {
|
|
|
|
return a;
|
|
|
|
} else {
|
|
|
|
output.s.high = input.s.high >> @intCast(S, b);
|
2020-09-03 16:09:55 +01:00
|
|
|
output.s.low = input.s.high << @intCast(S, dwords.bits - b);
|
2020-03-30 10:55:21 +01:00
|
|
|
// Avoid sign-extension here
|
|
|
|
output.s.low |= @bitCast(
|
|
|
|
dwords.HalfT,
|
|
|
|
@bitCast(dwords.HalfTU, input.s.low) >> @intCast(S, b),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return output.all;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Logical shift right
|
|
|
|
// Precondition: 0 <= b < T.bit_count
|
2022-01-02 02:49:34 +00:00
|
|
|
pub inline fn lshrXi3(comptime T: type, a: T, b: i32) T {
|
2020-03-30 10:55:21 +01:00
|
|
|
const dwords = Dwords(T, false);
|
|
|
|
const S = Log2Int(dwords.HalfT);
|
|
|
|
|
|
|
|
const input = dwords{ .all = a };
|
|
|
|
var output: dwords = undefined;
|
|
|
|
|
2020-09-03 16:09:55 +01:00
|
|
|
if (b >= dwords.bits) {
|
2020-03-30 10:55:21 +01:00
|
|
|
output.s.high = 0;
|
2020-09-03 16:09:55 +01:00
|
|
|
output.s.low = input.s.high >> @intCast(S, b - dwords.bits);
|
2020-03-30 10:55:21 +01:00
|
|
|
} else if (b == 0) {
|
|
|
|
return a;
|
|
|
|
} else {
|
|
|
|
output.s.high = input.s.high >> @intCast(S, b);
|
2020-09-03 16:09:55 +01:00
|
|
|
output.s.low = input.s.high << @intCast(S, dwords.bits - b);
|
2020-03-30 10:55:21 +01:00
|
|
|
output.s.low |= input.s.low >> @intCast(S, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
return output.all;
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn __ashldi3(a: i64, b: i32) callconv(.C) i64 {
|
2022-01-02 02:49:34 +00:00
|
|
|
return ashlXi3(i64, a, b);
|
2020-03-30 10:55:21 +01:00
|
|
|
}
|
|
|
|
pub fn __ashlti3(a: i128, b: i32) callconv(.C) i128 {
|
2022-01-02 02:49:34 +00:00
|
|
|
return ashlXi3(i128, a, b);
|
2020-03-30 10:55:21 +01:00
|
|
|
}
|
|
|
|
pub fn __ashrdi3(a: i64, b: i32) callconv(.C) i64 {
|
2022-01-02 02:49:34 +00:00
|
|
|
return ashrXi3(i64, a, b);
|
2020-03-30 10:55:21 +01:00
|
|
|
}
|
|
|
|
pub fn __ashrti3(a: i128, b: i32) callconv(.C) i128 {
|
2022-01-02 02:49:34 +00:00
|
|
|
return ashrXi3(i128, a, b);
|
2020-03-30 10:55:21 +01:00
|
|
|
}
|
|
|
|
pub fn __lshrdi3(a: i64, b: i32) callconv(.C) i64 {
|
2022-01-02 02:49:34 +00:00
|
|
|
return lshrXi3(i64, a, b);
|
2020-03-30 10:55:21 +01:00
|
|
|
}
|
|
|
|
pub fn __lshrti3(a: i128, b: i32) callconv(.C) i128 {
|
2022-01-02 02:49:34 +00:00
|
|
|
return lshrXi3(i128, a, b);
|
2020-03-30 10:55:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn __aeabi_llsl(a: i64, b: i32) callconv(.AAPCS) i64 {
|
2022-01-02 02:49:34 +00:00
|
|
|
return ashlXi3(i64, a, b);
|
2020-03-30 10:55:21 +01:00
|
|
|
}
|
|
|
|
pub fn __aeabi_lasr(a: i64, b: i32) callconv(.AAPCS) i64 {
|
2022-01-02 02:49:34 +00:00
|
|
|
return ashrXi3(i64, a, b);
|
2020-03-30 10:55:21 +01:00
|
|
|
}
|
|
|
|
pub fn __aeabi_llsr(a: i64, b: i32) callconv(.AAPCS) i64 {
|
2022-01-02 02:49:34 +00:00
|
|
|
return lshrXi3(i64, a, b);
|
2020-03-30 10:55:21 +01:00
|
|
|
}
|
|
|
|
|
2021-01-22 14:45:28 +00:00
|
|
|
test {
|
2020-03-30 10:55:21 +01:00
|
|
|
_ = @import("ashrdi3_test.zig");
|
|
|
|
_ = @import("ashrti3_test.zig");
|
|
|
|
|
|
|
|
_ = @import("ashldi3_test.zig");
|
|
|
|
_ = @import("ashlti3_test.zig");
|
|
|
|
|
|
|
|
_ = @import("lshrdi3_test.zig");
|
|
|
|
_ = @import("lshrti3_test.zig");
|
|
|
|
}
|