authorgravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2026-06-04 10:59:37+02:00
committergravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2026-06-04 10:59:37+02:00
log645a38aeb69846b7b692fabdd63f62d6e5a17464
tree99c4f0f99473166983a22483d46a0bfc193f7038
parent3391ad7a9091edec0b368b0e98e61ec02043e91b
parent8a5899f53c50fc59168ecb80fa804bd9eb653fea

Merge pull request 'add `sparc-linux` arch bits + some bonus commits' (#35613) from alexrp/zig:sparc32-linux into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/35613

6 files changed, 328 insertions(+), 40 deletions(-)

lib/std/Thread.zig+1-1
......@@ -1376,7 +1376,7 @@ const LinuxThreadImpl = struct {
13761376 \\ mov %%g1, %%o0 // ptr
13771377 \\ mov %%g2, %%o1 // len
13781378 \\ mov 73, %%g1 // SYS_munmap
1379 \\ t 0x3 # ST_FLUSH_WINDOWS
1379 \\ t 0x3 // ST_FLUSH_WINDOWS
13801380 \\ t 0x10
13811381 \\ mov 1, %%g1 // SYS_exit
13821382 \\ mov 0, %%o0
lib/std/os.zig-4
......@@ -15,8 +15,6 @@ pub fn targetRequiresLibC(target: *const std.Target) bool {
1515 if (target.requiresLibC()) return true;
1616 return switch (target.os.tag) {
1717 .linux => switch (target.cpu.arch) {
18 // https://codeberg.org/ziglang/zig/issues/30942
19 .csky,
2018 // https://codeberg.org/ziglang/zig/issues/30943
2119 .hppa,
2220 .hppa64,
......@@ -26,8 +24,6 @@ pub fn targetRequiresLibC(target: *const std.Target) bool {
2624 // https://codeberg.org/ziglang/zig/issues/30946
2725 .sh,
2826 .sheb,
29 // https://codeberg.org/ziglang/zig/issues/30945
30 .sparc,
3127 => true,
3228 else => false,
3329 },
lib/std/os/linux.zig+5-4
......@@ -51,6 +51,7 @@ const arch_bits = switch (native_arch) {
5151 .riscv32 => @import("linux/riscv32.zig"),
5252 .riscv64 => @import("linux/riscv64.zig"),
5353 .s390x => @import("linux/s390x.zig"),
54 .sparc => @import("linux/sparc.zig"),
5455 .sparc64 => @import("linux/sparc64.zig"),
5556 .x86 => @import("linux/x86.zig"),
5657 .x86_64 => switch (builtin.abi) {
......@@ -223,7 +224,7 @@ pub const MAP = switch (native_arch) {
223224 UNINITIALIZED: bool = false,
224225 _: u5 = 0,
225226 },
226 .sparc64 => packed struct(u32) {
227 .sparc, .sparc64 => packed struct(u32) {
227228 TYPE: MAP_TYPE,
228229 FIXED: bool = false,
229230 ANONYMOUS: bool = false,
......@@ -444,7 +445,7 @@ pub const O = switch (native_arch) {
444445 TMPFILE: bool = false,
445446 _23: u9 = 0,
446447 },
447 .sparc64 => packed struct(u32) {
448 .sparc, .sparc64 => packed struct(u32) {
448449 ACCMODE: ACCMODE = .RDONLY,
449450 _2: u1 = 0,
450451 APPEND: bool = false,
......@@ -1994,7 +1995,7 @@ pub const F = struct {
19941995 const SETLKW = 7;
19951996 },
19961997 },
1997 .alpha, .sparc64 => struct {
1998 .alpha, .sparc, .sparc64 => struct {
19981999 const GETLK = 7;
19992000 const SETLK = 8;
20002001 const SETLKW = 9;
......@@ -6585,7 +6586,7 @@ const TFD_TIMER = packed struct(u32) {
65856586};
65866587
65876588pub const TFD = switch (native_arch) {
6588 .sparc64 => packed struct(u32) {
6589 .sparc, .sparc64 => packed struct(u32) {
65896590 _0: u14 = 0,
65906591 NONBLOCK: bool = false,
65916592 _15: u7 = 0,
lib/std/os/linux/sparc.zig created+277
......@@ -0,0 +1,277 @@
1const builtin = @import("builtin");
2const std = @import("../../std.zig");
3const SYS = std.os.linux.SYS;
4
5pub const syscall_arg_t = u32;
6
7pub fn syscall0(
8 number: SYS,
9) u32 {
10 return asm volatile (
11 \\ t 0x10
12 \\ bcc 1f
13 \\ nop
14 \\ neg %%o0
15 \\1:
16 : [ret] "={o0}" (-> u32),
17 : [number] "{g1}" (@intFromEnum(number)),
18 : .{ .memory = true, .xcc = true, .o1 = true, .o2 = true, .o3 = true, .o4 = true, .o5 = true, .o7 = true });
19}
20
21pub fn syscall1(
22 number: SYS,
23 arg1: syscall_arg_t,
24) u32 {
25 return asm volatile (
26 \\ t 0x10
27 \\ bcc 1f
28 \\ nop
29 \\ neg %%o0
30 \\1:
31 : [ret] "={o0}" (-> u32),
32 : [number] "{g1}" (@intFromEnum(number)),
33 [arg1] "{o0}" (arg1),
34 : .{ .memory = true, .xcc = true, .o1 = true, .o2 = true, .o3 = true, .o4 = true, .o5 = true, .o7 = true });
35}
36
37pub fn syscall2(
38 number: SYS,
39 arg1: syscall_arg_t,
40 arg2: syscall_arg_t,
41) u32 {
42 return asm volatile (
43 \\ t 0x10
44 \\ bcc 1f
45 \\ nop
46 \\ neg %%o0
47 \\1:
48 : [ret] "={o0}" (-> u32),
49 : [number] "{g1}" (@intFromEnum(number)),
50 [arg1] "{o0}" (arg1),
51 [arg2] "{o1}" (arg2),
52 : .{ .memory = true, .xcc = true, .o1 = true, .o2 = true, .o3 = true, .o4 = true, .o5 = true, .o7 = true });
53}
54
55pub fn syscall3(
56 number: SYS,
57 arg1: syscall_arg_t,
58 arg2: syscall_arg_t,
59 arg3: syscall_arg_t,
60) u32 {
61 return asm volatile (
62 \\ t 0x10
63 \\ bcc 1f
64 \\ nop
65 \\ neg %%o0
66 \\1:
67 : [ret] "={o0}" (-> u32),
68 : [number] "{g1}" (@intFromEnum(number)),
69 [arg1] "{o0}" (arg1),
70 [arg2] "{o1}" (arg2),
71 [arg3] "{o2}" (arg3),
72 : .{ .memory = true, .xcc = true, .o1 = true, .o2 = true, .o3 = true, .o4 = true, .o5 = true, .o7 = true });
73}
74
75pub fn syscall4(
76 number: SYS,
77 arg1: syscall_arg_t,
78 arg2: syscall_arg_t,
79 arg3: syscall_arg_t,
80 arg4: syscall_arg_t,
81) u32 {
82 return asm volatile (
83 \\ t 0x10
84 \\ bcc 1f
85 \\ nop
86 \\ neg %%o0
87 \\1:
88 : [ret] "={o0}" (-> u32),
89 : [number] "{g1}" (@intFromEnum(number)),
90 [arg1] "{o0}" (arg1),
91 [arg2] "{o1}" (arg2),
92 [arg3] "{o2}" (arg3),
93 [arg4] "{o3}" (arg4),
94 : .{ .memory = true, .xcc = true, .o1 = true, .o2 = true, .o3 = true, .o4 = true, .o5 = true, .o7 = true });
95}
96
97pub fn syscall5(
98 number: SYS,
99 arg1: syscall_arg_t,
100 arg2: syscall_arg_t,
101 arg3: syscall_arg_t,
102 arg4: syscall_arg_t,
103 arg5: syscall_arg_t,
104) u32 {
105 return asm volatile (
106 \\ t 0x10
107 \\ bcc 1f
108 \\ nop
109 \\ neg %%o0
110 \\1:
111 : [ret] "={o0}" (-> u32),
112 : [number] "{g1}" (@intFromEnum(number)),
113 [arg1] "{o0}" (arg1),
114 [arg2] "{o1}" (arg2),
115 [arg3] "{o2}" (arg3),
116 [arg4] "{o3}" (arg4),
117 [arg5] "{o4}" (arg5),
118 : .{ .memory = true, .xcc = true, .o1 = true, .o2 = true, .o3 = true, .o4 = true, .o5 = true, .o7 = true });
119}
120
121pub fn syscall6(
122 number: SYS,
123 arg1: syscall_arg_t,
124 arg2: syscall_arg_t,
125 arg3: syscall_arg_t,
126 arg4: syscall_arg_t,
127 arg5: syscall_arg_t,
128 arg6: syscall_arg_t,
129) u32 {
130 return asm volatile (
131 \\ t 0x10
132 \\ bcc 1f
133 \\ nop
134 \\ neg %%o0
135 \\1:
136 : [ret] "={o0}" (-> u32),
137 : [number] "{g1}" (@intFromEnum(number)),
138 [arg1] "{o0}" (arg1),
139 [arg2] "{o1}" (arg2),
140 [arg3] "{o2}" (arg3),
141 [arg4] "{o3}" (arg4),
142 [arg5] "{o4}" (arg5),
143 [arg6] "{o5}" (arg6),
144 : .{ .memory = true, .xcc = true, .o1 = true, .o2 = true, .o3 = true, .o4 = true, .o5 = true, .o7 = true });
145}
146
147pub fn syscall_pipe(
148 fd: *[2]std.os.linux.fd_t,
149) u32 {
150 return asm volatile (
151 \\ mov %[arg], %%g3
152 \\ t 0x10
153 \\ bcc 1f
154 \\ nop
155 \\ # Return the error code
156 \\ ba 2f
157 \\ neg %%o0
158 \\1:
159 \\ st %%o0, [%%g3+0]
160 \\ st %%o1, [%%g3+4]
161 \\ clr %%o0
162 \\2:
163 : [ret] "={o0}" (-> u32),
164 : [number] "{g1}" (@intFromEnum(SYS.pipe)),
165 [arg] "r" (fd),
166 : .{ .memory = true, .g3 = true });
167}
168
169pub fn syscall_fork() u32 {
170 // Linux/sparc fork() returns two values in %o0 and %o1:
171 // - On the parent's side, %o0 is the child's PID and %o1 is 0.
172 // - On the child's side, %o0 is the parent's PID and %o1 is 1.
173 // We need to clear the child's %o0 so that the return values
174 // conform to the libc convention.
175 return asm volatile (
176 \\ t 0x10
177 \\ bcc 1f
178 \\ nop
179 \\ ba 2f
180 \\ neg %%o0
181 \\1:
182 \\ # Clear the child's %%o0
183 \\ dec %%o1
184 \\ and %%o1, %%o0, %%o0
185 \\2:
186 : [ret] "={o0}" (-> u32),
187 : [number] "{g1}" (@intFromEnum(SYS.fork)),
188 : .{ .memory = true, .xcc = true, .o1 = true, .o2 = true, .o3 = true, .o4 = true, .o5 = true, .o7 = true });
189}
190
191pub fn clone() callconv(.naked) u32 {
192 // __clone(func, stack, flags, arg, ptid, tls, ctid)
193 // i0, i1, i2, i3, i4, i5, sp
194 //
195 // syscall(SYS_clone, flags, stack, ptid, tls, ctid)
196 // g1 o0, o1, o2, o3, o4
197 asm volatile (
198 \\ save %%sp, -96, %%sp
199 \\
200 \\ // clone() on SPARC can fail with EFAULT if %%sp points to uncommitted memory, so flush
201 \\ // all register windows up to this point to ensure that the kernel has enough committed
202 \\ // memory for its stack frame.
203 \\ save %%sp, -96, %%sp
204 \\ t 0x3
205 \\ restore
206 \\
207 \\ # Save the func pointer and the arg pointer
208 \\ mov %%i0, %%g2
209 \\ mov %%i3, %%g3
210 \\
211 \\ # Shuffle the arguments
212 \\ mov 217, %%g1 // SYS_clone
213 \\ mov %%i2, %%o0
214 \\
215 \\ # Align, and add some extra space for the initial frame
216 \\ and %%i1, -8, %%i1
217 \\ sub %%i1, 96 + 2047, %%o1
218 \\
219 \\ mov %%i4, %%o2
220 \\ mov %%i5, %%o3
221 \\ ld [%%fp + 92 + 2047], %%o4
222 \\ t 0x10
223 \\ bcs 1f
224 \\ nop
225 \\ # The child pid is returned in o0 while o1 tells if this
226 \\ # process is the child (=1) or the parent (=0).
227 \\ tst %%o1
228 \\ bne 2f
229 \\ nop
230 \\
231 \\ # Parent process, return the child pid
232 \\ mov %%o0, %%i0
233 \\ ret
234 \\ restore
235 \\
236 \\1:
237 \\ # The syscall failed
238 \\ sub %%g0, %%o0, %%i0
239 \\ ret
240 \\ restore
241 \\
242 \\2:
243 \\ # Child process
244 );
245 if (builtin.unwind_tables != .none or !builtin.strip_debug_info) asm volatile (
246 \\ .cfi_undefined %%i7
247 );
248 asm volatile (
249 \\ mov %%g0, %%fp
250 \\ mov %%g0, %%i7
251 \\
252 \\ # call func(arg)
253 \\ call %%g2
254 \\ mov %%g3, %%o0
255 \\ # Exit
256 \\ mov 1, %%g1 // SYS_exit
257 \\ t 0x10
258 );
259}
260
261pub const restore = restore_rt;
262
263// Need to use C ABI here instead of naked
264// to prevent an infinite loop when calling rt_sigreturn.
265pub fn restore_rt() callconv(.c) void {
266 return asm volatile ("t 0x10"
267 :
268 : [number] "{g1}" (@intFromEnum(SYS.rt_sigreturn)),
269 : .{ .memory = true, .xcc = true, .o0 = true, .o1 = true, .o2 = true, .o3 = true, .o4 = true, .o5 = true, .o7 = true });
270}
271
272pub const VDSO = struct {
273 pub const CGT_SYM = "__vdso_clock_gettime";
274 pub const CGT_VER = "LINUX_2.6";
275};
276
277pub const time_t = i32;
lib/std/os/linux/sparc64.zig+44-30
......@@ -10,9 +10,9 @@ pub fn syscall0(
1010 return asm volatile (
1111 \\ t 0x6d
1212 \\ bcc,pt %%xcc, 1f
13 \\ nop
13 \\ nop
1414 \\ neg %%o0
15 \\ 1:
15 \\1:
1616 : [ret] "={o0}" (-> u64),
1717 : [number] "{g1}" (@intFromEnum(number)),
1818 : .{ .memory = true, .xcc = true, .o1 = true, .o2 = true, .o3 = true, .o4 = true, .o5 = true, .o7 = true });
......@@ -25,9 +25,9 @@ pub fn syscall1(
2525 return asm volatile (
2626 \\ t 0x6d
2727 \\ bcc,pt %%xcc, 1f
28 \\ nop
28 \\ nop
2929 \\ neg %%o0
30 \\ 1:
30 \\1:
3131 : [ret] "={o0}" (-> u64),
3232 : [number] "{g1}" (@intFromEnum(number)),
3333 [arg1] "{o0}" (arg1),
......@@ -42,9 +42,9 @@ pub fn syscall2(
4242 return asm volatile (
4343 \\ t 0x6d
4444 \\ bcc,pt %%xcc, 1f
45 \\ nop
45 \\ nop
4646 \\ neg %%o0
47 \\ 1:
47 \\1:
4848 : [ret] "={o0}" (-> u64),
4949 : [number] "{g1}" (@intFromEnum(number)),
5050 [arg1] "{o0}" (arg1),
......@@ -61,9 +61,9 @@ pub fn syscall3(
6161 return asm volatile (
6262 \\ t 0x6d
6363 \\ bcc,pt %%xcc, 1f
64 \\ nop
64 \\ nop
6565 \\ neg %%o0
66 \\ 1:
66 \\1:
6767 : [ret] "={o0}" (-> u64),
6868 : [number] "{g1}" (@intFromEnum(number)),
6969 [arg1] "{o0}" (arg1),
......@@ -82,9 +82,9 @@ pub fn syscall4(
8282 return asm volatile (
8383 \\ t 0x6d
8484 \\ bcc,pt %%xcc, 1f
85 \\ nop
85 \\ nop
8686 \\ neg %%o0
87 \\ 1:
87 \\1:
8888 : [ret] "={o0}" (-> u64),
8989 : [number] "{g1}" (@intFromEnum(number)),
9090 [arg1] "{o0}" (arg1),
......@@ -105,9 +105,9 @@ pub fn syscall5(
105105 return asm volatile (
106106 \\ t 0x6d
107107 \\ bcc,pt %%xcc, 1f
108 \\ nop
108 \\ nop
109109 \\ neg %%o0
110 \\ 1:
110 \\1:
111111 : [ret] "={o0}" (-> u64),
112112 : [number] "{g1}" (@intFromEnum(number)),
113113 [arg1] "{o0}" (arg1),
......@@ -130,9 +130,9 @@ pub fn syscall6(
130130 return asm volatile (
131131 \\ t 0x6d
132132 \\ bcc,pt %%xcc, 1f
133 \\ nop
133 \\ nop
134134 \\ neg %%o0
135 \\ 1:
135 \\1:
136136 : [ret] "={o0}" (-> u64),
137137 : [number] "{g1}" (@intFromEnum(number)),
138138 [arg1] "{o0}" (arg1),
......@@ -151,10 +151,10 @@ pub fn syscall_pipe(
151151 \\ mov %[arg], %%g3
152152 \\ t 0x6d
153153 \\ bcc,pt %%xcc, 1f
154 \\ nop
154 \\ nop
155155 \\ # Return the error code
156156 \\ ba 2f
157 \\ neg %%o0
157 \\ neg %%o0
158158 \\1:
159159 \\ st %%o0, [%%g3+0]
160160 \\ st %%o1, [%%g3+4]
......@@ -175,14 +175,14 @@ pub fn syscall_fork() u64 {
175175 return asm volatile (
176176 \\ t 0x6d
177177 \\ bcc,pt %%xcc, 1f
178 \\ nop
178 \\ nop
179179 \\ ba 2f
180 \\ neg %%o0
181 \\ 1:
180 \\ neg %%o0
181 \\1:
182182 \\ # Clear the child's %%o0
183183 \\ dec %%o1
184184 \\ and %%o1, %%o0, %%o0
185 \\ 2:
185 \\2:
186186 : [ret] "={o0}" (-> u64),
187187 : [number] "{g1}" (@intFromEnum(SYS.fork)),
188188 : .{ .memory = true, .xcc = true, .o1 = true, .o2 = true, .o3 = true, .o4 = true, .o5 = true, .o7 = true });
......@@ -196,33 +196,48 @@ pub fn clone() callconv(.naked) u64 {
196196 // g1 o0, o1, o2, o3, o4
197197 asm volatile (
198198 \\ save %%sp, -192, %%sp
199 \\
200 \\ // clone() on SPARC can fail with EFAULT if %%sp points to uncommitted memory, so flush
201 \\ // all register windows up to this point to ensure that the kernel has enough committed
202 \\ // memory for its stack frame.
203 \\ save %%sp, -192, %%sp
204 \\ flushw
205 \\ restore
206 \\
199207 \\ # Save the func pointer and the arg pointer
200208 \\ mov %%i0, %%g2
201209 \\ mov %%i3, %%g3
210 \\
202211 \\ # Shuffle the arguments
203212 \\ mov 217, %%g1 // SYS_clone
204213 \\ mov %%i2, %%o0
205 \\ # Add some extra space for the initial frame
206 \\ sub %%i1, 176 + 2047, %%o1
214 \\
215 \\ # Align, and add some extra space for the initial frame
216 \\ and %%i1, -16, %%i1
217 \\ sub %%i1, 192 + 2047, %%o1
218 \\
207219 \\ mov %%i4, %%o2
208220 \\ mov %%i5, %%o3
209 \\ ldx [%%fp + 0x8af], %%o4
221 \\ ldx [%%fp + 176 + 2047], %%o4
210222 \\ t 0x6d
211223 \\ bcs,pn %%xcc, 1f
212 \\ nop
224 \\ nop
213225 \\ # The child pid is returned in o0 while o1 tells if this
214 \\ # process is # the child (=1) or the parent (=0).
226 \\ # process is the child (=1) or the parent (=0).
215227 \\ brnz %%o1, 2f
216 \\ nop
228 \\ nop
229 \\
217230 \\ # Parent process, return the child pid
218231 \\ mov %%o0, %%i0
219232 \\ ret
220 \\ restore
233 \\ restore
234 \\
221235 \\1:
222236 \\ # The syscall failed
223237 \\ sub %%g0, %%o0, %%i0
224238 \\ ret
225 \\ restore
239 \\ restore
240 \\
226241 \\2:
227242 \\ # Child process
228243 );
......@@ -234,9 +249,8 @@ pub fn clone() callconv(.naked) u64 {
234249 \\ mov %%g0, %%i7
235250 \\
236251 \\ # call func(arg)
237 \\ mov %%g0, %%fp
238252 \\ call %%g2
239 \\ mov %%g3, %%o0
253 \\ mov %%g3, %%o0
240254 \\ # Exit
241255 \\ mov 1, %%g1 // SYS_exit
242256 \\ t 0x6d
lib/std/zig/system.zig+1-1
......@@ -152,7 +152,7 @@ pub fn getExternalExecutor(io: Io, candidate: *const std.Target, options: GetExt
152152 // TODO: Actually check the SuperH version.
153153 .sh => "qemu-sh4",
154154 .sheb => "qemu-sh4eb",
155 .sparc => if (candidate.cpu.has(.sparc, .v8plus)) "qemu-sparc32plus" else "qemu-sparc",
155 .sparc => "qemu-sparc32plus",
156156 .thumb => "qemu-arm",
157157 .thumbeb => "qemu-armeb",
158158 else => "qemu-" ++ @tagName(t),