authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-05-28 15:42:05+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-10-15 07:02:38-07:00
logf5edaa96dd7c820ffb7c5b8fc8da849a620d69b1
tree92f3bbfab91e1f1d288bc66fc6b5af6d83a16a6b
parent8bb2e96ac3b61a8aa393f250144fb9e1195ca60a

compiler_rt: Move mem implementations from c.zig

This moves functions that LLVM generates calls to, to the compiler_rt implementation itself, rather than c.zig. This is a prerequisite for native backends to link with compiler-rt. This also allows native backends to generate calls to `memcpy` and the like.

7 files changed, 147 insertions(+), 119 deletions(-)

lib/c.zig-119
...@@ -1,8 +1,6 @@...@@ -1,8 +1,6 @@
1//! This is Zig's multi-target implementation of libc.1//! This is Zig's multi-target implementation of libc.
2//! When builtin.link_libc is true, we need to export all the functions and2//! When builtin.link_libc is true, we need to export all the functions and
3//! provide an entire C API.3//! provide an entire C API.
4//! Otherwise, only the functions which LLVM generates calls to need to be generated,
5//! such as memcpy, memset, and some math functions.
64
7const std = @import("std");5const std = @import("std");
8const builtin = @import("builtin");6const builtin = @import("builtin");
...@@ -35,13 +33,6 @@ comptime {...@@ -35,13 +33,6 @@ comptime {
35 @export(clone, .{ .name = "clone" });33 @export(clone, .{ .name = "clone" });
36 }34 }
3735
38 @export(memset, .{ .name = "memset", .linkage = .Strong });
39 @export(__memset, .{ .name = "__memset", .linkage = .Strong });
40 @export(memcpy, .{ .name = "memcpy", .linkage = .Strong });
41 @export(memmove, .{ .name = "memmove", .linkage = .Strong });
42 @export(memcmp, .{ .name = "memcmp", .linkage = .Strong });
43 @export(bcmp, .{ .name = "bcmp", .linkage = .Strong });
44
45 if (builtin.link_libc) {36 if (builtin.link_libc) {
46 @export(strcmp, .{ .name = "strcmp", .linkage = .Strong });37 @export(strcmp, .{ .name = "strcmp", .linkage = .Strong });
47 @export(strncmp, .{ .name = "strncmp", .linkage = .Strong });38 @export(strncmp, .{ .name = "strncmp", .linkage = .Strong });
...@@ -75,116 +66,6 @@ fn wasm_start() callconv(.C) void {...@@ -75,116 +66,6 @@ fn wasm_start() callconv(.C) void {
75 _ = main(0, undefined);66 _ = main(0, undefined);
76}67}
7768
78fn memset(dest: ?[*]u8, c: u8, len: usize) callconv(.C) ?[*]u8 {
79 @setRuntimeSafety(false);
80
81 if (len != 0) {
82 var d = dest.?;
83 var n = len;
84 while (true) {
85 d[0] = c;
86 n -= 1;
87 if (n == 0) break;
88 d += 1;
89 }
90 }
91
92 return dest;
93}
94
95fn __memset(dest: ?[*]u8, c: u8, n: usize, dest_n: usize) callconv(.C) ?[*]u8 {
96 if (dest_n < n)
97 @panic("buffer overflow");
98 return memset(dest, c, n);
99}
100
101fn memcpy(noalias dest: ?[*]u8, noalias src: ?[*]const u8, len: usize) callconv(.C) ?[*]u8 {
102 @setRuntimeSafety(false);
103
104 if (len != 0) {
105 var d = dest.?;
106 var s = src.?;
107 var n = len;
108 while (true) {
109 d[0] = s[0];
110 n -= 1;
111 if (n == 0) break;
112 d += 1;
113 s += 1;
114 }
115 }
116
117 return dest;
118}
119
120fn memmove(dest: ?[*]u8, src: ?[*]const u8, n: usize) callconv(.C) ?[*]u8 {
121 @setRuntimeSafety(false);
122
123 if (@ptrToInt(dest) < @ptrToInt(src)) {
124 var index: usize = 0;
125 while (index != n) : (index += 1) {
126 dest.?[index] = src.?[index];
127 }
128 } else {
129 var index = n;
130 while (index != 0) {
131 index -= 1;
132 dest.?[index] = src.?[index];
133 }
134 }
135
136 return dest;
137}
138
139fn memcmp(vl: ?[*]const u8, vr: ?[*]const u8, n: usize) callconv(.C) c_int {
140 @setRuntimeSafety(false);
141
142 var index: usize = 0;
143 while (index != n) : (index += 1) {
144 const compare_val = @bitCast(i8, vl.?[index] -% vr.?[index]);
145 if (compare_val != 0) {
146 return compare_val;
147 }
148 }
149
150 return 0;
151}
152
153test "memcmp" {
154 const base_arr = &[_]u8{ 1, 1, 1 };
155 const arr1 = &[_]u8{ 1, 1, 1 };
156 const arr2 = &[_]u8{ 1, 0, 1 };
157 const arr3 = &[_]u8{ 1, 2, 1 };
158
159 try std.testing.expect(memcmp(base_arr[0..], arr1[0..], base_arr.len) == 0);
160 try std.testing.expect(memcmp(base_arr[0..], arr2[0..], base_arr.len) > 0);
161 try std.testing.expect(memcmp(base_arr[0..], arr3[0..], base_arr.len) < 0);
162}
163
164fn bcmp(vl: [*]allowzero const u8, vr: [*]allowzero const u8, n: usize) callconv(.C) c_int {
165 @setRuntimeSafety(false);
166
167 var index: usize = 0;
168 while (index != n) : (index += 1) {
169 if (vl[index] != vr[index]) {
170 return 1;
171 }
172 }
173
174 return 0;
175}
176
177test "bcmp" {
178 const base_arr = &[_]u8{ 1, 1, 1 };
179 const arr1 = &[_]u8{ 1, 1, 1 };
180 const arr2 = &[_]u8{ 1, 0, 1 };
181 const arr3 = &[_]u8{ 1, 2, 1 };
182
183 try std.testing.expect(bcmp(base_arr[0..], arr1[0..], base_arr.len) == 0);
184 try std.testing.expect(bcmp(base_arr[0..], arr2[0..], base_arr.len) != 0);
185 try std.testing.expect(bcmp(base_arr[0..], arr3[0..], base_arr.len) != 0);
186}
187
188var _fltused: c_int = 1;69var _fltused: c_int = 1;
18970
190fn strcpy(dest: [*:0]u8, src: [*:0]const u8) callconv(.C) [*:0]u8 {71fn strcpy(dest: [*:0]u8, src: [*:0]const u8) callconv(.C) [*:0]u8 {
lib/compiler_rt.zig+6
...@@ -198,4 +198,10 @@ comptime {...@@ -198,4 +198,10 @@ comptime {
198 _ = @import("compiler_rt/aulldiv.zig");198 _ = @import("compiler_rt/aulldiv.zig");
199 _ = @import("compiler_rt/aullrem.zig");199 _ = @import("compiler_rt/aullrem.zig");
200 _ = @import("compiler_rt/clear_cache.zig");200 _ = @import("compiler_rt/clear_cache.zig");
201
202 _ = @import("compiler_rt/memcpy.zig");
203 _ = @import("compiler_rt/memset.zig");
204 _ = @import("compiler_rt/memmove.zig");
205 _ = @import("compiler_rt/cmp.zig");
206 _ = @import("compiler_rt/bcmp.zig");
201}207}
lib/compiler_rt/bcmp.zig created+30
...@@ -0,0 +1,30 @@
1const std = @import("std");
2const common = @import("./common.zig");
3
4comptime {
5 @export(bcmp, .{ .name = "bcmp", .linkage = common.linkage });
6}
7
8pub fn bcmp(vl: [*]allowzero const u8, vr: [*]allowzero const u8, n: usize) callconv(.C) c_int {
9 @setRuntimeSafety(false);
10
11 var index: usize = 0;
12 while (index != n) : (index += 1) {
13 if (vl[index] != vr[index]) {
14 return 1;
15 }
16 }
17
18 return 0;
19}
20
21test "bcmp" {
22 const base_arr = &[_]u8{ 1, 1, 1 };
23 const arr1 = &[_]u8{ 1, 1, 1 };
24 const arr2 = &[_]u8{ 1, 0, 1 };
25 const arr3 = &[_]u8{ 1, 2, 1 };
26
27 try std.testing.expect(bcmp(base_arr[0..], arr1[0..], base_arr.len) == 0);
28 try std.testing.expect(bcmp(base_arr[0..], arr2[0..], base_arr.len) != 0);
29 try std.testing.expect(bcmp(base_arr[0..], arr3[0..], base_arr.len) != 0);
30}
lib/compiler_rt/memcmp.zig created+31
...@@ -0,0 +1,31 @@
1const std = @import("std");
2const common = @import("./common.zig");
3
4comptime {
5 @export(memcmp, .{ .name = "memcmp", .linkage = common.linkage });
6}
7
8pub fn memcmp(vl: ?[*]const u8, vr: ?[*]const u8, n: usize) callconv(.C) c_int {
9 @setRuntimeSafety(false);
10
11 var index: usize = 0;
12 while (index != n) : (index += 1) {
13 const compare_val = @bitCast(i8, vl.?[index] -% vr.?[index]);
14 if (compare_val != 0) {
15 return compare_val;
16 }
17 }
18
19 return 0;
20}
21
22test "memcmp" {
23 const base_arr = &[_]u8{ 1, 1, 1 };
24 const arr1 = &[_]u8{ 1, 1, 1 };
25 const arr2 = &[_]u8{ 1, 0, 1 };
26 const arr3 = &[_]u8{ 1, 2, 1 };
27
28 try std.testing.expect(memcmp(base_arr[0..], arr1[0..], base_arr.len) == 0);
29 try std.testing.expect(memcmp(base_arr[0..], arr2[0..], base_arr.len) > 0);
30 try std.testing.expect(memcmp(base_arr[0..], arr3[0..], base_arr.len) < 0);
31}
lib/compiler_rt/memcpy.zig created+25
...@@ -0,0 +1,25 @@
1const std = @import("std");
2const common = @import("./common.zig");
3
4comptime {
5 @export(memcpy, .{ .name = "memcpy", .linkage = common.linkage });
6}
7
8pub fn memcpy(noalias dest: ?[*]u8, noalias src: ?[*]const u8, len: usize) callconv(.C) ?[*]u8 {
9 @setRuntimeSafety(false);
10
11 if (len != 0) {
12 var d = dest.?;
13 var s = src.?;
14 var n = len;
15 while (true) {
16 d[0] = s[0];
17 n -= 1;
18 if (n == 0) break;
19 d += 1;
20 s += 1;
21 }
22 }
23
24 return dest;
25}
lib/compiler_rt/memmove.zig created+25
...@@ -0,0 +1,25 @@
1const std = @import("std");
2const common = @import("./common.zig");
3
4comptime {
5 @export(memmove, .{ .name = "memmove", .linkage = common.linkage });
6}
7
8pub fn memmove(dest: ?[*]u8, src: ?[*]const u8, n: usize) callconv(.C) ?[*]u8 {
9 @setRuntimeSafety(false);
10
11 if (@ptrToInt(dest) < @ptrToInt(src)) {
12 var index: usize = 0;
13 while (index != n) : (index += 1) {
14 dest.?[index] = src.?[index];
15 }
16 } else {
17 var index = n;
18 while (index != 0) {
19 index -= 1;
20 dest.?[index] = src.?[index];
21 }
22 }
23
24 return dest;
25}
lib/compiler_rt/memset.zig created+30
...@@ -0,0 +1,30 @@
1const std = @import("std");
2const common = @import("./common.zig");
3
4comptime {
5 @export(memset, .{ .name = "memset", .linkage = common.linkage });
6 @export(__memset, .{ .name = "__memset", .linkage = common.linkage });
7}
8
9pub fn memset(dest: ?[*]u8, c: u8, len: usize) callconv(.C) ?[*]u8 {
10 @setRuntimeSafety(false);
11
12 if (len != 0) {
13 var d = dest.?;
14 var n = len;
15 while (true) {
16 d[0] = c;
17 n -= 1;
18 if (n == 0) break;
19 d += 1;
20 }
21 }
22
23 return dest;
24}
25
26pub fn __memset(dest: ?[*]u8, c: u8, n: usize, dest_n: usize) callconv(.C) ?[*]u8 {
27 if (dest_n < n)
28 @panic("buffer overflow");
29 return memset(dest, c, n);
30}