1const std = @import("std");
2const builtin = @import("builtin");
3const expect = std.testing.expect;
4const expectEqual = std.testing.expectEqual;
5
6const is_x86_64_linux = builtin.cpu.arch == .x86_64 and builtin.os.tag == .linux;
7
8comptime {
9 if (builtin.zig_backend != .stage2_arm and
10 !(builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) and // MSVC doesn't support inline assembly
11 is_x86_64_linux)
12 {
13 asm (
14 \\.globl this_is_my_alias;
15 );
16 // test multiple asm per comptime block
17 asm (
18 \\.type this_is_my_alias, @function;
19 \\.set this_is_my_alias, derp;
20 );
21 } else if (builtin.zig_backend == .stage2_spirv) {
22 asm (
23 \\%a = OpString "hello there"
24 );
25 }
26}
27
28test "module level assembly" {
29 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
30 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
31 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
32 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
33
34 if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // MSVC doesn't support inline assembly
35
36 if (is_x86_64_linux) {
37 try expect(this_is_my_alias() == 1234);
38 }
39}
40
41test "output constraint modifiers" {
42 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
43 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
44 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
45 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
46 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
47 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
48
49 if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // MSVC doesn't support inline assembly
50
51 // This is only testing compilation.
52 var a: u32 = 3;
53 asm volatile (""
54 : [_] "=m,r" (a),
55 :
56 : .{});
57 asm volatile (""
58 : [_] "=r,m" (a),
59 :
60 : .{});
61}
62
63test "alternative constraints" {
64 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
65 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
66 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
67 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
68 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
69 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
70
71 if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // MSVC doesn't support inline assembly
72
73 // Make sure we allow commas as a separator for alternative constraints.
74 var a: u32 = 3;
75 asm volatile (""
76 : [_] "=r,m" (a),
77 : [_] "r,m" (a),
78 );
79}
80
81test "sized integer/float in asm input" {
82 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
83 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
84 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
85 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
86
87 if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // MSVC doesn't support inline assembly
88
89 asm volatile (""
90 :
91 : [_] "m" (@as(usize, 3)),
92 );
93 asm volatile (""
94 :
95 : [_] "m" (@as(i15, -3)),
96 );
97 asm volatile (""
98 :
99 : [_] "m" (@as(u3, 3)),
100 );
101 asm volatile (""
102 :
103 : [_] "m" (@as(i3, 3)),
104 );
105 asm volatile (""
106 :
107 : [_] "m" (@as(u121, 3)),
108 );
109 asm volatile (""
110 :
111 : [_] "m" (@as(i121, 3)),
112 );
113 asm volatile (""
114 :
115 : [_] "m" (@as(f32, 3.17)),
116 );
117 asm volatile (""
118 :
119 : [_] "m" (@as(f64, 3.17)),
120 );
121}
122
123test "struct/array/union types as input values" {
124 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
125 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
126 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
127 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
128
129 if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // MSVC doesn't support inline assembly
130
131 asm volatile (""
132 :
133 : [_] "m" (@as([1]u32, undefined)),
134 ); // fails
135 asm volatile (""
136 :
137 : [_] "m" (@as(struct { x: u32, y: u8 }, undefined)),
138 ); // fails
139 asm volatile (""
140 :
141 : [_] "m" (@as(union { x: u32, y: u8 }, undefined)),
142 ); // fails
143}
144
145extern fn this_is_my_alias() i32;
146
147export fn derp() i32 {
148 return 1234;
149}
150
151test "rw constraint (x86_64)" {
152 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
153 if (builtin.target.cpu.arch != .x86_64) return error.SkipZigTest;
154
155 var res: i32 = 5;
156 asm ("addl %[b], %[a]"
157 : [a] "+r" (res),
158 : [b] "r" (@as(i32, 13)),
159 : .{ .flags = true });
160 try expectEqual(@as(i32, 18), res);
161}
162
163test "asm modifiers (AArch64)" {
164 if (!builtin.target.cpu.arch.isAARCH64()) return error.SkipZigTest;
165
166 if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // MSVC doesn't support inline assembly
167
168 var x: u32 = 15;
169 _ = &x;
170 const double = asm ("add %[ret:w], %[in:w], %[in:w]"
171 : [ret] "=r" (-> u32),
172 : [in] "r" (x),
173 );
174 try expectEqual(2 * x, double);
175}
176
177test "packed output types (x86_64)" {
178 if (builtin.target.cpu.arch != .x86_64) return error.SkipZigTest;
179 if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // MSVC doesn't support inline assembly
180
181 const S = packed struct(u32) { x: u32 };
182 {
183 const s: S = asm volatile ("mov $123, %[ret]"
184 : [ret] "=r" (-> S),
185 );
186 try expect(s.x == 123);
187 }
188 {
189 var s: S = undefined;
190 asm volatile ("mov $123, %[ret]"
191 : [ret] "=r" (s),
192 );
193 try expect(s.x == 123);
194 }
195
196 const U = packed union(u32) { x: u32 };
197 {
198 const u: U = asm volatile ("mov $123, %[ret]"
199 : [ret] "=r" (-> U),
200 );
201 try expect(u.x == 123);
202 }
203 {
204 var u: U = undefined;
205 asm volatile ("mov $123, %[ret]"
206 : [ret] "=r" (u),
207 );
208 try expect(u.x == 123);
209 }
210}
211
212test "abi register aliases as clobbers (RISC-V)" {
213 if (!builtin.target.cpu.arch.isRISCV()) return error.SkipZigTest;
214 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
215
216 // Verify that ABI alias names are accepted as clobbers for RISC-V.
217 asm volatile ("" ::: .{ .ra = true, .sp = true, .gp = true, .tp = true });
218 asm volatile ("" ::: .{ .a0 = true, .a1 = true, .a2 = true, .a3 = true, .a4 = true, .a5 = true, .a6 = true, .a7 = true });
219 asm volatile ("" ::: .{ .t0 = true, .t1 = true, .t2 = true, .t3 = true, .t4 = true, .t5 = true, .t6 = true });
220 asm volatile ("" ::: .{ .s0 = true, .fp = true, .s1 = true, .s2 = true, .s3 = true, .s4 = true, .s5 = true, .s6 = true, .s7 = true, .s8 = true, .s9 = true, .s10 = true, .s11 = true });
221 asm volatile ("" ::: .{ .fa0 = true, .fa1 = true, .ft0 = true, .fs0 = true });
222}