blob: 739eed4d11b9ea3a81ac26f5d094a422023d82fe [file] [log] [blame]
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001/*
2 * Copyright 2018 Google Inc.
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#ifndef SKSL_STANDALONE
9
Ethan Nicholasae9633b2019-05-24 12:46:34 -040010#include "include/core/SkPoint3.h"
Brian Osman569f12f2019-06-13 11:23:57 -040011#include "include/private/SkVx.h"
Brian Osman80164412019-06-07 13:00:23 -040012#include "src/sksl/SkSLByteCode.h"
Brian Osman07c117b2019-05-23 12:51:06 -070013#include "src/sksl/SkSLByteCodeGenerator.h"
Ethan Nicholas91164d12019-05-15 15:29:54 -040014#include "src/sksl/SkSLExternalValue.h"
Brian Osman80164412019-06-07 13:00:23 -040015
16#include <vector>
Ethan Nicholas26a9aad2018-03-27 14:10:52 -040017
18namespace SkSL {
Brian Osman80164412019-06-07 13:00:23 -040019namespace Interpreter {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -040020
Brian Osman569f12f2019-06-13 11:23:57 -040021constexpr int VecWidth = 16;
22
23using F32 = skvx::Vec<VecWidth, float>;
24using I32 = skvx::Vec<VecWidth, int32_t>;
25using U32 = skvx::Vec<VecWidth, uint32_t>;
26
Mike Klein76346ac2019-05-17 11:57:10 -050027template <typename T>
28static T unaligned_load(const void* ptr) {
29 T val;
30 memcpy(&val, ptr, sizeof(val));
31 return val;
32}
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040033
Mike Kleine7007382019-05-21 08:36:32 -050034#define READ8() (*(ip++))
Mike Klein76346ac2019-05-17 11:57:10 -050035#define READ16() (ip += 2, unaligned_load<uint16_t>(ip - 2))
36#define READ32() (ip += 4, unaligned_load<uint32_t>(ip - 4))
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040037
Brian Osman3e833e12019-05-23 13:23:24 -070038#define VECTOR_DISASSEMBLE(op, text) \
Ethan Nicholas48a75aa2019-05-16 17:15:56 -040039 case ByteCodeInstruction::op: printf(text); break; \
40 case ByteCodeInstruction::op##2: printf(text "2"); break; \
41 case ByteCodeInstruction::op##3: printf(text "3"); break; \
42 case ByteCodeInstruction::op##4: printf(text "4"); break;
43
Brian Osman1e855b22019-05-29 15:21:52 -040044#define VECTOR_MATRIX_DISASSEMBLE(op, text) \
45 case ByteCodeInstruction::op: printf(text); break; \
46 case ByteCodeInstruction::op##2: printf(text "2"); break; \
47 case ByteCodeInstruction::op##3: printf(text "3"); break; \
48 case ByteCodeInstruction::op##4: printf(text "4"); break; \
49 case ByteCodeInstruction::op##N: printf(text "N %d", READ8()); break;
50
Brian Osman3e833e12019-05-23 13:23:24 -070051static const uint8_t* disassemble_instruction(const uint8_t* ip) {
52 switch ((ByteCodeInstruction) READ16()) {
Brian Osman1e855b22019-05-29 15:21:52 -040053 VECTOR_MATRIX_DISASSEMBLE(kAddF, "addf")
Brian Osman3e833e12019-05-23 13:23:24 -070054 VECTOR_DISASSEMBLE(kAddI, "addi")
Brian Osman32c526b2019-06-03 16:13:52 -040055 case ByteCodeInstruction::kAndB: printf("andb"); break;
Brian Osman3e833e12019-05-23 13:23:24 -070056 case ByteCodeInstruction::kBranch: printf("branch %d", READ16()); break;
57 case ByteCodeInstruction::kCall: printf("call %d", READ8()); break;
58 case ByteCodeInstruction::kCallExternal: {
59 int argumentCount = READ8();
60 int returnCount = READ8();
61 int externalValue = READ8();
62 printf("callexternal %d, %d, %d", argumentCount, returnCount, externalValue);
63 break;
64 }
65 VECTOR_DISASSEMBLE(kCompareIEQ, "compareieq")
66 VECTOR_DISASSEMBLE(kCompareINEQ, "compareineq")
Brian Osman1e855b22019-05-29 15:21:52 -040067 VECTOR_MATRIX_DISASSEMBLE(kCompareFEQ, "comparefeq")
68 VECTOR_MATRIX_DISASSEMBLE(kCompareFNEQ, "comparefneq")
Brian Osman3e833e12019-05-23 13:23:24 -070069 VECTOR_DISASSEMBLE(kCompareFGT, "comparefgt")
70 VECTOR_DISASSEMBLE(kCompareFGTEQ, "comparefgteq")
71 VECTOR_DISASSEMBLE(kCompareFLT, "compareflt")
72 VECTOR_DISASSEMBLE(kCompareFLTEQ, "compareflteq")
73 VECTOR_DISASSEMBLE(kCompareSGT, "comparesgt")
74 VECTOR_DISASSEMBLE(kCompareSGTEQ, "comparesgteq")
75 VECTOR_DISASSEMBLE(kCompareSLT, "compareslt")
76 VECTOR_DISASSEMBLE(kCompareSLTEQ, "compareslteq")
77 VECTOR_DISASSEMBLE(kCompareUGT, "compareugt")
78 VECTOR_DISASSEMBLE(kCompareUGTEQ, "compareugteq")
79 VECTOR_DISASSEMBLE(kCompareULT, "compareult")
80 VECTOR_DISASSEMBLE(kCompareULTEQ, "compareulteq")
Brian Osman3e833e12019-05-23 13:23:24 -070081 VECTOR_DISASSEMBLE(kConvertFtoI, "convertftoi")
82 VECTOR_DISASSEMBLE(kConvertStoF, "convertstof")
83 VECTOR_DISASSEMBLE(kConvertUtoF, "convertutof")
84 VECTOR_DISASSEMBLE(kCos, "cos")
Brian Osman1e855b22019-05-29 15:21:52 -040085 VECTOR_MATRIX_DISASSEMBLE(kDivideF, "dividef")
Brian Osman3e833e12019-05-23 13:23:24 -070086 VECTOR_DISASSEMBLE(kDivideS, "divideS")
87 VECTOR_DISASSEMBLE(kDivideU, "divideu")
Brian Osman1e855b22019-05-29 15:21:52 -040088 VECTOR_MATRIX_DISASSEMBLE(kDup, "dup")
Brian Osman3e833e12019-05-23 13:23:24 -070089 case ByteCodeInstruction::kLoad: printf("load %d", READ8()); break;
90 case ByteCodeInstruction::kLoad2: printf("load2 %d", READ8()); break;
91 case ByteCodeInstruction::kLoad3: printf("load3 %d", READ8()); break;
92 case ByteCodeInstruction::kLoad4: printf("load4 %d", READ8()); break;
93 case ByteCodeInstruction::kLoadGlobal: printf("loadglobal %d", READ8()); break;
94 case ByteCodeInstruction::kLoadGlobal2: printf("loadglobal2 %d", READ8()); break;
95 case ByteCodeInstruction::kLoadGlobal3: printf("loadglobal3 %d", READ8()); break;
96 case ByteCodeInstruction::kLoadGlobal4: printf("loadglobal4 %d", READ8()); break;
97 case ByteCodeInstruction::kLoadSwizzle: {
98 int target = READ8();
99 int count = READ8();
100 printf("loadswizzle %d %d", target, count);
101 for (int i = 0; i < count; ++i) {
102 printf(", %d", READ8());
103 }
104 break;
105 }
106 case ByteCodeInstruction::kLoadSwizzleGlobal: {
107 int target = READ8();
108 int count = READ8();
109 printf("loadswizzleglobal %d %d", target, count);
110 for (int i = 0; i < count; ++i) {
111 printf(", %d", READ8());
112 }
113 break;
114 }
115 case ByteCodeInstruction::kLoadExtended: printf("loadextended %d", READ8()); break;
116 case ByteCodeInstruction::kLoadExtendedGlobal: printf("loadextendedglobal %d", READ8());
117 break;
Brian Osman29e013d2019-05-28 17:16:03 -0400118 case ByteCodeInstruction::kMatrixToMatrix: {
119 int srcCols = READ8();
120 int srcRows = READ8();
121 int dstCols = READ8();
122 int dstRows = READ8();
123 printf("matrixtomatrix %dx%d %dx%d", srcCols, srcRows, dstCols, dstRows);
124 break;
125 }
Brian Osman909231c2019-05-29 15:34:36 -0400126 case ByteCodeInstruction::kMatrixMultiply: {
127 int lCols = READ8();
128 int lRows = READ8();
129 int rCols = READ8();
130 printf("matrixmultiply %dx%d %dx%d", lCols, lRows, rCols, lCols);
131 break;
132 }
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400133 VECTOR_DISASSEMBLE(kMix, "mix")
Brian Osman1e855b22019-05-29 15:21:52 -0400134 VECTOR_MATRIX_DISASSEMBLE(kMultiplyF, "multiplyf")
Brian Osman3e833e12019-05-23 13:23:24 -0700135 VECTOR_DISASSEMBLE(kMultiplyI, "multiplyi")
Brian Osman1e855b22019-05-29 15:21:52 -0400136 VECTOR_MATRIX_DISASSEMBLE(kNegateF, "negatef")
Brian Osman3e833e12019-05-23 13:23:24 -0700137 VECTOR_DISASSEMBLE(kNegateI, "negatei")
Brian Osman569f12f2019-06-13 11:23:57 -0400138 case ByteCodeInstruction::kNotB: printf("notb"); break;
Brian Osman32c526b2019-06-03 16:13:52 -0400139 case ByteCodeInstruction::kOrB: printf("orb"); break;
Brian Osman1e855b22019-05-29 15:21:52 -0400140 VECTOR_MATRIX_DISASSEMBLE(kPop, "pop")
Brian Osman3e833e12019-05-23 13:23:24 -0700141 case ByteCodeInstruction::kPushImmediate: {
142 uint32_t v = READ32();
143 union { uint32_t u; float f; } pun = { v };
144 printf("pushimmediate %s", (to_string(v) + "(" + to_string(pun.f) + ")").c_str());
145 break;
146 }
147 case ByteCodeInstruction::kReadExternal: printf("readexternal %d", READ8()); break;
148 case ByteCodeInstruction::kReadExternal2: printf("readexternal2 %d", READ8()); break;
149 case ByteCodeInstruction::kReadExternal3: printf("readexternal3 %d", READ8()); break;
150 case ByteCodeInstruction::kReadExternal4: printf("readexternal4 %d", READ8()); break;
151 VECTOR_DISASSEMBLE(kRemainderF, "remainderf")
152 VECTOR_DISASSEMBLE(kRemainderS, "remainders")
153 VECTOR_DISASSEMBLE(kRemainderU, "remainderu")
154 case ByteCodeInstruction::kReturn: printf("return %d", READ8()); break;
Brian Osman29e013d2019-05-28 17:16:03 -0400155 case ByteCodeInstruction::kScalarToMatrix: {
156 int cols = READ8();
157 int rows = READ8();
158 printf("scalartomatrix %dx%d", cols, rows);
159 break;
160 }
Brian Osman3e833e12019-05-23 13:23:24 -0700161 VECTOR_DISASSEMBLE(kSin, "sin")
162 VECTOR_DISASSEMBLE(kSqrt, "sqrt")
163 case ByteCodeInstruction::kStore: printf("store %d", READ8()); break;
164 case ByteCodeInstruction::kStore2: printf("store2 %d", READ8()); break;
165 case ByteCodeInstruction::kStore3: printf("store3 %d", READ8()); break;
166 case ByteCodeInstruction::kStore4: printf("store4 %d", READ8()); break;
167 case ByteCodeInstruction::kStoreGlobal: printf("storeglobal %d", READ8()); break;
168 case ByteCodeInstruction::kStoreGlobal2: printf("storeglobal2 %d", READ8()); break;
169 case ByteCodeInstruction::kStoreGlobal3: printf("storeglobal3 %d", READ8()); break;
170 case ByteCodeInstruction::kStoreGlobal4: printf("storeglobal4 %d", READ8()); break;
171 case ByteCodeInstruction::kStoreSwizzle: {
172 int target = READ8();
173 int count = READ8();
174 printf("storeswizzle %d %d", target, count);
175 for (int i = 0; i < count; ++i) {
176 printf(", %d", READ8());
177 }
178 break;
179 }
180 case ByteCodeInstruction::kStoreSwizzleGlobal: {
181 int target = READ8();
182 int count = READ8();
183 printf("storeswizzleglobal %d %d", target, count);
184 for (int i = 0; i < count; ++i) {
185 printf(", %d", READ8());
186 }
187 break;
188 }
189 case ByteCodeInstruction::kStoreSwizzleIndirect: {
190 int count = READ8();
191 printf("storeswizzleindirect %d", count);
192 for (int i = 0; i < count; ++i) {
193 printf(", %d", READ8());
194 }
195 break;
196 }
197 case ByteCodeInstruction::kStoreSwizzleIndirectGlobal: {
198 int count = READ8();
199 printf("storeswizzleindirectglobal %d", count);
200 for (int i = 0; i < count; ++i) {
201 printf(", %d", READ8());
202 }
203 break;
204 }
205 case ByteCodeInstruction::kStoreExtended: printf("storeextended %d", READ8()); break;
206 case ByteCodeInstruction::kStoreExtendedGlobal: printf("storeextendedglobal %d", READ8());
207 break;
Brian Osman1e855b22019-05-29 15:21:52 -0400208 VECTOR_MATRIX_DISASSEMBLE(kSubtractF, "subtractf")
Brian Osman3e833e12019-05-23 13:23:24 -0700209 VECTOR_DISASSEMBLE(kSubtractI, "subtracti")
210 case ByteCodeInstruction::kSwizzle: {
211 printf("swizzle %d, ", READ8());
212 int count = READ8();
213 printf("%d", count);
214 for (int i = 0; i < count; ++i) {
215 printf(", %d", READ8());
216 }
217 break;
218 }
219 VECTOR_DISASSEMBLE(kTan, "tan")
220 case ByteCodeInstruction::kWriteExternal: printf("writeexternal %d", READ8()); break;
221 case ByteCodeInstruction::kWriteExternal2: printf("writeexternal2 %d", READ8()); break;
222 case ByteCodeInstruction::kWriteExternal3: printf("writeexternal3 %d", READ8()); break;
223 case ByteCodeInstruction::kWriteExternal4: printf("writeexternal4 %d", READ8()); break;
Brian Osman569f12f2019-06-13 11:23:57 -0400224 case ByteCodeInstruction::kXorB: printf("xorb"); break;
225 case ByteCodeInstruction::kMaskPush: printf("maskpush"); break;
226 case ByteCodeInstruction::kMaskPop: printf("maskpop"); break;
227 case ByteCodeInstruction::kMaskNegate: printf("masknegate"); break;
228 case ByteCodeInstruction::kMaskBlend: printf("maskblend %d", READ8()); break;
229 case ByteCodeInstruction::kBranchIfAllFalse:
230 printf("branchifallfalse %d", READ16());
231 break;
232 case ByteCodeInstruction::kLoopBegin: printf("loopbegin"); break;
233 case ByteCodeInstruction::kLoopNext: printf("loopnext"); break;
234 case ByteCodeInstruction::kLoopMask: printf("loopmask"); break;
235 case ByteCodeInstruction::kLoopEnd: printf("loopend"); break;
236 case ByteCodeInstruction::kLoopContinue: printf("loopcontinue"); break;
237 case ByteCodeInstruction::kLoopBreak: printf("loopbreak"); break;
Brian Osman3e833e12019-05-23 13:23:24 -0700238 default: printf("unknown(%d)\n", *(ip - 1)); SkASSERT(false);
239 }
240 return ip;
241}
242
Mike Klein459aed12019-05-21 15:46:36 -0500243#define VECTOR_BINARY_OP(base, field, op) \
Mike Kleine7007382019-05-21 08:36:32 -0500244 case ByteCodeInstruction::base ## 4: \
Mike Klein459aed12019-05-21 15:46:36 -0500245 sp[-4] = sp[-4].field op sp[0].field; \
Mike Kleine7007382019-05-21 08:36:32 -0500246 POP(); \
247 /* fall through */ \
248 case ByteCodeInstruction::base ## 3: { \
249 int count = (int) ByteCodeInstruction::base - (int) inst - 1; \
Mike Klein459aed12019-05-21 15:46:36 -0500250 sp[count] = sp[count].field op sp[0].field; \
Mike Kleine7007382019-05-21 08:36:32 -0500251 POP(); \
252 } /* fall through */ \
253 case ByteCodeInstruction::base ## 2: { \
254 int count = (int) ByteCodeInstruction::base - (int) inst - 1; \
Mike Klein459aed12019-05-21 15:46:36 -0500255 sp[count] = sp[count].field op sp[0].field; \
Mike Kleine7007382019-05-21 08:36:32 -0500256 POP(); \
257 } /* fall through */ \
258 case ByteCodeInstruction::base: { \
259 int count = (int) ByteCodeInstruction::base - (int) inst - 1; \
Mike Klein459aed12019-05-21 15:46:36 -0500260 sp[count] = sp[count].field op sp[0].field; \
Mike Kleine7007382019-05-21 08:36:32 -0500261 POP(); \
262 break; \
263 }
Ethan Nicholasaeb71ce2019-05-20 09:55:44 -0400264
Brian Osman1e855b22019-05-29 15:21:52 -0400265#define VECTOR_MATRIX_BINARY_OP(base, field, op) \
266 VECTOR_BINARY_OP(base, field, op) \
267 case ByteCodeInstruction::base ## N: { \
268 int count = READ8(); \
269 for (int i = count; i > 0; --i) { \
270 sp[-count] = sp[-count].field op sp[0].field; \
271 POP(); \
272 } \
273 break; \
274 }
275
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400276#define VECTOR_BINARY_FN(base, field, fn) \
277 case ByteCodeInstruction::base ## 4: \
278 sp[-4] = fn(sp[-4].field, sp[0].field); \
279 POP(); \
280 /* fall through */ \
281 case ByteCodeInstruction::base ## 3: { \
282 int target = (int) ByteCodeInstruction::base - (int) inst - 1; \
283 sp[target] = fn(sp[target].field, sp[0].field); \
284 POP(); \
285 } /* fall through */ \
286 case ByteCodeInstruction::base ## 2: { \
287 int target = (int) ByteCodeInstruction::base - (int) inst - 1; \
288 sp[target] = fn(sp[target].field, sp[0].field); \
289 POP(); \
290 } /* fall through */ \
291 case ByteCodeInstruction::base: { \
292 int target = (int) ByteCodeInstruction::base - (int) inst - 1; \
293 sp[target] = fn(sp[target].field, sp[0].field); \
294 POP(); \
295 break; \
Mike Kleine7007382019-05-21 08:36:32 -0500296 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400297
Mike Klein459aed12019-05-21 15:46:36 -0500298#define VECTOR_UNARY_FN(base, fn, field) \
299 case ByteCodeInstruction::base ## 4: sp[-3] = fn(sp[-3].field); \
300 case ByteCodeInstruction::base ## 3: sp[-2] = fn(sp[-2].field); \
301 case ByteCodeInstruction::base ## 2: sp[-1] = fn(sp[-1].field); \
302 case ByteCodeInstruction::base: sp[ 0] = fn(sp[ 0].field); \
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400303 break;
304
Brian Osman569f12f2019-06-13 11:23:57 -0400305#define VECTOR_UNARY_FN_VEC(base, fn) \
306 case ByteCodeInstruction::base ## 4: \
307 case ByteCodeInstruction::base ## 3: \
308 case ByteCodeInstruction::base ## 2: \
309 case ByteCodeInstruction::base : { \
310 int count = (int)inst - (int)ByteCodeInstruction::base + 1; \
311 float* v = (float*)sp - count + 1; \
312 for (int i = VecWidth * count; i > 0; --i, ++v) { \
313 *v = fn(*v); \
314 } \
315 break; \
316 }
317
318union VValue {
319 VValue() {}
320
321 VValue(F32 f)
322 : fFloat(f) {
323 }
324
325 VValue(I32 s)
326 : fSigned(s) {
327 }
328
329 VValue(U32 u)
330 : fUnsigned(u) {
331 }
332
333 F32 fFloat;
334 I32 fSigned;
335 U32 fUnsigned;
336};
337
Brian Osman226668a2019-05-14 16:47:30 -0400338struct StackFrame {
339 const uint8_t* fCode;
340 const uint8_t* fIP;
Brian Osman569f12f2019-06-13 11:23:57 -0400341 VValue* fStack;
Brian Osman226668a2019-05-14 16:47:30 -0400342};
343
Brian Osman569f12f2019-06-13 11:23:57 -0400344static F32 mix(F32 start, F32 end, F32 t) {
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400345 return start * (1 - t) + end * t;
346}
347
Brian Osman569f12f2019-06-13 11:23:57 -0400348// TODO: trunc on integers?
349template <typename T>
350static T vec_mod(T a, T b) {
351 return a - skvx::trunc(a / b) * b;
352}
Mike Kleine7007382019-05-21 08:36:32 -0500353
Brian Osman08a84962019-06-14 10:17:16 -0400354void innerRun(const ByteCode* byteCode, const ByteCodeFunction* f, VValue* stack,
355 float* outReturn, I32 initMask, VValue globals[]) {
Brian Osman569f12f2019-06-13 11:23:57 -0400356 VValue* sp = stack + f->fParameterCount + f->fLocalCount - 1;
357
358 auto POP = [&] { SkASSERT(sp >= stack); return *(sp--); };
359 auto PUSH = [&](VValue v) { SkASSERT(sp + 1 >= stack); *(++sp) = v; };
Mike Kleine7007382019-05-21 08:36:32 -0500360
Brian Osman80164412019-06-07 13:00:23 -0400361 const uint8_t* code = f->fCode.data();
Ethan Nicholasdfcad062019-05-07 12:53:34 -0400362 const uint8_t* ip = code;
Brian Osman226668a2019-05-14 16:47:30 -0400363 std::vector<StackFrame> frames;
364
Brian Osman569f12f2019-06-13 11:23:57 -0400365 I32 condStack[16]; // Independent condition masks
366 I32 maskStack[16]; // Combined masks (eg maskStack[0] & maskStack[1] & ...)
367 I32 contStack[16]; // Continue flags for loops
368 I32 loopStack[16]; // Loop execution masks
369 condStack[0] = maskStack[0] = initMask;
370 contStack[0] = I32( 0);
371 loopStack[0] = I32(~0);
372 I32* condPtr = condStack;
373 I32* maskPtr = maskStack;
374 I32* contPtr = contStack;
375 I32* loopPtr = loopStack;
376
377 auto mask = [&]() { return *maskPtr & *loopPtr; };
378
Ethan Nicholas7e603db2019-05-03 12:57:47 -0400379 for (;;) {
Ethan Nicholasdfcad062019-05-07 12:53:34 -0400380#ifdef TRACE
Brian Osman3e833e12019-05-23 13:23:24 -0700381 printf("at %3d ", (int) (ip - code));
382 disassemble_instruction(ip);
383 printf("\n");
Ethan Nicholasdfcad062019-05-07 12:53:34 -0400384#endif
Brian Osmane85b6a52019-05-22 14:50:59 -0700385 ByteCodeInstruction inst = (ByteCodeInstruction) READ16();
Ethan Nicholas9764ebd2019-05-01 14:43:54 -0400386 switch (inst) {
Mike Kleinc1999982019-05-21 13:03:49 -0500387 VECTOR_BINARY_OP(kAddI, fSigned, +)
Brian Osman1e855b22019-05-29 15:21:52 -0400388 VECTOR_MATRIX_BINARY_OP(kAddF, fFloat, +)
Brian Osman569f12f2019-06-13 11:23:57 -0400389
390 // Booleans are integer masks: 0/~0 for false/true. So bitwise ops do what we want:
Brian Osman32c526b2019-06-03 16:13:52 -0400391 case ByteCodeInstruction::kAndB:
Brian Osman569f12f2019-06-13 11:23:57 -0400392 sp[-1] = sp[-1].fSigned & sp[0].fSigned;
393 POP();
394 break;
395 case ByteCodeInstruction::kNotB:
396 sp[0] = ~sp[0].fSigned;
397 break;
398 case ByteCodeInstruction::kOrB:
399 sp[-1] = sp[-1].fSigned | sp[0].fSigned;
400 POP();
401 break;
402 case ByteCodeInstruction::kXorB:
403 sp[-1] = sp[-1].fSigned ^ sp[0].fSigned;
Brian Osman32c526b2019-06-03 16:13:52 -0400404 POP();
405 break;
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400406
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400407 case ByteCodeInstruction::kBranch:
Ethan Nicholasdfcad062019-05-07 12:53:34 -0400408 ip = code + READ16();
Ethan Nicholas9764ebd2019-05-01 14:43:54 -0400409 break;
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400410
Brian Osman226668a2019-05-14 16:47:30 -0400411 case ByteCodeInstruction::kCall: {
412 // Precursor code has pushed all parameters to the stack. Update our bottom of
413 // stack to point at the first parameter, and our sp to point past those parameters
414 // (plus space for locals).
Mike Kleine7007382019-05-21 08:36:32 -0500415 int target = READ8();
Brian Osman80164412019-06-07 13:00:23 -0400416 const ByteCodeFunction* fun = byteCode->fFunctions[target].get();
Brian Osman569f12f2019-06-13 11:23:57 -0400417 if (skvx::any(mask())) {
418 frames.push_back({ code, ip, stack });
419 ip = code = fun->fCode.data();
420 stack = sp - fun->fParameterCount + 1;
421 sp = stack + fun->fParameterCount + fun->fLocalCount - 1;
422 } else {
423 sp -= fun->fParameterCount;
424 sp += fun->fReturnCount;
425 }
Brian Osman226668a2019-05-14 16:47:30 -0400426 break;
427 }
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400428
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400429 case ByteCodeInstruction::kCallExternal: {
430 int argumentCount = READ8();
431 int returnCount = READ8();
Mike Kleine7007382019-05-21 08:36:32 -0500432 int target = READ8();
Brian Osman80164412019-06-07 13:00:23 -0400433 ExternalValue* v = byteCode->fExternalValues[target];
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400434 sp -= argumentCount - 1;
Mike Kleine7007382019-05-21 08:36:32 -0500435
Brian Osman08a84962019-06-14 10:17:16 -0400436 int32_t tmpArgs[4];
437 int32_t tmpReturn[4];
Brian Osman569f12f2019-06-13 11:23:57 -0400438 SkASSERT(argumentCount <= (int)SK_ARRAY_COUNT(tmpArgs));
439 SkASSERT(returnCount <= (int)SK_ARRAY_COUNT(tmpReturn));
440
441 I32 m = mask();
442 for (int i = 0; i < VecWidth; ++i) {
443 if (m[i]) {
444 for (int j = 0; j < argumentCount; ++j) {
Brian Osman08a84962019-06-14 10:17:16 -0400445 tmpArgs[j] = sp[j].fSigned[i];
Brian Osman569f12f2019-06-13 11:23:57 -0400446 }
447 v->call(tmpArgs, tmpReturn);
448 for (int j = 0; j < returnCount; ++j) {
Brian Osman08a84962019-06-14 10:17:16 -0400449 sp[j].fSigned[i] = tmpReturn[j];
Brian Osman569f12f2019-06-13 11:23:57 -0400450 }
451 }
452 }
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400453 sp += returnCount - 1;
454 break;
455 }
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400456
Mike Kleinc1999982019-05-21 13:03:49 -0500457 VECTOR_BINARY_OP(kCompareIEQ, fSigned, ==)
Brian Osman1e855b22019-05-29 15:21:52 -0400458 VECTOR_MATRIX_BINARY_OP(kCompareFEQ, fFloat, ==)
Mike Kleinc1999982019-05-21 13:03:49 -0500459 VECTOR_BINARY_OP(kCompareINEQ, fSigned, !=)
Brian Osman1e855b22019-05-29 15:21:52 -0400460 VECTOR_MATRIX_BINARY_OP(kCompareFNEQ, fFloat, !=)
Mike Kleinc1999982019-05-21 13:03:49 -0500461 VECTOR_BINARY_OP(kCompareSGT, fSigned, >)
462 VECTOR_BINARY_OP(kCompareUGT, fUnsigned, >)
463 VECTOR_BINARY_OP(kCompareFGT, fFloat, >)
464 VECTOR_BINARY_OP(kCompareSGTEQ, fSigned, >=)
465 VECTOR_BINARY_OP(kCompareUGTEQ, fUnsigned, >=)
466 VECTOR_BINARY_OP(kCompareFGTEQ, fFloat, >=)
467 VECTOR_BINARY_OP(kCompareSLT, fSigned, <)
468 VECTOR_BINARY_OP(kCompareULT, fUnsigned, <)
469 VECTOR_BINARY_OP(kCompareFLT, fFloat, <)
470 VECTOR_BINARY_OP(kCompareSLTEQ, fSigned, <=)
471 VECTOR_BINARY_OP(kCompareULTEQ, fUnsigned, <=)
472 VECTOR_BINARY_OP(kCompareFLTEQ, fFloat, <=)
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400473
Brian Osman569f12f2019-06-13 11:23:57 -0400474 case ByteCodeInstruction::kConvertFtoI4: sp[-3] = skvx::cast<int>(sp[-3].fFloat);
475 case ByteCodeInstruction::kConvertFtoI3: sp[-2] = skvx::cast<int>(sp[-2].fFloat);
476 case ByteCodeInstruction::kConvertFtoI2: sp[-1] = skvx::cast<int>(sp[-1].fFloat);
477 case ByteCodeInstruction::kConvertFtoI: sp[ 0] = skvx::cast<int>(sp[ 0].fFloat);
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400478 break;
479
Brian Osman569f12f2019-06-13 11:23:57 -0400480 case ByteCodeInstruction::kConvertStoF4: sp[-3] = skvx::cast<float>(sp[-3].fSigned);
481 case ByteCodeInstruction::kConvertStoF3: sp[-2] = skvx::cast<float>(sp[-2].fSigned);
482 case ByteCodeInstruction::kConvertStoF2: sp[-1] = skvx::cast<float>(sp[-1].fSigned);
483 case ByteCodeInstruction::kConvertStoF : sp[ 0] = skvx::cast<float>(sp[ 0].fSigned);
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400484 break;
485
Brian Osman569f12f2019-06-13 11:23:57 -0400486 case ByteCodeInstruction::kConvertUtoF4: sp[-3] = skvx::cast<float>(sp[-3].fUnsigned);
487 case ByteCodeInstruction::kConvertUtoF3: sp[-2] = skvx::cast<float>(sp[-2].fUnsigned);
488 case ByteCodeInstruction::kConvertUtoF2: sp[-1] = skvx::cast<float>(sp[-1].fUnsigned);
489 case ByteCodeInstruction::kConvertUtoF : sp[ 0] = skvx::cast<float>(sp[ 0].fUnsigned);
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400490 break;
491
Brian Osman569f12f2019-06-13 11:23:57 -0400492 VECTOR_UNARY_FN_VEC(kCos, cosf)
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400493
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400494 case ByteCodeInstruction::kCross: {
Brian Osman569f12f2019-06-13 11:23:57 -0400495 F32 ax = sp[-5].fFloat, ay = sp[-4].fFloat, az = sp[-3].fFloat,
496 bx = sp[-2].fFloat, by = sp[-1].fFloat, bz = sp[ 0].fFloat;
497 F32 cx = ay*bz - az*by,
498 cy = az*bx - ax*bz,
499 cz = ax*by - ay*bx;
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400500 sp -= 3;
Brian Osman569f12f2019-06-13 11:23:57 -0400501 sp[-2] = cx;
502 sp[-1] = cy;
503 sp[ 0] = cz;
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400504 break;
505 }
506
Mike Kleinc1999982019-05-21 13:03:49 -0500507 VECTOR_BINARY_OP(kDivideS, fSigned, /)
508 VECTOR_BINARY_OP(kDivideU, fUnsigned, /)
Brian Osman1e855b22019-05-29 15:21:52 -0400509 VECTOR_MATRIX_BINARY_OP(kDivideF, fFloat, /)
Mike Kleine7007382019-05-21 08:36:32 -0500510
511 case ByteCodeInstruction::kDup4: PUSH(sp[(int)ByteCodeInstruction::kDup - (int)inst]);
512 case ByteCodeInstruction::kDup3: PUSH(sp[(int)ByteCodeInstruction::kDup - (int)inst]);
513 case ByteCodeInstruction::kDup2: PUSH(sp[(int)ByteCodeInstruction::kDup - (int)inst]);
514 case ByteCodeInstruction::kDup : PUSH(sp[(int)ByteCodeInstruction::kDup - (int)inst]);
515 break;
516
Brian Osman07c117b2019-05-23 12:51:06 -0700517 case ByteCodeInstruction::kDupN: {
518 int count = READ8();
Brian Osman569f12f2019-06-13 11:23:57 -0400519 memcpy(sp + 1, sp - count + 1, count * sizeof(VValue));
Brian Osman07c117b2019-05-23 12:51:06 -0700520 sp += count;
521 break;
522 }
523
Mike Kleine7007382019-05-21 08:36:32 -0500524 case ByteCodeInstruction::kLoad4: sp[4] = stack[*ip + 3];
525 case ByteCodeInstruction::kLoad3: sp[3] = stack[*ip + 2];
526 case ByteCodeInstruction::kLoad2: sp[2] = stack[*ip + 1];
527 case ByteCodeInstruction::kLoad : sp[1] = stack[*ip + 0];
528 ++ip;
529 sp += (int)inst - (int)ByteCodeInstruction::kLoad + 1;
530 break;
531
Brian Osman80164412019-06-07 13:00:23 -0400532 case ByteCodeInstruction::kLoadGlobal4: sp[4] = globals[*ip + 3];
533 case ByteCodeInstruction::kLoadGlobal3: sp[3] = globals[*ip + 2];
534 case ByteCodeInstruction::kLoadGlobal2: sp[2] = globals[*ip + 1];
535 case ByteCodeInstruction::kLoadGlobal : sp[1] = globals[*ip + 0];
Mike Kleine7007382019-05-21 08:36:32 -0500536 ++ip;
Brian Osman07c117b2019-05-23 12:51:06 -0700537 sp += (int)inst -
538 (int)ByteCodeInstruction::kLoadGlobal + 1;
Mike Kleine7007382019-05-21 08:36:32 -0500539 break;
540
Brian Osman07c117b2019-05-23 12:51:06 -0700541 case ByteCodeInstruction::kLoadExtended: {
542 int count = READ8();
Brian Osman569f12f2019-06-13 11:23:57 -0400543 I32 src = POP().fSigned;
544 I32 m = mask();
545 for (int i = 0; i < count; ++i) {
546 for (int j = 0; j < VecWidth; ++j) {
547 if (m[j]) {
548 sp[i + 1].fSigned[j] = stack[src[j] + i].fSigned[j];
549 }
550 }
551 }
Brian Osman07c117b2019-05-23 12:51:06 -0700552 sp += count;
553 break;
554 }
555
556 case ByteCodeInstruction::kLoadExtendedGlobal: {
557 int count = READ8();
Brian Osman569f12f2019-06-13 11:23:57 -0400558 I32 src = POP().fSigned;
559 I32 m = mask();
560 for (int i = 0; i < count; ++i) {
561 for (int j = 0; j < VecWidth; ++j) {
562 if (m[j]) {
563 sp[i + 1].fSigned[j] = globals[src[j] + i].fSigned[j];
564 }
565 }
566 }
Brian Osman07c117b2019-05-23 12:51:06 -0700567 sp += count;
568 break;
569 }
570
Mike Kleine7007382019-05-21 08:36:32 -0500571 case ByteCodeInstruction::kLoadSwizzle: {
572 int src = READ8();
573 int count = READ8();
Ethan Nicholas9764ebd2019-05-01 14:43:54 -0400574 for (int i = 0; i < count; ++i) {
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400575 PUSH(stack[src + *(ip + i)]);
Ethan Nicholas9764ebd2019-05-01 14:43:54 -0400576 }
Ethan Nicholas7e603db2019-05-03 12:57:47 -0400577 ip += count;
Ethan Nicholas9764ebd2019-05-01 14:43:54 -0400578 break;
Mike Kleine7007382019-05-21 08:36:32 -0500579 }
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400580
Mike Kleine7007382019-05-21 08:36:32 -0500581 case ByteCodeInstruction::kLoadSwizzleGlobal: {
582 int src = READ8();
Mike Kleine7007382019-05-21 08:36:32 -0500583 int count = READ8();
Brian Osmanb7451292019-05-15 13:02:13 -0400584 for (int i = 0; i < count; ++i) {
Brian Osman80164412019-06-07 13:00:23 -0400585 PUSH(globals[src + *(ip + i)]);
Brian Osmanb7451292019-05-15 13:02:13 -0400586 }
587 ip += count;
588 break;
Mike Kleine7007382019-05-21 08:36:32 -0500589 }
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400590
Brian Osman29e013d2019-05-28 17:16:03 -0400591 case ByteCodeInstruction::kMatrixToMatrix: {
592 int srcCols = READ8();
593 int srcRows = READ8();
594 int dstCols = READ8();
595 int dstRows = READ8();
596 SkASSERT(srcCols >= 2 && srcCols <= 4);
597 SkASSERT(srcRows >= 2 && srcRows <= 4);
598 SkASSERT(dstCols >= 2 && dstCols <= 4);
599 SkASSERT(dstRows >= 2 && dstRows <= 4);
Brian Osman569f12f2019-06-13 11:23:57 -0400600 F32 tmp[16];
601 memset(tmp, 0, sizeof(tmp));
602 tmp[0] = tmp[5] = tmp[10] = tmp[15] = F32(1.0f);
Brian Osman29e013d2019-05-28 17:16:03 -0400603 for (int c = srcCols - 1; c >= 0; --c) {
604 for (int r = srcRows - 1; r >= 0; --r) {
Brian Osman569f12f2019-06-13 11:23:57 -0400605 tmp[c*4 + r] = POP().fFloat;
Brian Osman29e013d2019-05-28 17:16:03 -0400606 }
607 }
608 for (int c = 0; c < dstCols; ++c) {
609 for (int r = 0; r < dstRows; ++r) {
Brian Osman569f12f2019-06-13 11:23:57 -0400610 PUSH(tmp[c*4 + r]);
Brian Osman29e013d2019-05-28 17:16:03 -0400611 }
612 }
613 break;
614 }
615
Brian Osman909231c2019-05-29 15:34:36 -0400616 case ByteCodeInstruction::kMatrixMultiply: {
617 int lCols = READ8();
618 int lRows = READ8();
619 int rCols = READ8();
620 int rRows = lCols;
Brian Osman569f12f2019-06-13 11:23:57 -0400621 F32 tmp[16] = { 0.0f };
622 F32* B = &(sp - (rCols * rRows) + 1)->fFloat;
623 F32* A = B - (lCols * lRows);
Brian Osman909231c2019-05-29 15:34:36 -0400624 for (int c = 0; c < rCols; ++c) {
625 for (int r = 0; r < lRows; ++r) {
626 for (int j = 0; j < lCols; ++j) {
627 tmp[c*lRows + r] += A[j*lRows + r] * B[c*rRows + j];
628 }
629 }
630 }
631 sp -= (lCols * lRows) + (rCols * rRows);
Brian Osman569f12f2019-06-13 11:23:57 -0400632 memcpy(sp + 1, tmp, rCols * lRows * sizeof(VValue));
Brian Osman909231c2019-05-29 15:34:36 -0400633 sp += (rCols * lRows);
634 break;
635 }
636
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400637 // stack looks like: X1 Y1 Z1 W1 X2 Y2 Z2 W2 T
638 case ByteCodeInstruction::kMix4:
639 sp[-5] = mix(sp[-5].fFloat, sp[-1].fFloat, sp[0].fFloat);
640 // fall through
641 case ByteCodeInstruction::kMix3: {
642 int count = (int) inst - (int) ByteCodeInstruction::kMix + 1;
643 int target = 2 - count * 2;
644 sp[target] = mix(sp[target].fFloat, sp[2 - count].fFloat, sp[0].fFloat);
645 // fall through
646 }
647 case ByteCodeInstruction::kMix2: {
648 int count = (int) inst - (int) ByteCodeInstruction::kMix + 1;
649 int target = 1 - count * 2;
650 sp[target] = mix(sp[target].fFloat, sp[1 - count].fFloat, sp[0].fFloat);
651 // fall through
652 }
653 case ByteCodeInstruction::kMix: {
654 int count = (int) inst - (int) ByteCodeInstruction::kMix + 1;
655 int target = -count * 2;
656 sp[target] = mix(sp[target].fFloat, sp[-count].fFloat, sp[0].fFloat);
657 sp -= 1 + count;
658 break;
659 }
660
Mike Kleinc1999982019-05-21 13:03:49 -0500661 VECTOR_BINARY_OP(kMultiplyI, fSigned, *)
Brian Osman1e855b22019-05-29 15:21:52 -0400662 VECTOR_MATRIX_BINARY_OP(kMultiplyF, fFloat, *)
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400663
Mike Kleinc1999982019-05-21 13:03:49 -0500664 case ByteCodeInstruction::kNegateF4: sp[-3] = -sp[-3].fFloat;
665 case ByteCodeInstruction::kNegateF3: sp[-2] = -sp[-2].fFloat;
666 case ByteCodeInstruction::kNegateF2: sp[-1] = -sp[-1].fFloat;
667 case ByteCodeInstruction::kNegateF : sp[ 0] = -sp[ 0].fFloat;
Mike Kleine7007382019-05-21 08:36:32 -0500668 break;
669
Brian Osman1e855b22019-05-29 15:21:52 -0400670 case ByteCodeInstruction::kNegateFN: {
671 int count = READ8();
672 for (int i = count - 1; i >= 0; --i) {
673 sp[-i] = -sp[-i].fFloat;
674 }
675 break;
676 }
677
Mike Kleinc1999982019-05-21 13:03:49 -0500678 case ByteCodeInstruction::kNegateI4: sp[-3] = -sp[-3].fSigned;
679 case ByteCodeInstruction::kNegateI3: sp[-2] = -sp[-2].fSigned;
680 case ByteCodeInstruction::kNegateI2: sp[-1] = -sp[-1].fSigned;
Brian Osman569f12f2019-06-13 11:23:57 -0400681 case ByteCodeInstruction::kNegateI : sp[ 0] = -sp[ 0].fSigned;
Mike Kleine7007382019-05-21 08:36:32 -0500682 break;
683
684 case ByteCodeInstruction::kPop4: POP();
685 case ByteCodeInstruction::kPop3: POP();
686 case ByteCodeInstruction::kPop2: POP();
687 case ByteCodeInstruction::kPop : POP();
688 break;
689
Brian Osman07c117b2019-05-23 12:51:06 -0700690 case ByteCodeInstruction::kPopN:
691 sp -= READ8();
692 break;
693
Ethan Nicholas9764ebd2019-05-01 14:43:54 -0400694 case ByteCodeInstruction::kPushImmediate:
Brian Osman569f12f2019-06-13 11:23:57 -0400695 PUSH(U32(READ32()));
Ethan Nicholas9764ebd2019-05-01 14:43:54 -0400696 break;
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400697
Brian Osman569f12f2019-06-13 11:23:57 -0400698 case ByteCodeInstruction::kReadExternal:
699 case ByteCodeInstruction::kReadExternal2:
700 case ByteCodeInstruction::kReadExternal3:
Mike Kleine7007382019-05-21 08:36:32 -0500701 case ByteCodeInstruction::kReadExternal4: {
Brian Osman569f12f2019-06-13 11:23:57 -0400702 // TODO: Support striped external values, or passing lane index? This model is odd.
703 int count = (int)inst - (int)ByteCodeInstruction::kReadExternal + 1;
Mike Kleine7007382019-05-21 08:36:32 -0500704 int src = READ8();
Brian Osman569f12f2019-06-13 11:23:57 -0400705 int32_t tmp[4];
706 I32 m = mask();
707 for (int i = 0; i < VecWidth; ++i) {
708 if (m[i]) {
709 byteCode->fExternalValues[src]->read(tmp);
710 for (int j = 0; j < count; ++j) {
711 sp[j + 1].fSigned[i] = tmp[j];
712 }
713 }
714 }
715 sp += count;
Ethan Nicholas91164d12019-05-15 15:29:54 -0400716 break;
Mike Kleine7007382019-05-21 08:36:32 -0500717 }
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400718
Brian Osman569f12f2019-06-13 11:23:57 -0400719 VECTOR_BINARY_FN(kRemainderF, fFloat, vec_mod<F32>)
720 VECTOR_BINARY_FN(kRemainderS, fSigned, vec_mod<I32>)
721 VECTOR_BINARY_FN(kRemainderU, fUnsigned, vec_mod<U32>)
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400722
Mike Kleine7007382019-05-21 08:36:32 -0500723 case ByteCodeInstruction::kReturn: {
724 int count = READ8();
Brian Osman226668a2019-05-14 16:47:30 -0400725 if (frames.empty()) {
726 if (outReturn) {
Brian Osman569f12f2019-06-13 11:23:57 -0400727 // TODO: This can be smarter, knowing that mask is left-justified
728 I32 m = mask();
729 VValue* src = sp - count + 1;
730 for (int i = 0; i < count; ++i) {
731 for (int j = 0; j < VecWidth; ++j) {
732 if (m[j]) {
Brian Osman08a84962019-06-14 10:17:16 -0400733 outReturn[count * j] = src->fFloat[j];
Brian Osman569f12f2019-06-13 11:23:57 -0400734 }
735 }
736 ++outReturn;
737 ++src;
738 }
Brian Osman226668a2019-05-14 16:47:30 -0400739 }
740 return;
741 } else {
742 // When we were called, 'stack' was positioned at the old top-of-stack (where
743 // our parameters were placed). So copy our return values to that same spot.
Brian Osman569f12f2019-06-13 11:23:57 -0400744 memmove(stack, sp - count + 1, count * sizeof(VValue));
Brian Osman226668a2019-05-14 16:47:30 -0400745
746 // Now move the stack pointer to the end of the just-pushed return values,
747 // and restore everything else.
748 const StackFrame& frame(frames.back());
749 sp = stack + count - 1;
750 stack = frame.fStack;
751 code = frame.fCode;
752 ip = frame.fIP;
753 frames.pop_back();
754 break;
Ethan Nicholas9764ebd2019-05-01 14:43:54 -0400755 }
Mike Kleine7007382019-05-21 08:36:32 -0500756 }
757
Brian Osman29e013d2019-05-28 17:16:03 -0400758 case ByteCodeInstruction::kScalarToMatrix: {
759 int cols = READ8();
760 int rows = READ8();
Brian Osman569f12f2019-06-13 11:23:57 -0400761 VValue v = POP();
Brian Osman29e013d2019-05-28 17:16:03 -0400762 for (int c = 0; c < cols; ++c) {
763 for (int r = 0; r < rows; ++r) {
Brian Osman569f12f2019-06-13 11:23:57 -0400764 PUSH(c == r ? v : F32(0.0f));
Brian Osman29e013d2019-05-28 17:16:03 -0400765 }
766 }
767 break;
768 }
769
Brian Osman569f12f2019-06-13 11:23:57 -0400770 VECTOR_UNARY_FN_VEC(kSin, sinf)
771 VECTOR_UNARY_FN(kSqrt, skvx::sqrt, fFloat)
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400772
Brian Osman569f12f2019-06-13 11:23:57 -0400773 case ByteCodeInstruction::kStore4:
774 stack[*ip+3] = skvx::if_then_else(mask(), POP().fFloat, stack[*ip+3].fFloat);
775 case ByteCodeInstruction::kStore3:
776 stack[*ip+2] = skvx::if_then_else(mask(), POP().fFloat, stack[*ip+2].fFloat);
777 case ByteCodeInstruction::kStore2:
778 stack[*ip+1] = skvx::if_then_else(mask(), POP().fFloat, stack[*ip+1].fFloat);
779 case ByteCodeInstruction::kStore :
780 stack[*ip+0] = skvx::if_then_else(mask(), POP().fFloat, stack[*ip+0].fFloat);
781 ++ip;
782 break;
Mike Kleine7007382019-05-21 08:36:32 -0500783
Brian Osman569f12f2019-06-13 11:23:57 -0400784 case ByteCodeInstruction::kStoreGlobal4:
785 globals[*ip+3] = skvx::if_then_else(mask(), POP().fFloat, globals[*ip+3].fFloat);
786 case ByteCodeInstruction::kStoreGlobal3:
787 globals[*ip+2] = skvx::if_then_else(mask(), POP().fFloat, globals[*ip+2].fFloat);
788 case ByteCodeInstruction::kStoreGlobal2:
789 globals[*ip+1] = skvx::if_then_else(mask(), POP().fFloat, globals[*ip+1].fFloat);
790 case ByteCodeInstruction::kStoreGlobal :
791 globals[*ip+0] = skvx::if_then_else(mask(), POP().fFloat, globals[*ip+0].fFloat);
792 ++ip;
793 break;
Mike Kleine7007382019-05-21 08:36:32 -0500794
Brian Osman07c117b2019-05-23 12:51:06 -0700795 case ByteCodeInstruction::kStoreExtended: {
796 int count = READ8();
Brian Osman569f12f2019-06-13 11:23:57 -0400797 I32 target = POP().fSigned;
798 VValue* src = sp - count + 1;
799 I32 m = mask();
800 for (int i = 0; i < count; ++i) {
801 for (int j = 0; j < VecWidth; ++j) {
802 if (m[j]) {
803 stack[target[j] + i].fSigned[j] = src[i].fSigned[j];
804 }
805 }
806 }
Brian Osman07c117b2019-05-23 12:51:06 -0700807 sp -= count;
808 break;
809 }
810 case ByteCodeInstruction::kStoreExtendedGlobal: {
811 int count = READ8();
Brian Osman569f12f2019-06-13 11:23:57 -0400812 I32 target = POP().fSigned;
813 VValue* src = sp - count + 1;
814 I32 m = mask();
815 for (int i = 0; i < count; ++i) {
816 for (int j = 0; j < VecWidth; ++j) {
817 if (m[j]) {
818 globals[target[j] + i].fSigned[j] = src[i].fSigned[j];
819 }
820 }
821 }
Brian Osman07c117b2019-05-23 12:51:06 -0700822 sp -= count;
823 break;
824 }
825
Mike Kleine7007382019-05-21 08:36:32 -0500826 case ByteCodeInstruction::kStoreSwizzle: {
827 int target = READ8();
828 int count = READ8();
Ethan Nicholas9764ebd2019-05-01 14:43:54 -0400829 for (int i = count - 1; i >= 0; --i) {
Brian Osman569f12f2019-06-13 11:23:57 -0400830 stack[target + *(ip + i)] = skvx::if_then_else(
831 mask(), POP().fFloat, stack[target + *(ip + i)].fFloat);
Ethan Nicholas9764ebd2019-05-01 14:43:54 -0400832 }
Brian Osman1091f022019-05-16 09:42:16 -0400833 ip += count;
834 break;
Mike Kleine7007382019-05-21 08:36:32 -0500835 }
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400836
Mike Kleine7007382019-05-21 08:36:32 -0500837 case ByteCodeInstruction::kStoreSwizzleGlobal: {
838 int target = READ8();
839 int count = READ8();
Brian Osman1091f022019-05-16 09:42:16 -0400840 for (int i = count - 1; i >= 0; --i) {
Brian Osman569f12f2019-06-13 11:23:57 -0400841 globals[target + *(ip + i)] = skvx::if_then_else(
842 mask(), POP().fFloat, globals[target + *(ip + i)].fFloat);
Brian Osman1091f022019-05-16 09:42:16 -0400843 }
Ethan Nicholas7e603db2019-05-03 12:57:47 -0400844 ip += count;
Ethan Nicholas9764ebd2019-05-01 14:43:54 -0400845 break;
Mike Kleine7007382019-05-21 08:36:32 -0500846 }
Brian Osman569f12f2019-06-13 11:23:57 -0400847
Brian Osman07c117b2019-05-23 12:51:06 -0700848 case ByteCodeInstruction::kStoreSwizzleIndirect: {
Brian Osman07c117b2019-05-23 12:51:06 -0700849 int count = READ8();
Brian Osman569f12f2019-06-13 11:23:57 -0400850 I32 target = POP().fSigned;
851 I32 m = mask();
Brian Osman07c117b2019-05-23 12:51:06 -0700852 for (int i = count - 1; i >= 0; --i) {
Brian Osman569f12f2019-06-13 11:23:57 -0400853 I32 v = POP().fSigned;
854 for (int j = 0; j < VecWidth; ++j) {
855 if (m[j]) {
856 stack[target[j] + *(ip + i)].fSigned[j] = v[j];
857 }
858 }
Brian Osman07c117b2019-05-23 12:51:06 -0700859 }
860 ip += count;
861 break;
862 }
Brian Osman569f12f2019-06-13 11:23:57 -0400863
Brian Osman07c117b2019-05-23 12:51:06 -0700864 case ByteCodeInstruction::kStoreSwizzleIndirectGlobal: {
Brian Osman07c117b2019-05-23 12:51:06 -0700865 int count = READ8();
Brian Osman569f12f2019-06-13 11:23:57 -0400866 I32 target = POP().fSigned;
867 I32 m = mask();
Brian Osman07c117b2019-05-23 12:51:06 -0700868 for (int i = count - 1; i >= 0; --i) {
Brian Osman569f12f2019-06-13 11:23:57 -0400869 I32 v = POP().fSigned;
870 for (int j = 0; j < VecWidth; ++j) {
871 if (m[j]) {
872 globals[target[j] + *(ip + i)].fSigned[j] = v[j];
873 }
874 }
Brian Osman07c117b2019-05-23 12:51:06 -0700875 }
876 ip += count;
877 break;
878 }
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400879
Mike Kleinc1999982019-05-21 13:03:49 -0500880 VECTOR_BINARY_OP(kSubtractI, fSigned, -)
Brian Osman1e855b22019-05-29 15:21:52 -0400881 VECTOR_MATRIX_BINARY_OP(kSubtractF, fFloat, -)
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400882
Mike Kleine7007382019-05-21 08:36:32 -0500883 case ByteCodeInstruction::kSwizzle: {
Brian Osman569f12f2019-06-13 11:23:57 -0400884 VValue tmp[4];
Ethan Nicholas7e603db2019-05-03 12:57:47 -0400885 for (int i = READ8() - 1; i >= 0; --i) {
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400886 tmp[i] = POP();
Ethan Nicholas9764ebd2019-05-01 14:43:54 -0400887 }
Ethan Nicholas7e603db2019-05-03 12:57:47 -0400888 for (int i = READ8() - 1; i >= 0; --i) {
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400889 PUSH(tmp[READ8()]);
Ethan Nicholas9764ebd2019-05-01 14:43:54 -0400890 }
891 break;
Mike Kleine7007382019-05-21 08:36:32 -0500892 }
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400893
Brian Osman569f12f2019-06-13 11:23:57 -0400894 VECTOR_UNARY_FN_VEC(kTan, tanf)
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400895
Brian Osman569f12f2019-06-13 11:23:57 -0400896 case ByteCodeInstruction::kWriteExternal:
897 case ByteCodeInstruction::kWriteExternal2:
898 case ByteCodeInstruction::kWriteExternal3:
Mike Kleine7007382019-05-21 08:36:32 -0500899 case ByteCodeInstruction::kWriteExternal4: {
Brian Osman569f12f2019-06-13 11:23:57 -0400900 int count = (int)inst - (int)ByteCodeInstruction::kWriteExternal + 1;
Mike Kleine7007382019-05-21 08:36:32 -0500901 int target = READ8();
Brian Osman569f12f2019-06-13 11:23:57 -0400902 int32_t tmp[4];
903 I32 m = mask();
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400904 sp -= count;
Brian Osman569f12f2019-06-13 11:23:57 -0400905 for (int i = 0; i < VecWidth; ++i) {
906 if (m[i]) {
907 for (int j = 0; j < count; ++j) {
908 tmp[j] = sp[j + 1].fSigned[i];
909 }
910 byteCode->fExternalValues[target]->write(tmp);
911 }
912 }
913 break;
914 }
915
916 case ByteCodeInstruction::kMaskPush:
917 condPtr[1] = POP().fSigned;
918 maskPtr[1] = maskPtr[0] & condPtr[1];
919 ++condPtr; ++maskPtr;
920 break;
921 case ByteCodeInstruction::kMaskPop:
922 --condPtr; --maskPtr;
923 break;
924 case ByteCodeInstruction::kMaskNegate:
925 maskPtr[0] = maskPtr[-1] & ~condPtr[0];
926 break;
927 case ByteCodeInstruction::kMaskBlend: {
928 int count = READ8();
929 I32 m = condPtr[0];
930 --condPtr; --maskPtr;
931 for (int i = 0; i < count; ++i) {
932 sp[-count] = skvx::if_then_else(m, sp[-count].fFloat, sp[0].fFloat);
933 --sp;
934 }
935 break;
936 }
937 case ByteCodeInstruction::kBranchIfAllFalse: {
938 int target = READ16();
939 if (!skvx::any(mask())) {
940 ip = code + target;
941 }
942 break;
943 }
944
945 case ByteCodeInstruction::kLoopBegin:
946 *(++contPtr) = 0;
947 *(++loopPtr) = ~0;
948 break;
949 case ByteCodeInstruction::kLoopNext:
950 *loopPtr |= *contPtr;
951 *contPtr = 0;
952 break;
953 case ByteCodeInstruction::kLoopMask:
954 *loopPtr &= POP().fSigned;
955 break;
956 case ByteCodeInstruction::kLoopEnd:
957 --contPtr; --loopPtr;
958 break;
959 case ByteCodeInstruction::kLoopBreak:
960 *loopPtr &= ~mask();
961 break;
962 case ByteCodeInstruction::kLoopContinue: {
963 I32 m = mask();
964 *contPtr |= m;
965 *loopPtr &= ~m;
Ethan Nicholas9764ebd2019-05-01 14:43:54 -0400966 break;
Mike Kleine7007382019-05-21 08:36:32 -0500967 }
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400968
Ethan Nicholas9764ebd2019-05-01 14:43:54 -0400969 default:
Mike Kleine7007382019-05-21 08:36:32 -0500970 SkDEBUGFAILF("unsupported instruction %d\n", (int) inst);
Ethan Nicholas9764ebd2019-05-01 14:43:54 -0400971 }
Brian Osman569f12f2019-06-13 11:23:57 -0400972 }
973}
974
Brian Osman08a84962019-06-14 10:17:16 -0400975} // namespace Interpreter
976
977void ByteCodeFunction::disassemble() const {
978 const uint8_t* ip = fCode.data();
979 while (ip < fCode.data() + fCode.size()) {
980 printf("%d: ", (int)(ip - fCode.data()));
981 ip = Interpreter::disassemble_instruction(ip);
982 printf("\n");
983 }
984}
985
986void ByteCode::run(const ByteCodeFunction* f, float* args, float* outReturn, int N,
987 const float* uniforms, int uniformCount) const {
Ethan Nicholas9764ebd2019-05-01 14:43:54 -0400988#ifdef TRACE
Brian Osman08a84962019-06-14 10:17:16 -0400989 f->disassemble();
Ethan Nicholas9764ebd2019-05-01 14:43:54 -0400990#endif
Brian Osman08a84962019-06-14 10:17:16 -0400991 Interpreter::VValue smallStack[128];
Brian Osman569f12f2019-06-13 11:23:57 -0400992
Brian Osmanef787f72019-06-13 13:07:12 -0400993 // Needs to be the first N non-negative integers, at least as large as VecWidth
Brian Osman08a84962019-06-14 10:17:16 -0400994 static const Interpreter::I32 gLanes = {
995 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
996 };
Brian Osmanef787f72019-06-13 13:07:12 -0400997
Brian Osman08a84962019-06-14 10:17:16 -0400998 SkASSERT(uniformCount == (int)fInputSlots.size());
999 Interpreter::VValue globals[32];
1000 SkASSERT((int)SK_ARRAY_COUNT(globals) >= fGlobalCount);
1001 for (uint8_t slot : fInputSlots) {
1002 globals[slot].fFloat = *uniforms++;
Brian Osman569f12f2019-06-13 11:23:57 -04001003 }
1004
1005 while (N) {
Brian Osman08a84962019-06-14 10:17:16 -04001006 Interpreter::VValue* stack = smallStack;
Brian Osman569f12f2019-06-13 11:23:57 -04001007
Brian Osman08a84962019-06-14 10:17:16 -04001008 int w = std::min(N, Interpreter::VecWidth);
Brian Osman569f12f2019-06-13 11:23:57 -04001009 N -= w;
1010
1011 // Transpose args into stack
1012 {
Brian Osman08a84962019-06-14 10:17:16 -04001013 float* src = args;
Brian Osman569f12f2019-06-13 11:23:57 -04001014 for (int i = 0; i < w; ++i) {
Brian Osman08a84962019-06-14 10:17:16 -04001015 float* dst = (float*)stack + i;
Brian Osman569f12f2019-06-13 11:23:57 -04001016 for (int j = f->fParameterCount; j > 0; --j) {
1017 *dst = *src++;
Brian Osman08a84962019-06-14 10:17:16 -04001018 dst += Interpreter::VecWidth;
Brian Osman569f12f2019-06-13 11:23:57 -04001019 }
1020 }
1021 }
1022
1023 auto mask = w > gLanes;
Brian Osman08a84962019-06-14 10:17:16 -04001024 innerRun(this, f, stack, outReturn, mask, globals);
Brian Osman569f12f2019-06-13 11:23:57 -04001025
1026 // Transpose out parameters back
1027 {
Brian Osman08a84962019-06-14 10:17:16 -04001028 float* dst = args;
Brian Osman569f12f2019-06-13 11:23:57 -04001029 for (int i = 0; i < w; ++i) {
Brian Osman08a84962019-06-14 10:17:16 -04001030 float* src = (float*)stack + i;
Brian Osman569f12f2019-06-13 11:23:57 -04001031 for (const auto& p : f->fParameters) {
1032 if (p.fIsOutParameter) {
1033 for (int j = p.fSlotCount; j > 0; --j) {
1034 *dst++ = *src;
Brian Osman08a84962019-06-14 10:17:16 -04001035 src += Interpreter::VecWidth;
Brian Osman569f12f2019-06-13 11:23:57 -04001036 }
1037 } else {
1038 dst += p.fSlotCount;
Brian Osman08a84962019-06-14 10:17:16 -04001039 src += p.fSlotCount * Interpreter::VecWidth;
Brian Osman569f12f2019-06-13 11:23:57 -04001040 }
1041 }
1042 }
1043 }
1044
1045 args += f->fParameterCount * w;
1046 outReturn += f->fReturnCount * w;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001047 }
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001048}
1049
Brian Osman80164412019-06-07 13:00:23 -04001050} // namespace SkSL
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001051
1052#endif