blob: 231d6d6276fa76ead633377611bd24fb0ee7b090 [file] [log] [blame]
Mike Klein68c50d02019-05-29 12:57:54 -05001/*
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"
Mike Klein238105b2020-03-04 17:05:32 -060010#include "src/core/SkCpu.h"
Mike Klein3f7c8652019-11-07 10:33:56 -060011#include "src/core/SkMSAN.h"
Mike Klein68c50d02019-05-29 12:57:54 -050012#include "src/core/SkVM.h"
13#include "tests/Test.h"
Mike Klein267f5072019-06-03 16:27:46 -050014#include "tools/Resources.h"
Mike Klein7b7077c2019-06-03 17:10:59 -050015#include "tools/SkVMBuilders.h"
Mike Klein68c50d02019-05-29 12:57:54 -050016
Mike Klein7b7077c2019-06-03 17:10:59 -050017using Fmt = SrcoverBuilder_F32::Fmt;
Mike Klein68c50d02019-05-29 12:57:54 -050018const char* fmt_name(Fmt fmt) {
19 switch (fmt) {
Mike Klein7b7077c2019-06-03 17:10:59 -050020 case Fmt::A8: return "A8";
21 case Fmt::G8: return "G8";
22 case Fmt::RGBA_8888: return "RGBA_8888";
Mike Klein68c50d02019-05-29 12:57:54 -050023 }
24 return "";
25}
26
Mike Klein6b4143e2019-09-18 11:49:29 -050027static void dump(skvm::Builder& builder, SkWStream* o) {
28 skvm::Program program = builder.done();
29 builder.dump(o);
30 o->writeText("\n");
31 program.dump(o);
32 o->writeText("\n");
33}
Mike Klein7e650762019-07-02 15:21:11 -050034
Mike Kleinb5a30762019-10-16 10:11:56 -050035// TODO: I'd like this to go away and have every test in here run both JIT and interpreter.
Mike Klein9977efa2019-07-15 12:22:36 -050036template <typename Fn>
Mike Kleinb5a30762019-10-16 10:11:56 -050037static void test_interpreter_only(skiatest::Reporter* r, skvm::Program&& program, Fn&& test) {
Mike Kleinb5a30762019-10-16 10:11:56 -050038 REPORTER_ASSERT(r, !program.hasJIT());
Mike Klein4e115262019-10-16 16:48:52 +000039 test((const skvm::Program&) program);
Mike Klein52435502019-10-16 10:11:56 -050040}
41
Mike Kleinb5a30762019-10-16 10:11:56 -050042template <typename Fn>
43static void test_jit_and_interpreter(skiatest::Reporter* r, skvm::Program&& program, Fn&& test) {
Mike Klein3f7c8652019-11-07 10:33:56 -060044 static const bool can_jit = []{
45 // This is about the simplest program we can write, setting an int buffer to a constant.
46 // If this can't JIT, the platform does not support JITing.
47 skvm::Builder b;
48 b.store32(b.varying<int>(), b.splat(42));
49 skvm::Program p = b.done();
50 return p.hasJIT();
51 }();
52
53 if (can_jit) {
Mike Kleinb5a30762019-10-16 10:11:56 -050054 REPORTER_ASSERT(r, program.hasJIT());
55 test((const skvm::Program&) program);
56 program.dropJIT();
57 }
Mike Kleinb5a30762019-10-16 10:11:56 -050058 test_interpreter_only(r, std::move(program), std::move(test));
59}
60
61
Mike Klein68c50d02019-05-29 12:57:54 -050062DEF_TEST(SkVM, r) {
Mike Klein267f5072019-06-03 16:27:46 -050063 SkDynamicMemoryWStream buf;
Mike Klein7b7077c2019-06-03 17:10:59 -050064
65 // Write all combinations of SrcoverBuilder_F32
Mike Klein68c50d02019-05-29 12:57:54 -050066 for (int s = 0; s < 3; s++)
67 for (int d = 0; d < 3; d++) {
68 auto srcFmt = (Fmt)s,
69 dstFmt = (Fmt)d;
Mike Klein22ea7e92019-06-10 12:05:48 -050070 SrcoverBuilder_F32 builder{srcFmt, dstFmt};
Mike Klein68c50d02019-05-29 12:57:54 -050071
Mike Klein267f5072019-06-03 16:27:46 -050072 buf.writeText(fmt_name(srcFmt));
73 buf.writeText(" over ");
74 buf.writeText(fmt_name(dstFmt));
75 buf.writeText("\n");
Mike Klein62bccda2019-07-18 10:36:45 -050076 dump(builder, &buf);
Mike Klein267f5072019-06-03 16:27:46 -050077 }
Mike Klein68c50d02019-05-29 12:57:54 -050078
Mike Klein7b7077c2019-06-03 17:10:59 -050079 // Write the I32 Srcovers also.
80 {
Mike Kleinaab45b52019-07-02 15:39:23 -050081 SrcoverBuilder_I32_Naive builder;
Mike Klein397fc882019-06-20 11:37:10 -050082 buf.writeText("I32 (Naive) 8888 over 8888\n");
Mike Klein62bccda2019-07-18 10:36:45 -050083 dump(builder, &buf);
Mike Klein397fc882019-06-20 11:37:10 -050084 }
85 {
Mike Kleinaab45b52019-07-02 15:39:23 -050086 SrcoverBuilder_I32 builder;
Mike Klein7b7077c2019-06-03 17:10:59 -050087 buf.writeText("I32 8888 over 8888\n");
Mike Klein62bccda2019-07-18 10:36:45 -050088 dump(builder, &buf);
Mike Klein7b7077c2019-06-03 17:10:59 -050089 }
90 {
Mike Kleinaab45b52019-07-02 15:39:23 -050091 SrcoverBuilder_I32_SWAR builder;
Mike Klein7b7077c2019-06-03 17:10:59 -050092 buf.writeText("I32 (SWAR) 8888 over 8888\n");
Mike Klein62bccda2019-07-18 10:36:45 -050093 dump(builder, &buf);
Mike Klein7b7077c2019-06-03 17:10:59 -050094 }
95
Mike Kleinf9963112019-08-08 15:13:25 -040096 {
97 skvm::Builder b;
98 skvm::Arg arg = b.varying<int>();
99
100 // x and y can both be hoisted,
Mike Klein0f61c122019-10-16 10:46:01 -0500101 // and x can die at y, while y must live for the loop.
Mike Kleinf9963112019-08-08 15:13:25 -0400102 skvm::I32 x = b.splat(1),
103 y = b.add(x, b.splat(2));
104 b.store32(arg, b.mul(b.load32(arg), y));
105
106 skvm::Program program = b.done();
107 REPORTER_ASSERT(r, program.nregs() == 2);
108
Mike Kleined9b1f12020-02-06 13:02:32 -0600109 std::vector<skvm::OptimizedInstruction> insts = b.optimize();
Mike Kleinf9963112019-08-08 15:13:25 -0400110 REPORTER_ASSERT(r, insts.size() == 6);
Mike Klein0f61c122019-10-16 10:46:01 -0500111 REPORTER_ASSERT(r, insts[0].can_hoist && insts[0].death == 2 && !insts[0].used_in_loop);
112 REPORTER_ASSERT(r, insts[1].can_hoist && insts[1].death == 2 && !insts[1].used_in_loop);
113 REPORTER_ASSERT(r, insts[2].can_hoist && insts[2].death == 4 && insts[2].used_in_loop);
114 REPORTER_ASSERT(r, !insts[3].can_hoist);
115 REPORTER_ASSERT(r, !insts[4].can_hoist);
116 REPORTER_ASSERT(r, !insts[5].can_hoist);
Mike Kleinf9963112019-08-08 15:13:25 -0400117
118 dump(b, &buf);
119
Mike Kleinb5a30762019-10-16 10:11:56 -0500120 test_jit_and_interpreter(r, std::move(program), [&](const skvm::Program& program) {
Mike Kleinf9963112019-08-08 15:13:25 -0400121 int arg[] = {0,1,2,3,4,5,6,7,8,9};
122
123 program.eval(SK_ARRAY_COUNT(arg), arg);
124
125 for (int i = 0; i < (int)SK_ARRAY_COUNT(arg); i++) {
126 REPORTER_ASSERT(r, arg[i] == i*3);
127 }
128 });
129 }
130
Mike Kleind48488b2019-10-22 12:27:58 -0500131 {
132 // Demonstrate the value of program reordering.
133 skvm::Builder b;
134 skvm::Arg sp = b.varying<int>(),
135 dp = b.varying<int>();
136
137 skvm::I32 byte = b.splat(0xff);
138
139 skvm::I32 src = b.load32(sp),
140 sr = b.extract(src, 0, byte),
141 sg = b.extract(src, 8, byte),
142 sb = b.extract(src, 16, byte),
143 sa = b.extract(src, 24, byte);
144
145 skvm::I32 dst = b.load32(dp),
146 dr = b.extract(dst, 0, byte),
147 dg = b.extract(dst, 8, byte),
148 db = b.extract(dst, 16, byte),
149 da = b.extract(dst, 24, byte);
150
151 skvm::I32 R = b.add(sr, dr),
152 G = b.add(sg, dg),
153 B = b.add(sb, db),
154 A = b.add(sa, da);
155
156 skvm::I32 rg = b.pack(R, G, 8),
157 ba = b.pack(B, A, 8),
158 rgba = b.pack(rg, ba, 16);
159
160 b.store32(dp, rgba);
161
162 dump(b, &buf);
163 }
164
Mike Klein238105b2020-03-04 17:05:32 -0600165 // Our checked in dump expectations assume we have FMA support.
166 const bool fma_supported =
167 #if defined(SK_CPU_X86)
168 SkCpu::Supports(SkCpu::HSW);
169 #elif defined(SK_CPU_ARM64)
170 true;
171 #else
172 false;
173 #endif
174 if (fma_supported) {
175 sk_sp<SkData> blob = buf.detachAsData();
176 {
Mike Klein267f5072019-06-03 16:27:46 -0500177
Mike Klein238105b2020-03-04 17:05:32 -0600178 sk_sp<SkData> expected = GetResourceAsData("SkVMTest.expected");
179 REPORTER_ASSERT(r, expected, "Couldn't load SkVMTest.expected.");
180 if (expected) {
181 if (blob->size() != expected->size()
182 || 0 != memcmp(blob->data(), expected->data(), blob->size())) {
Mike Klein267f5072019-06-03 16:27:46 -0500183
Mike Klein238105b2020-03-04 17:05:32 -0600184 ERRORF(r, "SkVMTest expected\n%.*s\nbut got\n%.*s\n",
185 expected->size(), expected->data(),
186 blob->size(), blob->data());
187 }
Mike Klein77163312019-06-04 13:35:32 -0500188
Mike Klein238105b2020-03-04 17:05:32 -0600189 SkFILEWStream out(GetResourcePath("SkVMTest.expected").c_str());
190 if (out.isValid()) {
191 out.write(blob->data(), blob->size());
192 }
Mike Klein77163312019-06-04 13:35:32 -0500193 }
Mike Klein68c50d02019-05-29 12:57:54 -0500194 }
195 }
196
Mike Klein9977efa2019-07-15 12:22:36 -0500197 auto test_8888 = [&](skvm::Program&& program) {
Mike Klein3f593792019-06-12 12:54:52 -0500198 uint32_t src[9];
199 uint32_t dst[SK_ARRAY_COUNT(src)];
Mike Klein68c50d02019-05-29 12:57:54 -0500200
Mike Klein92ca3ba2020-01-08 15:49:47 -0600201 test_jit_and_interpreter(r, std::move(program), [&](const skvm::Program& program) {
Mike Klein9977efa2019-07-15 12:22:36 -0500202 for (int i = 0; i < (int)SK_ARRAY_COUNT(src); i++) {
203 src[i] = 0xbb007733;
204 dst[i] = 0xffaaccee;
Mike Klein3f593792019-06-12 12:54:52 -0500205 }
Mike Klein9977efa2019-07-15 12:22:36 -0500206
207 SkPMColor expected = SkPMSrcOver(src[0], dst[0]); // 0xff2dad73
208
209 program.eval((int)SK_ARRAY_COUNT(src), src, dst);
210
211 // dst is probably 0xff2dad72.
212 for (auto got : dst) {
213 auto want = expected;
214 for (int i = 0; i < 4; i++) {
215 uint8_t d = got & 0xff,
216 w = want & 0xff;
Mike Klein37607d42019-07-18 10:17:28 -0500217 if (abs(d-w) >= 2) {
218 SkDebugf("d %02x, w %02x\n", d,w);
219 }
Mike Klein9977efa2019-07-15 12:22:36 -0500220 REPORTER_ASSERT(r, abs(d-w) < 2);
221 got >>= 8;
222 want >>= 8;
223 }
224 }
225 });
Mike Klein3f593792019-06-12 12:54:52 -0500226 };
Mike Klein68c50d02019-05-29 12:57:54 -0500227
Mike Klein37607d42019-07-18 10:17:28 -0500228 test_8888(SrcoverBuilder_F32{Fmt::RGBA_8888, Fmt::RGBA_8888}.done("srcover_f32"));
229 test_8888(SrcoverBuilder_I32_Naive{}.done("srcover_i32_naive"));
230 test_8888(SrcoverBuilder_I32{}.done("srcover_i32"));
231 test_8888(SrcoverBuilder_I32_SWAR{}.done("srcover_i32_SWAR"));
Mike Klein7b7077c2019-06-03 17:10:59 -0500232
Mike Klein92ca3ba2020-01-08 15:49:47 -0600233 test_jit_and_interpreter(r, SrcoverBuilder_F32{Fmt::RGBA_8888, Fmt::G8}.done(),
Mike Klein9977efa2019-07-15 12:22:36 -0500234 [&](const skvm::Program& program) {
Mike Klein3f593792019-06-12 12:54:52 -0500235 uint32_t src[9];
236 uint8_t dst[SK_ARRAY_COUNT(src)];
237
238 for (int i = 0; i < (int)SK_ARRAY_COUNT(src); i++) {
239 src[i] = 0xbb007733;
240 dst[i] = 0x42;
241 }
242
243 SkPMColor over = SkPMSrcOver(SkPackARGB32(0xbb, 0x33, 0x77, 0x00),
244 0xff424242);
Mike Klein68c50d02019-05-29 12:57:54 -0500245
246 uint8_t want = SkComputeLuminance(SkGetPackedR32(over),
247 SkGetPackedG32(over),
248 SkGetPackedB32(over));
Mike Klein3f593792019-06-12 12:54:52 -0500249 program.eval((int)SK_ARRAY_COUNT(src), src, dst);
Mike Klein68c50d02019-05-29 12:57:54 -0500250
Mike Klein3f593792019-06-12 12:54:52 -0500251 for (auto got : dst) {
252 REPORTER_ASSERT(r, abs(got-want) < 3);
253 }
Mike Klein9977efa2019-07-15 12:22:36 -0500254 });
Mike Klein68c50d02019-05-29 12:57:54 -0500255
Mike Kleinb5a30762019-10-16 10:11:56 -0500256 test_jit_and_interpreter(r, SrcoverBuilder_F32{Fmt::A8, Fmt::A8}.done(),
Mike Klein9977efa2019-07-15 12:22:36 -0500257 [&](const skvm::Program& program) {
Mike Klein68c50d02019-05-29 12:57:54 -0500258 uint8_t src[256],
259 dst[256];
260 for (int i = 0; i < 256; i++) {
261 src[i] = 255 - i;
262 dst[i] = i;
263 }
264
265 program.eval(256, src, dst);
266
267 for (int i = 0; i < 256; i++) {
268 uint8_t want = SkGetPackedA32(SkPMSrcOver(SkPackARGB32(src[i], 0,0,0),
269 SkPackARGB32( i, 0,0,0)));
270 REPORTER_ASSERT(r, abs(dst[i]-want) < 2);
271 }
Mike Klein9977efa2019-07-15 12:22:36 -0500272 });
Mike Klein68c50d02019-05-29 12:57:54 -0500273}
Mike Klein81756e42019-06-12 11:36:28 -0500274
Mike Klein9fdadb92019-07-30 12:30:13 -0500275DEF_TEST(SkVM_Pointless, r) {
276 // Let's build a program with no memory arguments.
277 // It should all be pegged as dead code, but we should be able to "run" it.
278 skvm::Builder b;
279 {
280 b.add(b.splat(5.0f),
281 b.splat(4.0f));
282 }
283
Mike Kleinb5a30762019-10-16 10:11:56 -0500284 test_jit_and_interpreter(r, b.done(), [&](const skvm::Program& program) {
Mike Klein9fdadb92019-07-30 12:30:13 -0500285 for (int N = 0; N < 64; N++) {
286 program.eval(N);
287 }
288 });
289
Mike Kleined9b1f12020-02-06 13:02:32 -0600290 for (const skvm::OptimizedInstruction& inst : b.optimize()) {
Mike Klein0f61c122019-10-16 10:46:01 -0500291 REPORTER_ASSERT(r, inst.death == 0 && inst.can_hoist == true);
Mike Klein9fdadb92019-07-30 12:30:13 -0500292 }
293}
294
Mike Kleinb6149312020-02-26 13:04:23 -0600295#if defined(SKVM_LLVM)
Mike Klein11efa182020-02-27 12:04:37 -0600296DEF_TEST(SkVM_LLVM_memset, r) {
Mike Kleinb6149312020-02-26 13:04:23 -0600297 skvm::Builder b;
298 b.store32(b.varying<int>(), b.splat(42));
299
300 skvm::Program p = b.done();
301 REPORTER_ASSERT(r, p.hasJIT());
302
Mike Klein7b3999e2020-02-27 10:07:53 -0600303 int buf[18];
304 buf[17] = 47;
305
306 p.eval(17, buf);
307 for (int i = 0; i < 17; i++) {
308 REPORTER_ASSERT(r, buf[i] == 42);
Mike Kleinb6149312020-02-26 13:04:23 -0600309 }
Mike Klein7b3999e2020-02-27 10:07:53 -0600310 REPORTER_ASSERT(r, buf[17] == 47);
Mike Kleinb6149312020-02-26 13:04:23 -0600311}
Mike Klein11efa182020-02-27 12:04:37 -0600312
313DEF_TEST(SkVM_LLVM_memcpy, r) {
314 skvm::Builder b;
315 {
316 auto src = b.varying<int>(),
317 dst = b.varying<int>();
318 b.store32(dst, b.load32(src));
319 }
320
321 skvm::Program p = b.done();
322 REPORTER_ASSERT(r, p.hasJIT());
323
324 int src[] = {1,2,3,4,5,6,7,8,9},
325 dst[] = {0,0,0,0,0,0,0,0,0};
326
327 p.eval(SK_ARRAY_COUNT(src)-1, src, dst);
328 for (size_t i = 0; i < SK_ARRAY_COUNT(src)-1; i++) {
329 REPORTER_ASSERT(r, dst[i] == src[i]);
330 }
331 size_t i = SK_ARRAY_COUNT(src)-1;
332 REPORTER_ASSERT(r, dst[i] == 0);
333}
Mike Kleinb6149312020-02-26 13:04:23 -0600334#endif
335
Mike Klein81756e42019-06-12 11:36:28 -0500336DEF_TEST(SkVM_LoopCounts, r) {
337 // Make sure we cover all the exact N we want.
338
Mike Klein9977efa2019-07-15 12:22:36 -0500339 // buf[i] += 1
340 skvm::Builder b;
Mike Klein5591fdf2019-07-30 09:44:30 -0500341 skvm::Arg arg = b.varying<int>();
Mike Klein9977efa2019-07-15 12:22:36 -0500342 b.store32(arg,
343 b.add(b.splat(1),
344 b.load32(arg)));
345
Mike Kleinb5a30762019-10-16 10:11:56 -0500346 test_jit_and_interpreter(r, b.done(), [&](const skvm::Program& program) {
Mike Klein9e2218a2019-07-19 11:13:42 -0500347 int buf[64];
348 for (int N = 0; N <= (int)SK_ARRAY_COUNT(buf); N++) {
Mike Klein9977efa2019-07-15 12:22:36 -0500349 for (int i = 0; i < (int)SK_ARRAY_COUNT(buf); i++) {
350 buf[i] = i;
351 }
352 program.eval(N, buf);
Mike Klein81756e42019-06-12 11:36:28 -0500353
Mike Klein9977efa2019-07-15 12:22:36 -0500354 for (int i = 0; i < N; i++) {
355 REPORTER_ASSERT(r, buf[i] == i+1);
356 }
357 for (int i = N; i < (int)SK_ARRAY_COUNT(buf); i++) {
358 REPORTER_ASSERT(r, buf[i] == i);
359 }
Mike Klein9e2218a2019-07-19 11:13:42 -0500360 }
361 });
Mike Klein81756e42019-06-12 11:36:28 -0500362}
Mike Klein05642042019-06-18 12:16:06 -0500363
Mike Kleinb2b6a992020-01-13 16:34:30 -0600364DEF_TEST(SkVM_gather32, r) {
365 skvm::Builder b;
366 {
367 skvm::Arg uniforms = b.uniform(),
368 buf = b.varying<int>();
369 skvm::I32 x = b.load32(buf);
370 b.store32(buf, b.gather32(uniforms,0, b.bit_and(x, b.splat(7))));
371 }
372
373#if defined(SK_CPU_X86)
374 test_jit_and_interpreter
375#else
376 test_interpreter_only
377#endif
378 (r, b.done(), [&](const skvm::Program& program) {
379 const int img[] = {12,34,56,78, 90,98,76,54};
380
381 int buf[20];
382 for (int i = 0; i < 20; i++) {
383 buf[i] = i;
384 }
385
386 struct Uniforms {
387 const int* img;
388 } uniforms{img};
389
390 program.eval(20, &uniforms, buf);
391 int i = 0;
392 REPORTER_ASSERT(r, buf[i] == 12); i++;
393 REPORTER_ASSERT(r, buf[i] == 34); i++;
394 REPORTER_ASSERT(r, buf[i] == 56); i++;
395 REPORTER_ASSERT(r, buf[i] == 78); i++;
396 REPORTER_ASSERT(r, buf[i] == 90); i++;
397 REPORTER_ASSERT(r, buf[i] == 98); i++;
398 REPORTER_ASSERT(r, buf[i] == 76); i++;
399 REPORTER_ASSERT(r, buf[i] == 54); i++;
400
401 REPORTER_ASSERT(r, buf[i] == 12); i++;
402 REPORTER_ASSERT(r, buf[i] == 34); i++;
403 REPORTER_ASSERT(r, buf[i] == 56); i++;
404 REPORTER_ASSERT(r, buf[i] == 78); i++;
405 REPORTER_ASSERT(r, buf[i] == 90); i++;
406 REPORTER_ASSERT(r, buf[i] == 98); i++;
407 REPORTER_ASSERT(r, buf[i] == 76); i++;
408 REPORTER_ASSERT(r, buf[i] == 54); i++;
409
410 REPORTER_ASSERT(r, buf[i] == 12); i++;
411 REPORTER_ASSERT(r, buf[i] == 34); i++;
412 REPORTER_ASSERT(r, buf[i] == 56); i++;
413 REPORTER_ASSERT(r, buf[i] == 78); i++;
414 });
415}
416
Mike Klein81d52672019-07-30 11:11:09 -0500417DEF_TEST(SkVM_gathers, r) {
418 skvm::Builder b;
419 {
Mike Klein6dbd7ff2020-01-06 11:50:37 -0600420 skvm::Arg uniforms = b.uniform(),
421 buf32 = b.varying<int>(),
422 buf16 = b.varying<uint16_t>(),
423 buf8 = b.varying<uint8_t>();
Mike Klein81d52672019-07-30 11:11:09 -0500424
425 skvm::I32 x = b.load32(buf32);
426
Mike Klein6dbd7ff2020-01-06 11:50:37 -0600427 b.store32(buf32, b.gather32(uniforms,0, b.bit_and(x, b.splat( 7))));
428 b.store16(buf16, b.gather16(uniforms,0, b.bit_and(x, b.splat(15))));
429 b.store8 (buf8 , b.gather8 (uniforms,0, b.bit_and(x, b.splat(31))));
Mike Klein81d52672019-07-30 11:11:09 -0500430 }
431
Mike Klein22c007d2020-02-28 11:38:58 -0600432#if defined(SKVM_LLVM)
433 test_jit_and_interpreter
434#else
435 test_interpreter_only
436#endif
437 (r, b.done(), [&](const skvm::Program& program) {
Mike Klein81d52672019-07-30 11:11:09 -0500438 const int img[] = {12,34,56,78, 90,98,76,54};
439
440 constexpr int N = 20;
441 int buf32[N];
442 uint16_t buf16[N];
443 uint8_t buf8 [N];
444
445 for (int i = 0; i < 20; i++) {
446 buf32[i] = i;
447 }
448
Mike Klein6dbd7ff2020-01-06 11:50:37 -0600449 struct Uniforms {
450 const int* img;
451 } uniforms{img};
452
453 program.eval(N, &uniforms, buf32, buf16, buf8);
Mike Klein81d52672019-07-30 11:11:09 -0500454 int i = 0;
455 REPORTER_ASSERT(r, buf32[i] == 12 && buf16[i] == 12 && buf8[i] == 12); i++;
456 REPORTER_ASSERT(r, buf32[i] == 34 && buf16[i] == 0 && buf8[i] == 0); i++;
457 REPORTER_ASSERT(r, buf32[i] == 56 && buf16[i] == 34 && buf8[i] == 0); i++;
458 REPORTER_ASSERT(r, buf32[i] == 78 && buf16[i] == 0 && buf8[i] == 0); i++;
459 REPORTER_ASSERT(r, buf32[i] == 90 && buf16[i] == 56 && buf8[i] == 34); i++;
460 REPORTER_ASSERT(r, buf32[i] == 98 && buf16[i] == 0 && buf8[i] == 0); i++;
461 REPORTER_ASSERT(r, buf32[i] == 76 && buf16[i] == 78 && buf8[i] == 0); i++;
462 REPORTER_ASSERT(r, buf32[i] == 54 && buf16[i] == 0 && buf8[i] == 0); i++;
463
464 REPORTER_ASSERT(r, buf32[i] == 12 && buf16[i] == 90 && buf8[i] == 56); i++;
465 REPORTER_ASSERT(r, buf32[i] == 34 && buf16[i] == 0 && buf8[i] == 0); i++;
466 REPORTER_ASSERT(r, buf32[i] == 56 && buf16[i] == 98 && buf8[i] == 0); i++;
467 REPORTER_ASSERT(r, buf32[i] == 78 && buf16[i] == 0 && buf8[i] == 0); i++;
468 REPORTER_ASSERT(r, buf32[i] == 90 && buf16[i] == 76 && buf8[i] == 78); i++;
469 REPORTER_ASSERT(r, buf32[i] == 98 && buf16[i] == 0 && buf8[i] == 0); i++;
470 REPORTER_ASSERT(r, buf32[i] == 76 && buf16[i] == 54 && buf8[i] == 0); i++;
471 REPORTER_ASSERT(r, buf32[i] == 54 && buf16[i] == 0 && buf8[i] == 0); i++;
472
473 REPORTER_ASSERT(r, buf32[i] == 12 && buf16[i] == 12 && buf8[i] == 90); i++;
474 REPORTER_ASSERT(r, buf32[i] == 34 && buf16[i] == 0 && buf8[i] == 0); i++;
475 REPORTER_ASSERT(r, buf32[i] == 56 && buf16[i] == 34 && buf8[i] == 0); i++;
476 REPORTER_ASSERT(r, buf32[i] == 78 && buf16[i] == 0 && buf8[i] == 0); i++;
477 });
478}
479
480DEF_TEST(SkVM_bitops, r) {
481 skvm::Builder b;
482 {
483 skvm::Arg ptr = b.varying<int>();
484
485 skvm::I32 x = b.load32(ptr);
486
487 x = b.bit_and (x, b.splat(0xf1)); // 0x40
488 x = b.bit_or (x, b.splat(0x80)); // 0xc0
489 x = b.bit_xor (x, b.splat(0xfe)); // 0x3e
490 x = b.bit_clear(x, b.splat(0x30)); // 0x0e
491
492 x = b.shl(x, 28); // 0xe000'0000
493 x = b.sra(x, 28); // 0xffff'fffe
494 x = b.shr(x, 1); // 0x7fff'ffff
495
496 b.store32(ptr, x);
497 }
498
Mike Klein92ca3ba2020-01-08 15:49:47 -0600499 test_jit_and_interpreter(r, b.done(), [&](const skvm::Program& program) {
Mike Klein81d52672019-07-30 11:11:09 -0500500 int x = 0x42;
501 program.eval(1, &x);
502 REPORTER_ASSERT(r, x == 0x7fff'ffff);
503 });
504}
505
506DEF_TEST(SkVM_f32, r) {
507 skvm::Builder b;
508 {
509 skvm::Arg arg = b.varying<float>();
510
511 skvm::F32 x = b.bit_cast(b.load32(arg)),
512 y = b.add(x,x), // y = 2x
513 z = b.sub(y,x), // z = 2x-x = x
514 w = b.div(z,x); // w = x/x = 1
515 b.store32(arg, b.bit_cast(w));
516 }
517
Mike Kleinb5a30762019-10-16 10:11:56 -0500518 test_jit_and_interpreter(r, b.done(), [&](const skvm::Program& program) {
Mike Klein81d52672019-07-30 11:11:09 -0500519 float buf[] = { 1,2,3,4,5,6,7,8,9 };
520 program.eval(SK_ARRAY_COUNT(buf), buf);
521 for (float v : buf) {
522 REPORTER_ASSERT(r, v == 1.0f);
523 }
524 });
525}
526
527DEF_TEST(SkVM_cmp_i32, r) {
528 skvm::Builder b;
529 {
530 skvm::I32 x = b.load32(b.varying<int>());
531
532 auto to_bit = [&](int shift, skvm::I32 mask) {
533 return b.shl(b.bit_and(mask, b.splat(0x1)), shift);
534 };
535
536 skvm::I32 m = b.splat(0);
537 m = b.bit_or(m, to_bit(0, b. eq(x, b.splat(0))));
538 m = b.bit_or(m, to_bit(1, b.neq(x, b.splat(1))));
539 m = b.bit_or(m, to_bit(2, b. lt(x, b.splat(2))));
540 m = b.bit_or(m, to_bit(3, b.lte(x, b.splat(3))));
541 m = b.bit_or(m, to_bit(4, b. gt(x, b.splat(4))));
542 m = b.bit_or(m, to_bit(5, b.gte(x, b.splat(5))));
543
544 b.store32(b.varying<int>(), m);
545 }
Herb Derby5c5bd1a2020-02-28 11:00:36 -0600546#if defined(SKVM_LLVM)
547 test_jit_and_interpreter
548#else
549 test_interpreter_only
550#endif
551 (r, b.done(), [&](const skvm::Program& program) {
Mike Klein81d52672019-07-30 11:11:09 -0500552 int in[] = { 0,1,2,3,4,5,6,7,8,9 };
553 int out[SK_ARRAY_COUNT(in)];
554
555 program.eval(SK_ARRAY_COUNT(in), in, out);
556
557 REPORTER_ASSERT(r, out[0] == 0b001111);
558 REPORTER_ASSERT(r, out[1] == 0b001100);
559 REPORTER_ASSERT(r, out[2] == 0b001010);
560 REPORTER_ASSERT(r, out[3] == 0b001010);
561 REPORTER_ASSERT(r, out[4] == 0b000010);
562 for (int i = 5; i < (int)SK_ARRAY_COUNT(out); i++) {
563 REPORTER_ASSERT(r, out[i] == 0b110010);
564 }
565 });
566}
567
568DEF_TEST(SkVM_cmp_f32, r) {
569 skvm::Builder b;
570 {
571 skvm::F32 x = b.bit_cast(b.load32(b.varying<float>()));
572
573 auto to_bit = [&](int shift, skvm::I32 mask) {
574 return b.shl(b.bit_and(mask, b.splat(0x1)), shift);
575 };
576
577 skvm::I32 m = b.splat(0);
578 m = b.bit_or(m, to_bit(0, b. eq(x, b.splat(0.0f))));
579 m = b.bit_or(m, to_bit(1, b.neq(x, b.splat(1.0f))));
580 m = b.bit_or(m, to_bit(2, b. lt(x, b.splat(2.0f))));
581 m = b.bit_or(m, to_bit(3, b.lte(x, b.splat(3.0f))));
582 m = b.bit_or(m, to_bit(4, b. gt(x, b.splat(4.0f))));
583 m = b.bit_or(m, to_bit(5, b.gte(x, b.splat(5.0f))));
584
585 b.store32(b.varying<int>(), m);
586 }
587
Mike Klein92ca3ba2020-01-08 15:49:47 -0600588 test_jit_and_interpreter(r, b.done(), [&](const skvm::Program& program) {
Mike Klein81d52672019-07-30 11:11:09 -0500589 float in[] = { 0,1,2,3,4,5,6,7,8,9 };
590 int out[SK_ARRAY_COUNT(in)];
591
592 program.eval(SK_ARRAY_COUNT(in), in, out);
593
594 REPORTER_ASSERT(r, out[0] == 0b001111);
595 REPORTER_ASSERT(r, out[1] == 0b001100);
596 REPORTER_ASSERT(r, out[2] == 0b001010);
597 REPORTER_ASSERT(r, out[3] == 0b001010);
598 REPORTER_ASSERT(r, out[4] == 0b000010);
599 for (int i = 5; i < (int)SK_ARRAY_COUNT(out); i++) {
600 REPORTER_ASSERT(r, out[i] == 0b110010);
601 }
602 });
603}
604
Mike Klein14548b92020-02-28 14:02:29 -0600605DEF_TEST(SkVM_index, r) {
606 skvm::Builder b;
607 b.store32(b.varying<int>(), b.index());
608
609#if defined(SKVM_LLVM) || defined(SK_CPU_X86)
610 test_jit_and_interpreter
611#else
612 test_interpreter_only
613#endif
614 (r, b.done(), [&](const skvm::Program& program) {
615 int buf[23];
616 program.eval(SK_ARRAY_COUNT(buf), buf);
617 for (int i = 0; i < (int)SK_ARRAY_COUNT(buf); i++) {
618 REPORTER_ASSERT(r, buf[i] == (int)SK_ARRAY_COUNT(buf)-i);
619 }
620 });
621}
622
Mike Klein81d52672019-07-30 11:11:09 -0500623DEF_TEST(SkVM_i16x2, r) {
624 skvm::Builder b;
625 {
626 skvm::Arg buf = b.varying<int>();
627
628 skvm::I32 x = b.load32(buf),
629 y = b.add_16x2(x,x), // y = 2x
630 z = b.mul_16x2(x,y), // z = 2x^2
631 w = b.sub_16x2(z,x), // w = x(2x-1)
632 v = b.shl_16x2(w,7), // These shifts will be a no-op
633 u = b.sra_16x2(v,7); // for all but x=12 and x=13.
634 b.store32(buf, u);
635 }
636
Mike Kleine96207a2020-02-28 13:20:06 -0600637#if defined(SKVM_LLVM)
638 test_jit_and_interpreter
639#else
640 test_interpreter_only
641#endif
642 (r, b.done(), [&](const skvm::Program& program) {
Mike Klein81d52672019-07-30 11:11:09 -0500643 uint16_t buf[] = { 0,1,2,3,4,5,6,7,8,9,10,11,12,13 };
644
645 program.eval(SK_ARRAY_COUNT(buf)/2, buf);
646 for (int i = 0; i < 12; i++) {
647 REPORTER_ASSERT(r, buf[i] == i*(2*i-1));
648 }
649 REPORTER_ASSERT(r, buf[12] == 0xff14); // 12*23 = 0x114
650 REPORTER_ASSERT(r, buf[13] == 0xff45); // 13*25 = 0x145
651 });
652}
653
654DEF_TEST(SkVM_cmp_i16, r) {
655 skvm::Builder b;
656 {
657 skvm::Arg buf = b.varying<int>();
658 skvm::I32 x = b.load32(buf);
659
660 auto to_bit = [&](int shift, skvm::I32 mask) {
661 return b.shl_16x2(b.bit_and(mask, b.splat(0x0001'0001)), shift);
662 };
663
664 skvm::I32 m = b.splat(0);
665 m = b.bit_or(m, to_bit(0, b. eq_16x2(x, b.splat(0x0000'0000))));
666 m = b.bit_or(m, to_bit(1, b.neq_16x2(x, b.splat(0x0001'0001))));
667 m = b.bit_or(m, to_bit(2, b. lt_16x2(x, b.splat(0x0002'0002))));
668 m = b.bit_or(m, to_bit(3, b.lte_16x2(x, b.splat(0x0003'0003))));
669 m = b.bit_or(m, to_bit(4, b. gt_16x2(x, b.splat(0x0004'0004))));
670 m = b.bit_or(m, to_bit(5, b.gte_16x2(x, b.splat(0x0005'0005))));
671
672 b.store32(buf, m);
673 }
674
Mike Kleine96207a2020-02-28 13:20:06 -0600675#if defined(SKVM_LLVM)
676 test_jit_and_interpreter
677#else
678 test_interpreter_only
679#endif
680 (r, b.done(), [&](const skvm::Program& program) {
Mike Klein81d52672019-07-30 11:11:09 -0500681 int16_t buf[] = { 0,1, 2,3, 4,5, 6,7, 8,9 };
682
683 program.eval(SK_ARRAY_COUNT(buf)/2, buf);
684
685 REPORTER_ASSERT(r, buf[0] == 0b001111);
686 REPORTER_ASSERT(r, buf[1] == 0b001100);
687 REPORTER_ASSERT(r, buf[2] == 0b001010);
688 REPORTER_ASSERT(r, buf[3] == 0b001010);
689 REPORTER_ASSERT(r, buf[4] == 0b000010);
690 for (int i = 5; i < (int)SK_ARRAY_COUNT(buf); i++) {
691 REPORTER_ASSERT(r, buf[i] == 0b110010);
692 }
693 });
694}
695
696
Mike Klein4a131192019-07-19 13:56:41 -0500697DEF_TEST(SkVM_mad, r) {
698 // This program is designed to exercise the tricky corners of instruction
699 // and register selection for Op::mad_f32.
700
701 skvm::Builder b;
702 {
Mike Klein5591fdf2019-07-30 09:44:30 -0500703 skvm::Arg arg = b.varying<int>();
Mike Klein4a131192019-07-19 13:56:41 -0500704
705 skvm::F32 x = b.to_f32(b.load32(arg)),
706 y = b.mad(x,x,x), // x is needed in the future, so r[x] != r[y].
707 z = b.mad(y,y,x), // y is needed in the future, but r[z] = r[x] is ok.
708 w = b.mad(z,z,y), // w can alias z but not y.
709 v = b.mad(w,y,w); // Got to stop somewhere.
Mike Klein6e4aad92019-11-08 14:13:15 -0600710 b.store32(arg, b.trunc(v));
Mike Klein4a131192019-07-19 13:56:41 -0500711 }
712
Mike Kleinb5a30762019-10-16 10:11:56 -0500713 test_jit_and_interpreter(r, b.done(), [&](const skvm::Program& program) {
Mike Klein4a131192019-07-19 13:56:41 -0500714 int x = 2;
715 program.eval(1, &x);
716 // x = 2
717 // y = 2*2 + 2 = 6
718 // z = 6*6 + 2 = 38
719 // w = 38*38 + 6 = 1450
720 // v = 1450*6 + 1450 = 10150
721 REPORTER_ASSERT(r, x == 10150);
722 });
723}
724
Mike Klein7c0332c2020-03-05 14:18:04 -0600725DEF_TEST(SkVM_fms, r) {
726 // Create a pattern that can be peepholed into an Op::fms_f32.
727 skvm::Builder b;
728 {
729 skvm::Arg arg = b.varying<int>();
730
731 skvm::F32 x = b.to_f32(b.load32(arg)),
732 v = b.sub(b.mul(x, b.splat(2.0f)),
733 b.splat(1.0f));
734 b.store32(arg, b.trunc(v));
735 }
736
737 test_jit_and_interpreter(r, b.done(), [&](const skvm::Program& program) {
738 int buf[] = {0,1,2,3,4,5,6,7,8,9,10};
739 program.eval((int)SK_ARRAY_COUNT(buf), &buf);
740
741 for (int i = 0; i < (int)SK_ARRAY_COUNT(buf); i++) {
742 REPORTER_ASSERT(r, buf[i] = 2*i-1);
743 }
744 });
745}
746
747DEF_TEST(SkVM_fnma, r) {
748 // Create a pattern that can be peepholed into an Op::fnma_f32.
749 skvm::Builder b;
750 {
751 skvm::Arg arg = b.varying<int>();
752
753 skvm::F32 x = b.to_f32(b.load32(arg)),
754 v = b.sub(b.splat(1.0f),
755 b.mul(x, b.splat(2.0f)));
756 b.store32(arg, b.trunc(v));
757 }
758
759 test_jit_and_interpreter(r, b.done(), [&](const skvm::Program& program) {
760 int buf[] = {0,1,2,3,4,5,6,7,8,9,10};
761 program.eval((int)SK_ARRAY_COUNT(buf), &buf);
762
763 for (int i = 0; i < (int)SK_ARRAY_COUNT(buf); i++) {
764 REPORTER_ASSERT(r, buf[i] = 1-2*i);
765 }
766 });
767}
768
Mike Klein81d52672019-07-30 11:11:09 -0500769DEF_TEST(SkVM_madder, r) {
770 skvm::Builder b;
771 {
772 skvm::Arg arg = b.varying<float>();
773
774 skvm::F32 x = b.bit_cast(b.load32(arg)),
775 y = b.mad(x,x,x), // x is needed in the future, so r[x] != r[y].
776 z = b.mad(y,x,y), // r[x] can be reused after this instruction, but not r[y].
777 w = b.mad(y,y,z);
778 b.store32(arg, b.bit_cast(w));
779 }
780
Mike Kleinb5a30762019-10-16 10:11:56 -0500781 test_jit_and_interpreter(r, b.done(), [&](const skvm::Program& program) {
Mike Klein81d52672019-07-30 11:11:09 -0500782 float x = 2.0f;
783 // y = 2*2 + 2 = 6
784 // z = 6*2 + 6 = 18
785 // w = 6*6 + 18 = 54
786 program.eval(1, &x);
787 REPORTER_ASSERT(r, x == 54.0f);
788 });
789}
790
Mike Kleinf22faaf2020-01-09 07:27:39 -0600791DEF_TEST(SkVM_floor, r) {
792 skvm::Builder b;
793 {
794 skvm::Arg arg = b.varying<float>();
795 b.store32(arg, b.bit_cast(b.floor(b.bit_cast(b.load32(arg)))));
796 }
797
798#if defined(SK_CPU_X86)
799 test_jit_and_interpreter
800#else
801 test_interpreter_only
802#endif
803 (r, b.done(), [&](const skvm::Program& program) {
804 float buf[] = { -2.0f, -1.5f, -1.0f, 0.0f, 1.0f, 1.5f, 2.0f };
805 float want[] = { -2.0f, -2.0f, -1.0f, 0.0f, 1.0f, 1.0f, 2.0f };
806 program.eval(SK_ARRAY_COUNT(buf), buf);
807 for (int i = 0; i < (int)SK_ARRAY_COUNT(buf); i++) {
808 REPORTER_ASSERT(r, buf[i] == want[i]);
809 }
810 });
811}
812
Mike Klein5caf7de2020-03-12 11:05:46 -0500813DEF_TEST(SkVM_round, r) {
814 skvm::Builder b;
815 {
816 skvm::Arg src = b.varying<float>();
817 skvm::Arg dst = b.varying<int>();
818 b.store32(dst, b.round(b.bit_cast(b.load32(src))));
819 }
820
821 // The test cases on exact 0.5f boundaries assume the current rounding mode is nearest even.
822 // We haven't explicitly guaranteed that here... it just probably is.
823 test_jit_and_interpreter(r, b.done(), [&](const skvm::Program& program) {
824 float buf[] = { -1.5f, -0.5f, 0.0f, 0.5f, 0.2f, 0.6f, 1.0f, 1.4f, 1.5f, 2.0f };
825 int want[] = { -2 , 0 , 0 , 0 , 0 , 1 , 1 , 1 , 2 , 2 };
826 int dst[SK_ARRAY_COUNT(buf)];
827
828 program.eval(SK_ARRAY_COUNT(buf), buf, dst);
829 for (int i = 0; i < (int)SK_ARRAY_COUNT(dst); i++) {
830 REPORTER_ASSERT(r, dst[i] == want[i]);
831 }
832 });
833}
834
Herb Derbyc02a41f2020-02-28 14:25:45 -0600835DEF_TEST(SkVM_min, r) {
836 skvm::Builder b;
837 {
838 skvm::Arg src1 = b.varying<float>();
839 skvm::Arg src2 = b.varying<float>();
840 skvm::Arg dst = b.varying<float>();
841
842 b.store32(dst, b.bit_cast(b.min(b.bit_cast(b.load32(src1)), b.bit_cast(b.load32(src2)))));
843 }
844
845 test_jit_and_interpreter(r, b.done(), [&](const skvm::Program& program) {
846 float s1[] = { 0.0f, 1.0f, 4.0f, -1.0f, -1.0f};
847 float s2[] = { 0.0f, 2.0f, 3.0f, 1.0f, -2.0f};
848 float want[] = { 0.0f, 1.0f, 3.0f, -1.0f, -2.0f};
849 float d[SK_ARRAY_COUNT(s1)];
850 program.eval(SK_ARRAY_COUNT(d), s1, s2, d);
851 for (int i = 0; i < (int)SK_ARRAY_COUNT(d); i++) {
852 REPORTER_ASSERT(r, d[i] == want[i]);
853 }
854 });
855}
856
857DEF_TEST(SkVM_max, r) {
858 skvm::Builder b;
859 {
860 skvm::Arg src1 = b.varying<float>();
861 skvm::Arg src2 = b.varying<float>();
862 skvm::Arg dst = b.varying<float>();
863
864 b.store32(dst, b.bit_cast(b.max(b.bit_cast(b.load32(src1)), b.bit_cast(b.load32(src2)))));
865 }
866
867 test_jit_and_interpreter(r, b.done(), [&](const skvm::Program& program) {
868 float s1[] = { 0.0f, 1.0f, 4.0f, -1.0f, -1.0f};
869 float s2[] = { 0.0f, 2.0f, 3.0f, 1.0f, -2.0f};
870 float want[] = { 0.0f, 2.0f, 4.0f, 1.0f, -1.0f};
871 float d[SK_ARRAY_COUNT(s1)];
872 program.eval(SK_ARRAY_COUNT(d), s1, s2, d);
873 for (int i = 0; i < (int)SK_ARRAY_COUNT(d); i++) {
874 REPORTER_ASSERT(r, d[i] == want[i]);
875 }
876 });
Herb Derbyfb4ff8d2020-02-28 11:59:10 -0600877}
878
Mike Kleinf98d0d32019-07-22 14:30:18 -0500879DEF_TEST(SkVM_hoist, r) {
880 // This program uses enough constants that it will fail to JIT if we hoist them.
881 // The JIT will try again without hoisting, and that'll just need 2 registers.
882 skvm::Builder b;
883 {
Mike Klein5591fdf2019-07-30 09:44:30 -0500884 skvm::Arg arg = b.varying<int>();
Mike Kleinf98d0d32019-07-22 14:30:18 -0500885 skvm::I32 x = b.load32(arg);
886 for (int i = 0; i < 32; i++) {
887 x = b.add(x, b.splat(i));
888 }
889 b.store32(arg, x);
890 }
891
Mike Klein0f61c122019-10-16 10:46:01 -0500892 test_jit_and_interpreter(r, b.done(), [&](const skvm::Program& program) {
Mike Kleinf98d0d32019-07-22 14:30:18 -0500893 int x = 4;
894 program.eval(1, &x);
895 // x += 0 + 1 + 2 + 3 + ... + 30 + 31
896 // x += 496
897 REPORTER_ASSERT(r, x == 500);
898 });
899}
900
Mike Kleinb9944122019-08-02 12:22:39 -0500901DEF_TEST(SkVM_select, r) {
902 skvm::Builder b;
903 {
904 skvm::Arg buf = b.varying<int>();
905
906 skvm::I32 x = b.load32(buf);
907
908 x = b.select( b.gt(x, b.splat(4)), x, b.splat(42) );
909
910 b.store32(buf, x);
911 }
912
Mike Klein97afd2e2019-10-16 14:11:27 -0500913 test_jit_and_interpreter(r, b.done(), [&](const skvm::Program& program) {
Mike Kleinb9944122019-08-02 12:22:39 -0500914 int buf[] = { 0,1,2,3,4,5,6,7,8 };
915 program.eval(SK_ARRAY_COUNT(buf), buf);
916 for (int i = 0; i < (int)SK_ARRAY_COUNT(buf); i++) {
917 REPORTER_ASSERT(r, buf[i] == (i > 4 ? i : 42));
918 }
919 });
920}
921
Mike Klein8ac9f4e2019-07-25 14:32:19 -0500922DEF_TEST(SkVM_NewOps, r) {
923 // Exercise a somewhat arbitrary set of new ops.
924 skvm::Builder b;
925 {
Mike Klein5591fdf2019-07-30 09:44:30 -0500926 skvm::Arg buf = b.varying<int16_t>(),
Mike Klein8ac9f4e2019-07-25 14:32:19 -0500927 uniforms = b.uniform();
928
929 skvm::I32 x = b.load16(buf);
930
Mike Klein6dbd7ff2020-01-06 11:50:37 -0600931 const size_t kPtr = sizeof(const int*);
Mike Klein8ac9f4e2019-07-25 14:32:19 -0500932
Mike Klein6dbd7ff2020-01-06 11:50:37 -0600933 x = b.add(x, b.uniform32(uniforms, kPtr+0));
934 x = b.mul(x, b.uniform8 (uniforms, kPtr+4));
935 x = b.sub(x, b.uniform16(uniforms, kPtr+6));
936
937 skvm::I32 limit = b.uniform32(uniforms, kPtr+8);
Mike Klein8ac9f4e2019-07-25 14:32:19 -0500938 x = b.select(b.lt(x, b.splat(0)), b.splat(0), x);
939 x = b.select(b.gt(x, limit ), limit , x);
940
Mike Klein6dbd7ff2020-01-06 11:50:37 -0600941 x = b.gather8(uniforms,0, x);
Mike Klein8ac9f4e2019-07-25 14:32:19 -0500942
943 b.store16(buf, x);
944 }
945
946 if ((false)) {
947 SkDynamicMemoryWStream buf;
948 dump(b, &buf);
949 sk_sp<SkData> blob = buf.detachAsData();
950 SkDebugf("%.*s\n", blob->size(), blob->data());
951 }
952
Mike Klein22c007d2020-02-28 11:38:58 -0600953#if defined(SKVM_LLVM)
954 test_jit_and_interpreter
955#else
956 test_interpreter_only
957#endif
958 (r, b.done(), [&](const skvm::Program& program) {
Mike Klein8ac9f4e2019-07-25 14:32:19 -0500959 const int N = 31;
960 int16_t buf[N];
961 for (int i = 0; i < N; i++) {
962 buf[i] = i;
963 }
964
965 const int M = 16;
966 uint8_t img[M];
967 for (int i = 0; i < M; i++) {
968 img[i] = i*i;
969 }
970
971 struct {
Mike Klein6dbd7ff2020-01-06 11:50:37 -0600972 const uint8_t* img;
Mike Klein8ac9f4e2019-07-25 14:32:19 -0500973 int add = 5;
974 uint8_t mul = 3;
975 uint16_t sub = 18;
976 int limit = M-1;
Mike Klein6dbd7ff2020-01-06 11:50:37 -0600977 } uniforms{img};
Mike Klein8ac9f4e2019-07-25 14:32:19 -0500978
Mike Klein6dbd7ff2020-01-06 11:50:37 -0600979 program.eval(N, buf, &uniforms);
Mike Klein8ac9f4e2019-07-25 14:32:19 -0500980
981 for (int i = 0; i < N; i++) {
982 // Our first math calculates x = (i+5)*3 - 18 a.k.a 3*(i-1).
983 int x = 3*(i-1);
984
985 // Then that's pinned to the limits of img.
986 if (i < 2) { x = 0; } // Notice i == 1 hits x == 0 exactly...
987 if (i > 5) { x = 15; } // ...and i == 6 hits x == 15 exactly
988 REPORTER_ASSERT(r, buf[i] == img[x]);
989 }
990 });
991}
992
Mike Klein5a8404c2020-02-28 14:24:56 -0600993DEF_TEST(SkVM_sqrt, r) {
994 skvm::Builder b;
995 auto buf = b.varying<int>();
996 b.store32(buf, b.bit_cast(b.sqrt(b.bit_cast(b.load32(buf)))));
997
998#if defined(SKVM_LLVM) || defined(SK_CPU_X86)
999 test_jit_and_interpreter
1000#else
1001 test_interpreter_only
1002#endif
1003 (r, b.done(), [&](const skvm::Program& program) {
1004 constexpr int K = 17;
1005 float buf[K];
1006 for (int i = 0; i < K; i++) {
1007 buf[i] = (float)(i*i);
1008 }
1009
1010 // x^2 -> x
1011 program.eval(K, buf);
1012
1013 for (int i = 0; i < K; i++) {
1014 REPORTER_ASSERT(r, buf[i] == (float)i);
1015 }
1016 });
1017}
1018
Mike Klein3f7c8652019-11-07 10:33:56 -06001019DEF_TEST(SkVM_MSAN, r) {
1020 // This little memset32() program should be able to JIT, but if we run that
1021 // JIT code in an MSAN build, it won't see the writes initialize buf. So
1022 // this tests that we're using the interpreter instead.
1023 skvm::Builder b;
1024 b.store32(b.varying<int>(), b.splat(42));
1025
1026 test_jit_and_interpreter(r, b.done(), [&](const skvm::Program& program) {
1027 constexpr int K = 17;
1028 int buf[K]; // Intentionally uninitialized.
1029 program.eval(K, buf);
1030 sk_msan_assert_initialized(buf, buf+K);
1031 for (int x : buf) {
1032 REPORTER_ASSERT(r, x == 42);
1033 }
1034 });
1035}
1036
Mike Klein13601172019-11-08 15:01:02 -06001037DEF_TEST(SkVM_assert, r) {
1038 skvm::Builder b;
1039 b.assert_true(b.lt(b.load32(b.varying<int>()),
1040 b.splat(42)));
1041
1042 test_jit_and_interpreter(r, b.done(), [&](const skvm::Program& program) {
Mike Klein749eef62019-11-11 09:47:44 -06001043 int buf[] = { 0,1,2,3,4,5,6,7,8,9 };
Mike Klein13601172019-11-08 15:01:02 -06001044 program.eval(SK_ARRAY_COUNT(buf), buf);
1045 });
1046}
1047
Mike Kleinbc1ce2c2020-02-03 12:17:13 -06001048DEF_TEST(SkVM_premul, reporter) {
1049 // Test that premul is short-circuited when alpha is known opaque.
1050 {
1051 skvm::Builder p;
1052 auto rptr = p.varying<int>(),
1053 aptr = p.varying<int>();
1054
1055 skvm::F32 r = p.bit_cast(p.load32(rptr)),
1056 g = p.splat(0.0f),
1057 b = p.splat(0.0f),
1058 a = p.bit_cast(p.load32(aptr));
1059
1060 p.premul(&r, &g, &b, a);
1061 p.store32(rptr, p.bit_cast(r));
1062
1063 // load red, load alpha, red *= alpha, store red
1064 REPORTER_ASSERT(reporter, p.done().instructions().size() == 4);
1065 }
1066
1067 {
1068 skvm::Builder p;
1069 auto rptr = p.varying<int>();
1070
1071 skvm::F32 r = p.bit_cast(p.load32(rptr)),
1072 g = p.splat(0.0f),
1073 b = p.splat(0.0f),
1074 a = p.splat(1.0f);
1075
1076 p.premul(&r, &g, &b, a);
1077 p.store32(rptr, p.bit_cast(r));
1078
1079 // load red, store red
1080 REPORTER_ASSERT(reporter, p.done().instructions().size() == 2);
1081 }
1082
1083 // Same deal for unpremul.
1084 {
1085 skvm::Builder p;
1086 auto rptr = p.varying<int>(),
1087 aptr = p.varying<int>();
1088
1089 skvm::F32 r = p.bit_cast(p.load32(rptr)),
1090 g = p.splat(0.0f),
1091 b = p.splat(0.0f),
1092 a = p.bit_cast(p.load32(aptr));
1093
1094 p.unpremul(&r, &g, &b, a);
1095 p.store32(rptr, p.bit_cast(r));
1096
1097 // load red, load alpha, a bunch of unpremul instructions, store red
1098 REPORTER_ASSERT(reporter, p.done().instructions().size() >= 4);
1099 }
1100
1101 {
1102 skvm::Builder p;
1103 auto rptr = p.varying<int>();
1104
1105 skvm::F32 r = p.bit_cast(p.load32(rptr)),
1106 g = p.splat(0.0f),
1107 b = p.splat(0.0f),
1108 a = p.splat(1.0f);
1109
1110 p.unpremul(&r, &g, &b, a);
1111 p.store32(rptr, p.bit_cast(r));
1112
1113 // load red, store red
1114 REPORTER_ASSERT(reporter, p.done().instructions().size() == 2);
1115 }
1116}
Mike Klein05642042019-06-18 12:16:06 -05001117
Mike Klein05642042019-06-18 12:16:06 -05001118template <typename Fn>
1119static void test_asm(skiatest::Reporter* r, Fn&& fn, std::initializer_list<uint8_t> expected) {
Mike Klein88c0a902019-06-24 15:34:02 -04001120 uint8_t buf[4096];
1121 skvm::Assembler a{buf};
Mike Klein05642042019-06-18 12:16:06 -05001122 fn(a);
1123
1124 REPORTER_ASSERT(r, a.size() == expected.size());
1125
Mike Klein88c0a902019-06-24 15:34:02 -04001126 auto got = (const uint8_t*)buf,
Mike Klein05642042019-06-18 12:16:06 -05001127 want = expected.begin();
1128 for (int i = 0; i < (int)std::min(a.size(), expected.size()); i++) {
Mike Klein61703a62019-06-18 15:01:12 -05001129 REPORTER_ASSERT(r, got[i] == want[i],
1130 "byte %d was %02x, want %02x", i, got[i], want[i]);
Mike Klein05642042019-06-18 12:16:06 -05001131 }
1132}
1133
1134DEF_TEST(SkVM_Assembler, r) {
Mike Klein397fc882019-06-20 11:37:10 -05001135 // Easiest way to generate test cases is
1136 //
1137 // echo '...some asm...' | llvm-mc -show-encoding -x86-asm-syntax=intel
1138 //
1139 // The -x86-asm-syntax=intel bit is optional, controlling the
1140 // input syntax only; the output will always be AT&T op x,y,dst style.
1141 // Our APIs read more like Intel op dst,x,y as op(dst,x,y), so I find
1142 // that a bit easier to use here, despite maybe favoring AT&T overall.
1143
1144 using A = skvm::Assembler;
Mike Klein05642042019-06-18 12:16:06 -05001145 // Our exit strategy from AVX code.
Mike Klein397fc882019-06-20 11:37:10 -05001146 test_asm(r, [&](A& a) {
Mike Kleinee5864a2019-11-11 09:16:44 -06001147 a.int3();
Mike Klein05642042019-06-18 12:16:06 -05001148 a.vzeroupper();
1149 a.ret();
1150 },{
Mike Kleinee5864a2019-11-11 09:16:44 -06001151 0xcc,
Mike Klein05642042019-06-18 12:16:06 -05001152 0xc5, 0xf8, 0x77,
1153 0xc3,
1154 });
1155
Mike Klein237dbb42019-07-19 09:44:47 -05001156 // Align should pad with zero
Mike Klein397fc882019-06-20 11:37:10 -05001157 test_asm(r, [&](A& a) {
Mike Klein05642042019-06-18 12:16:06 -05001158 a.ret();
1159 a.align(4);
1160 },{
1161 0xc3,
Mike Klein237dbb42019-07-19 09:44:47 -05001162 0x00, 0x00, 0x00,
Mike Klein05642042019-06-18 12:16:06 -05001163 });
Mike Klein61703a62019-06-18 15:01:12 -05001164
Mike Klein397fc882019-06-20 11:37:10 -05001165 test_asm(r, [&](A& a) {
1166 a.add(A::rax, 8); // Always good to test rax.
1167 a.sub(A::rax, 32);
Mike Kleind3e75a72019-06-18 15:26:08 -05001168
Mike Klein397fc882019-06-20 11:37:10 -05001169 a.add(A::rdi, 12); // Last 0x48 REX
1170 a.sub(A::rdi, 8);
Mike Kleind3e75a72019-06-18 15:26:08 -05001171
Mike Klein86a645c2019-07-12 12:29:39 -05001172 a.add(A::r8 , 7); // First 0x49 REX
Mike Klein397fc882019-06-20 11:37:10 -05001173 a.sub(A::r8 , 4);
Mike Kleind3e75a72019-06-18 15:26:08 -05001174
Mike Klein397fc882019-06-20 11:37:10 -05001175 a.add(A::rsi, 128); // Requires 4 byte immediate.
1176 a.sub(A::r8 , 1000000);
Mike Klein61703a62019-06-18 15:01:12 -05001177 },{
Mike Kleind3e75a72019-06-18 15:26:08 -05001178 0x48, 0x83, 0b11'000'000, 0x08,
Mike Klein61703a62019-06-18 15:01:12 -05001179 0x48, 0x83, 0b11'101'000, 0x20,
Mike Kleind3e75a72019-06-18 15:26:08 -05001180
1181 0x48, 0x83, 0b11'000'111, 0x0c,
Mike Klein61703a62019-06-18 15:01:12 -05001182 0x48, 0x83, 0b11'101'111, 0x08,
Mike Kleind3e75a72019-06-18 15:26:08 -05001183
Mike Klein86a645c2019-07-12 12:29:39 -05001184 0x49, 0x83, 0b11'000'000, 0x07,
1185 0x49, 0x83, 0b11'101'000, 0x04,
Mike Kleind3e75a72019-06-18 15:26:08 -05001186
1187 0x48, 0x81, 0b11'000'110, 0x80, 0x00, 0x00, 0x00,
Mike Klein86a645c2019-07-12 12:29:39 -05001188 0x49, 0x81, 0b11'101'000, 0x40, 0x42, 0x0f, 0x00,
Mike Klein61703a62019-06-18 15:01:12 -05001189 });
Mike Klein397fc882019-06-20 11:37:10 -05001190
1191
1192 test_asm(r, [&](A& a) {
1193 a.vpaddd (A::ymm0, A::ymm1, A::ymm2); // Low registers and 0x0f map -> 2-byte VEX.
1194 a.vpaddd (A::ymm8, A::ymm1, A::ymm2); // A high dst register is ok -> 2-byte VEX.
1195 a.vpaddd (A::ymm0, A::ymm8, A::ymm2); // A high first argument register -> 2-byte VEX.
1196 a.vpaddd (A::ymm0, A::ymm1, A::ymm8); // A high second argument -> 3-byte VEX.
1197 a.vpmulld(A::ymm0, A::ymm1, A::ymm2); // Using non-0x0f map instruction -> 3-byte VEX.
1198 a.vpsubd (A::ymm0, A::ymm1, A::ymm2); // Test vpsubd to ensure argument order is right.
1199 },{
1200 /* VEX */ /*op*/ /*modRM*/
1201 0xc5, 0xf5, 0xfe, 0xc2,
1202 0xc5, 0x75, 0xfe, 0xc2,
1203 0xc5, 0xbd, 0xfe, 0xc2,
1204 0xc4, 0xc1, 0x75, 0xfe, 0xc0,
1205 0xc4, 0xe2, 0x75, 0x40, 0xc2,
1206 0xc5, 0xf5, 0xfa, 0xc2,
1207 });
Mike Kleinff0ae812019-06-20 15:03:44 -05001208
1209 test_asm(r, [&](A& a) {
Mike Klein714f8cc2019-11-06 12:54:46 -06001210 a.vpcmpeqd (A::ymm0, A::ymm1, A::ymm2);
1211 a.vpcmpgtd (A::ymm0, A::ymm1, A::ymm2);
1212 a.vcmpeqps (A::ymm0, A::ymm1, A::ymm2);
1213 a.vcmpltps (A::ymm0, A::ymm1, A::ymm2);
1214 a.vcmpleps (A::ymm0, A::ymm1, A::ymm2);
1215 a.vcmpneqps(A::ymm0, A::ymm1, A::ymm2);
Mike Kleinb9944122019-08-02 12:22:39 -05001216 },{
1217 0xc5,0xf5,0x76,0xc2,
1218 0xc5,0xf5,0x66,0xc2,
Mike Klein714f8cc2019-11-06 12:54:46 -06001219 0xc5,0xf4,0xc2,0xc2,0x00,
1220 0xc5,0xf4,0xc2,0xc2,0x01,
1221 0xc5,0xf4,0xc2,0xc2,0x02,
1222 0xc5,0xf4,0xc2,0xc2,0x04,
Mike Kleinb9944122019-08-02 12:22:39 -05001223 });
1224
1225 test_asm(r, [&](A& a) {
Mike Kleina53e47f2019-11-08 13:38:47 -06001226 a.vminps(A::ymm0, A::ymm1, A::ymm2);
1227 a.vmaxps(A::ymm0, A::ymm1, A::ymm2);
1228 },{
1229 0xc5,0xf4,0x5d,0xc2,
1230 0xc5,0xf4,0x5f,0xc2,
1231 });
1232
1233 test_asm(r, [&](A& a) {
Mike Kleinb9944122019-08-02 12:22:39 -05001234 a.vpblendvb(A::ymm0, A::ymm1, A::ymm2, A::ymm3);
1235 },{
1236 0xc4,0xe3,0x75, 0x4c, 0xc2, 0x30,
1237 });
1238
1239 test_asm(r, [&](A& a) {
Mike Kleinff0ae812019-06-20 15:03:44 -05001240 a.vpsrld(A::ymm15, A::ymm2, 8);
1241 a.vpsrld(A::ymm0 , A::ymm8, 5);
1242 },{
1243 0xc5, 0x85, 0x72,0xd2, 0x08,
1244 0xc4,0xc1,0x7d, 0x72,0xd0, 0x05,
1245 });
1246
1247 test_asm(r, [&](A& a) {
1248 a.vpermq(A::ymm1, A::ymm2, 5);
1249 },{
1250 0xc4,0xe3,0xfd, 0x00,0xca, 0x05,
1251 });
Mike Kleine5053412019-06-21 12:37:22 -05001252
1253 test_asm(r, [&](A& a) {
Mike Kleinf22faaf2020-01-09 07:27:39 -06001254 a.vroundps(A::ymm1, A::ymm2, A::NEAREST);
1255 a.vroundps(A::ymm1, A::ymm2, A::FLOOR);
1256 a.vroundps(A::ymm1, A::ymm2, A::CEIL);
1257 a.vroundps(A::ymm1, A::ymm2, A::TRUNC);
1258 },{
1259 0xc4,0xe3,0x7d,0x08,0xca,0x00,
1260 0xc4,0xe3,0x7d,0x08,0xca,0x01,
1261 0xc4,0xe3,0x7d,0x08,0xca,0x02,
1262 0xc4,0xe3,0x7d,0x08,0xca,0x03,
1263 });
1264
1265 test_asm(r, [&](A& a) {
Mike Kleine5053412019-06-21 12:37:22 -05001266 A::Label l = a.here();
1267 a.byte(1);
1268 a.byte(2);
1269 a.byte(3);
1270 a.byte(4);
Mike Klein04db9c22019-06-21 14:19:21 -05001271
Mike Klein65c10b52019-07-12 09:22:21 -05001272 a.vbroadcastss(A::ymm0 , &l);
1273 a.vbroadcastss(A::ymm1 , &l);
1274 a.vbroadcastss(A::ymm8 , &l);
1275 a.vbroadcastss(A::ymm15, &l);
Mike Klein04db9c22019-06-21 14:19:21 -05001276
Mike Klein65c10b52019-07-12 09:22:21 -05001277 a.vpshufb(A::ymm4, A::ymm3, &l);
Mike Klein7a13b462019-11-05 07:46:02 -06001278 a.vpaddd (A::ymm4, A::ymm3, &l);
1279 a.vpsubd (A::ymm4, A::ymm3, &l);
Mike Kleinee5864a2019-11-11 09:16:44 -06001280
1281 a.vptest(A::ymm4, &l);
Mike Klein8c1e0ef2019-11-12 09:07:23 -06001282
1283 a.vmulps (A::ymm4, A::ymm3, &l);
Mike Kleine5053412019-06-21 12:37:22 -05001284 },{
1285 0x01, 0x02, 0x03, 0x4,
Mike Klein04db9c22019-06-21 14:19:21 -05001286
Mike Kleine5053412019-06-21 12:37:22 -05001287 /* VEX */ /*op*/ /* ModRM */ /* offset */
1288 0xc4, 0xe2, 0x7d, 0x18, 0b00'000'101, 0xf3,0xff,0xff,0xff, // 0xfffffff3 == -13
1289 0xc4, 0xe2, 0x7d, 0x18, 0b00'001'101, 0xea,0xff,0xff,0xff, // 0xffffffea == -22
1290 0xc4, 0x62, 0x7d, 0x18, 0b00'000'101, 0xe1,0xff,0xff,0xff, // 0xffffffe1 == -31
1291 0xc4, 0x62, 0x7d, 0x18, 0b00'111'101, 0xd8,0xff,0xff,0xff, // 0xffffffd8 == -40
Mike Klein04db9c22019-06-21 14:19:21 -05001292
1293 0xc4, 0xe2, 0x65, 0x00, 0b00'100'101, 0xcf,0xff,0xff,0xff, // 0xffffffcf == -49
Mike Klein7a13b462019-11-05 07:46:02 -06001294
1295 0xc5, 0xe5, 0xfe, 0b00'100'101, 0xc7,0xff,0xff,0xff, // 0xffffffc7 == -57
1296 0xc5, 0xe5, 0xfa, 0b00'100'101, 0xbf,0xff,0xff,0xff, // 0xffffffbf == -65
Mike Kleinee5864a2019-11-11 09:16:44 -06001297
Mike Klein8c1e0ef2019-11-12 09:07:23 -06001298 0xc4, 0xe2, 0x7d, 0x17, 0b00'100'101, 0xb6,0xff,0xff,0xff, // 0xffffffb6 == -74
1299
1300 0xc5, 0xe4, 0x59, 0b00'100'101, 0xae,0xff,0xff,0xff, // 0xffffffaf == -82
Mike Kleine5053412019-06-21 12:37:22 -05001301 });
Mike Klein060eaaa2019-06-21 14:42:09 -05001302
1303 test_asm(r, [&](A& a) {
Mike Klein788967e2019-08-02 10:15:51 -05001304 a.vbroadcastss(A::ymm0, A::rdi, 0);
1305 a.vbroadcastss(A::ymm13, A::r14, 7);
1306 a.vbroadcastss(A::ymm8, A::rdx, -12);
1307 a.vbroadcastss(A::ymm8, A::rdx, 400);
Mike Klein94d054b2019-08-02 10:54:23 -05001308
1309 a.vbroadcastss(A::ymm8, A::xmm0);
1310 a.vbroadcastss(A::ymm0, A::xmm13);
Mike Klein788967e2019-08-02 10:15:51 -05001311 },{
1312 /* VEX */ /*op*/ /*ModRM*/ /*offset*/
1313 0xc4,0xe2,0x7d, 0x18, 0b00'000'111,
1314 0xc4,0x42,0x7d, 0x18, 0b01'101'110, 0x07,
1315 0xc4,0x62,0x7d, 0x18, 0b01'000'010, 0xf4,
1316 0xc4,0x62,0x7d, 0x18, 0b10'000'010, 0x90,0x01,0x00,0x00,
Mike Klein94d054b2019-08-02 10:54:23 -05001317
1318 0xc4,0x62,0x7d, 0x18, 0b11'000'000,
1319 0xc4,0xc2,0x7d, 0x18, 0b11'000'101,
Mike Klein788967e2019-08-02 10:15:51 -05001320 });
1321
1322 test_asm(r, [&](A& a) {
Mike Klein060eaaa2019-06-21 14:42:09 -05001323 A::Label l = a.here();
Mike Klein65c10b52019-07-12 09:22:21 -05001324 a.jne(&l);
1325 a.jne(&l);
Mike Klein35b97c32019-07-12 12:32:45 -05001326 a.je (&l);
1327 a.jmp(&l);
1328 a.jl (&l);
Mike Kleinee5864a2019-11-11 09:16:44 -06001329 a.jc (&l);
Mike Klein35b97c32019-07-12 12:32:45 -05001330
1331 a.cmp(A::rdx, 0);
1332 a.cmp(A::rax, 12);
1333 a.cmp(A::r14, 2000000000);
Mike Klein060eaaa2019-06-21 14:42:09 -05001334 },{
Mike Klein35b97c32019-07-12 12:32:45 -05001335 0x0f,0x85, 0xfa,0xff,0xff,0xff, // near jne -6 bytes
1336 0x0f,0x85, 0xf4,0xff,0xff,0xff, // near jne -12 bytes
1337 0x0f,0x84, 0xee,0xff,0xff,0xff, // near je -18 bytes
1338 0xe9, 0xe9,0xff,0xff,0xff, // near jmp -23 bytes
1339 0x0f,0x8c, 0xe3,0xff,0xff,0xff, // near jl -29 bytes
Mike Kleinee5864a2019-11-11 09:16:44 -06001340 0x0f,0x82, 0xdd,0xff,0xff,0xff, // near jc -35 bytes
Mike Klein35b97c32019-07-12 12:32:45 -05001341
1342 0x48,0x83,0xfa,0x00,
1343 0x48,0x83,0xf8,0x0c,
1344 0x49,0x81,0xfe,0x00,0x94,0x35,0x77,
Mike Klein060eaaa2019-06-21 14:42:09 -05001345 });
Mike Klein120d9e82019-06-21 15:52:55 -05001346
1347 test_asm(r, [&](A& a) {
1348 a.vmovups(A::ymm5, A::rsi);
1349 a.vmovups(A::rsi, A::ymm5);
Mike Kleinae51aa32019-06-21 16:06:03 -05001350
Mike Klein95529e82019-08-02 11:43:43 -05001351 a.vmovups(A::rsi, A::xmm5);
1352
Mike Klein52010b72019-08-02 11:18:00 -05001353 a.vpmovzxwd(A::ymm4, A::rsi);
Mike Kleinae51aa32019-06-21 16:06:03 -05001354 a.vpmovzxbd(A::ymm4, A::rsi);
Mike Kleinf3881b22019-06-21 16:20:24 -05001355
1356 a.vmovq(A::rdx, A::xmm15);
Mike Klein120d9e82019-06-21 15:52:55 -05001357 },{
Mike Kleinae51aa32019-06-21 16:06:03 -05001358 /* VEX */ /*Op*/ /* ModRM */
1359 0xc5, 0xfc, 0x10, 0b00'101'110,
1360 0xc5, 0xfc, 0x11, 0b00'101'110,
1361
Mike Klein95529e82019-08-02 11:43:43 -05001362 0xc5, 0xf8, 0x11, 0b00'101'110,
1363
Mike Klein52010b72019-08-02 11:18:00 -05001364 0xc4,0xe2,0x7d, 0x33, 0b00'100'110,
Mike Kleinae51aa32019-06-21 16:06:03 -05001365 0xc4,0xe2,0x7d, 0x31, 0b00'100'110,
Mike Kleinf3881b22019-06-21 16:20:24 -05001366
1367 0xc5, 0x79, 0xd6, 0b00'111'010,
Mike Klein120d9e82019-06-21 15:52:55 -05001368 });
Mike Klein2b7b2a22019-06-23 20:35:28 -04001369
1370 test_asm(r, [&](A& a) {
Mike Klein94d054b2019-08-02 10:54:23 -05001371 a.movzbl(A::rax, A::rsi, 0); // Low registers for src and dst.
1372 a.movzbl(A::rax, A::r8, 0); // High src register.
1373 a.movzbl(A::r8 , A::rsi, 0); // High dst register.
1374 a.movzbl(A::r8, A::rsi, 12);
1375 a.movzbl(A::r8, A::rsi, 400);
Mike Klein35b97c32019-07-12 12:32:45 -05001376
1377 a.vmovd(A::rax, A::xmm0);
1378 a.vmovd(A::rax, A::xmm8);
1379 a.vmovd(A::r8, A::xmm0);
1380
1381 a.vmovd(A::xmm0, A::rax);
1382 a.vmovd(A::xmm8, A::rax);
1383 a.vmovd(A::xmm0, A::r8);
1384
Mike Klein93d3fab2020-01-14 10:46:44 -06001385 a.vmovd(A::xmm0 , A::FOUR, A::rcx, A::rax);
1386 a.vmovd(A::xmm15, A::TWO, A::r8, A::rax);
1387 a.vmovd(A::xmm0 , A::ONE, A::rcx, A::r8);
1388
Mike Klein35b97c32019-07-12 12:32:45 -05001389 a.vmovd_direct(A::rax, A::xmm0);
1390 a.vmovd_direct(A::rax, A::xmm8);
1391 a.vmovd_direct(A::r8, A::xmm0);
1392
1393 a.vmovd_direct(A::xmm0, A::rax);
1394 a.vmovd_direct(A::xmm8, A::rax);
1395 a.vmovd_direct(A::xmm0, A::r8);
1396
1397 a.movb(A::rdx, A::rax);
1398 a.movb(A::rdx, A::r8);
1399 a.movb(A::r8 , A::rax);
1400 },{
1401 0x0f,0xb6,0x06,
1402 0x41,0x0f,0xb6,0x00,
1403 0x44,0x0f,0xb6,0x06,
Mike Klein94d054b2019-08-02 10:54:23 -05001404 0x44,0x0f,0xb6,0x46, 12,
1405 0x44,0x0f,0xb6,0x86, 0x90,0x01,0x00,0x00,
Mike Klein35b97c32019-07-12 12:32:45 -05001406
1407 0xc5,0xf9,0x7e,0x00,
1408 0xc5,0x79,0x7e,0x00,
1409 0xc4,0xc1,0x79,0x7e,0x00,
1410
1411 0xc5,0xf9,0x6e,0x00,
1412 0xc5,0x79,0x6e,0x00,
1413 0xc4,0xc1,0x79,0x6e,0x00,
1414
Mike Klein93d3fab2020-01-14 10:46:44 -06001415 0xc5,0xf9,0x6e,0x04,0x88,
1416 0xc4,0x21,0x79,0x6e,0x3c,0x40,
1417 0xc4,0xc1,0x79,0x6e,0x04,0x08,
1418
Mike Klein35b97c32019-07-12 12:32:45 -05001419 0xc5,0xf9,0x7e,0xc0,
1420 0xc5,0x79,0x7e,0xc0,
1421 0xc4,0xc1,0x79,0x7e,0xc0,
1422
1423 0xc5,0xf9,0x6e,0xc0,
1424 0xc5,0x79,0x6e,0xc0,
1425 0xc4,0xc1,0x79,0x6e,0xc0,
1426
1427 0x88, 0x02,
1428 0x44, 0x88, 0x02,
1429 0x41, 0x88, 0x00,
1430 });
1431
1432 test_asm(r, [&](A& a) {
Mike Klein52010b72019-08-02 11:18:00 -05001433 a.vpinsrw(A::xmm1, A::xmm8, A::rsi, 4);
1434 a.vpinsrw(A::xmm8, A::xmm1, A::r8, 12);
1435
Mike Klein35b97c32019-07-12 12:32:45 -05001436 a.vpinsrb(A::xmm1, A::xmm8, A::rsi, 4);
1437 a.vpinsrb(A::xmm8, A::xmm1, A::r8, 12);
1438
Mike Klein95529e82019-08-02 11:43:43 -05001439 a.vpextrw(A::rsi, A::xmm8, 7);
1440 a.vpextrw(A::r8, A::xmm1, 15);
1441
Mike Klein35b97c32019-07-12 12:32:45 -05001442 a.vpextrb(A::rsi, A::xmm8, 7);
1443 a.vpextrb(A::r8, A::xmm1, 15);
1444 },{
Mike Klein52010b72019-08-02 11:18:00 -05001445 0xc5,0xb9, 0xc4, 0x0e, 4,
1446 0xc4,0x41,0x71, 0xc4, 0x00, 12,
1447
Mike Klein35b97c32019-07-12 12:32:45 -05001448 0xc4,0xe3,0x39, 0x20, 0x0e, 4,
1449 0xc4,0x43,0x71, 0x20, 0x00, 12,
1450
Mike Klein95529e82019-08-02 11:43:43 -05001451 0xc4,0x63,0x79, 0x15, 0x06, 7,
1452 0xc4,0xc3,0x79, 0x15, 0x08, 15,
1453
Mike Klein35b97c32019-07-12 12:32:45 -05001454 0xc4,0x63,0x79, 0x14, 0x06, 7,
1455 0xc4,0xc3,0x79, 0x14, 0x08, 15,
1456 });
1457
1458 test_asm(r, [&](A& a) {
Mike Klein2b7b2a22019-06-23 20:35:28 -04001459 a.vpandn(A::ymm3, A::ymm12, A::ymm2);
1460 },{
1461 0xc5, 0x9d, 0xdf, 0xda,
1462 });
Mike Klein9f4df802019-06-24 18:47:16 -04001463
Mike Kleind4546d62019-07-30 12:15:40 -05001464 test_asm(r, [&](A& a) {
1465 a.vmovdqa (A::ymm3, A::ymm2);
1466 a.vcvttps2dq(A::ymm3, A::ymm2);
1467 a.vcvtdq2ps (A::ymm3, A::ymm2);
Mike Klein6e4aad92019-11-08 14:13:15 -06001468 a.vcvtps2dq (A::ymm3, A::ymm2);
Mike Kleinba9da462020-01-28 14:25:09 -06001469 a.vsqrtps (A::ymm3, A::ymm2);
Mike Kleind4546d62019-07-30 12:15:40 -05001470 },{
1471 0xc5,0xfd,0x6f,0xda,
1472 0xc5,0xfe,0x5b,0xda,
1473 0xc5,0xfc,0x5b,0xda,
Mike Klein6e4aad92019-11-08 14:13:15 -06001474 0xc5,0xfd,0x5b,0xda,
Mike Kleinba9da462020-01-28 14:25:09 -06001475 0xc5,0xfc,0x51,0xda,
Mike Kleind4546d62019-07-30 12:15:40 -05001476 });
1477
Mike Kleinbeaa1082020-01-13 14:04:18 -06001478 test_asm(r, [&](A& a) {
1479 a.vgatherdps(A::ymm1 , A::FOUR , A::ymm0 , A::rdi, A::ymm2 );
1480 a.vgatherdps(A::ymm0 , A::ONE , A::ymm2 , A::rax, A::ymm1 );
1481 a.vgatherdps(A::ymm10, A::ONE , A::ymm2 , A::rax, A::ymm1 );
1482 a.vgatherdps(A::ymm0 , A::ONE , A::ymm12, A::rax, A::ymm1 );
1483 a.vgatherdps(A::ymm0 , A::ONE , A::ymm2 , A::r9 , A::ymm1 );
1484 a.vgatherdps(A::ymm0 , A::ONE , A::ymm2 , A::rax, A::ymm12);
1485 a.vgatherdps(A::ymm0 , A::EIGHT, A::ymm2 , A::rax, A::ymm12);
1486 },{
1487 0xc4,0xe2,0x6d,0x92,0x0c,0x87,
1488 0xc4,0xe2,0x75,0x92,0x04,0x10,
1489 0xc4,0x62,0x75,0x92,0x14,0x10,
1490 0xc4,0xa2,0x75,0x92,0x04,0x20,
1491 0xc4,0xc2,0x75,0x92,0x04,0x11,
1492 0xc4,0xe2,0x1d,0x92,0x04,0x10,
1493 0xc4,0xe2,0x1d,0x92,0x04,0xd0,
1494 });
1495
Mike Kleinc322f632020-01-13 16:18:58 -06001496 test_asm(r, [&](A& a) {
1497 a.movq(A::rax, A::rdi, 0);
1498 a.movq(A::rax, A::rdi, 1);
1499 a.movq(A::rax, A::rdi, 512);
1500 a.movq(A::r15, A::r13, 42);
1501 a.movq(A::rax, A::r13, 42);
1502 a.movq(A::r15, A::rax, 42);
1503 },{
1504 0x48, 0x8b, 0x07,
1505 0x48, 0x8b, 0x47, 0x01,
1506 0x48, 0x8b, 0x87, 0x00,0x02,0x00,0x00,
1507 0x4d, 0x8b, 0x7d, 0x2a,
1508 0x49, 0x8b, 0x45, 0x2a,
1509 0x4c, 0x8b, 0x78, 0x2a,
1510 });
1511
Mike Klein9f4df802019-06-24 18:47:16 -04001512 // echo "fmul v4.4s, v3.4s, v1.4s" | llvm-mc -show-encoding -arch arm64
1513
1514 test_asm(r, [&](A& a) {
Mike Klein65809142019-06-25 09:44:02 -04001515 a.and16b(A::v4, A::v3, A::v1);
1516 a.orr16b(A::v4, A::v3, A::v1);
1517 a.eor16b(A::v4, A::v3, A::v1);
1518 a.bic16b(A::v4, A::v3, A::v1);
Mike Klein97afd2e2019-10-16 14:11:27 -05001519 a.bsl16b(A::v4, A::v3, A::v1);
Mike Klein81a8d282019-11-06 15:11:01 -06001520 a.not16b(A::v4, A::v3);
Mike Klein65809142019-06-25 09:44:02 -04001521
1522 a.add4s(A::v4, A::v3, A::v1);
1523 a.sub4s(A::v4, A::v3, A::v1);
1524 a.mul4s(A::v4, A::v3, A::v1);
1525
Mike Klein97afd2e2019-10-16 14:11:27 -05001526 a.cmeq4s(A::v4, A::v3, A::v1);
1527 a.cmgt4s(A::v4, A::v3, A::v1);
1528
Mike Klein65809142019-06-25 09:44:02 -04001529 a.sub8h(A::v4, A::v3, A::v1);
1530 a.mul8h(A::v4, A::v3, A::v1);
1531
Mike Klein9f4df802019-06-24 18:47:16 -04001532 a.fadd4s(A::v4, A::v3, A::v1);
1533 a.fsub4s(A::v4, A::v3, A::v1);
1534 a.fmul4s(A::v4, A::v3, A::v1);
1535 a.fdiv4s(A::v4, A::v3, A::v1);
Mike Kleina53e47f2019-11-08 13:38:47 -06001536 a.fmin4s(A::v4, A::v3, A::v1);
1537 a.fmax4s(A::v4, A::v3, A::v1);
Mike Klein7c0332c2020-03-05 14:18:04 -06001538 a.fneg4s(A::v4, A::v3);
Mike Klein9f4df802019-06-24 18:47:16 -04001539
Mike Klein65809142019-06-25 09:44:02 -04001540 a.fmla4s(A::v4, A::v3, A::v1);
Jarrett Phillipsf9734c32020-02-13 15:18:37 -06001541 a.fmls4s(A::v4, A::v3, A::v1);
Mike Klein81a8d282019-11-06 15:11:01 -06001542
1543 a.fcmeq4s(A::v4, A::v3, A::v1);
1544 a.fcmgt4s(A::v4, A::v3, A::v1);
1545 a.fcmge4s(A::v4, A::v3, A::v1);
Mike Klein9f4df802019-06-24 18:47:16 -04001546 },{
Mike Klein65809142019-06-25 09:44:02 -04001547 0x64,0x1c,0x21,0x4e,
1548 0x64,0x1c,0xa1,0x4e,
1549 0x64,0x1c,0x21,0x6e,
1550 0x64,0x1c,0x61,0x4e,
Mike Klein97afd2e2019-10-16 14:11:27 -05001551 0x64,0x1c,0x61,0x6e,
Mike Klein81a8d282019-11-06 15:11:01 -06001552 0x64,0x58,0x20,0x6e,
Mike Klein65809142019-06-25 09:44:02 -04001553
1554 0x64,0x84,0xa1,0x4e,
1555 0x64,0x84,0xa1,0x6e,
1556 0x64,0x9c,0xa1,0x4e,
1557
Mike Klein97afd2e2019-10-16 14:11:27 -05001558 0x64,0x8c,0xa1,0x6e,
1559 0x64,0x34,0xa1,0x4e,
1560
Mike Klein65809142019-06-25 09:44:02 -04001561 0x64,0x84,0x61,0x6e,
1562 0x64,0x9c,0x61,0x4e,
1563
Mike Klein9f4df802019-06-24 18:47:16 -04001564 0x64,0xd4,0x21,0x4e,
1565 0x64,0xd4,0xa1,0x4e,
1566 0x64,0xdc,0x21,0x6e,
1567 0x64,0xfc,0x21,0x6e,
Mike Kleina53e47f2019-11-08 13:38:47 -06001568 0x64,0xf4,0xa1,0x4e,
1569 0x64,0xf4,0x21,0x4e,
Mike Klein7c0332c2020-03-05 14:18:04 -06001570 0x64,0xf8,0xa0,0x6e,
Mike Klein9f4df802019-06-24 18:47:16 -04001571
Mike Klein65809142019-06-25 09:44:02 -04001572 0x64,0xcc,0x21,0x4e,
Jarrett Phillipsf9734c32020-02-13 15:18:37 -06001573 0x64,0xcc,0xa1,0x4e,
Mike Klein81a8d282019-11-06 15:11:01 -06001574
1575 0x64,0xe4,0x21,0x4e,
1576 0x64,0xe4,0xa1,0x6e,
1577 0x64,0xe4,0x21,0x6e,
Mike Klein65809142019-06-25 09:44:02 -04001578 });
1579
1580 test_asm(r, [&](A& a) {
1581 a.shl4s(A::v4, A::v3, 0);
1582 a.shl4s(A::v4, A::v3, 1);
1583 a.shl4s(A::v4, A::v3, 8);
1584 a.shl4s(A::v4, A::v3, 16);
1585 a.shl4s(A::v4, A::v3, 31);
1586
1587 a.sshr4s(A::v4, A::v3, 1);
1588 a.sshr4s(A::v4, A::v3, 8);
1589 a.sshr4s(A::v4, A::v3, 31);
1590
1591 a.ushr4s(A::v4, A::v3, 1);
1592 a.ushr4s(A::v4, A::v3, 8);
1593 a.ushr4s(A::v4, A::v3, 31);
1594
1595 a.ushr8h(A::v4, A::v3, 1);
1596 a.ushr8h(A::v4, A::v3, 8);
1597 a.ushr8h(A::v4, A::v3, 15);
1598 },{
1599 0x64,0x54,0x20,0x4f,
1600 0x64,0x54,0x21,0x4f,
1601 0x64,0x54,0x28,0x4f,
1602 0x64,0x54,0x30,0x4f,
1603 0x64,0x54,0x3f,0x4f,
1604
1605 0x64,0x04,0x3f,0x4f,
1606 0x64,0x04,0x38,0x4f,
1607 0x64,0x04,0x21,0x4f,
1608
1609 0x64,0x04,0x3f,0x6f,
1610 0x64,0x04,0x38,0x6f,
1611 0x64,0x04,0x21,0x6f,
1612
1613 0x64,0x04,0x1f,0x6f,
1614 0x64,0x04,0x18,0x6f,
1615 0x64,0x04,0x11,0x6f,
1616 });
1617
1618 test_asm(r, [&](A& a) {
Mike Klein13267492019-07-19 12:21:19 -05001619 a.sli4s(A::v4, A::v3, 0);
1620 a.sli4s(A::v4, A::v3, 1);
1621 a.sli4s(A::v4, A::v3, 8);
1622 a.sli4s(A::v4, A::v3, 16);
1623 a.sli4s(A::v4, A::v3, 31);
1624 },{
1625 0x64,0x54,0x20,0x6f,
1626 0x64,0x54,0x21,0x6f,
1627 0x64,0x54,0x28,0x6f,
1628 0x64,0x54,0x30,0x6f,
1629 0x64,0x54,0x3f,0x6f,
1630 });
1631
1632 test_asm(r, [&](A& a) {
Mike Klein65809142019-06-25 09:44:02 -04001633 a.scvtf4s (A::v4, A::v3);
1634 a.fcvtzs4s(A::v4, A::v3);
Mike Klein6e4aad92019-11-08 14:13:15 -06001635 a.fcvtns4s(A::v4, A::v3);
Mike Klein65809142019-06-25 09:44:02 -04001636 },{
1637 0x64,0xd8,0x21,0x4e,
1638 0x64,0xb8,0xa1,0x4e,
Mike Klein6e4aad92019-11-08 14:13:15 -06001639 0x64,0xa8,0x21,0x4e,
Mike Klein9f4df802019-06-24 18:47:16 -04001640 });
Mike Klein15a368d2019-06-26 10:21:12 -04001641
1642 test_asm(r, [&](A& a) {
Mike Klein37be7712019-11-13 13:19:01 -06001643 a.brk(0);
1644 a.brk(65535);
1645
Mike Klein15a368d2019-06-26 10:21:12 -04001646 a.ret(A::x30); // Conventional ret using link register.
1647 a.ret(A::x13); // Can really return using any register if we like.
1648
1649 a.add(A::x2, A::x2, 4);
1650 a.add(A::x3, A::x2, 32);
1651
Mike Klein4cfe3ed2019-07-11 11:25:37 -05001652 a.sub(A::x2, A::x2, 4);
1653 a.sub(A::x3, A::x2, 32);
1654
Mike Klein15a368d2019-06-26 10:21:12 -04001655 a.subs(A::x2, A::x2, 4);
1656 a.subs(A::x3, A::x2, 32);
1657
Mike Klein4cfe3ed2019-07-11 11:25:37 -05001658 a.subs(A::xzr, A::x2, 4); // These are actually the same instruction!
1659 a.cmp(A::x2, 4);
1660
Mike Klein15a368d2019-06-26 10:21:12 -04001661 A::Label l = a.here();
Mike Klein65c10b52019-07-12 09:22:21 -05001662 a.bne(&l);
1663 a.bne(&l);
1664 a.blt(&l);
1665 a.b(&l);
1666 a.cbnz(A::x2, &l);
Mike Kleince7b88c2019-07-11 14:06:40 -05001667 a.cbz(A::x2, &l);
Mike Klein15a368d2019-06-26 10:21:12 -04001668 },{
Mike Klein37be7712019-11-13 13:19:01 -06001669 0x00,0x00,0x20,0xd4,
1670 0xe0,0xff,0x3f,0xd4,
1671
Mike Klein15a368d2019-06-26 10:21:12 -04001672 0xc0,0x03,0x5f,0xd6,
1673 0xa0,0x01,0x5f,0xd6,
1674
1675 0x42,0x10,0x00,0x91,
1676 0x43,0x80,0x00,0x91,
1677
Mike Klein4cfe3ed2019-07-11 11:25:37 -05001678 0x42,0x10,0x00,0xd1,
1679 0x43,0x80,0x00,0xd1,
1680
Mike Klein15a368d2019-06-26 10:21:12 -04001681 0x42,0x10,0x00,0xf1,
1682 0x43,0x80,0x00,0xf1,
1683
Mike Klein4cfe3ed2019-07-11 11:25:37 -05001684 0x5f,0x10,0x00,0xf1,
1685 0x5f,0x10,0x00,0xf1,
1686
1687 0x01,0x00,0x00,0x54, // b.ne #0
1688 0xe1,0xff,0xff,0x54, // b.ne #-4
1689 0xcb,0xff,0xff,0x54, // b.lt #-8
1690 0xae,0xff,0xff,0x54, // b.al #-12
1691 0x82,0xff,0xff,0xb5, // cbnz x2, #-16
1692 0x62,0xff,0xff,0xb4, // cbz x2, #-20
Mike Klein15a368d2019-06-26 10:21:12 -04001693 });
Mike Kleine51632e2019-06-26 14:47:43 -04001694
Mike Kleince7b88c2019-07-11 14:06:40 -05001695 // Can we cbz() to a not-yet-defined label?
1696 test_asm(r, [&](A& a) {
1697 A::Label l;
1698 a.cbz(A::x2, &l);
1699 a.add(A::x3, A::x2, 32);
1700 a.label(&l);
1701 a.ret(A::x30);
1702 },{
1703 0x42,0x00,0x00,0xb4, // cbz x2, #8
1704 0x43,0x80,0x00,0x91, // add x3, x2, #32
1705 0xc0,0x03,0x5f,0xd6, // ret
1706 });
1707
1708 // If we start a label as a backward label,
1709 // can we redefine it to be a future label?
1710 // (Not sure this is useful... just want to test it works.)
1711 test_asm(r, [&](A& a) {
1712 A::Label l1 = a.here();
1713 a.add(A::x3, A::x2, 32);
1714 a.cbz(A::x2, &l1); // This will jump backward... nothing sneaky.
1715
1716 A::Label l2 = a.here(); // Start off the same...
1717 a.add(A::x3, A::x2, 32);
1718 a.cbz(A::x2, &l2); // Looks like this will go backward...
1719 a.add(A::x2, A::x2, 4);
1720 a.add(A::x3, A::x2, 32);
1721 a.label(&l2); // But no... actually forward! What a switcheroo!
1722 },{
1723 0x43,0x80,0x00,0x91, // add x3, x2, #32
1724 0xe2,0xff,0xff,0xb4, // cbz x2, #-4
1725
1726 0x43,0x80,0x00,0x91, // add x3, x2, #32
1727 0x62,0x00,0x00,0xb4, // cbz x2, #12
1728 0x42,0x10,0x00,0x91, // add x2, x2, #4
1729 0x43,0x80,0x00,0x91, // add x3, x2, #32
1730 });
1731
Mike Klein81d52672019-07-30 11:11:09 -05001732 // Loading from a label on ARM.
1733 test_asm(r, [&](A& a) {
1734 A::Label fore,aft;
1735 a.label(&fore);
1736 a.word(0x01234567);
1737 a.ldrq(A::v1, &fore);
1738 a.ldrq(A::v2, &aft);
1739 a.label(&aft);
1740 a.word(0x76543210);
1741 },{
1742 0x67,0x45,0x23,0x01,
1743 0xe1,0xff,0xff,0x9c, // ldr q1, #-4
1744 0x22,0x00,0x00,0x9c, // ldr q2, #4
1745 0x10,0x32,0x54,0x76,
1746 });
1747
Mike Kleine51632e2019-06-26 14:47:43 -04001748 test_asm(r, [&](A& a) {
1749 a.ldrq(A::v0, A::x8);
1750 a.strq(A::v0, A::x8);
1751 },{
Mike Klein4cfe3ed2019-07-11 11:25:37 -05001752 0x00,0x01,0xc0,0x3d,
1753 0x00,0x01,0x80,0x3d,
Mike Kleine51632e2019-06-26 14:47:43 -04001754 });
Mike Klein1fa149a2019-07-01 11:18:08 -05001755
1756 test_asm(r, [&](A& a) {
1757 a.xtns2h(A::v0, A::v0);
1758 a.xtnh2b(A::v0, A::v0);
1759 a.strs (A::v0, A::x0);
1760
1761 a.ldrs (A::v0, A::x0);
1762 a.uxtlb2h(A::v0, A::v0);
1763 a.uxtlh2s(A::v0, A::v0);
Mike Klein37be7712019-11-13 13:19:01 -06001764
1765 a.uminv4s(A::v3, A::v4);
1766 a.fmovs (A::x3, A::v4); // fmov w3,s4
Mike Klein1fa149a2019-07-01 11:18:08 -05001767 },{
1768 0x00,0x28,0x61,0x0e,
1769 0x00,0x28,0x21,0x0e,
1770 0x00,0x00,0x00,0xbd,
1771
1772 0x00,0x00,0x40,0xbd,
1773 0x00,0xa4,0x08,0x2f,
1774 0x00,0xa4,0x10,0x2f,
Mike Klein37be7712019-11-13 13:19:01 -06001775
1776 0x83,0xa8,0xb1,0x6e,
1777 0x83,0x00,0x26,0x1e,
Mike Klein1fa149a2019-07-01 11:18:08 -05001778 });
Mike Klein4cfe3ed2019-07-11 11:25:37 -05001779
1780 test_asm(r, [&](A& a) {
1781 a.ldrb(A::v0, A::x8);
1782 a.strb(A::v0, A::x8);
1783 },{
1784 0x00,0x01,0x40,0x3d,
1785 0x00,0x01,0x00,0x3d,
1786 });
Mike Klein81d52672019-07-30 11:11:09 -05001787
1788 test_asm(r, [&](A& a) {
1789 a.tbl(A::v0, A::v1, A::v2);
1790 },{
1791 0x20,0x00,0x02,0x4e,
1792 });
Mike Klein05642042019-06-18 12:16:06 -05001793}