| 1 | const std = @import("std"); |
| 2 | const builtin = @import("builtin"); |
| 3 | const expect = std.testing.expect; |
| 4 | const expectEqual = std.testing.expectEqual; |
| 5 | |
| 6 | const is_x86_64_linux = builtin.cpu.arch == .x86_64 and builtin.os.tag == .linux; |
| 7 | |
| 8 | comptime { |
| 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 | |
| 28 | test "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 | |
| 41 | test "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 | |
| 63 | test "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 | |
| 81 | test "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 | |
| 123 | test "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 | |
| 145 | extern fn this_is_my_alias() i32; |
| 146 | |
| 147 | export fn derp() i32 { |
| 148 | return 1234; |
| 149 | } |
| 150 | |
| 151 | test "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 | |
| 163 | test "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 | |
| 177 | test "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 | |
| 212 | test "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 | } |