blob: 59c8899569e0485d04d71094e83036d6f489a278 [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"
Mike Klein7a177b42019-06-17 17:17:47 -050012#include "src/core/SkUtils.h" // sk_unaligned_load
Brian Osman80164412019-06-07 13:00:23 -040013#include "src/sksl/SkSLByteCode.h"
Brian Osman07c117b2019-05-23 12:51:06 -070014#include "src/sksl/SkSLByteCodeGenerator.h"
Ethan Nicholas91164d12019-05-15 15:29:54 -040015#include "src/sksl/SkSLExternalValue.h"
Brian Osman80164412019-06-07 13:00:23 -040016
17#include <vector>
Ethan Nicholas26a9aad2018-03-27 14:10:52 -040018
19namespace SkSL {
Brian Osman80164412019-06-07 13:00:23 -040020namespace Interpreter {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -040021
Mike Reed3fd3cc92019-06-20 12:40:30 -040022constexpr int VecWidth = ByteCode::kVecWidth;
Brian Osman569f12f2019-06-13 11:23:57 -040023
24using F32 = skvx::Vec<VecWidth, float>;
25using I32 = skvx::Vec<VecWidth, int32_t>;
26using U32 = skvx::Vec<VecWidth, uint32_t>;
27
Mike Kleine7007382019-05-21 08:36:32 -050028#define READ8() (*(ip++))
Mike Klein7a177b42019-06-17 17:17:47 -050029#define READ16() (ip += 2, sk_unaligned_load<uint16_t>(ip - 2))
30#define READ32() (ip += 4, sk_unaligned_load<uint32_t>(ip - 4))
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040031
Brian Osman3e833e12019-05-23 13:23:24 -070032#define VECTOR_DISASSEMBLE(op, text) \
Ethan Nicholas48a75aa2019-05-16 17:15:56 -040033 case ByteCodeInstruction::op: printf(text); break; \
34 case ByteCodeInstruction::op##2: printf(text "2"); break; \
35 case ByteCodeInstruction::op##3: printf(text "3"); break; \
36 case ByteCodeInstruction::op##4: printf(text "4"); break;
37
Brian Osman1e855b22019-05-29 15:21:52 -040038#define VECTOR_MATRIX_DISASSEMBLE(op, text) \
39 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 case ByteCodeInstruction::op##N: printf(text "N %d", READ8()); break;
44
Brian Osman3e833e12019-05-23 13:23:24 -070045static const uint8_t* disassemble_instruction(const uint8_t* ip) {
46 switch ((ByteCodeInstruction) READ16()) {
Brian Osman1e855b22019-05-29 15:21:52 -040047 VECTOR_MATRIX_DISASSEMBLE(kAddF, "addf")
Brian Osman3e833e12019-05-23 13:23:24 -070048 VECTOR_DISASSEMBLE(kAddI, "addi")
Brian Osman32c526b2019-06-03 16:13:52 -040049 case ByteCodeInstruction::kAndB: printf("andb"); break;
Brian Osman3e833e12019-05-23 13:23:24 -070050 case ByteCodeInstruction::kBranch: printf("branch %d", READ16()); break;
51 case ByteCodeInstruction::kCall: printf("call %d", READ8()); break;
52 case ByteCodeInstruction::kCallExternal: {
53 int argumentCount = READ8();
54 int returnCount = READ8();
55 int externalValue = READ8();
56 printf("callexternal %d, %d, %d", argumentCount, returnCount, externalValue);
57 break;
58 }
59 VECTOR_DISASSEMBLE(kCompareIEQ, "compareieq")
60 VECTOR_DISASSEMBLE(kCompareINEQ, "compareineq")
Brian Osman1e855b22019-05-29 15:21:52 -040061 VECTOR_MATRIX_DISASSEMBLE(kCompareFEQ, "comparefeq")
62 VECTOR_MATRIX_DISASSEMBLE(kCompareFNEQ, "comparefneq")
Brian Osman3e833e12019-05-23 13:23:24 -070063 VECTOR_DISASSEMBLE(kCompareFGT, "comparefgt")
64 VECTOR_DISASSEMBLE(kCompareFGTEQ, "comparefgteq")
65 VECTOR_DISASSEMBLE(kCompareFLT, "compareflt")
66 VECTOR_DISASSEMBLE(kCompareFLTEQ, "compareflteq")
67 VECTOR_DISASSEMBLE(kCompareSGT, "comparesgt")
68 VECTOR_DISASSEMBLE(kCompareSGTEQ, "comparesgteq")
69 VECTOR_DISASSEMBLE(kCompareSLT, "compareslt")
70 VECTOR_DISASSEMBLE(kCompareSLTEQ, "compareslteq")
71 VECTOR_DISASSEMBLE(kCompareUGT, "compareugt")
72 VECTOR_DISASSEMBLE(kCompareUGTEQ, "compareugteq")
73 VECTOR_DISASSEMBLE(kCompareULT, "compareult")
74 VECTOR_DISASSEMBLE(kCompareULTEQ, "compareulteq")
Brian Osman3e833e12019-05-23 13:23:24 -070075 VECTOR_DISASSEMBLE(kConvertFtoI, "convertftoi")
76 VECTOR_DISASSEMBLE(kConvertStoF, "convertstof")
77 VECTOR_DISASSEMBLE(kConvertUtoF, "convertutof")
78 VECTOR_DISASSEMBLE(kCos, "cos")
Brian Osmanecb3bb52019-06-20 14:59:12 -040079 case ByteCodeInstruction::kCross: printf("cross"); break;
Brian Osman1e855b22019-05-29 15:21:52 -040080 VECTOR_MATRIX_DISASSEMBLE(kDivideF, "dividef")
Brian Osman3e833e12019-05-23 13:23:24 -070081 VECTOR_DISASSEMBLE(kDivideS, "divideS")
82 VECTOR_DISASSEMBLE(kDivideU, "divideu")
Brian Osman1e855b22019-05-29 15:21:52 -040083 VECTOR_MATRIX_DISASSEMBLE(kDup, "dup")
Brian Osman3e833e12019-05-23 13:23:24 -070084 case ByteCodeInstruction::kLoad: printf("load %d", READ8()); break;
85 case ByteCodeInstruction::kLoad2: printf("load2 %d", READ8()); break;
86 case ByteCodeInstruction::kLoad3: printf("load3 %d", READ8()); break;
87 case ByteCodeInstruction::kLoad4: printf("load4 %d", READ8()); break;
88 case ByteCodeInstruction::kLoadGlobal: printf("loadglobal %d", READ8()); break;
89 case ByteCodeInstruction::kLoadGlobal2: printf("loadglobal2 %d", READ8()); break;
90 case ByteCodeInstruction::kLoadGlobal3: printf("loadglobal3 %d", READ8()); break;
91 case ByteCodeInstruction::kLoadGlobal4: printf("loadglobal4 %d", READ8()); break;
92 case ByteCodeInstruction::kLoadSwizzle: {
93 int target = READ8();
94 int count = READ8();
95 printf("loadswizzle %d %d", target, count);
96 for (int i = 0; i < count; ++i) {
97 printf(", %d", READ8());
98 }
99 break;
100 }
101 case ByteCodeInstruction::kLoadSwizzleGlobal: {
102 int target = READ8();
103 int count = READ8();
104 printf("loadswizzleglobal %d %d", target, count);
105 for (int i = 0; i < count; ++i) {
106 printf(", %d", READ8());
107 }
108 break;
109 }
110 case ByteCodeInstruction::kLoadExtended: printf("loadextended %d", READ8()); break;
111 case ByteCodeInstruction::kLoadExtendedGlobal: printf("loadextendedglobal %d", READ8());
112 break;
Brian Osman29e013d2019-05-28 17:16:03 -0400113 case ByteCodeInstruction::kMatrixToMatrix: {
114 int srcCols = READ8();
115 int srcRows = READ8();
116 int dstCols = READ8();
117 int dstRows = READ8();
118 printf("matrixtomatrix %dx%d %dx%d", srcCols, srcRows, dstCols, dstRows);
119 break;
120 }
Brian Osman909231c2019-05-29 15:34:36 -0400121 case ByteCodeInstruction::kMatrixMultiply: {
122 int lCols = READ8();
123 int lRows = READ8();
124 int rCols = READ8();
125 printf("matrixmultiply %dx%d %dx%d", lCols, lRows, rCols, lCols);
126 break;
127 }
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400128 VECTOR_DISASSEMBLE(kMix, "mix")
Brian Osman1e855b22019-05-29 15:21:52 -0400129 VECTOR_MATRIX_DISASSEMBLE(kMultiplyF, "multiplyf")
Brian Osman3e833e12019-05-23 13:23:24 -0700130 VECTOR_DISASSEMBLE(kMultiplyI, "multiplyi")
Brian Osman1e855b22019-05-29 15:21:52 -0400131 VECTOR_MATRIX_DISASSEMBLE(kNegateF, "negatef")
Brian Osman3e833e12019-05-23 13:23:24 -0700132 VECTOR_DISASSEMBLE(kNegateI, "negatei")
Brian Osman569f12f2019-06-13 11:23:57 -0400133 case ByteCodeInstruction::kNotB: printf("notb"); break;
Brian Osman32c526b2019-06-03 16:13:52 -0400134 case ByteCodeInstruction::kOrB: printf("orb"); break;
Brian Osman1e855b22019-05-29 15:21:52 -0400135 VECTOR_MATRIX_DISASSEMBLE(kPop, "pop")
Brian Osman3e833e12019-05-23 13:23:24 -0700136 case ByteCodeInstruction::kPushImmediate: {
137 uint32_t v = READ32();
138 union { uint32_t u; float f; } pun = { v };
139 printf("pushimmediate %s", (to_string(v) + "(" + to_string(pun.f) + ")").c_str());
140 break;
141 }
142 case ByteCodeInstruction::kReadExternal: printf("readexternal %d", READ8()); break;
143 case ByteCodeInstruction::kReadExternal2: printf("readexternal2 %d", READ8()); break;
144 case ByteCodeInstruction::kReadExternal3: printf("readexternal3 %d", READ8()); break;
145 case ByteCodeInstruction::kReadExternal4: printf("readexternal4 %d", READ8()); break;
146 VECTOR_DISASSEMBLE(kRemainderF, "remainderf")
147 VECTOR_DISASSEMBLE(kRemainderS, "remainders")
148 VECTOR_DISASSEMBLE(kRemainderU, "remainderu")
Brian Osmand3494ed2019-06-20 15:41:34 -0400149 case ByteCodeInstruction::kReserve: printf("reserve %d", READ8()); break;
Brian Osman3e833e12019-05-23 13:23:24 -0700150 case ByteCodeInstruction::kReturn: printf("return %d", READ8()); break;
Brian Osman29e013d2019-05-28 17:16:03 -0400151 case ByteCodeInstruction::kScalarToMatrix: {
152 int cols = READ8();
153 int rows = READ8();
154 printf("scalartomatrix %dx%d", cols, rows);
155 break;
156 }
Brian Osman3e833e12019-05-23 13:23:24 -0700157 VECTOR_DISASSEMBLE(kSin, "sin")
158 VECTOR_DISASSEMBLE(kSqrt, "sqrt")
159 case ByteCodeInstruction::kStore: printf("store %d", READ8()); break;
160 case ByteCodeInstruction::kStore2: printf("store2 %d", READ8()); break;
161 case ByteCodeInstruction::kStore3: printf("store3 %d", READ8()); break;
162 case ByteCodeInstruction::kStore4: printf("store4 %d", READ8()); break;
163 case ByteCodeInstruction::kStoreGlobal: printf("storeglobal %d", READ8()); break;
164 case ByteCodeInstruction::kStoreGlobal2: printf("storeglobal2 %d", READ8()); break;
165 case ByteCodeInstruction::kStoreGlobal3: printf("storeglobal3 %d", READ8()); break;
166 case ByteCodeInstruction::kStoreGlobal4: printf("storeglobal4 %d", READ8()); break;
167 case ByteCodeInstruction::kStoreSwizzle: {
168 int target = READ8();
169 int count = READ8();
170 printf("storeswizzle %d %d", target, count);
171 for (int i = 0; i < count; ++i) {
172 printf(", %d", READ8());
173 }
174 break;
175 }
176 case ByteCodeInstruction::kStoreSwizzleGlobal: {
177 int target = READ8();
178 int count = READ8();
179 printf("storeswizzleglobal %d %d", target, count);
180 for (int i = 0; i < count; ++i) {
181 printf(", %d", READ8());
182 }
183 break;
184 }
185 case ByteCodeInstruction::kStoreSwizzleIndirect: {
186 int count = READ8();
187 printf("storeswizzleindirect %d", count);
188 for (int i = 0; i < count; ++i) {
189 printf(", %d", READ8());
190 }
191 break;
192 }
193 case ByteCodeInstruction::kStoreSwizzleIndirectGlobal: {
194 int count = READ8();
195 printf("storeswizzleindirectglobal %d", count);
196 for (int i = 0; i < count; ++i) {
197 printf(", %d", READ8());
198 }
199 break;
200 }
201 case ByteCodeInstruction::kStoreExtended: printf("storeextended %d", READ8()); break;
202 case ByteCodeInstruction::kStoreExtendedGlobal: printf("storeextendedglobal %d", READ8());
203 break;
Brian Osman1e855b22019-05-29 15:21:52 -0400204 VECTOR_MATRIX_DISASSEMBLE(kSubtractF, "subtractf")
Brian Osman3e833e12019-05-23 13:23:24 -0700205 VECTOR_DISASSEMBLE(kSubtractI, "subtracti")
206 case ByteCodeInstruction::kSwizzle: {
207 printf("swizzle %d, ", READ8());
208 int count = READ8();
209 printf("%d", count);
210 for (int i = 0; i < count; ++i) {
211 printf(", %d", READ8());
212 }
213 break;
214 }
215 VECTOR_DISASSEMBLE(kTan, "tan")
216 case ByteCodeInstruction::kWriteExternal: printf("writeexternal %d", READ8()); break;
217 case ByteCodeInstruction::kWriteExternal2: printf("writeexternal2 %d", READ8()); break;
218 case ByteCodeInstruction::kWriteExternal3: printf("writeexternal3 %d", READ8()); break;
219 case ByteCodeInstruction::kWriteExternal4: printf("writeexternal4 %d", READ8()); break;
Brian Osman569f12f2019-06-13 11:23:57 -0400220 case ByteCodeInstruction::kXorB: printf("xorb"); break;
221 case ByteCodeInstruction::kMaskPush: printf("maskpush"); break;
222 case ByteCodeInstruction::kMaskPop: printf("maskpop"); break;
223 case ByteCodeInstruction::kMaskNegate: printf("masknegate"); break;
224 case ByteCodeInstruction::kMaskBlend: printf("maskblend %d", READ8()); break;
225 case ByteCodeInstruction::kBranchIfAllFalse:
226 printf("branchifallfalse %d", READ16());
227 break;
228 case ByteCodeInstruction::kLoopBegin: printf("loopbegin"); break;
229 case ByteCodeInstruction::kLoopNext: printf("loopnext"); break;
230 case ByteCodeInstruction::kLoopMask: printf("loopmask"); break;
231 case ByteCodeInstruction::kLoopEnd: printf("loopend"); break;
232 case ByteCodeInstruction::kLoopContinue: printf("loopcontinue"); break;
233 case ByteCodeInstruction::kLoopBreak: printf("loopbreak"); break;
Brian Osman3e833e12019-05-23 13:23:24 -0700234 default: printf("unknown(%d)\n", *(ip - 1)); SkASSERT(false);
235 }
236 return ip;
237}
238
Mike Klein459aed12019-05-21 15:46:36 -0500239#define VECTOR_BINARY_OP(base, field, op) \
Mike Kleine7007382019-05-21 08:36:32 -0500240 case ByteCodeInstruction::base ## 4: \
Mike Klein459aed12019-05-21 15:46:36 -0500241 sp[-4] = sp[-4].field op sp[0].field; \
Mike Kleine7007382019-05-21 08:36:32 -0500242 POP(); \
243 /* fall through */ \
244 case ByteCodeInstruction::base ## 3: { \
245 int count = (int) ByteCodeInstruction::base - (int) inst - 1; \
Mike Klein459aed12019-05-21 15:46:36 -0500246 sp[count] = sp[count].field op sp[0].field; \
Mike Kleine7007382019-05-21 08:36:32 -0500247 POP(); \
248 } /* fall through */ \
249 case ByteCodeInstruction::base ## 2: { \
250 int count = (int) ByteCodeInstruction::base - (int) inst - 1; \
Mike Klein459aed12019-05-21 15:46:36 -0500251 sp[count] = sp[count].field op sp[0].field; \
Mike Kleine7007382019-05-21 08:36:32 -0500252 POP(); \
253 } /* fall through */ \
254 case ByteCodeInstruction::base: { \
255 int count = (int) ByteCodeInstruction::base - (int) inst - 1; \
Mike Klein459aed12019-05-21 15:46:36 -0500256 sp[count] = sp[count].field op sp[0].field; \
Mike Kleine7007382019-05-21 08:36:32 -0500257 POP(); \
258 break; \
259 }
Ethan Nicholasaeb71ce2019-05-20 09:55:44 -0400260
Brian Osman1e855b22019-05-29 15:21:52 -0400261#define VECTOR_MATRIX_BINARY_OP(base, field, op) \
262 VECTOR_BINARY_OP(base, field, op) \
263 case ByteCodeInstruction::base ## N: { \
264 int count = READ8(); \
265 for (int i = count; i > 0; --i) { \
266 sp[-count] = sp[-count].field op sp[0].field; \
267 POP(); \
268 } \
269 break; \
270 }
271
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400272#define VECTOR_BINARY_FN(base, field, fn) \
273 case ByteCodeInstruction::base ## 4: \
274 sp[-4] = fn(sp[-4].field, sp[0].field); \
275 POP(); \
276 /* fall through */ \
277 case ByteCodeInstruction::base ## 3: { \
278 int target = (int) ByteCodeInstruction::base - (int) inst - 1; \
279 sp[target] = fn(sp[target].field, sp[0].field); \
280 POP(); \
281 } /* fall through */ \
282 case ByteCodeInstruction::base ## 2: { \
283 int target = (int) ByteCodeInstruction::base - (int) inst - 1; \
284 sp[target] = fn(sp[target].field, sp[0].field); \
285 POP(); \
286 } /* fall through */ \
287 case ByteCodeInstruction::base: { \
288 int target = (int) ByteCodeInstruction::base - (int) inst - 1; \
289 sp[target] = fn(sp[target].field, sp[0].field); \
290 POP(); \
291 break; \
Mike Kleine7007382019-05-21 08:36:32 -0500292 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400293
Mike Klein459aed12019-05-21 15:46:36 -0500294#define VECTOR_UNARY_FN(base, fn, field) \
295 case ByteCodeInstruction::base ## 4: sp[-3] = fn(sp[-3].field); \
296 case ByteCodeInstruction::base ## 3: sp[-2] = fn(sp[-2].field); \
297 case ByteCodeInstruction::base ## 2: sp[-1] = fn(sp[-1].field); \
298 case ByteCodeInstruction::base: sp[ 0] = fn(sp[ 0].field); \
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400299 break;
300
Brian Osman569f12f2019-06-13 11:23:57 -0400301#define VECTOR_UNARY_FN_VEC(base, fn) \
302 case ByteCodeInstruction::base ## 4: \
303 case ByteCodeInstruction::base ## 3: \
304 case ByteCodeInstruction::base ## 2: \
305 case ByteCodeInstruction::base : { \
306 int count = (int)inst - (int)ByteCodeInstruction::base + 1; \
307 float* v = (float*)sp - count + 1; \
308 for (int i = VecWidth * count; i > 0; --i, ++v) { \
309 *v = fn(*v); \
310 } \
311 break; \
312 }
313
314union VValue {
315 VValue() {}
316
317 VValue(F32 f)
318 : fFloat(f) {
319 }
320
321 VValue(I32 s)
322 : fSigned(s) {
323 }
324
325 VValue(U32 u)
326 : fUnsigned(u) {
327 }
328
329 F32 fFloat;
330 I32 fSigned;
331 U32 fUnsigned;
332};
333
Brian Osman226668a2019-05-14 16:47:30 -0400334struct StackFrame {
335 const uint8_t* fCode;
336 const uint8_t* fIP;
Brian Osman569f12f2019-06-13 11:23:57 -0400337 VValue* fStack;
Brian Osmand3494ed2019-06-20 15:41:34 -0400338 int fParameterCount;
Brian Osman226668a2019-05-14 16:47:30 -0400339};
340
Brian Osman569f12f2019-06-13 11:23:57 -0400341static F32 mix(F32 start, F32 end, F32 t) {
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400342 return start * (1 - t) + end * t;
343}
344
Brian Osman569f12f2019-06-13 11:23:57 -0400345// TODO: trunc on integers?
346template <typename T>
347static T vec_mod(T a, T b) {
348 return a - skvx::trunc(a / b) * b;
349}
Mike Kleine7007382019-05-21 08:36:32 -0500350
Brian Osman4b202a32019-06-21 09:50:29 -0400351static void innerRun(const ByteCode* byteCode, const ByteCodeFunction* f, VValue* stack,
352 float* outReturn[], VValue globals[], bool stripedOutput, int N) {
353 // Needs to be the first N non-negative integers, at least as large as VecWidth
354 static const Interpreter::I32 gLanes = {
355 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
356 };
357
Brian Osman569f12f2019-06-13 11:23:57 -0400358 VValue* sp = stack + f->fParameterCount + f->fLocalCount - 1;
359
360 auto POP = [&] { SkASSERT(sp >= stack); return *(sp--); };
361 auto PUSH = [&](VValue v) { SkASSERT(sp + 1 >= stack); *(++sp) = v; };
Mike Kleine7007382019-05-21 08:36:32 -0500362
Brian Osman80164412019-06-07 13:00:23 -0400363 const uint8_t* code = f->fCode.data();
Ethan Nicholasdfcad062019-05-07 12:53:34 -0400364 const uint8_t* ip = code;
Brian Osman226668a2019-05-14 16:47:30 -0400365 std::vector<StackFrame> frames;
366
Brian Osman569f12f2019-06-13 11:23:57 -0400367 I32 condStack[16]; // Independent condition masks
368 I32 maskStack[16]; // Combined masks (eg maskStack[0] & maskStack[1] & ...)
369 I32 contStack[16]; // Continue flags for loops
370 I32 loopStack[16]; // Loop execution masks
Brian Osman4b202a32019-06-21 09:50:29 -0400371 condStack[0] = maskStack[0] = (gLanes < N);
Brian Osman569f12f2019-06-13 11:23:57 -0400372 contStack[0] = I32( 0);
373 loopStack[0] = I32(~0);
374 I32* condPtr = condStack;
375 I32* maskPtr = maskStack;
376 I32* contPtr = contStack;
377 I32* loopPtr = loopStack;
378
379 auto mask = [&]() { return *maskPtr & *loopPtr; };
380
Ethan Nicholas7e603db2019-05-03 12:57:47 -0400381 for (;;) {
Ethan Nicholasdfcad062019-05-07 12:53:34 -0400382#ifdef TRACE
Brian Osman3e833e12019-05-23 13:23:24 -0700383 printf("at %3d ", (int) (ip - code));
384 disassemble_instruction(ip);
385 printf("\n");
Ethan Nicholasdfcad062019-05-07 12:53:34 -0400386#endif
Brian Osmane85b6a52019-05-22 14:50:59 -0700387 ByteCodeInstruction inst = (ByteCodeInstruction) READ16();
Ethan Nicholas9764ebd2019-05-01 14:43:54 -0400388 switch (inst) {
Mike Kleinc1999982019-05-21 13:03:49 -0500389 VECTOR_BINARY_OP(kAddI, fSigned, +)
Brian Osman1e855b22019-05-29 15:21:52 -0400390 VECTOR_MATRIX_BINARY_OP(kAddF, fFloat, +)
Brian Osman569f12f2019-06-13 11:23:57 -0400391
392 // Booleans are integer masks: 0/~0 for false/true. So bitwise ops do what we want:
Brian Osman32c526b2019-06-03 16:13:52 -0400393 case ByteCodeInstruction::kAndB:
Brian Osman569f12f2019-06-13 11:23:57 -0400394 sp[-1] = sp[-1].fSigned & sp[0].fSigned;
395 POP();
396 break;
397 case ByteCodeInstruction::kNotB:
398 sp[0] = ~sp[0].fSigned;
399 break;
400 case ByteCodeInstruction::kOrB:
401 sp[-1] = sp[-1].fSigned | sp[0].fSigned;
402 POP();
403 break;
404 case ByteCodeInstruction::kXorB:
405 sp[-1] = sp[-1].fSigned ^ sp[0].fSigned;
Brian Osman32c526b2019-06-03 16:13:52 -0400406 POP();
407 break;
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400408
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400409 case ByteCodeInstruction::kBranch:
Ethan Nicholasdfcad062019-05-07 12:53:34 -0400410 ip = code + READ16();
Ethan Nicholas9764ebd2019-05-01 14:43:54 -0400411 break;
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400412
Brian Osman226668a2019-05-14 16:47:30 -0400413 case ByteCodeInstruction::kCall: {
Brian Osmand3494ed2019-06-20 15:41:34 -0400414 // Precursor code reserved space for the return value, and pushed all parameters to
415 // the stack. Update our bottom of stack to point at the first parameter, and our
416 // sp to point past those parameters (plus space for locals).
Mike Kleine7007382019-05-21 08:36:32 -0500417 int target = READ8();
Brian Osman80164412019-06-07 13:00:23 -0400418 const ByteCodeFunction* fun = byteCode->fFunctions[target].get();
Brian Osman569f12f2019-06-13 11:23:57 -0400419 if (skvx::any(mask())) {
Brian Osmand3494ed2019-06-20 15:41:34 -0400420 frames.push_back({ code, ip, stack, fun->fParameterCount });
Brian Osman569f12f2019-06-13 11:23:57 -0400421 ip = code = fun->fCode.data();
422 stack = sp - fun->fParameterCount + 1;
423 sp = stack + fun->fParameterCount + fun->fLocalCount - 1;
Brian Osman569f12f2019-06-13 11:23:57 -0400424 }
Brian Osman226668a2019-05-14 16:47:30 -0400425 break;
426 }
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400427
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400428 case ByteCodeInstruction::kCallExternal: {
429 int argumentCount = READ8();
430 int returnCount = READ8();
Mike Kleine7007382019-05-21 08:36:32 -0500431 int target = READ8();
Brian Osman80164412019-06-07 13:00:23 -0400432 ExternalValue* v = byteCode->fExternalValues[target];
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400433 sp -= argumentCount - 1;
Mike Kleine7007382019-05-21 08:36:32 -0500434
Brian Osman08a84962019-06-14 10:17:16 -0400435 int32_t tmpArgs[4];
436 int32_t tmpReturn[4];
Brian Osman569f12f2019-06-13 11:23:57 -0400437 SkASSERT(argumentCount <= (int)SK_ARRAY_COUNT(tmpArgs));
438 SkASSERT(returnCount <= (int)SK_ARRAY_COUNT(tmpReturn));
439
440 I32 m = mask();
441 for (int i = 0; i < VecWidth; ++i) {
442 if (m[i]) {
443 for (int j = 0; j < argumentCount; ++j) {
Brian Osman08a84962019-06-14 10:17:16 -0400444 tmpArgs[j] = sp[j].fSigned[i];
Brian Osman569f12f2019-06-13 11:23:57 -0400445 }
446 v->call(tmpArgs, tmpReturn);
447 for (int j = 0; j < returnCount; ++j) {
Brian Osman08a84962019-06-14 10:17:16 -0400448 sp[j].fSigned[i] = tmpReturn[j];
Brian Osman569f12f2019-06-13 11:23:57 -0400449 }
450 }
451 }
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400452 sp += returnCount - 1;
453 break;
454 }
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400455
Mike Kleinc1999982019-05-21 13:03:49 -0500456 VECTOR_BINARY_OP(kCompareIEQ, fSigned, ==)
Brian Osman1e855b22019-05-29 15:21:52 -0400457 VECTOR_MATRIX_BINARY_OP(kCompareFEQ, fFloat, ==)
Mike Kleinc1999982019-05-21 13:03:49 -0500458 VECTOR_BINARY_OP(kCompareINEQ, fSigned, !=)
Brian Osman1e855b22019-05-29 15:21:52 -0400459 VECTOR_MATRIX_BINARY_OP(kCompareFNEQ, fFloat, !=)
Mike Kleinc1999982019-05-21 13:03:49 -0500460 VECTOR_BINARY_OP(kCompareSGT, fSigned, >)
461 VECTOR_BINARY_OP(kCompareUGT, fUnsigned, >)
462 VECTOR_BINARY_OP(kCompareFGT, fFloat, >)
463 VECTOR_BINARY_OP(kCompareSGTEQ, fSigned, >=)
464 VECTOR_BINARY_OP(kCompareUGTEQ, fUnsigned, >=)
465 VECTOR_BINARY_OP(kCompareFGTEQ, fFloat, >=)
466 VECTOR_BINARY_OP(kCompareSLT, fSigned, <)
467 VECTOR_BINARY_OP(kCompareULT, fUnsigned, <)
468 VECTOR_BINARY_OP(kCompareFLT, fFloat, <)
469 VECTOR_BINARY_OP(kCompareSLTEQ, fSigned, <=)
470 VECTOR_BINARY_OP(kCompareULTEQ, fUnsigned, <=)
471 VECTOR_BINARY_OP(kCompareFLTEQ, fFloat, <=)
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400472
Brian Osman569f12f2019-06-13 11:23:57 -0400473 case ByteCodeInstruction::kConvertFtoI4: sp[-3] = skvx::cast<int>(sp[-3].fFloat);
474 case ByteCodeInstruction::kConvertFtoI3: sp[-2] = skvx::cast<int>(sp[-2].fFloat);
475 case ByteCodeInstruction::kConvertFtoI2: sp[-1] = skvx::cast<int>(sp[-1].fFloat);
476 case ByteCodeInstruction::kConvertFtoI: sp[ 0] = skvx::cast<int>(sp[ 0].fFloat);
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400477 break;
478
Brian Osman569f12f2019-06-13 11:23:57 -0400479 case ByteCodeInstruction::kConvertStoF4: sp[-3] = skvx::cast<float>(sp[-3].fSigned);
480 case ByteCodeInstruction::kConvertStoF3: sp[-2] = skvx::cast<float>(sp[-2].fSigned);
481 case ByteCodeInstruction::kConvertStoF2: sp[-1] = skvx::cast<float>(sp[-1].fSigned);
482 case ByteCodeInstruction::kConvertStoF : sp[ 0] = skvx::cast<float>(sp[ 0].fSigned);
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400483 break;
484
Brian Osman569f12f2019-06-13 11:23:57 -0400485 case ByteCodeInstruction::kConvertUtoF4: sp[-3] = skvx::cast<float>(sp[-3].fUnsigned);
486 case ByteCodeInstruction::kConvertUtoF3: sp[-2] = skvx::cast<float>(sp[-2].fUnsigned);
487 case ByteCodeInstruction::kConvertUtoF2: sp[-1] = skvx::cast<float>(sp[-1].fUnsigned);
488 case ByteCodeInstruction::kConvertUtoF : sp[ 0] = skvx::cast<float>(sp[ 0].fUnsigned);
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400489 break;
490
Brian Osman569f12f2019-06-13 11:23:57 -0400491 VECTOR_UNARY_FN_VEC(kCos, cosf)
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400492
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400493 case ByteCodeInstruction::kCross: {
Brian Osman569f12f2019-06-13 11:23:57 -0400494 F32 ax = sp[-5].fFloat, ay = sp[-4].fFloat, az = sp[-3].fFloat,
495 bx = sp[-2].fFloat, by = sp[-1].fFloat, bz = sp[ 0].fFloat;
496 F32 cx = ay*bz - az*by,
497 cy = az*bx - ax*bz,
498 cz = ax*by - ay*bx;
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400499 sp -= 3;
Brian Osman569f12f2019-06-13 11:23:57 -0400500 sp[-2] = cx;
501 sp[-1] = cy;
502 sp[ 0] = cz;
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400503 break;
504 }
505
Mike Kleinc1999982019-05-21 13:03:49 -0500506 VECTOR_BINARY_OP(kDivideS, fSigned, /)
507 VECTOR_BINARY_OP(kDivideU, fUnsigned, /)
Brian Osman1e855b22019-05-29 15:21:52 -0400508 VECTOR_MATRIX_BINARY_OP(kDivideF, fFloat, /)
Mike Kleine7007382019-05-21 08:36:32 -0500509
510 case ByteCodeInstruction::kDup4: PUSH(sp[(int)ByteCodeInstruction::kDup - (int)inst]);
511 case ByteCodeInstruction::kDup3: PUSH(sp[(int)ByteCodeInstruction::kDup - (int)inst]);
512 case ByteCodeInstruction::kDup2: PUSH(sp[(int)ByteCodeInstruction::kDup - (int)inst]);
513 case ByteCodeInstruction::kDup : PUSH(sp[(int)ByteCodeInstruction::kDup - (int)inst]);
514 break;
515
Brian Osman07c117b2019-05-23 12:51:06 -0700516 case ByteCodeInstruction::kDupN: {
517 int count = READ8();
Brian Osman569f12f2019-06-13 11:23:57 -0400518 memcpy(sp + 1, sp - count + 1, count * sizeof(VValue));
Brian Osman07c117b2019-05-23 12:51:06 -0700519 sp += count;
520 break;
521 }
522
Mike Kleine7007382019-05-21 08:36:32 -0500523 case ByteCodeInstruction::kLoad4: sp[4] = stack[*ip + 3];
524 case ByteCodeInstruction::kLoad3: sp[3] = stack[*ip + 2];
525 case ByteCodeInstruction::kLoad2: sp[2] = stack[*ip + 1];
526 case ByteCodeInstruction::kLoad : sp[1] = stack[*ip + 0];
527 ++ip;
528 sp += (int)inst - (int)ByteCodeInstruction::kLoad + 1;
529 break;
530
Brian Osman80164412019-06-07 13:00:23 -0400531 case ByteCodeInstruction::kLoadGlobal4: sp[4] = globals[*ip + 3];
532 case ByteCodeInstruction::kLoadGlobal3: sp[3] = globals[*ip + 2];
533 case ByteCodeInstruction::kLoadGlobal2: sp[2] = globals[*ip + 1];
534 case ByteCodeInstruction::kLoadGlobal : sp[1] = globals[*ip + 0];
Mike Kleine7007382019-05-21 08:36:32 -0500535 ++ip;
Brian Osman07c117b2019-05-23 12:51:06 -0700536 sp += (int)inst -
537 (int)ByteCodeInstruction::kLoadGlobal + 1;
Mike Kleine7007382019-05-21 08:36:32 -0500538 break;
539
Brian Osman07c117b2019-05-23 12:51:06 -0700540 case ByteCodeInstruction::kLoadExtended: {
541 int count = READ8();
Brian Osman569f12f2019-06-13 11:23:57 -0400542 I32 src = POP().fSigned;
543 I32 m = mask();
544 for (int i = 0; i < count; ++i) {
545 for (int j = 0; j < VecWidth; ++j) {
546 if (m[j]) {
547 sp[i + 1].fSigned[j] = stack[src[j] + i].fSigned[j];
548 }
549 }
550 }
Brian Osman07c117b2019-05-23 12:51:06 -0700551 sp += count;
552 break;
553 }
554
555 case ByteCodeInstruction::kLoadExtendedGlobal: {
556 int count = READ8();
Brian Osman569f12f2019-06-13 11:23:57 -0400557 I32 src = POP().fSigned;
558 I32 m = mask();
559 for (int i = 0; i < count; ++i) {
560 for (int j = 0; j < VecWidth; ++j) {
561 if (m[j]) {
562 sp[i + 1].fSigned[j] = globals[src[j] + i].fSigned[j];
563 }
564 }
565 }
Brian Osman07c117b2019-05-23 12:51:06 -0700566 sp += count;
567 break;
568 }
569
Mike Kleine7007382019-05-21 08:36:32 -0500570 case ByteCodeInstruction::kLoadSwizzle: {
571 int src = READ8();
572 int count = READ8();
Ethan Nicholas9764ebd2019-05-01 14:43:54 -0400573 for (int i = 0; i < count; ++i) {
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400574 PUSH(stack[src + *(ip + i)]);
Ethan Nicholas9764ebd2019-05-01 14:43:54 -0400575 }
Ethan Nicholas7e603db2019-05-03 12:57:47 -0400576 ip += count;
Ethan Nicholas9764ebd2019-05-01 14:43:54 -0400577 break;
Mike Kleine7007382019-05-21 08:36:32 -0500578 }
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400579
Mike Kleine7007382019-05-21 08:36:32 -0500580 case ByteCodeInstruction::kLoadSwizzleGlobal: {
581 int src = READ8();
Mike Kleine7007382019-05-21 08:36:32 -0500582 int count = READ8();
Brian Osmanb7451292019-05-15 13:02:13 -0400583 for (int i = 0; i < count; ++i) {
Brian Osman80164412019-06-07 13:00:23 -0400584 PUSH(globals[src + *(ip + i)]);
Brian Osmanb7451292019-05-15 13:02:13 -0400585 }
586 ip += count;
587 break;
Mike Kleine7007382019-05-21 08:36:32 -0500588 }
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400589
Brian Osman29e013d2019-05-28 17:16:03 -0400590 case ByteCodeInstruction::kMatrixToMatrix: {
591 int srcCols = READ8();
592 int srcRows = READ8();
593 int dstCols = READ8();
594 int dstRows = READ8();
595 SkASSERT(srcCols >= 2 && srcCols <= 4);
596 SkASSERT(srcRows >= 2 && srcRows <= 4);
597 SkASSERT(dstCols >= 2 && dstCols <= 4);
598 SkASSERT(dstRows >= 2 && dstRows <= 4);
Brian Osman569f12f2019-06-13 11:23:57 -0400599 F32 tmp[16];
600 memset(tmp, 0, sizeof(tmp));
601 tmp[0] = tmp[5] = tmp[10] = tmp[15] = F32(1.0f);
Brian Osman29e013d2019-05-28 17:16:03 -0400602 for (int c = srcCols - 1; c >= 0; --c) {
603 for (int r = srcRows - 1; r >= 0; --r) {
Brian Osman569f12f2019-06-13 11:23:57 -0400604 tmp[c*4 + r] = POP().fFloat;
Brian Osman29e013d2019-05-28 17:16:03 -0400605 }
606 }
607 for (int c = 0; c < dstCols; ++c) {
608 for (int r = 0; r < dstRows; ++r) {
Brian Osman569f12f2019-06-13 11:23:57 -0400609 PUSH(tmp[c*4 + r]);
Brian Osman29e013d2019-05-28 17:16:03 -0400610 }
611 }
612 break;
613 }
614
Brian Osman909231c2019-05-29 15:34:36 -0400615 case ByteCodeInstruction::kMatrixMultiply: {
616 int lCols = READ8();
617 int lRows = READ8();
618 int rCols = READ8();
619 int rRows = lCols;
Brian Osman569f12f2019-06-13 11:23:57 -0400620 F32 tmp[16] = { 0.0f };
621 F32* B = &(sp - (rCols * rRows) + 1)->fFloat;
622 F32* A = B - (lCols * lRows);
Brian Osman909231c2019-05-29 15:34:36 -0400623 for (int c = 0; c < rCols; ++c) {
624 for (int r = 0; r < lRows; ++r) {
625 for (int j = 0; j < lCols; ++j) {
626 tmp[c*lRows + r] += A[j*lRows + r] * B[c*rRows + j];
627 }
628 }
629 }
630 sp -= (lCols * lRows) + (rCols * rRows);
Brian Osman569f12f2019-06-13 11:23:57 -0400631 memcpy(sp + 1, tmp, rCols * lRows * sizeof(VValue));
Brian Osman909231c2019-05-29 15:34:36 -0400632 sp += (rCols * lRows);
633 break;
634 }
635
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400636 // stack looks like: X1 Y1 Z1 W1 X2 Y2 Z2 W2 T
637 case ByteCodeInstruction::kMix4:
638 sp[-5] = mix(sp[-5].fFloat, sp[-1].fFloat, sp[0].fFloat);
639 // fall through
640 case ByteCodeInstruction::kMix3: {
641 int count = (int) inst - (int) ByteCodeInstruction::kMix + 1;
642 int target = 2 - count * 2;
643 sp[target] = mix(sp[target].fFloat, sp[2 - count].fFloat, sp[0].fFloat);
644 // fall through
645 }
646 case ByteCodeInstruction::kMix2: {
647 int count = (int) inst - (int) ByteCodeInstruction::kMix + 1;
648 int target = 1 - count * 2;
649 sp[target] = mix(sp[target].fFloat, sp[1 - count].fFloat, sp[0].fFloat);
650 // fall through
651 }
652 case ByteCodeInstruction::kMix: {
653 int count = (int) inst - (int) ByteCodeInstruction::kMix + 1;
654 int target = -count * 2;
655 sp[target] = mix(sp[target].fFloat, sp[-count].fFloat, sp[0].fFloat);
656 sp -= 1 + count;
657 break;
658 }
659
Mike Kleinc1999982019-05-21 13:03:49 -0500660 VECTOR_BINARY_OP(kMultiplyI, fSigned, *)
Brian Osman1e855b22019-05-29 15:21:52 -0400661 VECTOR_MATRIX_BINARY_OP(kMultiplyF, fFloat, *)
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400662
Mike Kleinc1999982019-05-21 13:03:49 -0500663 case ByteCodeInstruction::kNegateF4: sp[-3] = -sp[-3].fFloat;
664 case ByteCodeInstruction::kNegateF3: sp[-2] = -sp[-2].fFloat;
665 case ByteCodeInstruction::kNegateF2: sp[-1] = -sp[-1].fFloat;
666 case ByteCodeInstruction::kNegateF : sp[ 0] = -sp[ 0].fFloat;
Mike Kleine7007382019-05-21 08:36:32 -0500667 break;
668
Brian Osman1e855b22019-05-29 15:21:52 -0400669 case ByteCodeInstruction::kNegateFN: {
670 int count = READ8();
671 for (int i = count - 1; i >= 0; --i) {
672 sp[-i] = -sp[-i].fFloat;
673 }
674 break;
675 }
676
Mike Kleinc1999982019-05-21 13:03:49 -0500677 case ByteCodeInstruction::kNegateI4: sp[-3] = -sp[-3].fSigned;
678 case ByteCodeInstruction::kNegateI3: sp[-2] = -sp[-2].fSigned;
679 case ByteCodeInstruction::kNegateI2: sp[-1] = -sp[-1].fSigned;
Brian Osman569f12f2019-06-13 11:23:57 -0400680 case ByteCodeInstruction::kNegateI : sp[ 0] = -sp[ 0].fSigned;
Mike Kleine7007382019-05-21 08:36:32 -0500681 break;
682
683 case ByteCodeInstruction::kPop4: POP();
684 case ByteCodeInstruction::kPop3: POP();
685 case ByteCodeInstruction::kPop2: POP();
686 case ByteCodeInstruction::kPop : POP();
687 break;
688
Brian Osman07c117b2019-05-23 12:51:06 -0700689 case ByteCodeInstruction::kPopN:
690 sp -= READ8();
691 break;
692
Ethan Nicholas9764ebd2019-05-01 14:43:54 -0400693 case ByteCodeInstruction::kPushImmediate:
Brian Osman569f12f2019-06-13 11:23:57 -0400694 PUSH(U32(READ32()));
Ethan Nicholas9764ebd2019-05-01 14:43:54 -0400695 break;
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400696
Brian Osman569f12f2019-06-13 11:23:57 -0400697 case ByteCodeInstruction::kReadExternal:
698 case ByteCodeInstruction::kReadExternal2:
699 case ByteCodeInstruction::kReadExternal3:
Mike Kleine7007382019-05-21 08:36:32 -0500700 case ByteCodeInstruction::kReadExternal4: {
Brian Osman569f12f2019-06-13 11:23:57 -0400701 // TODO: Support striped external values, or passing lane index? This model is odd.
702 int count = (int)inst - (int)ByteCodeInstruction::kReadExternal + 1;
Mike Kleine7007382019-05-21 08:36:32 -0500703 int src = READ8();
Brian Osman569f12f2019-06-13 11:23:57 -0400704 int32_t tmp[4];
705 I32 m = mask();
706 for (int i = 0; i < VecWidth; ++i) {
707 if (m[i]) {
708 byteCode->fExternalValues[src]->read(tmp);
709 for (int j = 0; j < count; ++j) {
710 sp[j + 1].fSigned[i] = tmp[j];
711 }
712 }
713 }
714 sp += count;
Ethan Nicholas91164d12019-05-15 15:29:54 -0400715 break;
Mike Kleine7007382019-05-21 08:36:32 -0500716 }
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400717
Brian Osman569f12f2019-06-13 11:23:57 -0400718 VECTOR_BINARY_FN(kRemainderF, fFloat, vec_mod<F32>)
719 VECTOR_BINARY_FN(kRemainderS, fSigned, vec_mod<I32>)
720 VECTOR_BINARY_FN(kRemainderU, fUnsigned, vec_mod<U32>)
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400721
Brian Osmand3494ed2019-06-20 15:41:34 -0400722 case ByteCodeInstruction::kReserve:
723 sp += READ8();
724 break;
725
Mike Kleine7007382019-05-21 08:36:32 -0500726 case ByteCodeInstruction::kReturn: {
727 int count = READ8();
Brian Osman226668a2019-05-14 16:47:30 -0400728 if (frames.empty()) {
729 if (outReturn) {
Brian Osman569f12f2019-06-13 11:23:57 -0400730 VValue* src = sp - count + 1;
Mike Reed3fd3cc92019-06-20 12:40:30 -0400731 if (stripedOutput) {
732 for (int i = 0; i < count; ++i) {
Brian Osman4b202a32019-06-21 09:50:29 -0400733 memcpy(outReturn[i], &src->fFloat, N * sizeof(float));
734 ++src;
Brian Osman569f12f2019-06-13 11:23:57 -0400735 }
Mike Reed3fd3cc92019-06-20 12:40:30 -0400736 } else {
737 float* outPtr = outReturn[0];
738 for (int i = 0; i < count; ++i) {
Brian Osman4b202a32019-06-21 09:50:29 -0400739 for (int j = 0; j < N; ++j) {
740 outPtr[count * j] = src->fFloat[j];
Mike Reed3fd3cc92019-06-20 12:40:30 -0400741 }
742 ++outPtr;
743 ++src;
744 }
Brian Osman569f12f2019-06-13 11:23:57 -0400745 }
Brian Osman226668a2019-05-14 16:47:30 -0400746 }
747 return;
748 } else {
Brian Osmand3494ed2019-06-20 15:41:34 -0400749 // When we were called, the caller reserved stack space for their copy of our
750 // return value, then 'stack' was positioned after that, where our parameters
751 // were placed. Copy our return values to their reserved area.
752 memcpy(stack - count, sp - count + 1, count * sizeof(VValue));
Brian Osman226668a2019-05-14 16:47:30 -0400753
Brian Osmand3494ed2019-06-20 15:41:34 -0400754 // Now move the stack pointer to the end of the passed-in parameters. This odd
755 // calling convention requires the caller to pop the arguments after calling,
756 // but allows them to store any out-parameters back during that unwinding.
757 // After that sequence finishes, the return value will be the top of the stack.
Brian Osman226668a2019-05-14 16:47:30 -0400758 const StackFrame& frame(frames.back());
Brian Osmand3494ed2019-06-20 15:41:34 -0400759 sp = stack + frame.fParameterCount - 1;
Brian Osman226668a2019-05-14 16:47:30 -0400760 stack = frame.fStack;
761 code = frame.fCode;
762 ip = frame.fIP;
763 frames.pop_back();
764 break;
Ethan Nicholas9764ebd2019-05-01 14:43:54 -0400765 }
Mike Kleine7007382019-05-21 08:36:32 -0500766 }
767
Brian Osman29e013d2019-05-28 17:16:03 -0400768 case ByteCodeInstruction::kScalarToMatrix: {
769 int cols = READ8();
770 int rows = READ8();
Brian Osman569f12f2019-06-13 11:23:57 -0400771 VValue v = POP();
Brian Osman29e013d2019-05-28 17:16:03 -0400772 for (int c = 0; c < cols; ++c) {
773 for (int r = 0; r < rows; ++r) {
Brian Osman569f12f2019-06-13 11:23:57 -0400774 PUSH(c == r ? v : F32(0.0f));
Brian Osman29e013d2019-05-28 17:16:03 -0400775 }
776 }
777 break;
778 }
779
Brian Osman569f12f2019-06-13 11:23:57 -0400780 VECTOR_UNARY_FN_VEC(kSin, sinf)
781 VECTOR_UNARY_FN(kSqrt, skvx::sqrt, fFloat)
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400782
Brian Osman569f12f2019-06-13 11:23:57 -0400783 case ByteCodeInstruction::kStore4:
784 stack[*ip+3] = skvx::if_then_else(mask(), POP().fFloat, stack[*ip+3].fFloat);
785 case ByteCodeInstruction::kStore3:
786 stack[*ip+2] = skvx::if_then_else(mask(), POP().fFloat, stack[*ip+2].fFloat);
787 case ByteCodeInstruction::kStore2:
788 stack[*ip+1] = skvx::if_then_else(mask(), POP().fFloat, stack[*ip+1].fFloat);
789 case ByteCodeInstruction::kStore :
790 stack[*ip+0] = skvx::if_then_else(mask(), POP().fFloat, stack[*ip+0].fFloat);
791 ++ip;
792 break;
Mike Kleine7007382019-05-21 08:36:32 -0500793
Brian Osman569f12f2019-06-13 11:23:57 -0400794 case ByteCodeInstruction::kStoreGlobal4:
795 globals[*ip+3] = skvx::if_then_else(mask(), POP().fFloat, globals[*ip+3].fFloat);
796 case ByteCodeInstruction::kStoreGlobal3:
797 globals[*ip+2] = skvx::if_then_else(mask(), POP().fFloat, globals[*ip+2].fFloat);
798 case ByteCodeInstruction::kStoreGlobal2:
799 globals[*ip+1] = skvx::if_then_else(mask(), POP().fFloat, globals[*ip+1].fFloat);
800 case ByteCodeInstruction::kStoreGlobal :
801 globals[*ip+0] = skvx::if_then_else(mask(), POP().fFloat, globals[*ip+0].fFloat);
802 ++ip;
803 break;
Mike Kleine7007382019-05-21 08:36:32 -0500804
Brian Osman07c117b2019-05-23 12:51:06 -0700805 case ByteCodeInstruction::kStoreExtended: {
806 int count = READ8();
Brian Osman569f12f2019-06-13 11:23:57 -0400807 I32 target = POP().fSigned;
808 VValue* src = sp - count + 1;
809 I32 m = mask();
810 for (int i = 0; i < count; ++i) {
811 for (int j = 0; j < VecWidth; ++j) {
812 if (m[j]) {
813 stack[target[j] + i].fSigned[j] = src[i].fSigned[j];
814 }
815 }
816 }
Brian Osman07c117b2019-05-23 12:51:06 -0700817 sp -= count;
818 break;
819 }
820 case ByteCodeInstruction::kStoreExtendedGlobal: {
821 int count = READ8();
Brian Osman569f12f2019-06-13 11:23:57 -0400822 I32 target = POP().fSigned;
823 VValue* src = sp - count + 1;
824 I32 m = mask();
825 for (int i = 0; i < count; ++i) {
826 for (int j = 0; j < VecWidth; ++j) {
827 if (m[j]) {
828 globals[target[j] + i].fSigned[j] = src[i].fSigned[j];
829 }
830 }
831 }
Brian Osman07c117b2019-05-23 12:51:06 -0700832 sp -= count;
833 break;
834 }
835
Mike Kleine7007382019-05-21 08:36:32 -0500836 case ByteCodeInstruction::kStoreSwizzle: {
837 int target = READ8();
838 int count = READ8();
Ethan Nicholas9764ebd2019-05-01 14:43:54 -0400839 for (int i = count - 1; i >= 0; --i) {
Brian Osman569f12f2019-06-13 11:23:57 -0400840 stack[target + *(ip + i)] = skvx::if_then_else(
841 mask(), POP().fFloat, stack[target + *(ip + i)].fFloat);
Ethan Nicholas9764ebd2019-05-01 14:43:54 -0400842 }
Brian Osman1091f022019-05-16 09:42:16 -0400843 ip += count;
844 break;
Mike Kleine7007382019-05-21 08:36:32 -0500845 }
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400846
Mike Kleine7007382019-05-21 08:36:32 -0500847 case ByteCodeInstruction::kStoreSwizzleGlobal: {
848 int target = READ8();
849 int count = READ8();
Brian Osman1091f022019-05-16 09:42:16 -0400850 for (int i = count - 1; i >= 0; --i) {
Brian Osman569f12f2019-06-13 11:23:57 -0400851 globals[target + *(ip + i)] = skvx::if_then_else(
852 mask(), POP().fFloat, globals[target + *(ip + i)].fFloat);
Brian Osman1091f022019-05-16 09:42:16 -0400853 }
Ethan Nicholas7e603db2019-05-03 12:57:47 -0400854 ip += count;
Ethan Nicholas9764ebd2019-05-01 14:43:54 -0400855 break;
Mike Kleine7007382019-05-21 08:36:32 -0500856 }
Brian Osman569f12f2019-06-13 11:23:57 -0400857
Brian Osman07c117b2019-05-23 12:51:06 -0700858 case ByteCodeInstruction::kStoreSwizzleIndirect: {
Brian Osman07c117b2019-05-23 12:51:06 -0700859 int count = READ8();
Brian Osman569f12f2019-06-13 11:23:57 -0400860 I32 target = POP().fSigned;
861 I32 m = mask();
Brian Osman07c117b2019-05-23 12:51:06 -0700862 for (int i = count - 1; i >= 0; --i) {
Brian Osman569f12f2019-06-13 11:23:57 -0400863 I32 v = POP().fSigned;
864 for (int j = 0; j < VecWidth; ++j) {
865 if (m[j]) {
866 stack[target[j] + *(ip + i)].fSigned[j] = v[j];
867 }
868 }
Brian Osman07c117b2019-05-23 12:51:06 -0700869 }
870 ip += count;
871 break;
872 }
Brian Osman569f12f2019-06-13 11:23:57 -0400873
Brian Osman07c117b2019-05-23 12:51:06 -0700874 case ByteCodeInstruction::kStoreSwizzleIndirectGlobal: {
Brian Osman07c117b2019-05-23 12:51:06 -0700875 int count = READ8();
Brian Osman569f12f2019-06-13 11:23:57 -0400876 I32 target = POP().fSigned;
877 I32 m = mask();
Brian Osman07c117b2019-05-23 12:51:06 -0700878 for (int i = count - 1; i >= 0; --i) {
Brian Osman569f12f2019-06-13 11:23:57 -0400879 I32 v = POP().fSigned;
880 for (int j = 0; j < VecWidth; ++j) {
881 if (m[j]) {
882 globals[target[j] + *(ip + i)].fSigned[j] = v[j];
883 }
884 }
Brian Osman07c117b2019-05-23 12:51:06 -0700885 }
886 ip += count;
887 break;
888 }
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400889
Mike Kleinc1999982019-05-21 13:03:49 -0500890 VECTOR_BINARY_OP(kSubtractI, fSigned, -)
Brian Osman1e855b22019-05-29 15:21:52 -0400891 VECTOR_MATRIX_BINARY_OP(kSubtractF, fFloat, -)
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400892
Mike Kleine7007382019-05-21 08:36:32 -0500893 case ByteCodeInstruction::kSwizzle: {
Brian Osman569f12f2019-06-13 11:23:57 -0400894 VValue tmp[4];
Ethan Nicholas7e603db2019-05-03 12:57:47 -0400895 for (int i = READ8() - 1; i >= 0; --i) {
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400896 tmp[i] = POP();
Ethan Nicholas9764ebd2019-05-01 14:43:54 -0400897 }
Ethan Nicholas7e603db2019-05-03 12:57:47 -0400898 for (int i = READ8() - 1; i >= 0; --i) {
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400899 PUSH(tmp[READ8()]);
Ethan Nicholas9764ebd2019-05-01 14:43:54 -0400900 }
901 break;
Mike Kleine7007382019-05-21 08:36:32 -0500902 }
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400903
Brian Osman569f12f2019-06-13 11:23:57 -0400904 VECTOR_UNARY_FN_VEC(kTan, tanf)
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400905
Brian Osman569f12f2019-06-13 11:23:57 -0400906 case ByteCodeInstruction::kWriteExternal:
907 case ByteCodeInstruction::kWriteExternal2:
908 case ByteCodeInstruction::kWriteExternal3:
Mike Kleine7007382019-05-21 08:36:32 -0500909 case ByteCodeInstruction::kWriteExternal4: {
Brian Osman569f12f2019-06-13 11:23:57 -0400910 int count = (int)inst - (int)ByteCodeInstruction::kWriteExternal + 1;
Mike Kleine7007382019-05-21 08:36:32 -0500911 int target = READ8();
Brian Osman569f12f2019-06-13 11:23:57 -0400912 int32_t tmp[4];
913 I32 m = mask();
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400914 sp -= count;
Brian Osman569f12f2019-06-13 11:23:57 -0400915 for (int i = 0; i < VecWidth; ++i) {
916 if (m[i]) {
917 for (int j = 0; j < count; ++j) {
918 tmp[j] = sp[j + 1].fSigned[i];
919 }
920 byteCode->fExternalValues[target]->write(tmp);
921 }
922 }
923 break;
924 }
925
926 case ByteCodeInstruction::kMaskPush:
927 condPtr[1] = POP().fSigned;
928 maskPtr[1] = maskPtr[0] & condPtr[1];
929 ++condPtr; ++maskPtr;
930 break;
931 case ByteCodeInstruction::kMaskPop:
932 --condPtr; --maskPtr;
933 break;
934 case ByteCodeInstruction::kMaskNegate:
935 maskPtr[0] = maskPtr[-1] & ~condPtr[0];
936 break;
937 case ByteCodeInstruction::kMaskBlend: {
938 int count = READ8();
939 I32 m = condPtr[0];
940 --condPtr; --maskPtr;
941 for (int i = 0; i < count; ++i) {
942 sp[-count] = skvx::if_then_else(m, sp[-count].fFloat, sp[0].fFloat);
943 --sp;
944 }
945 break;
946 }
947 case ByteCodeInstruction::kBranchIfAllFalse: {
948 int target = READ16();
949 if (!skvx::any(mask())) {
950 ip = code + target;
951 }
952 break;
953 }
954
955 case ByteCodeInstruction::kLoopBegin:
Brian Osman8d564572019-06-19 11:00:28 -0400956 contPtr[1] = 0;
957 loopPtr[1] = loopPtr[0];
958 ++contPtr; ++loopPtr;
Brian Osman569f12f2019-06-13 11:23:57 -0400959 break;
960 case ByteCodeInstruction::kLoopNext:
961 *loopPtr |= *contPtr;
962 *contPtr = 0;
963 break;
964 case ByteCodeInstruction::kLoopMask:
965 *loopPtr &= POP().fSigned;
966 break;
967 case ByteCodeInstruction::kLoopEnd:
968 --contPtr; --loopPtr;
969 break;
970 case ByteCodeInstruction::kLoopBreak:
971 *loopPtr &= ~mask();
972 break;
973 case ByteCodeInstruction::kLoopContinue: {
974 I32 m = mask();
975 *contPtr |= m;
976 *loopPtr &= ~m;
Ethan Nicholas9764ebd2019-05-01 14:43:54 -0400977 break;
Mike Kleine7007382019-05-21 08:36:32 -0500978 }
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400979
Ethan Nicholas9764ebd2019-05-01 14:43:54 -0400980 default:
Mike Kleine7007382019-05-21 08:36:32 -0500981 SkDEBUGFAILF("unsupported instruction %d\n", (int) inst);
Ethan Nicholas9764ebd2019-05-01 14:43:54 -0400982 }
Brian Osman569f12f2019-06-13 11:23:57 -0400983 }
984}
985
Brian Osman08a84962019-06-14 10:17:16 -0400986} // namespace Interpreter
987
988void ByteCodeFunction::disassemble() const {
989 const uint8_t* ip = fCode.data();
990 while (ip < fCode.data() + fCode.size()) {
991 printf("%d: ", (int)(ip - fCode.data()));
992 ip = Interpreter::disassemble_instruction(ip);
993 printf("\n");
994 }
995}
996
997void ByteCode::run(const ByteCodeFunction* f, float* args, float* outReturn, int N,
998 const float* uniforms, int uniformCount) const {
Ethan Nicholas9764ebd2019-05-01 14:43:54 -0400999#ifdef TRACE
Brian Osman08a84962019-06-14 10:17:16 -04001000 f->disassemble();
Ethan Nicholas9764ebd2019-05-01 14:43:54 -04001001#endif
Brian Osman4b202a32019-06-21 09:50:29 -04001002 Interpreter::VValue stack[128];
Brian Osmanef787f72019-06-13 13:07:12 -04001003
Brian Osman08a84962019-06-14 10:17:16 -04001004 SkASSERT(uniformCount == (int)fInputSlots.size());
1005 Interpreter::VValue globals[32];
1006 SkASSERT((int)SK_ARRAY_COUNT(globals) >= fGlobalCount);
1007 for (uint8_t slot : fInputSlots) {
1008 globals[slot].fFloat = *uniforms++;
Brian Osman569f12f2019-06-13 11:23:57 -04001009 }
1010
1011 while (N) {
Brian Osman08a84962019-06-14 10:17:16 -04001012 int w = std::min(N, Interpreter::VecWidth);
Brian Osman569f12f2019-06-13 11:23:57 -04001013
1014 // Transpose args into stack
1015 {
Brian Osman08a84962019-06-14 10:17:16 -04001016 float* src = args;
Brian Osman569f12f2019-06-13 11:23:57 -04001017 for (int i = 0; i < w; ++i) {
Brian Osman08a84962019-06-14 10:17:16 -04001018 float* dst = (float*)stack + i;
Brian Osman569f12f2019-06-13 11:23:57 -04001019 for (int j = f->fParameterCount; j > 0; --j) {
1020 *dst = *src++;
Brian Osman08a84962019-06-14 10:17:16 -04001021 dst += Interpreter::VecWidth;
Brian Osman569f12f2019-06-13 11:23:57 -04001022 }
1023 }
1024 }
1025
Mike Reed3fd3cc92019-06-20 12:40:30 -04001026 bool stripedOutput = false;
1027 float** outArray = outReturn ? &outReturn : nullptr;
Brian Osman4b202a32019-06-21 09:50:29 -04001028 innerRun(this, f, stack, outArray, globals, stripedOutput, w);
Brian Osman569f12f2019-06-13 11:23:57 -04001029
1030 // Transpose out parameters back
1031 {
Brian Osman08a84962019-06-14 10:17:16 -04001032 float* dst = args;
Brian Osman569f12f2019-06-13 11:23:57 -04001033 for (int i = 0; i < w; ++i) {
Brian Osman08a84962019-06-14 10:17:16 -04001034 float* src = (float*)stack + i;
Brian Osman569f12f2019-06-13 11:23:57 -04001035 for (const auto& p : f->fParameters) {
1036 if (p.fIsOutParameter) {
1037 for (int j = p.fSlotCount; j > 0; --j) {
1038 *dst++ = *src;
Brian Osman08a84962019-06-14 10:17:16 -04001039 src += Interpreter::VecWidth;
Brian Osman569f12f2019-06-13 11:23:57 -04001040 }
1041 } else {
1042 dst += p.fSlotCount;
Brian Osman08a84962019-06-14 10:17:16 -04001043 src += p.fSlotCount * Interpreter::VecWidth;
Brian Osman569f12f2019-06-13 11:23:57 -04001044 }
1045 }
1046 }
1047 }
1048
1049 args += f->fParameterCount * w;
Mike Reed3fd3cc92019-06-20 12:40:30 -04001050 if (outReturn) {
1051 outReturn += f->fReturnCount * w;
1052 }
Brian Osman4b202a32019-06-21 09:50:29 -04001053 N -= w;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001054 }
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001055}
1056
Brian Osman2b1a5442019-06-19 11:40:33 -04001057void ByteCode::runStriped(const ByteCodeFunction* f, float* args[], int nargs, int N,
Mike Reed3fd3cc92019-06-20 12:40:30 -04001058 const float* uniforms, int uniformCount,
1059 float* outArgs[], int outCount) const {
Brian Osman2b1a5442019-06-19 11:40:33 -04001060#ifdef TRACE
Brian Osmanecb3bb52019-06-20 14:59:12 -04001061 f->disassemble();
Brian Osman2b1a5442019-06-19 11:40:33 -04001062#endif
1063 Interpreter::VValue stack[128];
1064
Mike Reed3fd3cc92019-06-20 12:40:30 -04001065 // innerRun just takes outArgs, so clear it if the count is zero
1066 if (outCount == 0) {
1067 outArgs = nullptr;
1068 }
1069
Brian Osman2b1a5442019-06-19 11:40:33 -04001070 SkASSERT(nargs == f->fParameterCount);
Mike Reed3fd3cc92019-06-20 12:40:30 -04001071 SkASSERT(outCount == f->fReturnCount);
Brian Osman2b1a5442019-06-19 11:40:33 -04001072 SkASSERT(uniformCount == (int)fInputSlots.size());
1073 Interpreter::VValue globals[32];
1074 SkASSERT((int)SK_ARRAY_COUNT(globals) >= fGlobalCount);
1075 for (uint8_t slot : fInputSlots) {
1076 globals[slot].fFloat = *uniforms++;
1077 }
1078
1079 while (N) {
1080 int w = std::min(N, Interpreter::VecWidth);
1081
1082 // Copy args into stack
1083 for (int i = 0; i < nargs; ++i) {
1084 memcpy(stack + i, args[i], w * sizeof(float));
1085 }
1086
Mike Reed3fd3cc92019-06-20 12:40:30 -04001087 bool stripedOutput = true;
Brian Osman4b202a32019-06-21 09:50:29 -04001088 innerRun(this, f, stack, outArgs, globals, stripedOutput, w);
Brian Osman2b1a5442019-06-19 11:40:33 -04001089
1090 // Copy out parameters back
1091 int slot = 0;
1092 for (const auto& p : f->fParameters) {
1093 if (p.fIsOutParameter) {
1094 for (int i = slot; i < slot + p.fSlotCount; ++i) {
1095 memcpy(args[i], stack + i, w * sizeof(float));
1096 }
1097 }
1098 slot += p.fSlotCount;
1099 }
1100
1101 // Step each argument pointer ahead
1102 for (int i = 0; i < nargs; ++i) {
1103 args[i] += w;
1104 }
1105 N -= w;
1106 }
1107}
1108
Brian Osman80164412019-06-07 13:00:23 -04001109} // namespace SkSL
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001110
1111#endif