blob: 63e8f032cb48a3bb6f5d5008a11c09e871013468 [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"
10#include "src/core/SkVM.h"
11#include "tests/Test.h"
Mike Klein267f5072019-06-03 16:27:46 -050012#include "tools/Resources.h"
Mike Klein7b7077c2019-06-03 17:10:59 -050013#include "tools/SkVMBuilders.h"
Mike Klein68c50d02019-05-29 12:57:54 -050014
Mike Klein7b7077c2019-06-03 17:10:59 -050015using Fmt = SrcoverBuilder_F32::Fmt;
Mike Klein68c50d02019-05-29 12:57:54 -050016const char* fmt_name(Fmt fmt) {
17 switch (fmt) {
Mike Klein7b7077c2019-06-03 17:10:59 -050018 case Fmt::A8: return "A8";
19 case Fmt::G8: return "G8";
20 case Fmt::RGBA_8888: return "RGBA_8888";
Mike Klein68c50d02019-05-29 12:57:54 -050021 }
22 return "";
23}
24
Mike Klein68c50d02019-05-29 12:57:54 -050025DEF_TEST(SkVM, r) {
Mike Klein267f5072019-06-03 16:27:46 -050026 SkDynamicMemoryWStream buf;
Mike Klein7b7077c2019-06-03 17:10:59 -050027
28 // Write all combinations of SrcoverBuilder_F32
Mike Klein68c50d02019-05-29 12:57:54 -050029 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 Klein22ea7e92019-06-10 12:05:48 -050033 SrcoverBuilder_F32 builder{srcFmt, dstFmt};
34 skvm::Program program = builder.done();
Mike Klein68c50d02019-05-29 12:57:54 -050035
Mike Klein267f5072019-06-03 16:27:46 -050036 buf.writeText(fmt_name(srcFmt));
37 buf.writeText(" over ");
38 buf.writeText(fmt_name(dstFmt));
39 buf.writeText("\n");
Mike Klein22ea7e92019-06-10 12:05:48 -050040 builder.dump(&buf);
41 buf.writeText("\n");
Mike Klein68c50d02019-05-29 12:57:54 -050042 program.dump(&buf);
Mike Klein267f5072019-06-03 16:27:46 -050043 buf.writeText("\n");
44 }
Mike Klein68c50d02019-05-29 12:57:54 -050045
Mike Klein7b7077c2019-06-03 17:10:59 -050046 // Write the I32 Srcovers also.
47 {
Mike Klein397fc882019-06-20 11:37:10 -050048 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 Klein7b7077c2019-06-03 17:10:59 -050054 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 Klein267f5072019-06-03 16:27:46 -050066 sk_sp<SkData> blob = buf.detachAsData();
67 {
68
69 sk_sp<SkData> expected = GetResourceAsData("SkVMTest.expected");
Mike Klein77163312019-06-04 13:35:32 -050070 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 Klein267f5072019-06-03 16:27:46 -050074
Mike Klein77163312019-06-04 13:35:32 -050075 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 Klein68c50d02019-05-29 12:57:54 -050084 }
85 }
86
Mike Klein3f593792019-06-12 12:54:52 -050087 auto test_8888 = [&](const skvm::Program& program) {
88 uint32_t src[9];
89 uint32_t dst[SK_ARRAY_COUNT(src)];
Mike Klein68c50d02019-05-29 12:57:54 -050090
Mike Klein3f593792019-06-12 12:54:52 -050091 for (int i = 0; i < (int)SK_ARRAY_COUNT(src); i++) {
92 src[i] = 0xbb007733;
93 dst[i] = 0xffaaccee;
94 }
Mike Klein68c50d02019-05-29 12:57:54 -050095
Mike Klein3f593792019-06-12 12:54:52 -050096 SkPMColor expected = SkPMSrcOver(src[0], dst[0]); // 0xff2dad73
97
98 program.eval((int)SK_ARRAY_COUNT(src), src, dst);
Mike Klein68c50d02019-05-29 12:57:54 -050099
100 // dst is probably 0xff2dad72.
Mike Klein3f593792019-06-12 12:54:52 -0500101 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 Klein68c50d02019-05-29 12:57:54 -0500110 }
Mike Klein3f593792019-06-12 12:54:52 -0500111 };
Mike Klein68c50d02019-05-29 12:57:54 -0500112
Mike Klein3f593792019-06-12 12:54:52 -0500113 test_8888(SrcoverBuilder_F32{Fmt::RGBA_8888, Fmt::RGBA_8888}.done());
Mike Klein397fc882019-06-20 11:37:10 -0500114 test_8888(SrcoverBuilder_I32_Naive{}.done());
Mike Klein56403972019-06-12 14:01:10 -0500115 test_8888(SrcoverBuilder_I32{}.done());
Mike Klein3f593792019-06-12 12:54:52 -0500116 test_8888(SrcoverBuilder_I32_SWAR{}.done());
Mike Klein7b7077c2019-06-03 17:10:59 -0500117
118 {
119 skvm::Program program = SrcoverBuilder_F32{Fmt::RGBA_8888, Fmt::G8}.done();
Mike Klein68c50d02019-05-29 12:57:54 -0500120
Mike Klein3f593792019-06-12 12:54:52 -0500121 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 Klein68c50d02019-05-29 12:57:54 -0500131
132 uint8_t want = SkComputeLuminance(SkGetPackedR32(over),
133 SkGetPackedG32(over),
134 SkGetPackedB32(over));
Mike Klein3f593792019-06-12 12:54:52 -0500135 program.eval((int)SK_ARRAY_COUNT(src), src, dst);
Mike Klein68c50d02019-05-29 12:57:54 -0500136
Mike Klein3f593792019-06-12 12:54:52 -0500137 for (auto got : dst) {
138 REPORTER_ASSERT(r, abs(got-want) < 3);
139 }
Mike Klein68c50d02019-05-29 12:57:54 -0500140 }
141
142 {
Mike Klein7b7077c2019-06-03 17:10:59 -0500143 skvm::Program program = SrcoverBuilder_F32{Fmt::A8, Fmt::A8}.done();
Mike Klein68c50d02019-05-29 12:57:54 -0500144
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 Klein81756e42019-06-12 11:36:28 -0500161
162DEF_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 Klein05642042019-06-18 12:16:06 -0500188
189
Mike Klein05642042019-06-18 12:16:06 -0500190template <typename Fn>
191static void test_asm(skiatest::Reporter* r, Fn&& fn, std::initializer_list<uint8_t> expected) {
Mike Klein88c0a902019-06-24 15:34:02 -0400192 uint8_t buf[4096];
193 skvm::Assembler a{buf};
Mike Klein05642042019-06-18 12:16:06 -0500194 fn(a);
195
196 REPORTER_ASSERT(r, a.size() == expected.size());
197
Mike Klein88c0a902019-06-24 15:34:02 -0400198 auto got = (const uint8_t*)buf,
Mike Klein05642042019-06-18 12:16:06 -0500199 want = expected.begin();
200 for (int i = 0; i < (int)std::min(a.size(), expected.size()); i++) {
Mike Klein61703a62019-06-18 15:01:12 -0500201 REPORTER_ASSERT(r, got[i] == want[i],
202 "byte %d was %02x, want %02x", i, got[i], want[i]);
Mike Klein05642042019-06-18 12:16:06 -0500203 }
204}
205
206DEF_TEST(SkVM_Assembler, r) {
Mike Klein397fc882019-06-20 11:37:10 -0500207 // 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 Klein05642042019-06-18 12:16:06 -0500217 // Our exit strategy from AVX code.
Mike Klein397fc882019-06-20 11:37:10 -0500218 test_asm(r, [&](A& a) {
Mike Klein05642042019-06-18 12:16:06 -0500219 a.vzeroupper();
220 a.ret();
221 },{
222 0xc5, 0xf8, 0x77,
223 0xc3,
224 });
225
226 // Align should pad with nop().
Mike Klein397fc882019-06-20 11:37:10 -0500227 test_asm(r, [&](A& a) {
Mike Klein05642042019-06-18 12:16:06 -0500228 a.ret();
229 a.align(4);
230 },{
231 0xc3,
232 0x90, 0x90, 0x90,
233 });
Mike Klein61703a62019-06-18 15:01:12 -0500234
Mike Klein397fc882019-06-20 11:37:10 -0500235 test_asm(r, [&](A& a) {
236 a.add(A::rax, 8); // Always good to test rax.
237 a.sub(A::rax, 32);
Mike Kleind3e75a72019-06-18 15:26:08 -0500238
Mike Klein397fc882019-06-20 11:37:10 -0500239 a.add(A::rdi, 12); // Last 0x48 REX
240 a.sub(A::rdi, 8);
Mike Kleind3e75a72019-06-18 15:26:08 -0500241
Mike Klein397fc882019-06-20 11:37:10 -0500242 a.add(A::r8 , 7); // First 0x4c REX
243 a.sub(A::r8 , 4);
Mike Kleind3e75a72019-06-18 15:26:08 -0500244
Mike Klein397fc882019-06-20 11:37:10 -0500245 a.add(A::rsi, 128); // Requires 4 byte immediate.
246 a.sub(A::r8 , 1000000);
Mike Klein61703a62019-06-18 15:01:12 -0500247 },{
Mike Kleind3e75a72019-06-18 15:26:08 -0500248 0x48, 0x83, 0b11'000'000, 0x08,
Mike Klein61703a62019-06-18 15:01:12 -0500249 0x48, 0x83, 0b11'101'000, 0x20,
Mike Kleind3e75a72019-06-18 15:26:08 -0500250
251 0x48, 0x83, 0b11'000'111, 0x0c,
Mike Klein61703a62019-06-18 15:01:12 -0500252 0x48, 0x83, 0b11'101'111, 0x08,
Mike Kleind3e75a72019-06-18 15:26:08 -0500253
254 0x4c, 0x83, 0b11'000'000, 0x07,
Mike Klein61703a62019-06-18 15:01:12 -0500255 0x4c, 0x83, 0b11'101'000, 0x04,
Mike Kleind3e75a72019-06-18 15:26:08 -0500256
257 0x48, 0x81, 0b11'000'110, 0x80, 0x00, 0x00, 0x00,
Mike Klein61703a62019-06-18 15:01:12 -0500258 0x4c, 0x81, 0b11'101'000, 0x40, 0x42, 0x0f, 0x00,
259 });
Mike Klein397fc882019-06-20 11:37:10 -0500260
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 Kleinff0ae812019-06-20 15:03:44 -0500278
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 Kleine5053412019-06-21 12:37:22 -0500292
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 Klein04db9c22019-06-21 14:19:21 -0500299
Mike Kleine5053412019-06-21 12:37:22 -0500300 a.vbroadcastss(A::ymm0 , l);
301 a.vbroadcastss(A::ymm1 , l);
302 a.vbroadcastss(A::ymm8 , l);
303 a.vbroadcastss(A::ymm15, l);
Mike Klein04db9c22019-06-21 14:19:21 -0500304
305 a.vpshufb(A::ymm4, A::ymm3, l);
Mike Kleine5053412019-06-21 12:37:22 -0500306 },{
307 0x01, 0x02, 0x03, 0x4,
Mike Klein04db9c22019-06-21 14:19:21 -0500308
Mike Kleine5053412019-06-21 12:37:22 -0500309 /* 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 Klein04db9c22019-06-21 14:19:21 -0500314
315 0xc4, 0xe2, 0x65, 0x00, 0b00'100'101, 0xcf,0xff,0xff,0xff, // 0xffffffcf == -49
Mike Kleine5053412019-06-21 12:37:22 -0500316 });
Mike Klein060eaaa2019-06-21 14:42:09 -0500317
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 Klein120d9e82019-06-21 15:52:55 -0500349
350 test_asm(r, [&](A& a) {
351 a.vmovups(A::ymm5, A::rsi);
352 a.vmovups(A::rsi, A::ymm5);
Mike Kleinae51aa32019-06-21 16:06:03 -0500353
354 a.vpmovzxbd(A::ymm4, A::rsi);
Mike Kleinf3881b22019-06-21 16:20:24 -0500355
356 a.vmovq(A::rdx, A::xmm15);
Mike Klein120d9e82019-06-21 15:52:55 -0500357 },{
Mike Kleinae51aa32019-06-21 16:06:03 -0500358 /* 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 Kleinf3881b22019-06-21 16:20:24 -0500363
364 0xc5, 0x79, 0xd6, 0b00'111'010,
Mike Klein120d9e82019-06-21 15:52:55 -0500365 });
Mike Klein2b7b2a22019-06-23 20:35:28 -0400366
367 test_asm(r, [&](A& a) {
368 a.vpandn(A::ymm3, A::ymm12, A::ymm2);
369 },{
370 0xc5, 0x9d, 0xdf, 0xda,
371 });
Mike Klein9f4df802019-06-24 18:47:16 -0400372
373 // echo "fmul v4.4s, v3.4s, v1.4s" | llvm-mc -show-encoding -arch arm64
374
375 test_asm(r, [&](A& a) {
Mike Klein65809142019-06-25 09:44:02 -0400376 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 Klein9f4df802019-06-24 18:47:16 -0400388 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 Klein65809142019-06-25 09:44:02 -0400393 a.fmla4s(A::v4, A::v3, A::v1);
Mike Klein9f4df802019-06-24 18:47:16 -0400394 },{
Mike Klein65809142019-06-25 09:44:02 -0400395 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 Klein9f4df802019-06-24 18:47:16 -0400407 0x64,0xd4,0x21,0x4e,
408 0x64,0xd4,0xa1,0x4e,
409 0x64,0xdc,0x21,0x6e,
410 0x64,0xfc,0x21,0x6e,
411
Mike Klein65809142019-06-25 09:44:02 -0400412 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 Klein9f4df802019-06-24 18:47:16 -0400459 });
Mike Klein15a368d2019-06-26 10:21:12 -0400460
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 Kleine51632e2019-06-26 14:47:43 -0400487
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 Klein05642042019-06-18 12:16:06 -0500495}