Mike Klein | 68c50d0 | 2019-05-29 12:57:54 -0500 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2019 Google LLC |
| 3 | * |
| 4 | * Use of this source code is governed by a BSD-style license that can be |
| 5 | * found in the LICENSE file. |
| 6 | */ |
| 7 | |
| 8 | #include "include/core/SkColorPriv.h" |
| 9 | #include "include/private/SkColorData.h" |
| 10 | #include "src/core/SkVM.h" |
| 11 | #include "tests/Test.h" |
Mike Klein | 267f507 | 2019-06-03 16:27:46 -0500 | [diff] [blame] | 12 | #include "tools/Resources.h" |
Mike Klein | 7b7077c | 2019-06-03 17:10:59 -0500 | [diff] [blame] | 13 | #include "tools/SkVMBuilders.h" |
Mike Klein | 68c50d0 | 2019-05-29 12:57:54 -0500 | [diff] [blame] | 14 | |
Mike Klein | 7b7077c | 2019-06-03 17:10:59 -0500 | [diff] [blame] | 15 | using Fmt = SrcoverBuilder_F32::Fmt; |
Mike Klein | 68c50d0 | 2019-05-29 12:57:54 -0500 | [diff] [blame] | 16 | const char* fmt_name(Fmt fmt) { |
| 17 | switch (fmt) { |
Mike Klein | 7b7077c | 2019-06-03 17:10:59 -0500 | [diff] [blame] | 18 | case Fmt::A8: return "A8"; |
| 19 | case Fmt::G8: return "G8"; |
| 20 | case Fmt::RGBA_8888: return "RGBA_8888"; |
Mike Klein | 68c50d0 | 2019-05-29 12:57:54 -0500 | [diff] [blame] | 21 | } |
| 22 | return ""; |
| 23 | } |
| 24 | |
Mike Klein | 68c50d0 | 2019-05-29 12:57:54 -0500 | [diff] [blame] | 25 | DEF_TEST(SkVM, r) { |
Mike Klein | 267f507 | 2019-06-03 16:27:46 -0500 | [diff] [blame] | 26 | SkDynamicMemoryWStream buf; |
Mike Klein | 7b7077c | 2019-06-03 17:10:59 -0500 | [diff] [blame] | 27 | |
| 28 | // Write all combinations of SrcoverBuilder_F32 |
Mike Klein | 68c50d0 | 2019-05-29 12:57:54 -0500 | [diff] [blame] | 29 | for (int s = 0; s < 3; s++) |
| 30 | for (int d = 0; d < 3; d++) { |
| 31 | auto srcFmt = (Fmt)s, |
| 32 | dstFmt = (Fmt)d; |
Mike Klein | 22ea7e9 | 2019-06-10 12:05:48 -0500 | [diff] [blame] | 33 | SrcoverBuilder_F32 builder{srcFmt, dstFmt}; |
| 34 | skvm::Program program = builder.done(); |
Mike Klein | 68c50d0 | 2019-05-29 12:57:54 -0500 | [diff] [blame] | 35 | |
Mike Klein | 267f507 | 2019-06-03 16:27:46 -0500 | [diff] [blame] | 36 | buf.writeText(fmt_name(srcFmt)); |
| 37 | buf.writeText(" over "); |
| 38 | buf.writeText(fmt_name(dstFmt)); |
| 39 | buf.writeText("\n"); |
Mike Klein | 22ea7e9 | 2019-06-10 12:05:48 -0500 | [diff] [blame] | 40 | builder.dump(&buf); |
| 41 | buf.writeText("\n"); |
Mike Klein | 68c50d0 | 2019-05-29 12:57:54 -0500 | [diff] [blame] | 42 | program.dump(&buf); |
Mike Klein | 267f507 | 2019-06-03 16:27:46 -0500 | [diff] [blame] | 43 | buf.writeText("\n"); |
| 44 | } |
Mike Klein | 68c50d0 | 2019-05-29 12:57:54 -0500 | [diff] [blame] | 45 | |
Mike Klein | 7b7077c | 2019-06-03 17:10:59 -0500 | [diff] [blame] | 46 | // Write the I32 Srcovers also. |
| 47 | { |
Mike Klein | 397fc88 | 2019-06-20 11:37:10 -0500 | [diff] [blame] | 48 | skvm::Program program = SrcoverBuilder_I32_Naive{}.done(); |
| 49 | buf.writeText("I32 (Naive) 8888 over 8888\n"); |
| 50 | program.dump(&buf); |
| 51 | buf.writeText("\n"); |
| 52 | } |
| 53 | { |
Mike Klein | 7b7077c | 2019-06-03 17:10:59 -0500 | [diff] [blame] | 54 | skvm::Program program = SrcoverBuilder_I32{}.done(); |
| 55 | buf.writeText("I32 8888 over 8888\n"); |
| 56 | program.dump(&buf); |
| 57 | buf.writeText("\n"); |
| 58 | } |
| 59 | { |
| 60 | skvm::Program program = SrcoverBuilder_I32_SWAR{}.done(); |
| 61 | buf.writeText("I32 (SWAR) 8888 over 8888\n"); |
| 62 | program.dump(&buf); |
| 63 | buf.writeText("\n"); |
| 64 | } |
| 65 | |
Mike Klein | 267f507 | 2019-06-03 16:27:46 -0500 | [diff] [blame] | 66 | sk_sp<SkData> blob = buf.detachAsData(); |
| 67 | { |
| 68 | |
| 69 | sk_sp<SkData> expected = GetResourceAsData("SkVMTest.expected"); |
Mike Klein | 7716331 | 2019-06-04 13:35:32 -0500 | [diff] [blame] | 70 | REPORTER_ASSERT(r, expected, "Couldn't load SkVMTest.expected."); |
| 71 | if (expected) { |
| 72 | if (blob->size() != expected->size() |
| 73 | || 0 != memcmp(blob->data(), expected->data(), blob->size())) { |
Mike Klein | 267f507 | 2019-06-03 16:27:46 -0500 | [diff] [blame] | 74 | |
Mike Klein | 7716331 | 2019-06-04 13:35:32 -0500 | [diff] [blame] | 75 | ERRORF(r, "SkVMTest expected\n%.*s\nbut got\n%.*s\n", |
| 76 | expected->size(), expected->data(), |
| 77 | blob->size(), blob->data()); |
| 78 | } |
| 79 | |
| 80 | SkFILEWStream out(GetResourcePath("SkVMTest.expected").c_str()); |
| 81 | if (out.isValid()) { |
| 82 | out.write(blob->data(), blob->size()); |
| 83 | } |
Mike Klein | 68c50d0 | 2019-05-29 12:57:54 -0500 | [diff] [blame] | 84 | } |
| 85 | } |
| 86 | |
Mike Klein | 3f59379 | 2019-06-12 12:54:52 -0500 | [diff] [blame] | 87 | auto test_8888 = [&](const skvm::Program& program) { |
| 88 | uint32_t src[9]; |
| 89 | uint32_t dst[SK_ARRAY_COUNT(src)]; |
Mike Klein | 68c50d0 | 2019-05-29 12:57:54 -0500 | [diff] [blame] | 90 | |
Mike Klein | 3f59379 | 2019-06-12 12:54:52 -0500 | [diff] [blame] | 91 | for (int i = 0; i < (int)SK_ARRAY_COUNT(src); i++) { |
| 92 | src[i] = 0xbb007733; |
| 93 | dst[i] = 0xffaaccee; |
| 94 | } |
Mike Klein | 68c50d0 | 2019-05-29 12:57:54 -0500 | [diff] [blame] | 95 | |
Mike Klein | 3f59379 | 2019-06-12 12:54:52 -0500 | [diff] [blame] | 96 | SkPMColor expected = SkPMSrcOver(src[0], dst[0]); // 0xff2dad73 |
| 97 | |
| 98 | program.eval((int)SK_ARRAY_COUNT(src), src, dst); |
Mike Klein | 68c50d0 | 2019-05-29 12:57:54 -0500 | [diff] [blame] | 99 | |
| 100 | // dst is probably 0xff2dad72. |
Mike Klein | 3f59379 | 2019-06-12 12:54:52 -0500 | [diff] [blame] | 101 | for (auto got : dst) { |
| 102 | auto want = expected; |
| 103 | for (int i = 0; i < 4; i++) { |
| 104 | uint8_t d = got & 0xff, |
| 105 | w = want & 0xff; |
| 106 | REPORTER_ASSERT(r, abs(d-w) < 2); |
| 107 | got >>= 8; |
| 108 | want >>= 8; |
| 109 | } |
Mike Klein | 68c50d0 | 2019-05-29 12:57:54 -0500 | [diff] [blame] | 110 | } |
Mike Klein | 3f59379 | 2019-06-12 12:54:52 -0500 | [diff] [blame] | 111 | }; |
Mike Klein | 68c50d0 | 2019-05-29 12:57:54 -0500 | [diff] [blame] | 112 | |
Mike Klein | 3f59379 | 2019-06-12 12:54:52 -0500 | [diff] [blame] | 113 | test_8888(SrcoverBuilder_F32{Fmt::RGBA_8888, Fmt::RGBA_8888}.done()); |
Mike Klein | 397fc88 | 2019-06-20 11:37:10 -0500 | [diff] [blame] | 114 | test_8888(SrcoverBuilder_I32_Naive{}.done()); |
Mike Klein | 5640397 | 2019-06-12 14:01:10 -0500 | [diff] [blame] | 115 | test_8888(SrcoverBuilder_I32{}.done()); |
Mike Klein | 3f59379 | 2019-06-12 12:54:52 -0500 | [diff] [blame] | 116 | test_8888(SrcoverBuilder_I32_SWAR{}.done()); |
Mike Klein | 7b7077c | 2019-06-03 17:10:59 -0500 | [diff] [blame] | 117 | |
| 118 | { |
| 119 | skvm::Program program = SrcoverBuilder_F32{Fmt::RGBA_8888, Fmt::G8}.done(); |
Mike Klein | 68c50d0 | 2019-05-29 12:57:54 -0500 | [diff] [blame] | 120 | |
Mike Klein | 3f59379 | 2019-06-12 12:54:52 -0500 | [diff] [blame] | 121 | uint32_t src[9]; |
| 122 | uint8_t dst[SK_ARRAY_COUNT(src)]; |
| 123 | |
| 124 | for (int i = 0; i < (int)SK_ARRAY_COUNT(src); i++) { |
| 125 | src[i] = 0xbb007733; |
| 126 | dst[i] = 0x42; |
| 127 | } |
| 128 | |
| 129 | SkPMColor over = SkPMSrcOver(SkPackARGB32(0xbb, 0x33, 0x77, 0x00), |
| 130 | 0xff424242); |
Mike Klein | 68c50d0 | 2019-05-29 12:57:54 -0500 | [diff] [blame] | 131 | |
| 132 | uint8_t want = SkComputeLuminance(SkGetPackedR32(over), |
| 133 | SkGetPackedG32(over), |
| 134 | SkGetPackedB32(over)); |
Mike Klein | 3f59379 | 2019-06-12 12:54:52 -0500 | [diff] [blame] | 135 | program.eval((int)SK_ARRAY_COUNT(src), src, dst); |
Mike Klein | 68c50d0 | 2019-05-29 12:57:54 -0500 | [diff] [blame] | 136 | |
Mike Klein | 3f59379 | 2019-06-12 12:54:52 -0500 | [diff] [blame] | 137 | for (auto got : dst) { |
| 138 | REPORTER_ASSERT(r, abs(got-want) < 3); |
| 139 | } |
Mike Klein | 68c50d0 | 2019-05-29 12:57:54 -0500 | [diff] [blame] | 140 | } |
| 141 | |
| 142 | { |
Mike Klein | 7b7077c | 2019-06-03 17:10:59 -0500 | [diff] [blame] | 143 | skvm::Program program = SrcoverBuilder_F32{Fmt::A8, Fmt::A8}.done(); |
Mike Klein | 68c50d0 | 2019-05-29 12:57:54 -0500 | [diff] [blame] | 144 | |
| 145 | uint8_t src[256], |
| 146 | dst[256]; |
| 147 | for (int i = 0; i < 256; i++) { |
| 148 | src[i] = 255 - i; |
| 149 | dst[i] = i; |
| 150 | } |
| 151 | |
| 152 | program.eval(256, src, dst); |
| 153 | |
| 154 | for (int i = 0; i < 256; i++) { |
| 155 | uint8_t want = SkGetPackedA32(SkPMSrcOver(SkPackARGB32(src[i], 0,0,0), |
| 156 | SkPackARGB32( i, 0,0,0))); |
| 157 | REPORTER_ASSERT(r, abs(dst[i]-want) < 2); |
| 158 | } |
| 159 | } |
| 160 | } |
Mike Klein | 81756e4 | 2019-06-12 11:36:28 -0500 | [diff] [blame] | 161 | |
| 162 | DEF_TEST(SkVM_LoopCounts, r) { |
| 163 | // Make sure we cover all the exact N we want. |
| 164 | |
| 165 | int buf[64]; |
| 166 | for (int N = 0; N <= (int)SK_ARRAY_COUNT(buf); N++) { |
| 167 | for (int i = 0; i < (int)SK_ARRAY_COUNT(buf); i++) { |
| 168 | buf[i] = i; |
| 169 | } |
| 170 | |
| 171 | // buf[i] += 1 |
| 172 | skvm::Builder b; |
| 173 | b.store32(b.arg(0), |
| 174 | b.add(b.splat(1), |
| 175 | b.load32(b.arg(0)))); |
| 176 | |
| 177 | skvm::Program program = b.done(); |
| 178 | program.eval(N, buf); |
| 179 | |
| 180 | for (int i = 0; i < N; i++) { |
| 181 | REPORTER_ASSERT(r, buf[i] == i+1); |
| 182 | } |
| 183 | for (int i = N; i < (int)SK_ARRAY_COUNT(buf); i++) { |
| 184 | REPORTER_ASSERT(r, buf[i] == i); |
| 185 | } |
| 186 | } |
| 187 | } |
Mike Klein | 0564204 | 2019-06-18 12:16:06 -0500 | [diff] [blame] | 188 | |
| 189 | |
Mike Klein | 0564204 | 2019-06-18 12:16:06 -0500 | [diff] [blame] | 190 | template <typename Fn> |
| 191 | static void test_asm(skiatest::Reporter* r, Fn&& fn, std::initializer_list<uint8_t> expected) { |
Mike Klein | 88c0a90 | 2019-06-24 15:34:02 -0400 | [diff] [blame] | 192 | uint8_t buf[4096]; |
| 193 | skvm::Assembler a{buf}; |
Mike Klein | 0564204 | 2019-06-18 12:16:06 -0500 | [diff] [blame] | 194 | fn(a); |
| 195 | |
| 196 | REPORTER_ASSERT(r, a.size() == expected.size()); |
| 197 | |
Mike Klein | 88c0a90 | 2019-06-24 15:34:02 -0400 | [diff] [blame] | 198 | auto got = (const uint8_t*)buf, |
Mike Klein | 0564204 | 2019-06-18 12:16:06 -0500 | [diff] [blame] | 199 | want = expected.begin(); |
| 200 | for (int i = 0; i < (int)std::min(a.size(), expected.size()); i++) { |
Mike Klein | 61703a6 | 2019-06-18 15:01:12 -0500 | [diff] [blame] | 201 | REPORTER_ASSERT(r, got[i] == want[i], |
| 202 | "byte %d was %02x, want %02x", i, got[i], want[i]); |
Mike Klein | 0564204 | 2019-06-18 12:16:06 -0500 | [diff] [blame] | 203 | } |
| 204 | } |
| 205 | |
| 206 | DEF_TEST(SkVM_Assembler, r) { |
Mike Klein | 397fc88 | 2019-06-20 11:37:10 -0500 | [diff] [blame] | 207 | // Easiest way to generate test cases is |
| 208 | // |
| 209 | // echo '...some asm...' | llvm-mc -show-encoding -x86-asm-syntax=intel |
| 210 | // |
| 211 | // The -x86-asm-syntax=intel bit is optional, controlling the |
| 212 | // input syntax only; the output will always be AT&T op x,y,dst style. |
| 213 | // Our APIs read more like Intel op dst,x,y as op(dst,x,y), so I find |
| 214 | // that a bit easier to use here, despite maybe favoring AT&T overall. |
| 215 | |
| 216 | using A = skvm::Assembler; |
Mike Klein | 0564204 | 2019-06-18 12:16:06 -0500 | [diff] [blame] | 217 | // Our exit strategy from AVX code. |
Mike Klein | 397fc88 | 2019-06-20 11:37:10 -0500 | [diff] [blame] | 218 | test_asm(r, [&](A& a) { |
Mike Klein | 0564204 | 2019-06-18 12:16:06 -0500 | [diff] [blame] | 219 | a.vzeroupper(); |
| 220 | a.ret(); |
| 221 | },{ |
| 222 | 0xc5, 0xf8, 0x77, |
| 223 | 0xc3, |
| 224 | }); |
| 225 | |
| 226 | // Align should pad with nop(). |
Mike Klein | 397fc88 | 2019-06-20 11:37:10 -0500 | [diff] [blame] | 227 | test_asm(r, [&](A& a) { |
Mike Klein | 0564204 | 2019-06-18 12:16:06 -0500 | [diff] [blame] | 228 | a.ret(); |
| 229 | a.align(4); |
| 230 | },{ |
| 231 | 0xc3, |
| 232 | 0x90, 0x90, 0x90, |
| 233 | }); |
Mike Klein | 61703a6 | 2019-06-18 15:01:12 -0500 | [diff] [blame] | 234 | |
Mike Klein | 397fc88 | 2019-06-20 11:37:10 -0500 | [diff] [blame] | 235 | test_asm(r, [&](A& a) { |
| 236 | a.add(A::rax, 8); // Always good to test rax. |
| 237 | a.sub(A::rax, 32); |
Mike Klein | d3e75a7 | 2019-06-18 15:26:08 -0500 | [diff] [blame] | 238 | |
Mike Klein | 397fc88 | 2019-06-20 11:37:10 -0500 | [diff] [blame] | 239 | a.add(A::rdi, 12); // Last 0x48 REX |
| 240 | a.sub(A::rdi, 8); |
Mike Klein | d3e75a7 | 2019-06-18 15:26:08 -0500 | [diff] [blame] | 241 | |
Mike Klein | 397fc88 | 2019-06-20 11:37:10 -0500 | [diff] [blame] | 242 | a.add(A::r8 , 7); // First 0x4c REX |
| 243 | a.sub(A::r8 , 4); |
Mike Klein | d3e75a7 | 2019-06-18 15:26:08 -0500 | [diff] [blame] | 244 | |
Mike Klein | 397fc88 | 2019-06-20 11:37:10 -0500 | [diff] [blame] | 245 | a.add(A::rsi, 128); // Requires 4 byte immediate. |
| 246 | a.sub(A::r8 , 1000000); |
Mike Klein | 61703a6 | 2019-06-18 15:01:12 -0500 | [diff] [blame] | 247 | },{ |
Mike Klein | d3e75a7 | 2019-06-18 15:26:08 -0500 | [diff] [blame] | 248 | 0x48, 0x83, 0b11'000'000, 0x08, |
Mike Klein | 61703a6 | 2019-06-18 15:01:12 -0500 | [diff] [blame] | 249 | 0x48, 0x83, 0b11'101'000, 0x20, |
Mike Klein | d3e75a7 | 2019-06-18 15:26:08 -0500 | [diff] [blame] | 250 | |
| 251 | 0x48, 0x83, 0b11'000'111, 0x0c, |
Mike Klein | 61703a6 | 2019-06-18 15:01:12 -0500 | [diff] [blame] | 252 | 0x48, 0x83, 0b11'101'111, 0x08, |
Mike Klein | d3e75a7 | 2019-06-18 15:26:08 -0500 | [diff] [blame] | 253 | |
| 254 | 0x4c, 0x83, 0b11'000'000, 0x07, |
Mike Klein | 61703a6 | 2019-06-18 15:01:12 -0500 | [diff] [blame] | 255 | 0x4c, 0x83, 0b11'101'000, 0x04, |
Mike Klein | d3e75a7 | 2019-06-18 15:26:08 -0500 | [diff] [blame] | 256 | |
| 257 | 0x48, 0x81, 0b11'000'110, 0x80, 0x00, 0x00, 0x00, |
Mike Klein | 61703a6 | 2019-06-18 15:01:12 -0500 | [diff] [blame] | 258 | 0x4c, 0x81, 0b11'101'000, 0x40, 0x42, 0x0f, 0x00, |
| 259 | }); |
Mike Klein | 397fc88 | 2019-06-20 11:37:10 -0500 | [diff] [blame] | 260 | |
| 261 | |
| 262 | test_asm(r, [&](A& a) { |
| 263 | a.vpaddd (A::ymm0, A::ymm1, A::ymm2); // Low registers and 0x0f map -> 2-byte VEX. |
| 264 | a.vpaddd (A::ymm8, A::ymm1, A::ymm2); // A high dst register is ok -> 2-byte VEX. |
| 265 | a.vpaddd (A::ymm0, A::ymm8, A::ymm2); // A high first argument register -> 2-byte VEX. |
| 266 | a.vpaddd (A::ymm0, A::ymm1, A::ymm8); // A high second argument -> 3-byte VEX. |
| 267 | a.vpmulld(A::ymm0, A::ymm1, A::ymm2); // Using non-0x0f map instruction -> 3-byte VEX. |
| 268 | a.vpsubd (A::ymm0, A::ymm1, A::ymm2); // Test vpsubd to ensure argument order is right. |
| 269 | },{ |
| 270 | /* VEX */ /*op*/ /*modRM*/ |
| 271 | 0xc5, 0xf5, 0xfe, 0xc2, |
| 272 | 0xc5, 0x75, 0xfe, 0xc2, |
| 273 | 0xc5, 0xbd, 0xfe, 0xc2, |
| 274 | 0xc4, 0xc1, 0x75, 0xfe, 0xc0, |
| 275 | 0xc4, 0xe2, 0x75, 0x40, 0xc2, |
| 276 | 0xc5, 0xf5, 0xfa, 0xc2, |
| 277 | }); |
Mike Klein | ff0ae81 | 2019-06-20 15:03:44 -0500 | [diff] [blame] | 278 | |
| 279 | test_asm(r, [&](A& a) { |
| 280 | a.vpsrld(A::ymm15, A::ymm2, 8); |
| 281 | a.vpsrld(A::ymm0 , A::ymm8, 5); |
| 282 | },{ |
| 283 | 0xc5, 0x85, 0x72,0xd2, 0x08, |
| 284 | 0xc4,0xc1,0x7d, 0x72,0xd0, 0x05, |
| 285 | }); |
| 286 | |
| 287 | test_asm(r, [&](A& a) { |
| 288 | a.vpermq(A::ymm1, A::ymm2, 5); |
| 289 | },{ |
| 290 | 0xc4,0xe3,0xfd, 0x00,0xca, 0x05, |
| 291 | }); |
Mike Klein | e505341 | 2019-06-21 12:37:22 -0500 | [diff] [blame] | 292 | |
| 293 | test_asm(r, [&](A& a) { |
| 294 | A::Label l = a.here(); |
| 295 | a.byte(1); |
| 296 | a.byte(2); |
| 297 | a.byte(3); |
| 298 | a.byte(4); |
Mike Klein | 04db9c2 | 2019-06-21 14:19:21 -0500 | [diff] [blame] | 299 | |
Mike Klein | e505341 | 2019-06-21 12:37:22 -0500 | [diff] [blame] | 300 | a.vbroadcastss(A::ymm0 , l); |
| 301 | a.vbroadcastss(A::ymm1 , l); |
| 302 | a.vbroadcastss(A::ymm8 , l); |
| 303 | a.vbroadcastss(A::ymm15, l); |
Mike Klein | 04db9c2 | 2019-06-21 14:19:21 -0500 | [diff] [blame] | 304 | |
| 305 | a.vpshufb(A::ymm4, A::ymm3, l); |
Mike Klein | e505341 | 2019-06-21 12:37:22 -0500 | [diff] [blame] | 306 | },{ |
| 307 | 0x01, 0x02, 0x03, 0x4, |
Mike Klein | 04db9c2 | 2019-06-21 14:19:21 -0500 | [diff] [blame] | 308 | |
Mike Klein | e505341 | 2019-06-21 12:37:22 -0500 | [diff] [blame] | 309 | /* VEX */ /*op*/ /* ModRM */ /* offset */ |
| 310 | 0xc4, 0xe2, 0x7d, 0x18, 0b00'000'101, 0xf3,0xff,0xff,0xff, // 0xfffffff3 == -13 |
| 311 | 0xc4, 0xe2, 0x7d, 0x18, 0b00'001'101, 0xea,0xff,0xff,0xff, // 0xffffffea == -22 |
| 312 | 0xc4, 0x62, 0x7d, 0x18, 0b00'000'101, 0xe1,0xff,0xff,0xff, // 0xffffffe1 == -31 |
| 313 | 0xc4, 0x62, 0x7d, 0x18, 0b00'111'101, 0xd8,0xff,0xff,0xff, // 0xffffffd8 == -40 |
Mike Klein | 04db9c2 | 2019-06-21 14:19:21 -0500 | [diff] [blame] | 314 | |
| 315 | 0xc4, 0xe2, 0x65, 0x00, 0b00'100'101, 0xcf,0xff,0xff,0xff, // 0xffffffcf == -49 |
Mike Klein | e505341 | 2019-06-21 12:37:22 -0500 | [diff] [blame] | 316 | }); |
Mike Klein | 060eaaa | 2019-06-21 14:42:09 -0500 | [diff] [blame] | 317 | |
| 318 | test_asm(r, [&](A& a) { |
| 319 | A::Label l = a.here(); |
| 320 | a.jne(l); |
| 321 | for (int i = 0; i < 124; i++) { |
| 322 | a.nop(); |
| 323 | } |
| 324 | a.jne(l); |
| 325 | a.jne(l); |
| 326 | },{ |
| 327 | 0x75, 0xfe, // short jump -2 bytes |
| 328 | |
| 329 | 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, |
| 330 | 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, |
| 331 | 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, |
| 332 | 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, |
| 333 | |
| 334 | 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, |
| 335 | 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, |
| 336 | 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, |
| 337 | 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, |
| 338 | |
| 339 | 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, |
| 340 | 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, |
| 341 | 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, |
| 342 | 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, |
| 343 | |
| 344 | 0x90, 0x90, 0x90, 0x90, |
| 345 | |
| 346 | 0x75, 0x80, // short jump -128 bytes |
| 347 | 0x0f, 0x85, 0x7a,0xff,0xff,0xff, // near jump back -134 bytes |
| 348 | }); |
Mike Klein | 120d9e8 | 2019-06-21 15:52:55 -0500 | [diff] [blame] | 349 | |
| 350 | test_asm(r, [&](A& a) { |
| 351 | a.vmovups(A::ymm5, A::rsi); |
| 352 | a.vmovups(A::rsi, A::ymm5); |
Mike Klein | ae51aa3 | 2019-06-21 16:06:03 -0500 | [diff] [blame] | 353 | |
| 354 | a.vpmovzxbd(A::ymm4, A::rsi); |
Mike Klein | f3881b2 | 2019-06-21 16:20:24 -0500 | [diff] [blame] | 355 | |
| 356 | a.vmovq(A::rdx, A::xmm15); |
Mike Klein | 120d9e8 | 2019-06-21 15:52:55 -0500 | [diff] [blame] | 357 | },{ |
Mike Klein | ae51aa3 | 2019-06-21 16:06:03 -0500 | [diff] [blame] | 358 | /* VEX */ /*Op*/ /* ModRM */ |
| 359 | 0xc5, 0xfc, 0x10, 0b00'101'110, |
| 360 | 0xc5, 0xfc, 0x11, 0b00'101'110, |
| 361 | |
| 362 | 0xc4,0xe2,0x7d, 0x31, 0b00'100'110, |
Mike Klein | f3881b2 | 2019-06-21 16:20:24 -0500 | [diff] [blame] | 363 | |
| 364 | 0xc5, 0x79, 0xd6, 0b00'111'010, |
Mike Klein | 120d9e8 | 2019-06-21 15:52:55 -0500 | [diff] [blame] | 365 | }); |
Mike Klein | 2b7b2a2 | 2019-06-23 20:35:28 -0400 | [diff] [blame] | 366 | |
| 367 | test_asm(r, [&](A& a) { |
| 368 | a.vpandn(A::ymm3, A::ymm12, A::ymm2); |
| 369 | },{ |
| 370 | 0xc5, 0x9d, 0xdf, 0xda, |
| 371 | }); |
Mike Klein | 9f4df80 | 2019-06-24 18:47:16 -0400 | [diff] [blame] | 372 | |
| 373 | // echo "fmul v4.4s, v3.4s, v1.4s" | llvm-mc -show-encoding -arch arm64 |
| 374 | |
| 375 | test_asm(r, [&](A& a) { |
Mike Klein | 6580914 | 2019-06-25 09:44:02 -0400 | [diff] [blame] | 376 | a.and16b(A::v4, A::v3, A::v1); |
| 377 | a.orr16b(A::v4, A::v3, A::v1); |
| 378 | a.eor16b(A::v4, A::v3, A::v1); |
| 379 | a.bic16b(A::v4, A::v3, A::v1); |
| 380 | |
| 381 | a.add4s(A::v4, A::v3, A::v1); |
| 382 | a.sub4s(A::v4, A::v3, A::v1); |
| 383 | a.mul4s(A::v4, A::v3, A::v1); |
| 384 | |
| 385 | a.sub8h(A::v4, A::v3, A::v1); |
| 386 | a.mul8h(A::v4, A::v3, A::v1); |
| 387 | |
Mike Klein | 9f4df80 | 2019-06-24 18:47:16 -0400 | [diff] [blame] | 388 | a.fadd4s(A::v4, A::v3, A::v1); |
| 389 | a.fsub4s(A::v4, A::v3, A::v1); |
| 390 | a.fmul4s(A::v4, A::v3, A::v1); |
| 391 | a.fdiv4s(A::v4, A::v3, A::v1); |
| 392 | |
Mike Klein | 6580914 | 2019-06-25 09:44:02 -0400 | [diff] [blame] | 393 | a.fmla4s(A::v4, A::v3, A::v1); |
Mike Klein | 9f4df80 | 2019-06-24 18:47:16 -0400 | [diff] [blame] | 394 | },{ |
Mike Klein | 6580914 | 2019-06-25 09:44:02 -0400 | [diff] [blame] | 395 | 0x64,0x1c,0x21,0x4e, |
| 396 | 0x64,0x1c,0xa1,0x4e, |
| 397 | 0x64,0x1c,0x21,0x6e, |
| 398 | 0x64,0x1c,0x61,0x4e, |
| 399 | |
| 400 | 0x64,0x84,0xa1,0x4e, |
| 401 | 0x64,0x84,0xa1,0x6e, |
| 402 | 0x64,0x9c,0xa1,0x4e, |
| 403 | |
| 404 | 0x64,0x84,0x61,0x6e, |
| 405 | 0x64,0x9c,0x61,0x4e, |
| 406 | |
Mike Klein | 9f4df80 | 2019-06-24 18:47:16 -0400 | [diff] [blame] | 407 | 0x64,0xd4,0x21,0x4e, |
| 408 | 0x64,0xd4,0xa1,0x4e, |
| 409 | 0x64,0xdc,0x21,0x6e, |
| 410 | 0x64,0xfc,0x21,0x6e, |
| 411 | |
Mike Klein | 6580914 | 2019-06-25 09:44:02 -0400 | [diff] [blame] | 412 | 0x64,0xcc,0x21,0x4e, |
| 413 | }); |
| 414 | |
| 415 | test_asm(r, [&](A& a) { |
| 416 | a.shl4s(A::v4, A::v3, 0); |
| 417 | a.shl4s(A::v4, A::v3, 1); |
| 418 | a.shl4s(A::v4, A::v3, 8); |
| 419 | a.shl4s(A::v4, A::v3, 16); |
| 420 | a.shl4s(A::v4, A::v3, 31); |
| 421 | |
| 422 | a.sshr4s(A::v4, A::v3, 1); |
| 423 | a.sshr4s(A::v4, A::v3, 8); |
| 424 | a.sshr4s(A::v4, A::v3, 31); |
| 425 | |
| 426 | a.ushr4s(A::v4, A::v3, 1); |
| 427 | a.ushr4s(A::v4, A::v3, 8); |
| 428 | a.ushr4s(A::v4, A::v3, 31); |
| 429 | |
| 430 | a.ushr8h(A::v4, A::v3, 1); |
| 431 | a.ushr8h(A::v4, A::v3, 8); |
| 432 | a.ushr8h(A::v4, A::v3, 15); |
| 433 | },{ |
| 434 | 0x64,0x54,0x20,0x4f, |
| 435 | 0x64,0x54,0x21,0x4f, |
| 436 | 0x64,0x54,0x28,0x4f, |
| 437 | 0x64,0x54,0x30,0x4f, |
| 438 | 0x64,0x54,0x3f,0x4f, |
| 439 | |
| 440 | 0x64,0x04,0x3f,0x4f, |
| 441 | 0x64,0x04,0x38,0x4f, |
| 442 | 0x64,0x04,0x21,0x4f, |
| 443 | |
| 444 | 0x64,0x04,0x3f,0x6f, |
| 445 | 0x64,0x04,0x38,0x6f, |
| 446 | 0x64,0x04,0x21,0x6f, |
| 447 | |
| 448 | 0x64,0x04,0x1f,0x6f, |
| 449 | 0x64,0x04,0x18,0x6f, |
| 450 | 0x64,0x04,0x11,0x6f, |
| 451 | }); |
| 452 | |
| 453 | test_asm(r, [&](A& a) { |
| 454 | a.scvtf4s (A::v4, A::v3); |
| 455 | a.fcvtzs4s(A::v4, A::v3); |
| 456 | },{ |
| 457 | 0x64,0xd8,0x21,0x4e, |
| 458 | 0x64,0xb8,0xa1,0x4e, |
Mike Klein | 9f4df80 | 2019-06-24 18:47:16 -0400 | [diff] [blame] | 459 | }); |
Mike Klein | 15a368d | 2019-06-26 10:21:12 -0400 | [diff] [blame] | 460 | |
| 461 | test_asm(r, [&](A& a) { |
| 462 | a.ret(A::x30); // Conventional ret using link register. |
| 463 | a.ret(A::x13); // Can really return using any register if we like. |
| 464 | |
| 465 | a.add(A::x2, A::x2, 4); |
| 466 | a.add(A::x3, A::x2, 32); |
| 467 | |
| 468 | a.subs(A::x2, A::x2, 4); |
| 469 | a.subs(A::x3, A::x2, 32); |
| 470 | |
| 471 | A::Label l = a.here(); |
| 472 | a.bne(l); |
| 473 | a.bne(l); |
| 474 | },{ |
| 475 | 0xc0,0x03,0x5f,0xd6, |
| 476 | 0xa0,0x01,0x5f,0xd6, |
| 477 | |
| 478 | 0x42,0x10,0x00,0x91, |
| 479 | 0x43,0x80,0x00,0x91, |
| 480 | |
| 481 | 0x42,0x10,0x00,0xf1, |
| 482 | 0x43,0x80,0x00,0xf1, |
| 483 | |
| 484 | 0x01,0x00,0x00,0x54, |
| 485 | 0xe1,0xff,0xff,0x54, |
| 486 | }); |
Mike Klein | e51632e | 2019-06-26 14:47:43 -0400 | [diff] [blame] | 487 | |
| 488 | test_asm(r, [&](A& a) { |
| 489 | a.ldrq(A::v0, A::x8); |
| 490 | a.strq(A::v0, A::x8); |
| 491 | },{ |
| 492 | 0x00, 0x01, 0xc0, 0x3d, |
| 493 | 0x00, 0x01, 0x80, 0x3d, |
| 494 | }); |
Mike Klein | 0564204 | 2019-06-18 12:16:06 -0500 | [diff] [blame] | 495 | } |