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