authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-07-31 01:56:43-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-07-31 03:49:21-04:00
log228c956377e4f33e45fad7e0ba5d9eb5073803a5
treec4731c4d85805cd6c5acf11e7b53d3d5443519c2
parent2ba787e3038d8776599fb968b3ddec6b7a62a3f3

std: finish cleanup up asm

This also required implementing the necessary syntax in the x86_64 backend.

35 files changed, 498 insertions(+), 418 deletions(-)

lib/c.zig+91-96
......@@ -200,72 +200,67 @@ fn clone() callconv(.Naked) void {
200200 // syscall(SYS_clone, flags, stack, ptid, tls, ctid)
201201 // eax, ebx, ecx, edx, esi, edi
202202 asm volatile (
203 \\ push %%ebp
204 \\ mov %%esp,%%ebp
205 \\ push %%ebx
206 \\ push %%esi
207 \\ push %%edi
203 \\ pushl %%ebp
204 \\ movl %%esp,%%ebp
205 \\ pushl %%ebx
206 \\ pushl %%esi
207 \\ pushl %%edi
208208 \\ // Setup the arguments
209 \\ mov 16(%%ebp),%%ebx
210 \\ mov 12(%%ebp),%%ecx
211 \\ and $-16,%%ecx
212 \\ sub $20,%%ecx
213 \\ mov 20(%%ebp),%%eax
214 \\ mov %%eax,4(%%ecx)
215 \\ mov 8(%%ebp),%%eax
216 \\ mov %%eax,0(%%ecx)
217 \\ mov 24(%%ebp),%%edx
218 \\ mov 28(%%ebp),%%esi
219 \\ mov 32(%%ebp),%%edi
220 \\ mov $120,%%eax
209 \\ movl 16(%%ebp),%%ebx
210 \\ movl 12(%%ebp),%%ecx
211 \\ andl $-16,%%ecx
212 \\ subl $20,%%ecx
213 \\ movl 20(%%ebp),%%eax
214 \\ movl %%eax,4(%%ecx)
215 \\ movl 8(%%ebp),%%eax
216 \\ movl %%eax,0(%%ecx)
217 \\ movl 24(%%ebp),%%edx
218 \\ movl 28(%%ebp),%%esi
219 \\ movl 32(%%ebp),%%edi
220 \\ movl $120,%%eax
221221 \\ int $128
222 \\ test %%eax,%%eax
222 \\ testl %%eax,%%eax
223223 \\ jnz 1f
224 \\ pop %%eax
225 \\ xor %%ebp,%%ebp
226 \\ call *%%eax
227 \\ mov %%eax,%%ebx
228 \\ xor %%eax,%%eax
229 \\ inc %%eax
224 \\ popl %%eax
225 \\ xorl %%ebp,%%ebp
226 \\ calll *%%eax
227 \\ movl %%eax,%%ebx
228 \\ movl $1,%%eax
230229 \\ int $128
231 \\ hlt
232230 \\1:
233 \\ pop %%edi
234 \\ pop %%esi
235 \\ pop %%ebx
236 \\ pop %%ebp
237 \\ ret
231 \\ popl %%edi
232 \\ popl %%esi
233 \\ popl %%ebx
234 \\ popl %%ebp
235 \\ retl
238236 );
239237 },
240238 .x86_64 => {
241239 asm volatile (
242 \\ xor %%eax,%%eax
243 \\ mov $56,%%al // SYS_clone
244 \\ mov %%rdi,%%r11
245 \\ mov %%rdx,%%rdi
246 \\ mov %%r8,%%rdx
247 \\ mov %%r9,%%r8
248 \\ mov 8(%%rsp),%%r10
249 \\ mov %%r11,%%r9
250 \\ and $-16,%%rsi
251 \\ sub $8,%%rsi
252 \\ mov %%rcx,(%%rsi)
240 \\ movl $56,%%eax // SYS_clone
241 \\ movq %%rdi,%%r11
242 \\ movq %%rdx,%%rdi
243 \\ movq %%r8,%%rdx
244 \\ movq %%r9,%%r8
245 \\ movq 8(%%rsp),%%r10
246 \\ movq %%r11,%%r9
247 \\ andq $-16,%%rsi
248 \\ subq $8,%%rsi
249 \\ movq %%rcx,(%%rsi)
253250 \\ syscall
254 \\ test %%eax,%%eax
251 \\ testq %%rax,%%rax
255252 \\ jnz 1f
256 \\ xor %%ebp,%%ebp
257 \\ pop %%rdi
258 \\ call *%%r9
259 \\ mov %%eax,%%edi
260 \\ xor %%eax,%%eax
261 \\ mov $60,%%al // SYS_exit
253 \\ xorl %%ebp,%%ebp
254 \\ popq %%rdi
255 \\ callq *%%r9
256 \\ movl %%eax,%%edi
257 \\ movl $60,%%eax // SYS_exit
262258 \\ syscall
263 \\ hlt
264259 \\1: ret
265260 \\
266261 );
267262 },
268 .aarch64 => {
263 .aarch64, .aarch64_be => {
269264 // __clone(func, stack, flags, arg, ptid, tls, ctid)
270265 // x0, x1, w2, x3, x4, x5, x6
271266
......@@ -400,69 +395,69 @@ fn clone() callconv(.Naked) void {
400395 \\ syscall
401396 );
402397 },
403 .powerpc => {
398 .powerpc, .powerpcle => {
404399 // __clone(func, stack, flags, arg, ptid, tls, ctid)
405400 // 3, 4, 5, 6, 7, 8, 9
406401
407402 // syscall(SYS_clone, flags, stack, ptid, tls, ctid)
408403 // 0 3, 4, 5, 6, 7
409404 asm volatile (
410 \\# store non-volatile regs r30, r31 on stack in order to put our
411 \\# start func and its arg there
412 \\stwu 30, -16(1)
413 \\stw 31, 4(1)
405 \\ # store non-volatile regs r30, r31 on stack in order to put our
406 \\ # start func and its arg there
407 \\ stwu 30, -16(1)
408 \\ stw 31, 4(1)
414409 \\
415 \\# save r3 (func) into r30, and r6(arg) into r31
416 \\mr 30, 3
417 \\mr 31, 6
410 \\ # save r3 (func) into r30, and r6(arg) into r31
411 \\ mr 30, 3
412 \\ mr 31, 6
418413 \\
419 \\# create initial stack frame for new thread
420 \\clrrwi 4, 4, 4
421 \\li 0, 0
422 \\stwu 0, -16(4)
414 \\ # create initial stack frame for new thread
415 \\ clrrwi 4, 4, 4
416 \\ li 0, 0
417 \\ stwu 0, -16(4)
423418 \\
424 \\#move c into first arg
425 \\mr 3, 5
426 \\#mr 4, 4
427 \\mr 5, 7
428 \\mr 6, 8
429 \\mr 7, 9
419 \\ #move c into first arg
420 \\ mr 3, 5
421 \\ #mr 4, 4
422 \\ mr 5, 7
423 \\ mr 6, 8
424 \\ mr 7, 9
430425 \\
431 \\# move syscall number into r0
432 \\li 0, 120
426 \\ # move syscall number into r0
427 \\ li 0, 120
433428 \\
434 \\sc
429 \\ sc
435430 \\
436 \\# check for syscall error
437 \\bns+ 1f # jump to label 1 if no summary overflow.
438 \\#else
439 \\neg 3, 3 #negate the result (errno)
440 \\1:
441 \\# compare sc result with 0
442 \\cmpwi cr7, 3, 0
431 \\ # check for syscall error
432 \\ bns+ 1f # jump to label 1 if no summary overflow.
433 \\ #else
434 \\ neg 3, 3 #negate the result (errno)
435 \\ 1:
436 \\ # compare sc result with 0
437 \\ cmpwi cr7, 3, 0
443438 \\
444 \\# if not 0, jump to end
445 \\bne cr7, 2f
439 \\ # if not 0, jump to end
440 \\ bne cr7, 2f
446441 \\
447 \\#else: we're the child
448 \\#call funcptr: move arg (d) into r3
449 \\mr 3, 31
450 \\#move r30 (funcptr) into CTR reg
451 \\mtctr 30
452 \\# call CTR reg
453 \\bctrl
454 \\# mov SYS_exit into r0 (the exit param is already in r3)
455 \\li 0, 1
456 \\sc
442 \\ #else: we're the child
443 \\ #call funcptr: move arg (d) into r3
444 \\ mr 3, 31
445 \\ #move r30 (funcptr) into CTR reg
446 \\ mtctr 30
447 \\ # call CTR reg
448 \\ bctrl
449 \\ # mov SYS_exit into r0 (the exit param is already in r3)
450 \\ li 0, 1
451 \\ sc
457452 \\
458 \\2:
453 \\ 2:
459454 \\
460 \\# restore stack
461 \\lwz 30, 0(1)
462 \\lwz 31, 4(1)
463 \\addi 1, 1, 16
455 \\ # restore stack
456 \\ lwz 30, 0(1)
457 \\ lwz 31, 4(1)
458 \\ addi 1, 1, 16
464459 \\
465 \\blr
460 \\ blr
466461 );
467462 },
468463 .powerpc64, .powerpc64le => {
lib/compiler_rt/arm.zig+1-1
......@@ -9,7 +9,7 @@ pub const panic = common.panic;
99
1010comptime {
1111 if (!builtin.is_test) {
12 if (arch.isARM() or arch.isThumb()) {
12 if (arch.isArmOrThumb()) {
1313 @export(__aeabi_unwind_cpp_pr0, .{ .name = "__aeabi_unwind_cpp_pr0", .linkage = common.linkage, .visibility = common.visibility });
1414 @export(__aeabi_unwind_cpp_pr1, .{ .name = "__aeabi_unwind_cpp_pr1", .linkage = common.linkage, .visibility = common.visibility });
1515 @export(__aeabi_unwind_cpp_pr2, .{ .name = "__aeabi_unwind_cpp_pr2", .linkage = common.linkage, .visibility = common.visibility });
lib/compiler_rt/clzsi2_test.zig+1-1
......@@ -268,7 +268,7 @@ test "clzsi2" {
268268 try test__clzsi2(0xFE000000, 0);
269269 try test__clzsi2(0xFF000000, 0);
270270 // arm and thumb1 assume input a != 0
271 if (!builtin.cpu.arch.isARM() and !builtin.cpu.arch.isThumb())
271 if (!builtin.cpu.arch.isArmOrThumb())
272272 try test__clzsi2(0x00000000, 32);
273273 try test__clzsi2(0x00000001, 31);
274274 try test__clzsi2(0x00000002, 30);
lib/std/builtin.zig+1-1
......@@ -568,7 +568,7 @@ pub const VaListX86_64 = extern struct {
568568/// This data structure is used by the Zig language code generation and
569569/// therefore must be kept in sync with the compiler implementation.
570570pub const VaList = switch (builtin.cpu.arch) {
571 .aarch64 => switch (builtin.os.tag) {
571 .aarch64, .aarch64_be => switch (builtin.os.tag) {
572572 .windows => *u8,
573573 .ios, .macos, .tvos, .watchos => *u8,
574574 else => @compileError("disabled due to miscompilations"), // VaListAarch64,
lib/std/os/linux.zig+6-8
......@@ -35,13 +35,13 @@ const syscall_bits = switch (native_arch) {
3535const arch_bits = switch (native_arch) {
3636 .x86 => @import("linux/x86.zig"),
3737 .x86_64 => @import("linux/x86_64.zig"),
38 .aarch64 => @import("linux/arm64.zig"),
38 .aarch64, .aarch64_be => @import("linux/arm64.zig"),
3939 .arm, .thumb => @import("linux/arm-eabi.zig"),
4040 .riscv64 => @import("linux/riscv64.zig"),
4141 .sparc64 => @import("linux/sparc64.zig"),
4242 .mips, .mipsel => @import("linux/mips.zig"),
4343 .mips64, .mips64el => @import("linux/mips64.zig"),
44 .powerpc => @import("linux/powerpc.zig"),
44 .powerpc, .powerpcle => @import("linux/powerpc.zig"),
4545 .powerpc64, .powerpc64le => @import("linux/powerpc64.zig"),
4646 else => struct {},
4747};
......@@ -98,13 +98,13 @@ pub const syscalls = @import("linux/syscalls.zig");
9898pub const SYS = switch (@import("builtin").cpu.arch) {
9999 .x86 => syscalls.X86,
100100 .x86_64 => syscalls.X64,
101 .aarch64 => syscalls.Arm64,
101 .aarch64, .aarch64_be => syscalls.Arm64,
102102 .arm, .thumb => syscalls.Arm,
103103 .riscv64 => syscalls.RiscV64,
104104 .sparc64 => syscalls.Sparc64,
105105 .mips, .mipsel => syscalls.Mips,
106106 .mips64, .mips64el => syscalls.Mips64,
107 .powerpc => syscalls.PowerPC,
107 .powerpc, .powerpcle => syscalls.PowerPC,
108108 .powerpc64, .powerpc64le => syscalls.PowerPC64,
109109 else => @compileError("The Zig Standard Library is missing syscall definitions for the target CPU architecture"),
110110};
......@@ -1176,14 +1176,12 @@ pub fn sigaction(sig: u6, noalias act: ?*const Sigaction, noalias oact: ?*Sigact
11761176 const mask_size = @sizeOf(@TypeOf(ksa.mask));
11771177
11781178 if (act) |new| {
1179 const restore_rt_ptr = &restore_rt;
1180 const restore_ptr = &restore;
1181 const restorer_fn = if ((new.flags & SA.SIGINFO) != 0) restore_rt_ptr else restore_ptr;
1179 const restorer_fn = if ((new.flags & SA.SIGINFO) != 0) &restore_rt else &restore;
11821180 ksa = k_sigaction{
11831181 .handler = new.handler.handler,
11841182 .flags = new.flags | SA.RESTORER,
11851183 .mask = undefined,
1186 .restorer = @as(k_sigaction_funcs.restorer, @ptrCast(restorer_fn)),
1184 .restorer = @ptrCast(restorer_fn),
11871185 };
11881186 @memcpy(@as([*]u8, @ptrCast(&ksa.mask))[0..mask_size], @as([*]const u8, @ptrCast(&new.mask)));
11891187 }
lib/std/os/linux/arm-eabi.zig+22-26
......@@ -103,44 +103,40 @@ const CloneFn = *const fn (arg: usize) callconv(.C) u8;
103103/// This matches the libc clone function.
104104pub extern fn clone(func: CloneFn, stack: usize, flags: u32, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize;
105105
106pub fn restore() callconv(.Naked) void {
107 if (@import("builtin").zig_backend == .stage2_c) {
108 asm volatile (
106pub fn restore() callconv(.Naked) noreturn {
107 switch (@import("builtin").zig_backend) {
108 .stage2_c => asm volatile (
109109 \\ mov r7, %[number]
110110 \\ svc #0
111 \\ bx lr
112111 :
113 : [number] "i" (@intFromEnum(SYS.sigreturn)),
112 : [number] "I" (@intFromEnum(SYS.sigreturn)),
114113 : "memory"
115 );
116 unreachable;
114 ),
115 else => asm volatile (
116 \\ svc #0
117 :
118 : [number] "{r7}" (@intFromEnum(SYS.sigreturn)),
119 : "memory"
120 ),
117121 }
118
119 asm volatile ("svc #0"
120 :
121 : [number] "{r7}" (@intFromEnum(SYS.sigreturn)),
122 : "memory"
123 );
124122}
125123
126pub fn restore_rt() callconv(.Naked) void {
127 if (@import("builtin").zig_backend == .stage2_c) {
128 asm volatile (
124pub fn restore_rt() callconv(.Naked) noreturn {
125 switch (@import("builtin").zig_backend) {
126 .stage2_c => asm volatile (
129127 \\ mov r7, %[number]
130128 \\ svc #0
131 \\ bx lr
132129 :
133 : [number] "i" (@intFromEnum(SYS.rt_sigreturn)),
130 : [number] "I" (@intFromEnum(SYS.rt_sigreturn)),
134131 : "memory"
135 );
136 unreachable;
132 ),
133 else => asm volatile (
134 \\ svc #0
135 :
136 : [number] "{r7}" (@intFromEnum(SYS.rt_sigreturn)),
137 : "memory"
138 ),
137139 }
138
139 asm volatile ("svc #0"
140 :
141 : [number] "{r7}" (@intFromEnum(SYS.rt_sigreturn)),
142 : "memory"
143 );
144140}
145141
146142pub const MMAP2_UNIT = 4096;
lib/std/os/linux/arm64.zig+10-13
......@@ -105,25 +105,22 @@ pub extern fn clone(func: CloneFn, stack: usize, flags: u32, arg: usize, ptid: *
105105
106106pub const restore = restore_rt;
107107
108pub fn restore_rt() callconv(.Naked) void {
109 if (@import("builtin").zig_backend == .stage2_c) {
110 asm volatile (
108pub fn restore_rt() callconv(.Naked) noreturn {
109 switch (@import("builtin").zig_backend) {
110 .stage2_c => asm volatile (
111111 \\ mov x8, %[number]
112112 \\ svc #0
113 \\ ret
114113 :
115114 : [number] "i" (@intFromEnum(SYS.rt_sigreturn)),
116115 : "memory", "cc"
117 );
118 unreachable;
116 ),
117 else => asm volatile (
118 \\ svc #0
119 :
120 : [number] "{x8}" (@intFromEnum(SYS.rt_sigreturn)),
121 : "memory", "cc"
122 ),
119123 }
120
121 asm volatile (
122 \\ svc #0
123 :
124 : [number] "{x8}" (@intFromEnum(SYS.rt_sigreturn)),
125 : "memory", "cc"
126 );
127124}
128125
129126pub const O = struct {
lib/std/os/linux/mips.zig+6-4
......@@ -195,16 +195,18 @@ const CloneFn = *const fn (arg: usize) callconv(.C) u8;
195195/// This matches the libc clone function.
196196pub extern fn clone(func: CloneFn, stack: usize, flags: u32, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize;
197197
198pub fn restore() callconv(.Naked) void {
199 return asm volatile ("syscall"
198pub fn restore() callconv(.Naked) noreturn {
199 asm volatile (
200 \\ syscall
200201 :
201202 : [number] "{$2}" (@intFromEnum(SYS.sigreturn)),
202203 : "$1", "$3", "$4", "$5", "$6", "$7", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$24", "$25", "hi", "lo", "memory"
203204 );
204205}
205206
206pub fn restore_rt() callconv(.Naked) void {
207 return asm volatile ("syscall"
207pub fn restore_rt() callconv(.Naked) noreturn {
208 asm volatile (
209 \\ syscall
208210 :
209211 : [number] "{$2}" (@intFromEnum(SYS.rt_sigreturn)),
210212 : "$1", "$3", "$4", "$5", "$6", "$7", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$24", "$25", "hi", "lo", "memory"
lib/std/os/linux/mips64.zig+6-4
......@@ -180,16 +180,18 @@ const CloneFn = *const fn (arg: usize) callconv(.C) u8;
180180/// This matches the libc clone function.
181181pub extern fn clone(func: CloneFn, stack: usize, flags: u32, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize;
182182
183pub fn restore() callconv(.Naked) void {
184 return asm volatile ("syscall"
183pub fn restore() callconv(.Naked) noreturn {
184 asm volatile (
185 \\ syscall
185186 :
186187 : [number] "{$2}" (@intFromEnum(SYS.rt_sigreturn)),
187188 : "$1", "$3", "$4", "$5", "$6", "$7", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$24", "$25", "hi", "lo", "memory"
188189 );
189190}
190191
191pub fn restore_rt() callconv(.Naked) void {
192 return asm volatile ("syscall"
192pub fn restore_rt() callconv(.Naked) noreturn {
193 asm volatile (
194 \\ syscall
193195 :
194196 : [number] "{$2}" (@intFromEnum(SYS.rt_sigreturn)),
195197 : "$1", "$3", "$4", "$5", "$6", "$7", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$24", "$25", "hi", "lo", "memory"
lib/std/os/linux/powerpc.zig+3-2
......@@ -133,8 +133,9 @@ pub extern fn clone(func: CloneFn, stack: usize, flags: usize, arg: usize, ptid:
133133
134134pub const restore = restore_rt;
135135
136pub fn restore_rt() callconv(.Naked) void {
137 return asm volatile ("sc"
136pub fn restore_rt() callconv(.Naked) noreturn {
137 asm volatile (
138 \\ sc
138139 :
139140 : [number] "{r0}" (@intFromEnum(SYS.rt_sigreturn)),
140141 : "memory", "cr0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12"
lib/std/os/linux/powerpc64.zig+3-2
......@@ -133,8 +133,9 @@ pub extern fn clone(func: CloneFn, stack: usize, flags: usize, arg: usize, ptid:
133133
134134pub const restore = restore_rt;
135135
136pub fn restore_rt() callconv(.Naked) void {
137 return asm volatile ("sc"
136pub fn restore_rt() callconv(.Naked) noreturn {
137 asm volatile (
138 \\ sc
138139 :
139140 : [number] "{r0}" (@intFromEnum(SYS.rt_sigreturn)),
140141 : "memory", "cr0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12"
lib/std/os/linux/riscv64.zig+3-2
......@@ -101,8 +101,9 @@ pub extern fn clone(func: CloneFn, stack: usize, flags: u32, arg: usize, ptid: *
101101
102102pub const restore = restore_rt;
103103
104pub fn restore_rt() callconv(.Naked) void {
105 return asm volatile ("ecall"
104pub fn restore_rt() callconv(.Naked) noreturn {
105 asm volatile (
106 \\ ecall
106107 :
107108 : [number] "{x17}" (@intFromEnum(SYS.rt_sigreturn)),
108109 : "memory"
lib/std/os/linux/thumb.zig+4-4
......@@ -141,8 +141,8 @@ pub fn syscall6(
141141 );
142142}
143143
144pub fn restore() callconv(.Naked) void {
145 return asm volatile (
144pub fn restore() callconv(.Naked) noreturn {
145 asm volatile (
146146 \\ mov r7, %[number]
147147 \\ svc #0
148148 :
......@@ -150,8 +150,8 @@ pub fn restore() callconv(.Naked) void {
150150 );
151151}
152152
153pub fn restore_rt() callconv(.Naked) void {
154 return asm volatile (
153pub fn restore_rt() callconv(.Naked) noreturn {
154 asm volatile (
155155 \\ mov r7, %[number]
156156 \\ svc #0
157157 :
lib/std/os/linux/tls.zig+3-3
......@@ -48,7 +48,7 @@ const TLSVariant = enum {
4848};
4949
5050const tls_variant = switch (native_arch) {
51 .arm, .armeb, .thumb, .aarch64, .aarch64_be, .riscv32, .riscv64, .mips, .mipsel, .mips64, .mips64el, .powerpc, .powerpc64, .powerpc64le => TLSVariant.VariantI,
51 .arm, .armeb, .thumb, .aarch64, .aarch64_be, .riscv32, .riscv64, .mips, .mipsel, .mips64, .mips64el, .powerpc, .powerpcle, .powerpc64, .powerpc64le => TLSVariant.VariantI,
5252 .x86_64, .x86, .sparc64 => TLSVariant.VariantII,
5353 else => @compileError("undefined tls_variant for this architecture"),
5454};
......@@ -140,7 +140,7 @@ pub fn setThreadPointer(addr: usize) void {
140140 const rc = std.os.linux.syscall2(.arch_prctl, std.os.linux.ARCH.SET_FS, addr);
141141 assert(rc == 0);
142142 },
143 .aarch64 => {
143 .aarch64, .aarch64_be => {
144144 asm volatile (
145145 \\ msr tpidr_el0, %[addr]
146146 :
......@@ -162,7 +162,7 @@ pub fn setThreadPointer(addr: usize) void {
162162 const rc = std.os.linux.syscall1(.set_thread_area, addr);
163163 assert(rc == 0);
164164 },
165 .powerpc => {
165 .powerpc, .powerpcle => {
166166 asm volatile (
167167 \\ mr 2, %[addr]
168168 :
lib/std/os/linux/x86.zig+23-28
......@@ -123,46 +123,40 @@ const CloneFn = *const fn (arg: usize) callconv(.C) u8;
123123/// This matches the libc clone function.
124124pub extern fn clone(func: CloneFn, stack: usize, flags: u32, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize;
125125
126pub fn restore() callconv(.Naked) void {
127 if (@import("builtin").zig_backend == .stage2_c) {
128 asm volatile (
126pub fn restore() callconv(.Naked) noreturn {
127 switch (@import("builtin").zig_backend) {
128 .stage2_c => asm volatile (
129129 \\ movl %[number], %%eax
130130 \\ int $0x80
131 \\ retl
132131 :
133132 : [number] "i" (@intFromEnum(SYS.sigreturn)),
134133 : "memory"
135 );
136 unreachable;
134 ),
135 else => asm volatile (
136 \\ int $0x80
137 :
138 : [number] "{eax}" (@intFromEnum(SYS.sigreturn)),
139 : "memory"
140 ),
137141 }
138
139 asm volatile (
140 \\ int $0x80
141 :
142 : [number] "{eax}" (@intFromEnum(SYS.sigreturn)),
143 : "memory"
144 );
145142}
146143
147pub fn restore_rt() callconv(.Naked) void {
148 if (@import("builtin").zig_backend == .stage2_c) {
149 asm volatile (
144pub fn restore_rt() callconv(.Naked) noreturn {
145 switch (@import("builtin").zig_backend) {
146 .stage2_c => asm volatile (
150147 \\ movl %[number], %%eax
151148 \\ int $0x80
152 \\ retl
153149 :
154150 : [number] "i" (@intFromEnum(SYS.rt_sigreturn)),
155151 : "memory"
156 );
157 unreachable;
152 ),
153 else => asm volatile (
154 \\ int $0x80
155 :
156 : [number] "{eax}" (@intFromEnum(SYS.rt_sigreturn)),
157 : "memory"
158 ),
158159 }
159
160 asm volatile (
161 \\ int $0x80
162 :
163 : [number] "{eax}" (@intFromEnum(SYS.rt_sigreturn)),
164 : "memory"
165 );
166160}
167161
168162pub const O = struct {
......@@ -401,7 +395,7 @@ noinline fn getContextReturnAddress() usize {
401395 return @returnAddress();
402396}
403397
404pub fn getContextInternal() callconv(.Naked) void {
398pub fn getContextInternal() callconv(.Naked) usize {
405399 asm volatile (
406400 \\ movl $0, %[flags_offset:c](%%edx)
407401 \\ movl $0, %[link_offset:c](%%edx)
......@@ -439,6 +433,7 @@ pub fn getContextInternal() callconv(.Naked) void {
439433 \\0:
440434 \\ popl %%esi
441435 \\ popl %%ebx
436 \\ retl
442437 :
443438 : [flags_offset] "i" (@offsetOf(ucontext_t, "flags")),
444439 [link_offset] "i" (@offsetOf(ucontext_t, "link")),
......@@ -466,7 +461,7 @@ pub fn getContextInternal() callconv(.Naked) void {
466461pub inline fn getcontext(context: *ucontext_t) usize {
467462 // This method is used so that getContextInternal can control
468463 // its prologue in order to read ESP from a constant offset.
469 // The unused &getContextInternal input is required so the function is included in the binary.
464 // An aligned stack is not needed for getContextInternal.
470465 var clobber_edx: usize = undefined;
471466 return asm volatile (
472467 \\ calll %[getContextInternal:P]
lib/std/os/linux/x86_64.zig+13-15
......@@ -107,25 +107,22 @@ pub extern fn clone(func: CloneFn, stack: usize, flags: usize, arg: usize, ptid:
107107
108108pub const restore = restore_rt;
109109
110pub fn restore_rt() callconv(.Naked) void {
111 if (@import("builtin").zig_backend == .stage2_c) {
112 asm volatile (
110pub fn restore_rt() callconv(.Naked) noreturn {
111 switch (@import("builtin").zig_backend) {
112 .stage2_c => asm volatile (
113113 \\ movl %[number], %%eax
114114 \\ syscall
115 \\ retq
116115 :
117116 : [number] "i" (@intFromEnum(SYS.rt_sigreturn)),
118117 : "rcx", "r11", "memory"
119 );
120 unreachable;
118 ),
119 else => asm volatile (
120 \\ syscall
121 :
122 : [number] "{rax}" (@intFromEnum(SYS.rt_sigreturn)),
123 : "rcx", "r11", "memory"
124 ),
121125 }
122
123 asm volatile (
124 \\ syscall
125 :
126 : [number] "{rax}" (@intFromEnum(SYS.rt_sigreturn)),
127 : "rcx", "r11", "memory"
128 );
129126}
130127
131128pub const mode_t = usize;
......@@ -400,7 +397,7 @@ fn gpRegisterOffset(comptime reg_index: comptime_int) usize {
400397 return @offsetOf(ucontext_t, "mcontext") + @offsetOf(mcontext_t, "gregs") + @sizeOf(usize) * reg_index;
401398}
402399
403fn getContextInternal() callconv(.Naked) void {
400fn getContextInternal() callconv(.Naked) usize {
404401 // TODO: Read GS/FS registers?
405402 asm volatile (
406403 \\ movq $0, %[flags_offset:c](%%rdi)
......@@ -444,6 +441,7 @@ fn getContextInternal() callconv(.Naked) void {
444441 \\ movl %[sigset_size], %%r10d
445442 \\ syscall
446443 \\0:
444 \\ retq
447445 :
448446 : [flags_offset] "i" (@offsetOf(ucontext_t, "flags")),
449447 [link_offset] "i" (@offsetOf(ucontext_t, "link")),
......@@ -480,7 +478,7 @@ fn getContextInternal() callconv(.Naked) void {
480478pub inline fn getcontext(context: *ucontext_t) usize {
481479 // This method is used so that getContextInternal can control
482480 // its prologue in order to read RSP from a constant offset
483 // The unused &getContextInternal input is required so the function is included in the binary.
481 // An aligned stack is not needed for getContextInternal.
484482 var clobber_rdi: usize = undefined;
485483 return asm volatile (
486484 \\ callq %[getContextInternal:P]
lib/std/start.zig+86-112
......@@ -101,7 +101,7 @@ fn main2() callconv(.C) c_int {
101101 return 0;
102102}
103103
104fn _start2() callconv(.Naked) noreturn {
104fn _start2() noreturn {
105105 callMain2();
106106}
107107
......@@ -254,116 +254,92 @@ fn EfiMain(handle: uefi.Handle, system_table: *uefi.tables.SystemTable) callconv
254254}
255255
256256fn _start() callconv(.Naked) noreturn {
257 switch (builtin.zig_backend) {
258 .stage2_c => {
259 asm volatile (switch (native_arch) {
260 .x86_64 =>
261 \\ xorl %%ebp, %%ebp
262 \\ movq %%rsp, %[argc_argv_ptr]
263 \\ andq $-16, %%rsp
264 \\ callq %[posixCallMainAndExit:P]
265 ,
266 .x86 =>
267 \\ xorl %%ebp, %%ebp
268 \\ movl %%esp, %[argc_argv_ptr]
269 \\ andl $-16, %%esp
270 \\ calll %[posixCallMainAndExit:P]
271 ,
272 .aarch64, .aarch64_be =>
273 \\ mov fp, #0
274 \\ mov lr, #0
275 \\ mov x0, sp
276 \\ str x0, %[argc_argv_ptr]
277 \\ b %[posixCallMainAndExit]
278 ,
279 .arm, .armeb, .thumb =>
280 \\ mov fp, #0
281 \\ mov lr, #0
282 \\ str sp, %[argc_argv_ptr]
283 \\ and sp, #-16
284 \\ b %[posixCallMainAndExit]
285 ,
286 else => @compileError("unsupported arch"),
287 }
288 : [argc_argv_ptr] "=m" (argc_argv_ptr),
289 : [posixCallMainAndExit] "X" (&posixCallMainAndExit),
290 );
291 unreachable;
292 },
293 else => switch (native_arch) {
294 .x86_64 => {
295 argc_argv_ptr = asm volatile (
296 \\ xor %%ebp, %%ebp
297 : [argc] "={rsp}" (-> [*]usize),
298 );
299 },
300 .x86 => {
301 argc_argv_ptr = asm volatile (
302 \\ xor %%ebp, %%ebp
303 : [argc] "={esp}" (-> [*]usize),
304 );
305 },
306 .aarch64, .aarch64_be, .arm, .armeb, .thumb => {
307 argc_argv_ptr = asm volatile (
308 \\ mov fp, #0
309 \\ mov lr, #0
310 : [argc] "={sp}" (-> [*]usize),
311 );
312 },
313 .riscv64 => {
314 argc_argv_ptr = asm volatile (
315 \\ li s0, 0
316 \\ li ra, 0
317 : [argc] "={sp}" (-> [*]usize),
318 );
319 },
320 .mips, .mipsel, .mips64, .mips64el => {
321 // The lr is already zeroed on entry, as specified by the ABI.
322 argc_argv_ptr = asm volatile (
323 \\ move $fp, $0
324 : [argc] "={sp}" (-> [*]usize),
325 );
326 },
327 .powerpc => {
328 // Setup the initial stack frame and clear the back chain pointer.
329 argc_argv_ptr = asm volatile (
330 \\ mr 4, 1
331 \\ li 0, 0
332 \\ stwu 1,-16(1)
333 \\ stw 0, 0(1)
334 \\ mtlr 0
335 : [argc] "={r4}" (-> [*]usize),
336 :
337 : "r0"
338 );
339 },
340 .powerpc64le => {
341 // Setup the initial stack frame and clear the back chain pointer.
342 // TODO: Support powerpc64 (big endian) on ELFv2.
343 argc_argv_ptr = asm volatile (
344 \\ mr 4, 1
345 \\ li 0, 0
346 \\ stdu 0, -32(1)
347 \\ mtlr 0
348 : [argc] "={r4}" (-> [*]usize),
349 :
350 : "r0"
351 );
352 },
353 .sparc64 => {
354 // argc is stored after a register window (16 registers) plus stack bias
355 argc_argv_ptr = asm (
356 \\ mov %%g0, %%i6
357 \\ add %%o6, 2175, %[argc]
358 : [argc] "=r" (-> [*]usize),
359 );
360 },
257 asm volatile (switch (native_arch) {
258 .x86_64 =>
259 \\ xorl %%ebp, %%ebp
260 \\ movq %%rsp, %[argc_argv_ptr]
261 \\ andq $-16, %%rsp
262 \\ callq %[posixCallMainAndExit:P]
263 ,
264 .x86 =>
265 \\ xorl %%ebp, %%ebp
266 \\ movl %%esp, %[argc_argv_ptr]
267 \\ andl $-16, %%esp
268 \\ calll %[posixCallMainAndExit:P]
269 ,
270 .aarch64, .aarch64_be =>
271 \\ mov fp, #0
272 \\ mov lr, #0
273 \\ mov x0, sp
274 \\ str x0, %[argc_argv_ptr]
275 \\ b %[posixCallMainAndExit]
276 ,
277 .arm, .armeb, .thumb, .thumbeb =>
278 \\ mov fp, #0
279 \\ mov lr, #0
280 \\ str sp, %[argc_argv_ptr]
281 \\ and sp, #-16
282 \\ b %[posixCallMainAndExit]
283 ,
284 .riscv64 =>
285 \\ li s0, 0
286 \\ li ra, 0
287 \\ sd sp, %[argc_argv_ptr]
288 \\ andi sp, sp, -16
289 \\ tail %[posixCallMainAndExit]@plt
290 ,
291 .mips, .mipsel =>
292 // The lr is already zeroed on entry, as specified by the ABI.
293 \\ addiu $fp, $zero, 0
294 \\ sw $sp, %[argc_argv_ptr]
295 \\ .set push
296 \\ .set noat
297 \\ addiu $1, $zero, -16
298 \\ and $sp, $sp, $1
299 \\ .set pop
300 \\ j %[posixCallMainAndExit]
301 ,
302 .mips64, .mips64el =>
303 // The lr is already zeroed on entry, as specified by the ABI.
304 \\ addiu $fp, $zero, 0
305 \\ sd $sp, %[argc_argv_ptr]
306 \\ .set push
307 \\ .set noat
308 \\ daddiu $1, $zero, -16
309 \\ and $sp, $sp, $1
310 \\ .set pop
311 \\ j %[posixCallMainAndExit]
312 ,
313 .powerpc, .powerpcle =>
314 // Setup the initial stack frame and clear the back chain pointer.
315 \\ stw 1, %[argc_argv_ptr]
316 \\ li 0, 0
317 \\ stwu 1, -16(1)
318 \\ stw 0, 0(1)
319 \\ mtlr 0
320 \\ b %[posixCallMainAndExit]
321 ,
322 .powerpc64, .powerpc64le =>
323 // Setup the initial stack frame and clear the back chain pointer.
324 // TODO: Support powerpc64 (big endian) on ELFv2.
325 \\ std 1, %[argc_argv_ptr]
326 \\ li 0, 0
327 \\ stdu 0, -32(1)
328 \\ mtlr 0
329 \\ b %[posixCallMainAndExit]
330 ,
331 .sparc64 =>
332 // argc is stored after a register window (16 registers) plus stack bias
333 \\ mov %%g0, %%i6
334 \\ add %%o6, 2175, %%l0
335 \\ stx %%l0, %[argc_argv_ptr]
336 \\ ba %[posixCallMainAndExit]
337 ,
361338 else => @compileError("unsupported arch"),
362 },
363 }
364 // If LLVM inlines stack variables into _start, they will overwrite
365 // the command line argument data.
366 @call(.never_inline, posixCallMainAndExit, .{});
339 }
340 : [argc_argv_ptr] "=m" (argc_argv_ptr),
341 : [posixCallMainAndExit] "X" (&posixCallMainAndExit),
342 );
367343}
368344
369345fn WinStartup() callconv(std.os.windows.WINAPI) noreturn {
......@@ -390,8 +366,6 @@ fn wWinMainCRTStartup() callconv(std.os.windows.WINAPI) noreturn {
390366}
391367
392368fn posixCallMainAndExit() callconv(.C) noreturn {
393 @setAlignStack(16);
394
395369 const argc = argc_argv_ptr[0];
396370 const argv = @as([*][*:0]u8, @ptrCast(argc_argv_ptr + 1));
397371
lib/std/target.zig+5
......@@ -899,6 +899,10 @@ pub const Target = struct {
899899 };
900900 }
901901
902 pub fn isArmOrThumb(arch: Arch) bool {
903 return arch.isARM() or arch.isThumb();
904 }
905
902906 pub fn isWasm(arch: Arch) bool {
903907 return switch (arch) {
904908 .wasm32, .wasm64 => true,
......@@ -1960,6 +1964,7 @@ pub const Target = struct {
19601964 .thumbeb,
19611965 => return if (target.os.tag.isDarwin() or target.os.tag == .windows) .signed else .unsigned,
19621966 .powerpc, .powerpc64 => return if (target.os.tag.isDarwin()) .signed else .unsigned,
1967 .powerpcle,
19631968 .powerpc64le,
19641969 .s390x,
19651970 .xcore,
src/arch/x86_64/CodeGen.zig+155-54
......@@ -177,7 +177,7 @@ pub const MCValue = union(enum) {
177177 /// The value is a tuple { wrapped, overflow } where wrapped value is stored in the GP register.
178178 register_overflow: struct { reg: Register, eflags: Condition },
179179 /// The value is in memory at a hard-coded address.
180 /// If the type is a pointer, it means the pointer address is at this memory location.
180 /// If the type is a pointer, it means the pointer address is stored at this memory location.
181181 memory: u64,
182182 /// The value is in memory at a constant offset from the address in a register.
183183 indirect: RegisterOffset,
......@@ -300,7 +300,7 @@ pub const MCValue = union(enum) {
300300 .load_tlv,
301301 .load_frame,
302302 .reserved_frame,
303 => unreachable, // not a dereferenceable
303 => unreachable, // not dereferenceable
304304 .immediate => |addr| .{ .memory = addr },
305305 .register => |reg| .{ .indirect = .{ .reg = reg } },
306306 .register_offset => |reg_off| .{ .indirect = reg_off },
......@@ -3468,14 +3468,14 @@ fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCVa
34683468 const mod = self.bin_file.options.module.?;
34693469 const abi_size: u32 = @intCast(ty.abiSize(mod));
34703470 const int_info = ty.intInfo(mod);
3471 const dividend: Register = switch (lhs) {
3471 const dividend = switch (lhs) {
34723472 .register => |reg| reg,
34733473 else => try self.copyToTmpRegister(ty, lhs),
34743474 };
34753475 const dividend_lock = self.register_manager.lockReg(dividend);
34763476 defer if (dividend_lock) |lock| self.register_manager.unlockReg(lock);
34773477
3478 const divisor: Register = switch (rhs) {
3478 const divisor = switch (rhs) {
34793479 .register => |reg| reg,
34803480 else => try self.copyToTmpRegister(ty, rhs),
34813481 };
......@@ -9184,6 +9184,7 @@ fn airBr(self: *Self, inst: Air.Inst.Index) !void {
91849184}
91859185
91869186fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
9187 const mod = self.bin_file.options.module.?;
91879188 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
91889189 const extra = self.air.extraData(Air.Asm, ty_pl.payload);
91899190 const clobbers_len: u31 = @truncate(extra.data.flags);
......@@ -9196,23 +9197,15 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
91969197
91979198 var result: MCValue = .none;
91989199 var args = std.StringArrayHashMap(MCValue).init(self.gpa);
9199 try args.ensureTotalCapacity(outputs.len + inputs.len + clobbers_len);
9200 try args.ensureTotalCapacity(outputs.len + inputs.len);
92009201 defer {
9201 for (args.values()) |arg| switch (arg) {
9202 .register => |reg| self.register_manager.unlockReg(.{ .register = reg }),
9203 else => {},
9204 };
9202 for (args.values()) |arg| if (arg.getReg()) |reg|
9203 self.register_manager.unlockReg(.{ .register = reg });
92059204 args.deinit();
92069205 }
92079206
9208 if (outputs.len > 1) {
9209 return self.fail("TODO implement codegen for asm with more than 1 output", .{});
9210 }
9211
9207 var outputs_extra_i = extra_i;
92129208 for (outputs) |output| {
9213 if (output != .none) {
9214 return self.fail("TODO implement codegen for non-expr asm", .{});
9215 }
92169209 const extra_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);
92179210 const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0);
92189211 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
......@@ -9220,21 +9213,48 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
92209213 // for the string, we still use the next u32 for the null terminator.
92219214 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
92229215
9223 const mcv: MCValue = if (mem.eql(u8, constraint, "=r"))
9224 .{ .register = self.register_manager.tryAllocReg(inst, gp) orelse
9225 return self.fail("ran out of registers lowering inline asm", .{}) }
9216 const maybe_inst = switch (output) {
9217 .none => inst,
9218 else => null,
9219 };
9220 const ty = switch (output) {
9221 .none => self.typeOfIndex(inst),
9222 else => self.typeOf(output).childType(mod),
9223 };
9224 const arg_maybe_reg: ?Register = if (mem.eql(u8, constraint, "=r"))
9225 self.register_manager.tryAllocReg(maybe_inst, regClassForType(ty, mod)) orelse
9226 return self.fail("ran out of registers lowering inline asm", .{})
9227 else if (mem.eql(u8, constraint, "=m"))
9228 if (output != .none) null else return self.fail(
9229 "memory constraint unsupported for asm result",
9230 .{},
9231 )
9232 else if (mem.eql(u8, constraint, "=g"))
9233 self.register_manager.tryAllocReg(maybe_inst, regClassForType(ty, mod)) orelse
9234 if (output != .none) null else return self.fail(
9235 "ran out of register lowering inline asm",
9236 .{},
9237 )
92269238 else if (mem.startsWith(u8, constraint, "={") and mem.endsWith(u8, constraint, "}"))
9227 .{ .register = parseRegName(constraint["={".len .. constraint.len - "}".len]) orelse
9228 return self.fail("unrecognized register constraint: '{s}'", .{constraint}) }
9239 parseRegName(constraint["={".len .. constraint.len - "}".len]) orelse
9240 return self.fail("invalid register constraint: '{s}'", .{constraint})
92299241 else
9230 return self.fail("unrecognized constraint: '{s}'", .{constraint});
9231 args.putAssumeCapacity(name, mcv);
9232 switch (mcv) {
9233 .register => |reg| _ = if (RegisterManager.indexOfRegIntoTracked(reg)) |_|
9234 self.register_manager.lockRegAssumeUnused(reg),
9235 else => {},
9236 }
9237 if (output == .none) result = mcv;
9242 return self.fail("invalid constraint: '{s}'", .{constraint});
9243 const arg_mcv: MCValue = if (arg_maybe_reg) |reg| .{ .register = reg } else arg: {
9244 const ptr_mcv = try self.resolveInst(output);
9245 switch (ptr_mcv) {
9246 .immediate => |addr| if (math.cast(i32, @as(i64, @bitCast(addr)))) |_|
9247 break :arg ptr_mcv.deref(),
9248 .register, .register_offset, .lea_frame => break :arg ptr_mcv.deref(),
9249 else => {},
9250 }
9251 break :arg .{ .indirect = .{ .reg = try self.copyToTmpRegister(Type.usize, ptr_mcv) } };
9252 };
9253 if (arg_mcv.getReg()) |reg| if (RegisterManager.indexOfRegIntoTracked(reg)) |_| {
9254 _ = self.register_manager.lockRegAssumeUnused(reg);
9255 };
9256 args.putAssumeCapacity(name, arg_mcv);
9257 if (output == .none) result = arg_mcv;
92389258 }
92399259
92409260 for (inputs) |input| {
......@@ -9245,16 +9265,53 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
92459265 // for the string, we still use the next u32 for the null terminator.
92469266 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
92479267
9248 if (constraint.len < 3 or constraint[0] != '{' or constraint[constraint.len - 1] != '}') {
9249 return self.fail("unrecognized asm input constraint: '{s}'", .{constraint});
9250 }
9251 const reg_name = constraint[1 .. constraint.len - 1];
9252 const reg = parseRegName(reg_name) orelse
9253 return self.fail("unrecognized register: '{s}'", .{reg_name});
9254
9255 const arg_mcv = try self.resolveInst(input);
9256 try self.register_manager.getReg(reg, null);
9257 try self.genSetReg(reg, self.typeOf(input), arg_mcv);
9268 const ty = self.typeOf(input);
9269 const input_mcv = try self.resolveInst(input);
9270 const arg_mcv: MCValue = if (mem.eql(u8, constraint, "r")) switch (input_mcv) {
9271 .register => input_mcv,
9272 else => .{ .register = try self.copyToTmpRegister(ty, input_mcv) },
9273 } else if (mem.eql(u8, constraint, "m")) arg: {
9274 switch (input_mcv) {
9275 .memory => |addr| if (math.cast(i32, @as(i64, @bitCast(addr)))) |_|
9276 break :arg input_mcv,
9277 .indirect, .load_frame => break :arg input_mcv,
9278 .load_direct, .load_got, .load_tlv => {},
9279 else => {
9280 const temp_mcv = try self.allocTempRegOrMem(ty, false);
9281 try self.genCopy(ty, temp_mcv, input_mcv);
9282 break :arg temp_mcv;
9283 },
9284 }
9285 const addr_reg = self.register_manager.tryAllocReg(null, gp) orelse {
9286 const temp_mcv = try self.allocTempRegOrMem(ty, false);
9287 try self.genCopy(ty, temp_mcv, input_mcv);
9288 break :arg temp_mcv;
9289 };
9290 try self.genSetReg(addr_reg, Type.usize, input_mcv.address());
9291 break :arg .{ .indirect = .{ .reg = addr_reg } };
9292 } else if (mem.eql(u8, constraint, "g")) arg: {
9293 switch (input_mcv) {
9294 .register, .indirect, .load_frame => break :arg input_mcv,
9295 .memory => |addr| if (math.cast(i32, @as(i64, @bitCast(addr)))) |_|
9296 break :arg input_mcv,
9297 else => {},
9298 }
9299 const temp_mcv = try self.allocTempRegOrMem(ty, true);
9300 try self.genCopy(ty, temp_mcv, input_mcv);
9301 break :arg temp_mcv;
9302 } else if (mem.eql(u8, constraint, "X"))
9303 input_mcv
9304 else if (mem.startsWith(u8, constraint, "{") and mem.endsWith(u8, constraint, "}")) arg: {
9305 const reg = parseRegName(constraint["{".len .. constraint.len - "}".len]) orelse
9306 return self.fail("invalid register constraint: '{s}'", .{constraint});
9307 try self.register_manager.getReg(reg, null);
9308 try self.genSetReg(reg, ty, input_mcv);
9309 break :arg .{ .register = reg };
9310 } else return self.fail("invalid constraint: '{s}'", .{constraint});
9311 if (arg_mcv.getReg()) |reg| if (RegisterManager.indexOfRegIntoTracked(reg)) |_| {
9312 _ = self.register_manager.lockReg(reg);
9313 };
9314 args.putAssumeCapacity(name, arg_mcv);
92589315 }
92599316
92609317 {
......@@ -9293,7 +9350,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
92939350 }
92949351 }
92959352 break :mnem std.meta.stringToEnum(Mir.Inst.Tag, mnem_str) orelse
9296 return self.fail("Invalid mnemonic: '{s}'", .{mnem_str});
9353 return self.fail("invalid mnemonic: '{s}'", .{mnem_str});
92979354 } };
92989355
92999356 var op_it = mem.tokenizeScalar(u8, mnem_it.rest(), ',');
......@@ -9304,43 +9361,73 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
93049361 if (mem.startsWith(u8, op_str, "%%")) {
93059362 const colon = mem.indexOfScalarPos(u8, op_str, "%%".len + 2, ':');
93069363 const reg = parseRegName(op_str["%%".len .. colon orelse op_str.len]) orelse
9307 return self.fail("Invalid register: '{s}'", .{op_str});
9364 return self.fail("invalid register: '{s}'", .{op_str});
93089365 if (colon) |colon_pos| {
93099366 const disp = std.fmt.parseInt(i32, op_str[colon_pos + 1 ..], 0) catch
9310 return self.fail("Invalid displacement: '{s}'", .{op_str});
9367 return self.fail("invalid displacement: '{s}'", .{op_str});
93119368 op.* = .{ .mem = Memory.sib(
9312 mnem_size orelse return self.fail("Unknown size: '{s}'", .{op_str}),
9369 mnem_size orelse return self.fail("unknown size: '{s}'", .{op_str}),
93139370 .{ .base = .{ .reg = reg }, .disp = disp },
93149371 ) };
93159372 } else {
93169373 if (mnem_size) |size| if (reg.bitSize() != size.bitSize())
9317 return self.fail("Invalid register size: '{s}'", .{op_str});
9374 return self.fail("invalid register size: '{s}'", .{op_str});
93189375 op.* = .{ .reg = reg };
93199376 }
93209377 } else if (mem.startsWith(u8, op_str, "%[") and mem.endsWith(u8, op_str, "]")) {
9321 switch (args.get(op_str["%[".len .. op_str.len - "]".len]) orelse
9322 return self.fail("No matching constraint: '{s}'", .{op_str})) {
9323 .register => |reg| op.* = .{ .reg = reg },
9324 else => return self.fail("Invalid constraint: '{s}'", .{op_str}),
9325 }
9378 const colon = mem.indexOfScalarPos(u8, op_str, "%[".len, ':');
9379 const modifier = if (colon) |colon_pos|
9380 op_str[colon_pos + 1 .. op_str.len - "]".len]
9381 else
9382 "";
9383 op.* = switch (args.get(op_str["%[".len .. colon orelse op_str.len - "]".len]) orelse
9384 return self.fail("no matching constraint: '{s}'", .{op_str})) {
9385 .register => |reg| if (std.mem.eql(u8, modifier, ""))
9386 .{ .reg = reg }
9387 else
9388 return self.fail("invalid modifier: '{s}'", .{modifier}),
9389 .memory => |addr| if (std.mem.eql(u8, modifier, "") or
9390 std.mem.eql(u8, modifier, "P"))
9391 .{ .mem = Memory.sib(
9392 mnem_size orelse return self.fail("unknown size: '{s}'", .{op_str}),
9393 .{ .base = .{ .reg = .ds }, .disp = @intCast(@as(i64, @bitCast(addr))) },
9394 ) }
9395 else
9396 return self.fail("invalid modifier: '{s}'", .{modifier}),
9397 .indirect => |reg_off| if (std.mem.eql(u8, modifier, ""))
9398 .{ .mem = Memory.sib(
9399 mnem_size orelse return self.fail("unknown size: '{s}'", .{op_str}),
9400 .{ .base = .{ .reg = reg_off.reg }, .disp = reg_off.off },
9401 ) }
9402 else
9403 return self.fail("invalid modifier: '{s}'", .{modifier}),
9404 .load_frame => |frame_addr| if (std.mem.eql(u8, modifier, ""))
9405 .{ .mem = Memory.sib(
9406 mnem_size orelse return self.fail("unknown size: '{s}'", .{op_str}),
9407 .{ .base = .{ .frame = frame_addr.index }, .disp = frame_addr.off },
9408 ) }
9409 else
9410 return self.fail("invalid modifier: '{s}'", .{modifier}),
9411 else => return self.fail("invalid constraint: '{s}'", .{op_str}),
9412 };
93269413 } else if (mem.startsWith(u8, op_str, "$")) {
93279414 if (std.fmt.parseInt(i32, op_str["$".len..], 0)) |s| {
93289415 if (mnem_size) |size| {
93299416 const max = @as(u64, math.maxInt(u64)) >> @intCast(64 - (size.bitSize() - 1));
93309417 if ((if (s < 0) ~s else s) > max)
9331 return self.fail("Invalid immediate size: '{s}'", .{op_str});
9418 return self.fail("invalid immediate size: '{s}'", .{op_str});
93329419 }
93339420 op.* = .{ .imm = Immediate.s(s) };
93349421 } else |_| if (std.fmt.parseInt(u64, op_str["$".len..], 0)) |u| {
93359422 if (mnem_size) |size| {
93369423 const max = @as(u64, math.maxInt(u64)) >> @intCast(64 - size.bitSize());
93379424 if (u > max)
9338 return self.fail("Invalid immediate size: '{s}'", .{op_str});
9425 return self.fail("invalid immediate size: '{s}'", .{op_str});
93399426 }
93409427 op.* = .{ .imm = Immediate.u(u) };
9341 } else |_| return self.fail("Invalid immediate: '{s}'", .{op_str});
9342 } else return self.fail("Invalid operand: '{s}'", .{op_str});
9343 } else if (op_it.next()) |op_str| return self.fail("Extra operand: '{s}'", .{op_str});
9428 } else |_| return self.fail("invalid immediate: '{s}'", .{op_str});
9429 } else return self.fail("invalid operand: '{s}'", .{op_str});
9430 } else if (op_it.next()) |op_str| return self.fail("extra operand: '{s}'", .{op_str});
93449431
93459432 (switch (ops[0]) {
93469433 .none => self.asmOpOnly(mnem_tag),
......@@ -9407,6 +9494,20 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
94079494 };
94089495 }
94099496
9497 for (outputs, args.values()[0..outputs.len]) |output, mcv| {
9498 const extra_bytes = std.mem.sliceAsBytes(self.air.extra[outputs_extra_i..]);
9499 const constraint =
9500 std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[outputs_extra_i..]), 0);
9501 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
9502 // This equation accounts for the fact that even if we have exactly 4 bytes
9503 // for the string, we still use the next u32 for the null terminator.
9504 outputs_extra_i += (constraint.len + name.len + (2 + 3)) / 4;
9505
9506 if (output == .none) continue;
9507 if (mcv != .register) continue;
9508 try self.store(self.typeOf(output), try self.resolveInst(output), mcv);
9509 }
9510
94109511 simple: {
94119512 var buf = [1]Air.Inst.Ref{.none} ** (Liveness.bpi - 1);
94129513 var buf_index: usize = 0;
src/codegen/c.zig+2
......@@ -4770,9 +4770,11 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {
47704770}
47714771
47724772fn asmInputNeedsLocal(f: *Function, constraint: []const u8, value: CValue) bool {
4773 const target = f.object.dg.module.getTarget();
47734774 return switch (constraint[0]) {
47744775 '{' => true,
47754776 'i', 'r' => false,
4777 'I' => !target.cpu.arch.isArmOrThumb(),
47764778 else => switch (value) {
47774779 .constant => |val| switch (f.object.dg.module.intern_pool.indexToKey(val)) {
47784780 .ptr => |ptr| switch (ptr.addr) {
src/codegen/llvm.zig+9-7
......@@ -417,7 +417,7 @@ const DataLayoutBuilder = struct {
417417 if (idx != size) try writer.print(":{d}", .{idx});
418418 }
419419 }
420 if (self.target.cpu.arch.isARM() or self.target.cpu.arch.isThumb())
420 if (self.target.cpu.arch.isArmOrThumb())
421421 try writer.writeAll("-Fi8"); // for thumb interwork
422422 if (self.target.cpu.arch != .hexagon) {
423423 if (self.target.cpu.arch == .s390x) try self.typeAlignment(.integer, 1, 8, 8, false, writer);
......@@ -620,7 +620,7 @@ const DataLayoutBuilder = struct {
620620 else => {},
621621 }
622622 },
623 .vector => if (self.target.cpu.arch.isARM() or self.target.cpu.arch.isThumb()) {
623 .vector => if (self.target.cpu.arch.isArmOrThumb()) {
624624 switch (size) {
625625 128 => abi = 64,
626626 else => {},
......@@ -670,7 +670,7 @@ const DataLayoutBuilder = struct {
670670 else => {},
671671 },
672672 .aggregate => if (self.target.os.tag == .uefi or self.target.os.tag == .windows or
673 self.target.cpu.arch.isARM() or self.target.cpu.arch.isThumb())
673 self.target.cpu.arch.isArmOrThumb())
674674 {
675675 pref = @min(pref, self.target.ptrBitWidth());
676676 } else if (self.target.cpu.arch == .hexagon) {
......@@ -6809,8 +6809,6 @@ pub const FuncGen = struct {
68096809 }
68106810 llvm_constraints.appendAssumeCapacity('=');
68116811
6812 // Pass any non-return outputs indirectly, if the constraint accepts a memory location
6813 is_indirect.* = (output != .none) and constraintAllowsMemory(constraint);
68146812 if (output != .none) {
68156813 const output_inst = try self.resolveInst(output);
68166814 const output_ty = self.typeOf(output);
......@@ -6825,6 +6823,8 @@ pub const FuncGen = struct {
68256823 }),
68266824 }
68276825
6826 // Pass any non-return outputs indirectly, if the constraint accepts a memory location
6827 is_indirect.* = constraintAllowsMemory(constraint);
68286828 if (is_indirect.*) {
68296829 // Pass the result by reference as an indirect output (e.g. "=*m")
68306830 llvm_constraints.appendAssumeCapacity('*');
......@@ -6841,11 +6841,13 @@ pub const FuncGen = struct {
68416841 } else {
68426842 switch (constraint[0]) {
68436843 '=' => {},
6844 else => return self.todo("unsupported output constraint on result type '{c}'", .{
6845 constraint[0],
6844 else => return self.todo("unsupported output constraint on result type '{s}'", .{
6845 constraint,
68466846 }),
68476847 }
68486848
6849 is_indirect.* = false;
6850
68496851 const ret_ty = self.typeOfIndex(inst);
68506852 llvm_ret_types[llvm_ret_i] = try o.lowerType(ret_ty);
68516853 llvm_ret_i += 1;
src/link/Elf.zig+1-1
......@@ -1654,7 +1654,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
16541654 }
16551655
16561656 if (self.base.options.link_mode == .Static) {
1657 if (target.cpu.arch.isARM() or target.cpu.arch.isThumb()) {
1657 if (target.cpu.arch.isArmOrThumb()) {
16581658 try argv.append("-Bstatic");
16591659 } else {
16601660 try argv.append("-static");
test/behavior/bitcast.zig+1-1
......@@ -421,7 +421,7 @@ test "bitcast nan float does modify signaling bit" {
421421 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
422422 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
423423 // TODO: https://github.com/ziglang/zig/issues/14366
424 if (builtin.cpu.arch == .arm and builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
424 if (builtin.zig_backend == .stage2_llvm and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
425425
426426 // 16 bit
427427 const snan_f16_const = math.nan_f16;
test/behavior/call_tail.zig+10-1
......@@ -32,7 +32,16 @@ noinline fn insertionSort(data: []u64) void {
3232
3333test "arguments pointed to on stack into tailcall" {
3434 switch (builtin.cpu.arch) {
35 .wasm32, .mips, .mipsel, .powerpc, .powerpcle, .powerpc64le => return error.SkipZigTest,
35 .wasm32,
36 .mips,
37 .mipsel,
38 .mips64,
39 .mips64el,
40 .powerpc,
41 .powerpcle,
42 .powerpc64,
43 .powerpc64le,
44 => return error.SkipZigTest,
3645 else => {},
3746 }
3847 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
test/behavior/cast.zig+2-2
......@@ -123,7 +123,7 @@ test "@floatFromInt(f80)" {
123123 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
124124 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
125125 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
126 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch == .arm) return error.SkipZigTest;
126 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
127127
128128 const S = struct {
129129 fn doTheTest(comptime Int: type) !void {
......@@ -1370,7 +1370,7 @@ test "cast f16 to wider types" {
13701370 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
13711371 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13721372 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1373 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch == .arm) return error.SkipZigTest;
1373 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
13741374
13751375 const S = struct {
13761376 fn doTheTest() !void {
test/behavior/eval.zig+1-1
......@@ -533,7 +533,7 @@ test "runtime 128 bit integer division" {
533533 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
534534 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
535535 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
536 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch == .arm) return error.SkipZigTest;
536 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
537537
538538 var a: u128 = 152313999999999991610955792383;
539539 var b: u128 = 10000000000000000000;
test/behavior/floatop.zig+9-9
......@@ -554,7 +554,7 @@ test "another, possibly redundant, @fabs test" {
554554 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
555555 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
556556 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
557 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch == .arm) return error.SkipZigTest;
557 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
558558
559559 try testFabsLegacy(f128, 12.0);
560560 try comptime testFabsLegacy(f128, 12.0);
......@@ -577,7 +577,7 @@ test "@fabs f80" {
577577 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
578578 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
579579 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
580 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch == .arm) return error.SkipZigTest;
580 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
581581
582582 try testFabsLegacy(f80, 12.0);
583583 try comptime testFabsLegacy(f80, 12.0);
......@@ -595,7 +595,7 @@ test "a third @fabs test, surely there should not be three fabs tests" {
595595 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
596596 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
597597 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
598 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch == .arm) return error.SkipZigTest;
598 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
599599
600600 inline for ([_]type{ f16, f32, f64, f80, f128, c_longdouble }) |T| {
601601 // normals
......@@ -687,7 +687,7 @@ test "@floor f80" {
687687 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
688688 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
689689 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
690 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch == .arm) return error.SkipZigTest;
690 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
691691
692692 if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) {
693693 // https://github.com/ziglang/zig/issues/12602
......@@ -704,7 +704,7 @@ test "@floor f128" {
704704 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
705705 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
706706 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
707 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch == .arm) return error.SkipZigTest;
707 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
708708
709709 try testFloorLegacy(f128, 12.0);
710710 try comptime testFloorLegacy(f128, 12.0);
......@@ -785,7 +785,7 @@ test "@ceil f80" {
785785 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
786786 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
787787 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
788 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch == .arm) return error.SkipZigTest;
788 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
789789
790790 if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) {
791791 // https://github.com/ziglang/zig/issues/12602
......@@ -802,7 +802,7 @@ test "@ceil f128" {
802802 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
803803 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
804804 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
805 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch == .arm) return error.SkipZigTest;
805 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
806806
807807 try testCeilLegacy(f128, 12.0);
808808 try comptime testCeilLegacy(f128, 12.0);
......@@ -882,7 +882,7 @@ test "@trunc f80" {
882882 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
883883 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
884884 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
885 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch == .arm) return error.SkipZigTest;
885 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
886886
887887 if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) {
888888 // https://github.com/ziglang/zig/issues/12602
......@@ -905,7 +905,7 @@ test "@trunc f128" {
905905 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
906906 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
907907 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
908 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch == .arm) return error.SkipZigTest;
908 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
909909
910910 try testTruncLegacy(f128, 12.0);
911911 try comptime testTruncLegacy(f128, 12.0);
test/behavior/math.zig+4-4
......@@ -664,7 +664,7 @@ test "128-bit multiplication" {
664664 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
665665 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
666666 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
667 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch == .arm) return error.SkipZigTest;
667 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
668668
669669 {
670670 var a: i128 = 3;
......@@ -1312,7 +1312,7 @@ test "remainder division" {
13121312 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13131313 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
13141314 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1315 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch == .arm) return error.SkipZigTest;
1315 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
13161316
13171317 if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) {
13181318 // https://github.com/ziglang/zig/issues/12602
......@@ -1457,7 +1457,7 @@ test "@round f80" {
14571457 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
14581458 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
14591459 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1460 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch == .arm) return error.SkipZigTest;
1460 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
14611461
14621462 try testRound(f80, 12.0);
14631463 try comptime testRound(f80, 12.0);
......@@ -1470,7 +1470,7 @@ test "@round f128" {
14701470 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
14711471 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
14721472 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1473 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch == .arm) return error.SkipZigTest;
1473 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
14741474
14751475 try testRound(f128, 12.0);
14761476 try comptime testRound(f128, 12.0);
test/behavior/maximum_minimum.zig+1-1
......@@ -110,7 +110,7 @@ test "@min/max for floats" {
110110 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
111111 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
112112 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
113 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch == .arm) return error.SkipZigTest;
113 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
114114
115115 const S = struct {
116116 fn doTheTest(comptime T: type) !void {
test/behavior/muladd.zig+4-4
......@@ -56,7 +56,7 @@ test "@mulAdd f80" {
5656 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
5757 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
5858 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
59 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch == .arm) return error.SkipZigTest;
59 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
6060
6161 try comptime testMulAdd80();
6262 try testMulAdd80();
......@@ -76,7 +76,7 @@ test "@mulAdd f128" {
7676 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
7777 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
7878 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
79 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch == .arm) return error.SkipZigTest;
79 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
8080
8181 try comptime testMulAdd128();
8282 try testMulAdd128();
......@@ -179,7 +179,7 @@ test "vector f80" {
179179 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
180180 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
181181 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
182 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch == .arm) return error.SkipZigTest;
182 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
183183
184184 try comptime vector80();
185185 try vector80();
......@@ -204,7 +204,7 @@ test "vector f128" {
204204 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
205205 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
206206 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
207 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch == .arm) return error.SkipZigTest;
207 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
208208
209209 try comptime vector128();
210210 try vector128();
test/behavior/saturating_arithmetic.zig+1-1
......@@ -157,7 +157,7 @@ test "saturating multiplication" {
157157 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
158158 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
159159 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
160 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch == .arm) return error.SkipZigTest;
160 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
161161
162162 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .wasm32) {
163163 // https://github.com/ziglang/zig/issues/9660
test/behavior/struct.zig+3-3
......@@ -428,7 +428,7 @@ test "packed struct 24bits" {
428428 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
429429 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
430430 if (builtin.cpu.arch == .wasm32) return error.SkipZigTest; // TODO
431 if (builtin.cpu.arch == .arm) return error.SkipZigTest; // TODO
431 if (comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest; // TODO
432432 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
433433 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
434434
......@@ -824,7 +824,7 @@ test "non-packed struct with u128 entry in union" {
824824 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
825825 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
826826 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
827 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch == .arm) return error.SkipZigTest;
827 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
828828
829829 const U = union(enum) {
830830 Num: u128,
......@@ -945,7 +945,7 @@ test "comptime struct field" {
945945 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
946946
947947 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
948 if (builtin.cpu.arch == .arm) return error.SkipZigTest; // TODO
948 if (comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest; // TODO
949949
950950 const T = struct {
951951 a: i32,
test/behavior/var_args.zig+4-4
......@@ -101,7 +101,7 @@ test "simple variadic function" {
101101 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
102102 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
103103 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
104 if (builtin.cpu.arch == .aarch64 and builtin.os.tag != .macos) {
104 if (builtin.os.tag != .macos and comptime builtin.cpu.arch.isAARCH64()) {
105105 // https://github.com/ziglang/zig/issues/14096
106106 return error.SkipZigTest;
107107 }
......@@ -151,7 +151,7 @@ test "variadic functions" {
151151 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
152152 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
153153 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
154 if (builtin.cpu.arch == .aarch64 and builtin.os.tag != .macos) {
154 if (builtin.os.tag != .macos and comptime builtin.cpu.arch.isAARCH64()) {
155155 // https://github.com/ziglang/zig/issues/14096
156156 return error.SkipZigTest;
157157 }
......@@ -195,7 +195,7 @@ test "copy VaList" {
195195 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
196196 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
197197 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
198 if (builtin.cpu.arch == .aarch64 and builtin.os.tag != .macos) {
198 if (builtin.os.tag != .macos and comptime builtin.cpu.arch.isAARCH64()) {
199199 // https://github.com/ziglang/zig/issues/14096
200200 return error.SkipZigTest;
201201 }
......@@ -228,7 +228,7 @@ test "unused VaList arg" {
228228 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
229229 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
230230 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
231 if (builtin.cpu.arch == .aarch64 and builtin.os.tag != .macos) {
231 if (builtin.os.tag != .macos and comptime builtin.cpu.arch.isAARCH64()) {
232232 // https://github.com/ziglang/zig/issues/14096
233233 return error.SkipZigTest;
234234 }
test/behavior/vector.zig+3-2
......@@ -102,7 +102,7 @@ test "vector float operators" {
102102 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
103103 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
104104 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
105 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch == .arm) return error.SkipZigTest;
105 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
106106
107107 inline for ([_]type{ f16, f32, f64, f80, f128 }) |T| {
108108 const S = struct {
......@@ -495,6 +495,7 @@ test "vector division operators" {
495495 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
496496 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
497497 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
498 if (builtin.zig_backend == .stage2_llvm and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
498499 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
499500 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
500501
......@@ -706,7 +707,7 @@ test "vector reduce operation" {
706707 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
707708 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
708709 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
709 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch == .arm) return error.SkipZigTest;
710 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
710711
711712 const S = struct {
712713 fn testReduce(comptime op: std.builtin.ReduceOp, x: anytype, expected: anytype) !void {
test/src/Cases.zig+1-1
......@@ -1524,7 +1524,7 @@ fn runOneCase(
15241524 }
15251525 } else switch (host.getExternalExecutor(target_info, .{ .link_libc = case.link_libc })) {
15261526 .native => {
1527 if (case.backend == .stage2 and case.target.getCpuArch() == .arm) {
1527 if (case.backend == .stage2 and case.target.getCpuArch().isArmOrThumb()) {
15281528 // https://github.com/ziglang/zig/issues/13623
15291529 continue :update; // Pass test.
15301530 }