blob: fa4f248fc35c6ab0418ea1efe08ffac0c4992d0e [file] [log] [blame]
Brian Osmanb380e712019-07-24 17:02:39 -04001/*
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04002 * Copyright 2019 Google LLC
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "src/sksl/SkSLByteCodeGenerator.h"
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04009
Brian Osman95253bd2019-06-05 10:28:45 -040010#include <algorithm>
11
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040012namespace SkSL {
13
Ethan Nicholas82162ee2019-05-21 16:05:08 -040014ByteCodeGenerator::ByteCodeGenerator(const Context* context, const Program* program, ErrorReporter* errors,
15 ByteCode* output)
16 : INHERITED(program, errors, nullptr)
17 , fContext(*context)
Ethan Nicholasae9633b2019-05-24 12:46:34 -040018 , fOutput(output)
19 , fIntrinsics {
Brian Osmanb380e712019-07-24 17:02:39 -040020 { "cos", ByteCodeInstruction::kCos },
21 { "cross", ByteCodeInstruction::kCross },
22 { "dot", SpecialIntrinsic::kDot },
23 { "inverse", ByteCodeInstruction::kInverse2x2 },
24 { "normalize", ByteCodeInstruction::kNormalize },
25 { "radians", SpecialIntrinsic::kRadians },
26 { "sin", ByteCodeInstruction::kSin },
27 { "sqrt", ByteCodeInstruction::kSqrt },
28 { "tan", ByteCodeInstruction::kTan },
29 { "mix", ByteCodeInstruction::kMix },
Ethan Nicholasae9633b2019-05-24 12:46:34 -040030 } {}
31
Ethan Nicholas82162ee2019-05-21 16:05:08 -040032
Brian Osman07c117b2019-05-23 12:51:06 -070033int ByteCodeGenerator::SlotCount(const Type& type) {
Brian Osmanfba386b2019-06-20 14:54:15 -040034 if (type.kind() == Type::kOther_Kind) {
35 return 0;
36 } else if (type.kind() == Type::kStruct_Kind) {
Brian Osman07c117b2019-05-23 12:51:06 -070037 int slots = 0;
38 for (const auto& f : type.fields()) {
39 slots += SlotCount(*f.fType);
40 }
41 SkASSERT(slots <= 255);
42 return slots;
43 } else if (type.kind() == Type::kArray_Kind) {
44 int columns = type.columns();
45 SkASSERT(columns >= 0);
46 int slots = columns * SlotCount(type.componentType());
47 SkASSERT(slots <= 255);
48 return slots;
49 } else {
50 return type.columns() * type.rows();
51 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040052}
53
54bool ByteCodeGenerator::generateCode() {
55 for (const auto& e : fProgram) {
56 switch (e.fKind) {
57 case ProgramElement::kFunction_Kind: {
58 std::unique_ptr<ByteCodeFunction> f = this->writeFunction((FunctionDefinition&) e);
59 if (!f) {
60 return false;
61 }
62 fOutput->fFunctions.push_back(std::move(f));
Brian Osman80164412019-06-07 13:00:23 -040063 fFunctions.push_back(&(FunctionDefinition&)e);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040064 break;
65 }
66 case ProgramElement::kVar_Kind: {
67 VarDeclarations& decl = (VarDeclarations&) e;
68 for (const auto& v : decl.fVars) {
69 const Variable* declVar = ((VarDeclaration&) *v).fVar;
70 if (declVar->fModifiers.fLayout.fBuiltin >= 0) {
71 continue;
72 }
73 if (declVar->fModifiers.fFlags & Modifiers::kIn_Flag) {
Brian Osman07c117b2019-05-23 12:51:06 -070074 for (int i = SlotCount(declVar->fType); i > 0; --i) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040075 fOutput->fInputSlots.push_back(fOutput->fGlobalCount++);
76 }
77 } else {
Brian Osman07c117b2019-05-23 12:51:06 -070078 fOutput->fGlobalCount += SlotCount(declVar->fType);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040079 }
80 }
81 break;
82 }
83 default:
84 ; // ignore
85 }
86 }
Brian Osman6f5358f2019-07-09 14:17:23 -040087 return 0 == fErrors.errorCount();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040088}
89
90std::unique_ptr<ByteCodeFunction> ByteCodeGenerator::writeFunction(const FunctionDefinition& f) {
91 fFunction = &f;
Brian Osman226668a2019-05-14 16:47:30 -040092 std::unique_ptr<ByteCodeFunction> result(new ByteCodeFunction(&f.fDeclaration));
Brian Osman80164412019-06-07 13:00:23 -040093 fParameterCount = result->fParameterCount;
Brian Osman4a47da72019-07-12 11:30:32 -040094 fLoopCount = fMaxLoopCount = 0;
95 fConditionCount = fMaxConditionCount = 0;
Brian Osmanaa2ca3f2019-07-15 13:24:48 -040096 fStackCount = fMaxStackCount = 0;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040097 fCode = &result->fCode;
Brian Osman4a47da72019-07-12 11:30:32 -040098
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040099 this->writeStatement(*f.fBody);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400100 if (0 == fErrors.errorCount()) {
101 SkASSERT(fLoopCount == 0);
102 SkASSERT(fConditionCount == 0);
103 SkASSERT(fStackCount == 0);
104 }
105 this->write(ByteCodeInstruction::kReturn, 0);
Ethan Nicholas7e603db2019-05-03 12:57:47 -0400106 this->write8(0);
Brian Osman4a47da72019-07-12 11:30:32 -0400107
108 result->fLocalCount = fLocals.size();
109 result->fConditionCount = fMaxConditionCount;
110 result->fLoopCount = fMaxLoopCount;
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400111 result->fStackCount = fMaxStackCount;
Brian Osman4a47da72019-07-12 11:30:32 -0400112
Ethan Nicholasdfcad062019-05-07 12:53:34 -0400113 const Type& returnType = f.fDeclaration.fReturnType;
114 if (returnType != *fContext.fVoid_Type) {
Brian Osman07c117b2019-05-23 12:51:06 -0700115 result->fReturnCount = SlotCount(returnType);
Ethan Nicholasdfcad062019-05-07 12:53:34 -0400116 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400117 fLocals.clear();
118 fFunction = nullptr;
119 return result;
120}
121
122enum class TypeCategory {
123 kBool,
124 kSigned,
125 kUnsigned,
126 kFloat,
127};
128
129static TypeCategory type_category(const Type& type) {
130 switch (type.kind()) {
131 case Type::Kind::kVector_Kind:
132 case Type::Kind::kMatrix_Kind:
133 return type_category(type.componentType());
134 default:
135 if (type.fName == "bool") {
136 return TypeCategory::kBool;
137 } else if (type.fName == "int" || type.fName == "short") {
138 return TypeCategory::kSigned;
139 } else if (type.fName == "uint" || type.fName == "ushort") {
140 return TypeCategory::kUnsigned;
141 } else {
142 SkASSERT(type.fName == "float" || type.fName == "half");
143 return TypeCategory::kFloat;
144 }
145 ABORT("unsupported type: %s\n", type.description().c_str());
146 }
147}
148
Brian Osman0785db02019-05-24 14:19:11 -0400149// A "simple" Swizzle is based on a variable (or a compound variable like a struct or array), and
150// that references consecutive values, such that it can be implemented using normal load/store ops
151// with an offset. Note that all single-component swizzles (of suitable base types) are simple.
152static bool swizzle_is_simple(const Swizzle& s) {
153 switch (s.fBase->fKind) {
154 case Expression::kFieldAccess_Kind:
155 case Expression::kIndex_Kind:
156 case Expression::kVariableReference_Kind:
157 break;
158 default:
159 return false;
160 }
161
162 for (size_t i = 1; i < s.fComponents.size(); ++i) {
163 if (s.fComponents[i] != s.fComponents[i - 1] + 1) {
164 return false;
165 }
166 }
167 return true;
168}
169
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400170int ByteCodeGenerator::StackUsage(ByteCodeInstruction inst, int count_) {
171 // Ensures that we use count iff we're passed a non-default value. Most instructions have an
172 // implicit count, so the caller shouldn't need to worry about it (or count makes no sense).
173 // The asserts avoids callers thinking they're supplying useful information in that scenario,
174 // or failing to supply necessary information for the ops that need a count.
175 struct CountValue {
176 operator int() {
177 SkASSERT(val != ByteCodeGenerator::kUnusedStackCount);
178 SkDEBUGCODE(used = true);
179 return val;
180 }
181 ~CountValue() {
182 SkASSERT(used || val == ByteCodeGenerator::kUnusedStackCount);
183 }
184 int val;
185 SkDEBUGCODE(bool used = false;)
186 } count = { count_ };
187
188 switch (inst) {
189 // Unary functions/operators that don't change stack depth at all:
190#define VECTOR_UNARY_OP(base) \
191 case ByteCodeInstruction::base: \
192 case ByteCodeInstruction::base ## 2: \
193 case ByteCodeInstruction::base ## 3: \
194 case ByteCodeInstruction::base ## 4: \
195 return 0;
196
197 VECTOR_UNARY_OP(kConvertFtoI)
198 VECTOR_UNARY_OP(kConvertStoF)
199 VECTOR_UNARY_OP(kConvertUtoF)
200
201 VECTOR_UNARY_OP(kCos)
Brian Osmanb380e712019-07-24 17:02:39 -0400202 VECTOR_UNARY_OP(kNormalize)
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400203 VECTOR_UNARY_OP(kSin)
204 VECTOR_UNARY_OP(kSqrt)
205 VECTOR_UNARY_OP(kTan)
206
207 VECTOR_UNARY_OP(kNegateF)
208 VECTOR_UNARY_OP(kNegateI)
209
Mike Reed634c9412019-07-18 13:20:04 -0400210 case ByteCodeInstruction::kInverse2x2:
211 case ByteCodeInstruction::kInverse3x3:
212 case ByteCodeInstruction::kInverse4x4: return 0;
213
Brian Osman869a3e82019-07-18 17:00:34 -0400214 case ByteCodeInstruction::kClampIndex: return 0;
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400215 case ByteCodeInstruction::kNotB: return 0;
216 case ByteCodeInstruction::kNegateFN: return 0;
217
218#undef VECTOR_UNARY_OP
219
220 // Binary functions/operators that do a 2 -> 1 reduction (possibly N times)
221#define VECTOR_BINARY_OP(base) \
222 case ByteCodeInstruction::base: return -1; \
223 case ByteCodeInstruction::base ## 2: return -2; \
224 case ByteCodeInstruction::base ## 3: return -3; \
225 case ByteCodeInstruction::base ## 4: return -4;
226
227#define VECTOR_MATRIX_BINARY_OP(base) \
228 VECTOR_BINARY_OP(base) \
229 case ByteCodeInstruction::base ## N: return -count;
230
231 case ByteCodeInstruction::kAndB: return -1;
232 case ByteCodeInstruction::kOrB: return -1;
233 case ByteCodeInstruction::kXorB: return -1;
234
235 VECTOR_BINARY_OP(kAddI)
236 VECTOR_MATRIX_BINARY_OP(kAddF)
237
238 VECTOR_BINARY_OP(kCompareIEQ)
239 VECTOR_MATRIX_BINARY_OP(kCompareFEQ)
240 VECTOR_BINARY_OP(kCompareINEQ)
241 VECTOR_MATRIX_BINARY_OP(kCompareFNEQ)
242 VECTOR_BINARY_OP(kCompareSGT)
243 VECTOR_BINARY_OP(kCompareUGT)
244 VECTOR_BINARY_OP(kCompareFGT)
245 VECTOR_BINARY_OP(kCompareSGTEQ)
246 VECTOR_BINARY_OP(kCompareUGTEQ)
247 VECTOR_BINARY_OP(kCompareFGTEQ)
248 VECTOR_BINARY_OP(kCompareSLT)
249 VECTOR_BINARY_OP(kCompareULT)
250 VECTOR_BINARY_OP(kCompareFLT)
251 VECTOR_BINARY_OP(kCompareSLTEQ)
252 VECTOR_BINARY_OP(kCompareULTEQ)
253 VECTOR_BINARY_OP(kCompareFLTEQ)
254
255 VECTOR_BINARY_OP(kDivideS)
256 VECTOR_BINARY_OP(kDivideU)
257 VECTOR_MATRIX_BINARY_OP(kDivideF)
258 VECTOR_BINARY_OP(kMultiplyI)
259 VECTOR_MATRIX_BINARY_OP(kMultiplyF)
260 VECTOR_BINARY_OP(kRemainderF)
261 VECTOR_BINARY_OP(kRemainderS)
262 VECTOR_BINARY_OP(kRemainderU)
263 VECTOR_BINARY_OP(kSubtractI)
264 VECTOR_MATRIX_BINARY_OP(kSubtractF)
265
266#undef VECTOR_BINARY_OP
267#undef VECTOR_MATRIX_BINARY_OP
268
269 // Strange math operations with other behavior:
270 case ByteCodeInstruction::kCross: return -3;
271 // Binary, but also consumes T:
272 case ByteCodeInstruction::kMix: return -2;
273 case ByteCodeInstruction::kMix2: return -3;
274 case ByteCodeInstruction::kMix3: return -4;
275 case ByteCodeInstruction::kMix4: return -5;
276
277 // Ops that push or load data to grow the stack:
278 case ByteCodeInstruction::kDup:
279 case ByteCodeInstruction::kLoad:
280 case ByteCodeInstruction::kLoadGlobal:
281 case ByteCodeInstruction::kReadExternal:
282 case ByteCodeInstruction::kPushImmediate:
283 return 1;
284
285 case ByteCodeInstruction::kDup2:
286 case ByteCodeInstruction::kLoad2:
287 case ByteCodeInstruction::kLoadGlobal2:
288 case ByteCodeInstruction::kReadExternal2:
289 return 2;
290
291 case ByteCodeInstruction::kDup3:
292 case ByteCodeInstruction::kLoad3:
293 case ByteCodeInstruction::kLoadGlobal3:
294 case ByteCodeInstruction::kReadExternal3:
295 return 3;
296
297 case ByteCodeInstruction::kDup4:
298 case ByteCodeInstruction::kLoad4:
299 case ByteCodeInstruction::kLoadGlobal4:
300 case ByteCodeInstruction::kReadExternal4:
301 return 4;
302
303 case ByteCodeInstruction::kDupN:
304 case ByteCodeInstruction::kLoadSwizzle:
305 case ByteCodeInstruction::kLoadSwizzleGlobal:
306 return count;
307
308 // Pushes 'count' values, minus one for the 'address' that's consumed first
309 case ByteCodeInstruction::kLoadExtended:
310 case ByteCodeInstruction::kLoadExtendedGlobal:
311 return count - 1;
312
313 // Ops that pop or store data to shrink the stack:
314 case ByteCodeInstruction::kPop:
315 case ByteCodeInstruction::kStore:
316 case ByteCodeInstruction::kStoreGlobal:
317 case ByteCodeInstruction::kWriteExternal:
318 return -1;
319
320 case ByteCodeInstruction::kPop2:
321 case ByteCodeInstruction::kStore2:
322 case ByteCodeInstruction::kStoreGlobal2:
323 case ByteCodeInstruction::kWriteExternal2:
324 return -2;
325
326 case ByteCodeInstruction::kPop3:
327 case ByteCodeInstruction::kStore3:
328 case ByteCodeInstruction::kStoreGlobal3:
329 case ByteCodeInstruction::kWriteExternal3:
330 return -3;
331
332 case ByteCodeInstruction::kPop4:
333 case ByteCodeInstruction::kStore4:
334 case ByteCodeInstruction::kStoreGlobal4:
335 case ByteCodeInstruction::kWriteExternal4:
336 return -4;
337
338 case ByteCodeInstruction::kPopN:
339 case ByteCodeInstruction::kStoreSwizzle:
340 case ByteCodeInstruction::kStoreSwizzleGlobal:
341 return -count;
342
343 // Consumes 'count' values, plus one for the 'address'
344 case ByteCodeInstruction::kStoreExtended:
345 case ByteCodeInstruction::kStoreExtendedGlobal:
346 case ByteCodeInstruction::kStoreSwizzleIndirect:
347 case ByteCodeInstruction::kStoreSwizzleIndirectGlobal:
348 return -count - 1;
349
350 // Strange ops where the caller computes the delta for us:
351 case ByteCodeInstruction::kCallExternal:
352 case ByteCodeInstruction::kMatrixToMatrix:
353 case ByteCodeInstruction::kMatrixMultiply:
354 case ByteCodeInstruction::kReserve:
355 case ByteCodeInstruction::kReturn:
356 case ByteCodeInstruction::kScalarToMatrix:
357 case ByteCodeInstruction::kSwizzle:
358 return count;
359
360 // Miscellaneous
361
362 // kCall is net-zero. Max stack depth is adjusted in writeFunctionCall.
363 case ByteCodeInstruction::kCall: return 0;
364 case ByteCodeInstruction::kBranch: return 0;
365 case ByteCodeInstruction::kBranchIfAllFalse: return 0;
366
367 case ByteCodeInstruction::kMaskPush: return -1;
368 case ByteCodeInstruction::kMaskPop: return 0;
369 case ByteCodeInstruction::kMaskNegate: return 0;
370 case ByteCodeInstruction::kMaskBlend: return -count;
371
372 case ByteCodeInstruction::kLoopBegin: return 0;
373 case ByteCodeInstruction::kLoopNext: return 0;
374 case ByteCodeInstruction::kLoopMask: return -1;
375 case ByteCodeInstruction::kLoopEnd: return 0;
376 case ByteCodeInstruction::kLoopBreak: return 0;
377 case ByteCodeInstruction::kLoopContinue: return 0;
378
379 default:
Brian Osmanc7ec9e22019-07-16 08:49:11 -0400380 ABORT("unsupported instruction %d\n", (int)inst);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400381 return 0;
382 }
383}
384
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400385int ByteCodeGenerator::getLocation(const Variable& var) {
386 // given that we seldom have more than a couple of variables, linear search is probably the most
387 // efficient way to handle lookups
388 switch (var.fStorage) {
389 case Variable::kLocal_Storage: {
390 for (int i = fLocals.size() - 1; i >= 0; --i) {
391 if (fLocals[i] == &var) {
Brian Osman1091f022019-05-16 09:42:16 -0400392 SkASSERT(fParameterCount + i <= 255);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400393 return fParameterCount + i;
394 }
395 }
396 int result = fParameterCount + fLocals.size();
397 fLocals.push_back(&var);
Brian Osman07c117b2019-05-23 12:51:06 -0700398 for (int i = 0; i < SlotCount(var.fType) - 1; ++i) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400399 fLocals.push_back(nullptr);
400 }
Brian Osman1091f022019-05-16 09:42:16 -0400401 SkASSERT(result <= 255);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400402 return result;
403 }
404 case Variable::kParameter_Storage: {
405 int offset = 0;
406 for (const auto& p : fFunction->fDeclaration.fParameters) {
407 if (p == &var) {
Brian Osman1091f022019-05-16 09:42:16 -0400408 SkASSERT(offset <= 255);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400409 return offset;
410 }
Brian Osman07c117b2019-05-23 12:51:06 -0700411 offset += SlotCount(p->fType);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400412 }
413 SkASSERT(false);
Brian Osman1091f022019-05-16 09:42:16 -0400414 return 0;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400415 }
416 case Variable::kGlobal_Storage: {
417 int offset = 0;
418 for (const auto& e : fProgram) {
419 if (e.fKind == ProgramElement::kVar_Kind) {
420 VarDeclarations& decl = (VarDeclarations&) e;
421 for (const auto& v : decl.fVars) {
422 const Variable* declVar = ((VarDeclaration&) *v).fVar;
423 if (declVar->fModifiers.fLayout.fBuiltin >= 0) {
424 continue;
425 }
426 if (declVar == &var) {
Brian Osmanb7451292019-05-15 13:02:13 -0400427 SkASSERT(offset <= 255);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400428 return offset;
429 }
Brian Osman07c117b2019-05-23 12:51:06 -0700430 offset += SlotCount(declVar->fType);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400431 }
432 }
433 }
434 SkASSERT(false);
Brian Osman1091f022019-05-16 09:42:16 -0400435 return 0;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400436 }
437 default:
438 SkASSERT(false);
439 return 0;
440 }
441}
442
Brian Osman07c117b2019-05-23 12:51:06 -0700443int ByteCodeGenerator::getLocation(const Expression& expr, Variable::Storage* storage) {
444 switch (expr.fKind) {
445 case Expression::kFieldAccess_Kind: {
446 const FieldAccess& f = (const FieldAccess&)expr;
447 int baseAddr = this->getLocation(*f.fBase, storage);
448 int offset = 0;
449 for (int i = 0; i < f.fFieldIndex; ++i) {
450 offset += SlotCount(*f.fBase->fType.fields()[i].fType);
451 }
452 if (baseAddr < 0) {
Brian Osman86769292019-06-21 11:05:47 -0400453 if (offset != 0) {
454 this->write(ByteCodeInstruction::kPushImmediate);
455 this->write32(offset);
456 this->write(ByteCodeInstruction::kAddI);
457 }
Brian Osman07c117b2019-05-23 12:51:06 -0700458 return -1;
459 } else {
460 return baseAddr + offset;
461 }
462 }
463 case Expression::kIndex_Kind: {
464 const IndexExpression& i = (const IndexExpression&)expr;
465 int stride = SlotCount(i.fType);
Brian Osman869a3e82019-07-18 17:00:34 -0400466 int length = i.fBase->fType.columns();
467 SkASSERT(length <= 255);
Brian Osman07c117b2019-05-23 12:51:06 -0700468 int offset = -1;
469 if (i.fIndex->isConstant()) {
Brian Osman869a3e82019-07-18 17:00:34 -0400470 int64_t index = i.fIndex->getConstantInt();
471 if (index < 0 || index >= length) {
472 fErrors.error(i.fIndex->fOffset, "Array index out of bounds.");
473 return 0;
474 }
475 offset = index * stride;
Brian Osman07c117b2019-05-23 12:51:06 -0700476 } else {
Brian Osman86769292019-06-21 11:05:47 -0400477 if (i.fIndex->hasSideEffects()) {
478 // Having a side-effect in an indexer is technically safe for an rvalue,
479 // but with lvalues we have to evaluate the indexer twice, so make it an error.
480 fErrors.error(i.fIndex->fOffset,
481 "Index expressions with side-effects not supported in byte code.");
482 return 0;
483 }
Brian Osman07c117b2019-05-23 12:51:06 -0700484 this->writeExpression(*i.fIndex);
Brian Osman869a3e82019-07-18 17:00:34 -0400485 this->write(ByteCodeInstruction::kClampIndex);
486 this->write8(length);
Brian Osman86769292019-06-21 11:05:47 -0400487 if (stride != 1) {
488 this->write(ByteCodeInstruction::kPushImmediate);
489 this->write32(stride);
490 this->write(ByteCodeInstruction::kMultiplyI);
491 }
Brian Osman07c117b2019-05-23 12:51:06 -0700492 }
493 int baseAddr = this->getLocation(*i.fBase, storage);
Brian Osman86769292019-06-21 11:05:47 -0400494
495 // Are both components known statically?
Brian Osman07c117b2019-05-23 12:51:06 -0700496 if (baseAddr >= 0 && offset >= 0) {
497 return baseAddr + offset;
498 }
Brian Osman86769292019-06-21 11:05:47 -0400499
500 // At least one component is dynamic (and on the stack).
501
502 // If the other component is zero, we're done
503 if (baseAddr == 0 || offset == 0) {
504 return -1;
505 }
506
507 // Push the non-dynamic component (if any) to the stack, then add the two
Brian Osman07c117b2019-05-23 12:51:06 -0700508 if (baseAddr >= 0) {
509 this->write(ByteCodeInstruction::kPushImmediate);
510 this->write32(baseAddr);
511 }
512 if (offset >= 0) {
513 this->write(ByteCodeInstruction::kPushImmediate);
514 this->write32(offset);
515 }
516 this->write(ByteCodeInstruction::kAddI);
517 return -1;
518 }
Brian Osman0785db02019-05-24 14:19:11 -0400519 case Expression::kSwizzle_Kind: {
520 const Swizzle& s = (const Swizzle&)expr;
521 SkASSERT(swizzle_is_simple(s));
522 int baseAddr = this->getLocation(*s.fBase, storage);
523 int offset = s.fComponents[0];
524 if (baseAddr < 0) {
Brian Osman86769292019-06-21 11:05:47 -0400525 if (offset != 0) {
526 this->write(ByteCodeInstruction::kPushImmediate);
527 this->write32(offset);
528 this->write(ByteCodeInstruction::kAddI);
529 }
Brian Osman0785db02019-05-24 14:19:11 -0400530 return -1;
531 } else {
532 return baseAddr + offset;
533 }
534 }
Brian Osman07c117b2019-05-23 12:51:06 -0700535 case Expression::kVariableReference_Kind: {
536 const Variable& var = ((const VariableReference&)expr).fVariable;
537 *storage = var.fStorage;
538 return this->getLocation(var);
539 }
540 default:
541 SkASSERT(false);
542 return 0;
543 }
544}
545
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400546void ByteCodeGenerator::write8(uint8_t b) {
547 fCode->push_back(b);
548}
549
550void ByteCodeGenerator::write16(uint16_t i) {
Mike Klein76346ac2019-05-17 11:57:10 -0500551 size_t n = fCode->size();
552 fCode->resize(n+2);
553 memcpy(fCode->data() + n, &i, 2);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400554}
555
556void ByteCodeGenerator::write32(uint32_t i) {
Mike Klein76346ac2019-05-17 11:57:10 -0500557 size_t n = fCode->size();
558 fCode->resize(n+4);
559 memcpy(fCode->data() + n, &i, 4);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400560}
561
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400562void ByteCodeGenerator::write(ByteCodeInstruction i, int count) {
Brian Osman4a47da72019-07-12 11:30:32 -0400563 switch (i) {
564 case ByteCodeInstruction::kLoopBegin: this->enterLoop(); break;
565 case ByteCodeInstruction::kLoopEnd: this->exitLoop(); break;
566
567 case ByteCodeInstruction::kMaskPush: this->enterCondition(); break;
568 case ByteCodeInstruction::kMaskPop:
569 case ByteCodeInstruction::kMaskBlend: this->exitCondition(); break;
570 default: /* Do nothing */ break;
571 }
Mike Klein108e9352019-05-21 11:05:17 -0500572 this->write16((uint16_t)i);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400573 fStackCount += StackUsage(i, count);
574 fMaxStackCount = std::max(fMaxStackCount, fStackCount);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400575}
576
Mike Klein76346ac2019-05-17 11:57:10 -0500577static ByteCodeInstruction vector_instruction(ByteCodeInstruction base, int count) {
Brian Osman07c117b2019-05-23 12:51:06 -0700578 SkASSERT(count >= 1 && count <= 4);
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400579 return ((ByteCodeInstruction) ((int) base + count - 1));
580}
581
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400582void ByteCodeGenerator::writeTypedInstruction(const Type& type, ByteCodeInstruction s,
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400583 ByteCodeInstruction u, ByteCodeInstruction f,
584 int count) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400585 switch (type_category(type)) {
586 case TypeCategory::kSigned:
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400587 this->write(vector_instruction(s, count));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400588 break;
589 case TypeCategory::kUnsigned:
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400590 this->write(vector_instruction(u, count));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400591 break;
Brian Osman1e855b22019-05-29 15:21:52 -0400592 case TypeCategory::kFloat: {
593 if (count > 4) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400594 this->write((ByteCodeInstruction)((int)f + 4), count);
Brian Osman1e855b22019-05-29 15:21:52 -0400595 this->write8(count);
596 } else {
597 this->write(vector_instruction(f, count));
598 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400599 break;
Brian Osman1e855b22019-05-29 15:21:52 -0400600 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400601 default:
602 SkASSERT(false);
603 }
604}
605
Brian Osman3e29f1d2019-05-28 09:35:05 -0400606bool ByteCodeGenerator::writeBinaryExpression(const BinaryExpression& b, bool discard) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400607 if (b.fOperator == Token::Kind::EQ) {
608 std::unique_ptr<LValue> lvalue = this->getLValue(*b.fLeft);
609 this->writeExpression(*b.fRight);
Brian Osman3e29f1d2019-05-28 09:35:05 -0400610 lvalue->store(discard);
611 discard = false;
612 return discard;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400613 }
Brian Osman16e6fd52019-05-29 11:19:00 -0400614 const Type& lType = b.fLeft->fType;
615 const Type& rType = b.fRight->fType;
Brian Osman909231c2019-05-29 15:34:36 -0400616 bool lVecOrMtx = (lType.kind() == Type::kVector_Kind || lType.kind() == Type::kMatrix_Kind);
617 bool rVecOrMtx = (rType.kind() == Type::kVector_Kind || rType.kind() == Type::kMatrix_Kind);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400618 Token::Kind op;
619 std::unique_ptr<LValue> lvalue;
620 if (is_assignment(b.fOperator)) {
621 lvalue = this->getLValue(*b.fLeft);
622 lvalue->load();
623 op = remove_assignment(b.fOperator);
624 } else {
625 this->writeExpression(*b.fLeft);
626 op = b.fOperator;
Brian Osman909231c2019-05-29 15:34:36 -0400627 if (!lVecOrMtx && rVecOrMtx) {
Brian Osman16e6fd52019-05-29 11:19:00 -0400628 for (int i = SlotCount(rType); i > 1; --i) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400629 this->write(ByteCodeInstruction::kDup);
630 }
631 }
632 }
633 this->writeExpression(*b.fRight);
Brian Osman909231c2019-05-29 15:34:36 -0400634 if (lVecOrMtx && !rVecOrMtx) {
Brian Osman16e6fd52019-05-29 11:19:00 -0400635 for (int i = SlotCount(lType); i > 1; --i) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400636 this->write(ByteCodeInstruction::kDup);
637 }
638 }
Brian Osman909231c2019-05-29 15:34:36 -0400639 // Special case for M*V, V*M, M*M (but not V*V!)
640 if (op == Token::Kind::STAR && lVecOrMtx && rVecOrMtx &&
641 !(lType.kind() == Type::kVector_Kind && rType.kind() == Type::kVector_Kind)) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400642 this->write(ByteCodeInstruction::kMatrixMultiply,
643 SlotCount(b.fType) - (SlotCount(lType) + SlotCount(rType)));
Brian Osman909231c2019-05-29 15:34:36 -0400644 int rCols = rType.columns(),
645 rRows = rType.rows(),
646 lCols = lType.columns(),
647 lRows = lType.rows();
648 // M*V treats the vector as a column
649 if (rType.kind() == Type::kVector_Kind) {
650 std::swap(rCols, rRows);
651 }
652 SkASSERT(lCols == rRows);
653 SkASSERT(SlotCount(b.fType) == lRows * rCols);
654 this->write8(lCols);
655 this->write8(lRows);
656 this->write8(rCols);
657 } else {
658 int count = std::max(SlotCount(lType), SlotCount(rType));
659 switch (op) {
660 case Token::Kind::EQEQ:
661 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareIEQ,
662 ByteCodeInstruction::kCompareIEQ,
663 ByteCodeInstruction::kCompareFEQ,
664 count);
665 // Collapse to a single bool
666 for (int i = count; i > 1; --i) {
667 this->write(ByteCodeInstruction::kAndB);
668 }
669 break;
670 case Token::Kind::GT:
671 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSGT,
672 ByteCodeInstruction::kCompareUGT,
673 ByteCodeInstruction::kCompareFGT,
674 count);
675 break;
676 case Token::Kind::GTEQ:
677 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSGTEQ,
678 ByteCodeInstruction::kCompareUGTEQ,
679 ByteCodeInstruction::kCompareFGTEQ,
680 count);
681 break;
682 case Token::Kind::LT:
683 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSLT,
684 ByteCodeInstruction::kCompareULT,
685 ByteCodeInstruction::kCompareFLT,
686 count);
687 break;
688 case Token::Kind::LTEQ:
689 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSLTEQ,
690 ByteCodeInstruction::kCompareULTEQ,
691 ByteCodeInstruction::kCompareFLTEQ,
692 count);
693 break;
694 case Token::Kind::MINUS:
695 this->writeTypedInstruction(lType, ByteCodeInstruction::kSubtractI,
696 ByteCodeInstruction::kSubtractI,
697 ByteCodeInstruction::kSubtractF,
698 count);
699 break;
700 case Token::Kind::NEQ:
701 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareINEQ,
702 ByteCodeInstruction::kCompareINEQ,
703 ByteCodeInstruction::kCompareFNEQ,
704 count);
705 // Collapse to a single bool
706 for (int i = count; i > 1; --i) {
707 this->write(ByteCodeInstruction::kOrB);
708 }
709 break;
710 case Token::Kind::PERCENT:
711 this->writeTypedInstruction(lType, ByteCodeInstruction::kRemainderS,
712 ByteCodeInstruction::kRemainderU,
713 ByteCodeInstruction::kRemainderF,
714 count);
715 break;
716 case Token::Kind::PLUS:
717 this->writeTypedInstruction(lType, ByteCodeInstruction::kAddI,
718 ByteCodeInstruction::kAddI,
719 ByteCodeInstruction::kAddF,
720 count);
721 break;
722 case Token::Kind::SLASH:
723 this->writeTypedInstruction(lType, ByteCodeInstruction::kDivideS,
724 ByteCodeInstruction::kDivideU,
725 ByteCodeInstruction::kDivideF,
726 count);
727 break;
728 case Token::Kind::STAR:
729 this->writeTypedInstruction(lType, ByteCodeInstruction::kMultiplyI,
730 ByteCodeInstruction::kMultiplyI,
731 ByteCodeInstruction::kMultiplyF,
732 count);
733 break;
Brian Osman569f12f2019-06-13 11:23:57 -0400734
735 case Token::Kind::LOGICALAND:
736 SkASSERT(type_category(lType) == SkSL::TypeCategory::kBool && count == 1);
737 this->write(ByteCodeInstruction::kAndB);
738 break;
739 case Token::Kind::LOGICALNOT:
740 SkASSERT(type_category(lType) == SkSL::TypeCategory::kBool && count == 1);
741 this->write(ByteCodeInstruction::kNotB);
742 break;
743 case Token::Kind::LOGICALOR:
744 SkASSERT(type_category(lType) == SkSL::TypeCategory::kBool && count == 1);
745 this->write(ByteCodeInstruction::kOrB);
746 break;
747 case Token::Kind::LOGICALXOR:
748 SkASSERT(type_category(lType) == SkSL::TypeCategory::kBool && count == 1);
749 this->write(ByteCodeInstruction::kXorB);
750 break;
751
Brian Osman909231c2019-05-29 15:34:36 -0400752 default:
753 SkASSERT(false);
754 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400755 }
756 if (lvalue) {
Brian Osman3e29f1d2019-05-28 09:35:05 -0400757 lvalue->store(discard);
758 discard = false;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400759 }
Brian Osman3e29f1d2019-05-28 09:35:05 -0400760 return discard;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400761}
762
763void ByteCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
764 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osman569f12f2019-06-13 11:23:57 -0400765 this->write32(b.fValue ? ~0 : 0);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400766}
767
768void ByteCodeGenerator::writeConstructor(const Constructor& c) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400769 for (const auto& arg : c.fArguments) {
770 this->writeExpression(*arg);
771 }
772 if (c.fArguments.size() == 1) {
Brian Osman29e013d2019-05-28 17:16:03 -0400773 const Type& inType = c.fArguments[0]->fType;
774 const Type& outType = c.fType;
775 TypeCategory inCategory = type_category(inType);
776 TypeCategory outCategory = type_category(outType);
777 int inCount = SlotCount(inType);
778 int outCount = SlotCount(outType);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400779 if (inCategory != outCategory) {
Brian Osmanc51d7912019-05-22 15:16:16 -0700780 SkASSERT(inCount == outCount);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400781 if (inCategory == TypeCategory::kFloat) {
782 SkASSERT(outCategory == TypeCategory::kSigned ||
783 outCategory == TypeCategory::kUnsigned);
Brian Osmanc51d7912019-05-22 15:16:16 -0700784 this->write(vector_instruction(ByteCodeInstruction::kConvertFtoI, outCount));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400785 } else if (outCategory == TypeCategory::kFloat) {
786 if (inCategory == TypeCategory::kSigned) {
Brian Osmanc51d7912019-05-22 15:16:16 -0700787 this->write(vector_instruction(ByteCodeInstruction::kConvertStoF, outCount));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400788 } else {
789 SkASSERT(inCategory == TypeCategory::kUnsigned);
Brian Osmanc51d7912019-05-22 15:16:16 -0700790 this->write(vector_instruction(ByteCodeInstruction::kConvertUtoF, outCount));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400791 }
792 } else {
793 SkASSERT(false);
794 }
795 }
Brian Osman29e013d2019-05-28 17:16:03 -0400796 if (inType.kind() == Type::kMatrix_Kind && outType.kind() == Type::kMatrix_Kind) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400797 this->write(ByteCodeInstruction::kMatrixToMatrix,
798 SlotCount(outType) - SlotCount(inType));
Brian Osman29e013d2019-05-28 17:16:03 -0400799 this->write8(inType.columns());
800 this->write8(inType.rows());
801 this->write8(outType.columns());
802 this->write8(outType.rows());
803 } else if (inCount != outCount) {
Brian Osmanc51d7912019-05-22 15:16:16 -0700804 SkASSERT(inCount == 1);
Brian Osman29e013d2019-05-28 17:16:03 -0400805 if (outType.kind() == Type::kMatrix_Kind) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400806 this->write(ByteCodeInstruction::kScalarToMatrix, SlotCount(outType) - 1);
Brian Osman29e013d2019-05-28 17:16:03 -0400807 this->write8(outType.columns());
808 this->write8(outType.rows());
809 } else {
810 SkASSERT(outType.kind() == Type::kVector_Kind);
811 for (; inCount != outCount; ++inCount) {
812 this->write(ByteCodeInstruction::kDup);
813 }
Brian Osmanc51d7912019-05-22 15:16:16 -0700814 }
815 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400816 }
817}
818
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400819void ByteCodeGenerator::writeExternalFunctionCall(const ExternalFunctionCall& f) {
820 int argumentCount = 0;
821 for (const auto& arg : f.fArguments) {
822 this->writeExpression(*arg);
Brian Osman07c117b2019-05-23 12:51:06 -0700823 argumentCount += SlotCount(arg->fType);
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400824 }
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400825 this->write(ByteCodeInstruction::kCallExternal, SlotCount(f.fType) - argumentCount);
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400826 SkASSERT(argumentCount <= 255);
827 this->write8(argumentCount);
Brian Osman07c117b2019-05-23 12:51:06 -0700828 this->write8(SlotCount(f.fType));
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400829 int index = fOutput->fExternalValues.size();
830 fOutput->fExternalValues.push_back(f.fFunction);
831 SkASSERT(index <= 255);
832 this->write8(index);
833}
834
Ethan Nicholas91164d12019-05-15 15:29:54 -0400835void ByteCodeGenerator::writeExternalValue(const ExternalValueReference& e) {
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400836 this->write(vector_instruction(ByteCodeInstruction::kReadExternal,
Brian Osman07c117b2019-05-23 12:51:06 -0700837 SlotCount(e.fValue->type())));
Ethan Nicholas91164d12019-05-15 15:29:54 -0400838 int index = fOutput->fExternalValues.size();
839 fOutput->fExternalValues.push_back(e.fValue);
840 SkASSERT(index <= 255);
841 this->write8(index);
842}
843
Brian Osman07c117b2019-05-23 12:51:06 -0700844void ByteCodeGenerator::writeVariableExpression(const Expression& expr) {
Brian Osman869a3e82019-07-18 17:00:34 -0400845 Variable::Storage storage = Variable::kLocal_Storage;
Brian Osman07c117b2019-05-23 12:51:06 -0700846 int location = this->getLocation(expr, &storage);
847 bool isGlobal = storage == Variable::kGlobal_Storage;
848 int count = SlotCount(expr.fType);
849 if (location < 0 || count > 4) {
850 if (location >= 0) {
851 this->write(ByteCodeInstruction::kPushImmediate);
852 this->write32(location);
853 }
854 this->write(isGlobal ? ByteCodeInstruction::kLoadExtendedGlobal
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400855 : ByteCodeInstruction::kLoadExtended,
856 count);
Brian Osman07c117b2019-05-23 12:51:06 -0700857 this->write8(count);
858 } else {
859 this->write(vector_instruction(isGlobal ? ByteCodeInstruction::kLoadGlobal
860 : ByteCodeInstruction::kLoad,
861 count));
862 this->write8(location);
863 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400864}
865
Brian Osmand30e0392019-06-14 14:05:14 -0400866static inline uint32_t float_to_bits(float x) {
867 uint32_t u;
868 memcpy(&u, &x, sizeof(uint32_t));
869 return u;
870}
871
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400872void ByteCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
873 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osmand30e0392019-06-14 14:05:14 -0400874 this->write32(float_to_bits(f.fValue));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400875}
876
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400877void ByteCodeGenerator::writeIntrinsicCall(const FunctionCall& c) {
878 auto found = fIntrinsics.find(c.fFunction.fName);
879 if (found == fIntrinsics.end()) {
880 fErrors.error(c.fOffset, "unsupported intrinsic function");
881 return;
882 }
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400883 int count = SlotCount(c.fArguments[0]->fType);
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400884 if (found->second.fIsSpecial) {
Brian Osmanb380e712019-07-24 17:02:39 -0400885 SpecialIntrinsic special = found->second.fValue.fSpecial;
886 switch (special) {
887 case SpecialIntrinsic::kDot: {
888 SkASSERT(c.fArguments.size() == 2);
889 SkASSERT(count == SlotCount(c.fArguments[1]->fType));
890 this->write((ByteCodeInstruction)((int)ByteCodeInstruction::kMultiplyF + count-1));
891 for (int i = count; i > 1; --i) {
892 this->write(ByteCodeInstruction::kAddF);
893 }
894 break;
895 }
896 case SpecialIntrinsic::kRadians: {
897 this->write(ByteCodeInstruction::kPushImmediate);
898 this->write32(float_to_bits(0.0174532925f)); // π/180
899 for (int i = count; i > 1; --i) {
900 this->write(ByteCodeInstruction::kDup);
901 }
902 this->write((ByteCodeInstruction)((int)ByteCodeInstruction::kMultiplyF + count-1));
903 break;
904 }
905 default:
906 SkASSERT(false);
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400907 }
908 } else {
909 switch (found->second.fValue.fInstruction) {
910 case ByteCodeInstruction::kCos:
911 case ByteCodeInstruction::kMix:
Brian Osmanb380e712019-07-24 17:02:39 -0400912 case ByteCodeInstruction::kNormalize:
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400913 case ByteCodeInstruction::kSin:
914 case ByteCodeInstruction::kSqrt:
915 case ByteCodeInstruction::kTan:
916 SkASSERT(c.fArguments.size() > 0);
917 this->write((ByteCodeInstruction) ((int) found->second.fValue.fInstruction +
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400918 count - 1));
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400919 break;
920 case ByteCodeInstruction::kCross:
921 this->write(found->second.fValue.fInstruction);
922 break;
Mike Reed634c9412019-07-18 13:20:04 -0400923 case ByteCodeInstruction::kInverse2x2: {
924 SkASSERT(c.fArguments.size() > 0);
925 auto op = ByteCodeInstruction::kInverse2x2;
926 switch (count) {
927 case 4: break; // float2x2
928 case 9: op = ByteCodeInstruction::kInverse3x3; break;
929 case 16: op = ByteCodeInstruction::kInverse4x4; break;
930 default: SkASSERT(false);
931 }
932 this->write(op);
Brian Osmanb380e712019-07-24 17:02:39 -0400933 break;
934 }
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400935 default:
936 SkASSERT(false);
937 }
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400938 }
939}
940
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400941void ByteCodeGenerator::writeFunctionCall(const FunctionCall& f) {
Brian Osmand3494ed2019-06-20 15:41:34 -0400942 // Builtins have simple signatures...
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400943 if (f.fFunction.fBuiltin) {
Brian Osmand3494ed2019-06-20 15:41:34 -0400944 for (const auto& arg : f.fArguments) {
945 this->writeExpression(*arg);
946 }
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400947 this->writeIntrinsicCall(f);
948 return;
949 }
Brian Osmand3494ed2019-06-20 15:41:34 -0400950
Brian Osman6f5358f2019-07-09 14:17:23 -0400951 // Find the index of the function we're calling. We explicitly do not allow calls to functions
952 // before they're defined. This is an easy-to-understand rule that prevents recursion.
953 size_t idx;
954 for (idx = 0; idx < fFunctions.size(); ++idx) {
955 if (f.fFunction.matches(fFunctions[idx]->fDeclaration)) {
956 break;
957 }
958 }
959 if (idx > 255) {
960 fErrors.error(f.fOffset, "Function count limit exceeded");
961 return;
962 } else if (idx >= fFunctions.size()) {
963 fErrors.error(f.fOffset, "Call to undefined function");
964 return;
965 }
966
967 // We may need to deal with out parameters, so the sequence is tricky
Brian Osmand3494ed2019-06-20 15:41:34 -0400968 if (int returnCount = SlotCount(f.fType)) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400969 this->write(ByteCodeInstruction::kReserve, returnCount);
Brian Osmand3494ed2019-06-20 15:41:34 -0400970 this->write8(returnCount);
971 }
972
973 int argCount = f.fArguments.size();
974 std::vector<std::unique_ptr<LValue>> lvalues;
975 for (int i = 0; i < argCount; ++i) {
976 const auto& param = f.fFunction.fParameters[i];
977 const auto& arg = f.fArguments[i];
978 if (param->fModifiers.fFlags & Modifiers::kOut_Flag) {
979 lvalues.emplace_back(this->getLValue(*arg));
980 lvalues.back()->load();
981 } else {
982 this->writeExpression(*arg);
983 }
984 }
985
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400986 // The space used by the call is based on the callee, but it also unwinds all of that before
987 // we continue execution. We adjust our max stack depths below.
Brian Osman226668a2019-05-14 16:47:30 -0400988 this->write(ByteCodeInstruction::kCall);
Brian Osman6f5358f2019-07-09 14:17:23 -0400989 this->write8(idx);
Brian Osmand3494ed2019-06-20 15:41:34 -0400990
Brian Osman4a47da72019-07-12 11:30:32 -0400991 const ByteCodeFunction* callee = fOutput->fFunctions[idx].get();
992 fMaxLoopCount = std::max(fMaxLoopCount, fLoopCount + callee->fLoopCount);
993 fMaxConditionCount = std::max(fMaxConditionCount, fConditionCount + callee->fConditionCount);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400994 fMaxStackCount = std::max(fMaxStackCount, fStackCount + callee->fLocalCount
995 + callee->fStackCount);
Brian Osman4a47da72019-07-12 11:30:32 -0400996
Brian Osmand3494ed2019-06-20 15:41:34 -0400997 // After the called function returns, the stack will still contain our arguments. We have to
998 // pop them (storing any out parameters back to their lvalues as we go). We glob together slot
999 // counts for all parameters that aren't out-params, so we can pop them in one big chunk.
1000 int popCount = 0;
1001 auto pop = [&]() {
1002 if (popCount > 4) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001003 this->write(ByteCodeInstruction::kPopN, popCount);
Brian Osmand3494ed2019-06-20 15:41:34 -04001004 this->write8(popCount);
1005 } else if (popCount > 0) {
1006 this->write(vector_instruction(ByteCodeInstruction::kPop, popCount));
1007 }
1008 popCount = 0;
1009 };
1010
1011 for (int i = argCount - 1; i >= 0; --i) {
1012 const auto& param = f.fFunction.fParameters[i];
1013 const auto& arg = f.fArguments[i];
1014 if (param->fModifiers.fFlags & Modifiers::kOut_Flag) {
1015 pop();
1016 lvalues.back()->store(true);
1017 lvalues.pop_back();
1018 } else {
1019 popCount += SlotCount(arg->fType);
1020 }
1021 }
1022 pop();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001023}
1024
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001025void ByteCodeGenerator::writeIntLiteral(const IntLiteral& i) {
1026 this->write(ByteCodeInstruction::kPushImmediate);
1027 this->write32(i.fValue);
1028}
1029
1030void ByteCodeGenerator::writeNullLiteral(const NullLiteral& n) {
1031 // not yet implemented
1032 abort();
1033}
1034
Brian Osman3e29f1d2019-05-28 09:35:05 -04001035bool ByteCodeGenerator::writePrefixExpression(const PrefixExpression& p, bool discard) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001036 switch (p.fOperator) {
1037 case Token::Kind::PLUSPLUS: // fall through
1038 case Token::Kind::MINUSMINUS: {
Brian Osman07c117b2019-05-23 12:51:06 -07001039 SkASSERT(SlotCount(p.fOperand->fType) == 1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001040 std::unique_ptr<LValue> lvalue = this->getLValue(*p.fOperand);
1041 lvalue->load();
1042 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osmand30e0392019-06-14 14:05:14 -04001043 this->write32(type_category(p.fType) == TypeCategory::kFloat ? float_to_bits(1.0f) : 1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001044 if (p.fOperator == Token::Kind::PLUSPLUS) {
1045 this->writeTypedInstruction(p.fType,
1046 ByteCodeInstruction::kAddI,
1047 ByteCodeInstruction::kAddI,
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001048 ByteCodeInstruction::kAddF,
1049 1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001050 } else {
1051 this->writeTypedInstruction(p.fType,
1052 ByteCodeInstruction::kSubtractI,
1053 ByteCodeInstruction::kSubtractI,
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001054 ByteCodeInstruction::kSubtractF,
1055 1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001056 }
Brian Osman3e29f1d2019-05-28 09:35:05 -04001057 lvalue->store(discard);
1058 discard = false;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001059 break;
1060 }
Ethan Nicholas354ecf32019-05-07 16:13:02 -04001061 case Token::Kind::MINUS: {
1062 this->writeExpression(*p.fOperand);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001063 this->writeTypedInstruction(p.fType,
Mike Klein12710912019-05-21 11:04:59 -05001064 ByteCodeInstruction::kNegateI,
1065 ByteCodeInstruction::kNegateI,
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001066 ByteCodeInstruction::kNegateF,
Brian Osman07c117b2019-05-23 12:51:06 -07001067 SlotCount(p.fOperand->fType));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001068 break;
Ethan Nicholas354ecf32019-05-07 16:13:02 -04001069 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001070 default:
1071 SkASSERT(false);
1072 }
Brian Osman3e29f1d2019-05-28 09:35:05 -04001073 return discard;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001074}
1075
Brian Osman3e29f1d2019-05-28 09:35:05 -04001076bool ByteCodeGenerator::writePostfixExpression(const PostfixExpression& p, bool discard) {
Brian Osmanf3fa6002019-05-17 14:26:53 -04001077 switch (p.fOperator) {
1078 case Token::Kind::PLUSPLUS: // fall through
1079 case Token::Kind::MINUSMINUS: {
Brian Osman07c117b2019-05-23 12:51:06 -07001080 SkASSERT(SlotCount(p.fOperand->fType) == 1);
Brian Osmanf3fa6002019-05-17 14:26:53 -04001081 std::unique_ptr<LValue> lvalue = this->getLValue(*p.fOperand);
1082 lvalue->load();
Brian Osman52c1bf12019-07-18 13:12:19 -04001083 // If we're not supposed to discard the result, then make a copy *before* the +/-
Brian Osman3e29f1d2019-05-28 09:35:05 -04001084 if (!discard) {
1085 this->write(ByteCodeInstruction::kDup);
1086 }
Brian Osmanf3fa6002019-05-17 14:26:53 -04001087 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osmand30e0392019-06-14 14:05:14 -04001088 this->write32(type_category(p.fType) == TypeCategory::kFloat ? float_to_bits(1.0f) : 1);
Brian Osmanf3fa6002019-05-17 14:26:53 -04001089 if (p.fOperator == Token::Kind::PLUSPLUS) {
1090 this->writeTypedInstruction(p.fType,
1091 ByteCodeInstruction::kAddI,
1092 ByteCodeInstruction::kAddI,
1093 ByteCodeInstruction::kAddF,
1094 1);
1095 } else {
1096 this->writeTypedInstruction(p.fType,
1097 ByteCodeInstruction::kSubtractI,
1098 ByteCodeInstruction::kSubtractI,
1099 ByteCodeInstruction::kSubtractF,
1100 1);
1101 }
Brian Osman52c1bf12019-07-18 13:12:19 -04001102 // Always consume the result as part of the store
1103 lvalue->store(true);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001104 discard = false;
Brian Osmanf3fa6002019-05-17 14:26:53 -04001105 break;
1106 }
1107 default:
1108 SkASSERT(false);
1109 }
Brian Osman3e29f1d2019-05-28 09:35:05 -04001110 return discard;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001111}
1112
1113void ByteCodeGenerator::writeSwizzle(const Swizzle& s) {
Brian Osman0785db02019-05-24 14:19:11 -04001114 if (swizzle_is_simple(s)) {
1115 this->writeVariableExpression(s);
1116 return;
1117 }
1118
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001119 switch (s.fBase->fKind) {
1120 case Expression::kVariableReference_Kind: {
1121 const Variable& var = ((VariableReference&) *s.fBase).fVariable;
Brian Osman1091f022019-05-16 09:42:16 -04001122 this->write(var.fStorage == Variable::kGlobal_Storage
1123 ? ByteCodeInstruction::kLoadSwizzleGlobal
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001124 : ByteCodeInstruction::kLoadSwizzle,
1125 s.fComponents.size());
Brian Osman1091f022019-05-16 09:42:16 -04001126 this->write8(this->getLocation(var));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001127 this->write8(s.fComponents.size());
1128 for (int c : s.fComponents) {
1129 this->write8(c);
1130 }
1131 break;
1132 }
1133 default:
1134 this->writeExpression(*s.fBase);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001135 this->write(ByteCodeInstruction::kSwizzle,
1136 s.fComponents.size() - s.fBase->fType.columns());
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001137 this->write8(s.fBase->fType.columns());
1138 this->write8(s.fComponents.size());
1139 for (int c : s.fComponents) {
1140 this->write8(c);
1141 }
1142 }
1143}
1144
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001145void ByteCodeGenerator::writeTernaryExpression(const TernaryExpression& t) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001146 int count = SlotCount(t.fType);
1147 SkASSERT(count == SlotCount(t.fIfTrue->fType));
1148 SkASSERT(count == SlotCount(t.fIfFalse->fType));
1149
Brian Osman4e93feb2019-05-16 15:38:00 -04001150 this->writeExpression(*t.fTest);
Brian Osman569f12f2019-06-13 11:23:57 -04001151 this->write(ByteCodeInstruction::kMaskPush);
Brian Osman4e93feb2019-05-16 15:38:00 -04001152 this->writeExpression(*t.fIfTrue);
Brian Osman569f12f2019-06-13 11:23:57 -04001153 this->write(ByteCodeInstruction::kMaskNegate);
1154 this->writeExpression(*t.fIfFalse);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001155 this->write(ByteCodeInstruction::kMaskBlend, count);
1156 this->write8(count);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001157}
1158
Brian Osman3e29f1d2019-05-28 09:35:05 -04001159void ByteCodeGenerator::writeExpression(const Expression& e, bool discard) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001160 switch (e.fKind) {
1161 case Expression::kBinary_Kind:
Brian Osman3e29f1d2019-05-28 09:35:05 -04001162 discard = this->writeBinaryExpression((BinaryExpression&) e, discard);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001163 break;
1164 case Expression::kBoolLiteral_Kind:
1165 this->writeBoolLiteral((BoolLiteral&) e);
1166 break;
1167 case Expression::kConstructor_Kind:
1168 this->writeConstructor((Constructor&) e);
1169 break;
Ethan Nicholas9e6a3932019-05-17 16:31:21 -04001170 case Expression::kExternalFunctionCall_Kind:
1171 this->writeExternalFunctionCall((ExternalFunctionCall&) e);
1172 break;
Ethan Nicholas91164d12019-05-15 15:29:54 -04001173 case Expression::kExternalValue_Kind:
1174 this->writeExternalValue((ExternalValueReference&) e);
1175 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001176 case Expression::kFieldAccess_Kind:
Brian Osman07c117b2019-05-23 12:51:06 -07001177 case Expression::kIndex_Kind:
1178 case Expression::kVariableReference_Kind:
1179 this->writeVariableExpression(e);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001180 break;
1181 case Expression::kFloatLiteral_Kind:
1182 this->writeFloatLiteral((FloatLiteral&) e);
1183 break;
1184 case Expression::kFunctionCall_Kind:
1185 this->writeFunctionCall((FunctionCall&) e);
1186 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001187 case Expression::kIntLiteral_Kind:
1188 this->writeIntLiteral((IntLiteral&) e);
1189 break;
1190 case Expression::kNullLiteral_Kind:
1191 this->writeNullLiteral((NullLiteral&) e);
1192 break;
1193 case Expression::kPrefix_Kind:
Brian Osman3e29f1d2019-05-28 09:35:05 -04001194 discard = this->writePrefixExpression((PrefixExpression&) e, discard);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001195 break;
1196 case Expression::kPostfix_Kind:
Brian Osman3e29f1d2019-05-28 09:35:05 -04001197 discard = this->writePostfixExpression((PostfixExpression&) e, discard);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001198 break;
1199 case Expression::kSwizzle_Kind:
1200 this->writeSwizzle((Swizzle&) e);
1201 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001202 case Expression::kTernary_Kind:
1203 this->writeTernaryExpression((TernaryExpression&) e);
1204 break;
1205 default:
1206 printf("unsupported expression %s\n", e.description().c_str());
1207 SkASSERT(false);
1208 }
Brian Osman3e29f1d2019-05-28 09:35:05 -04001209 if (discard) {
1210 int count = SlotCount(e.fType);
1211 if (count > 4) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001212 this->write(ByteCodeInstruction::kPopN, count);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001213 this->write8(count);
Brian Osmanfba386b2019-06-20 14:54:15 -04001214 } else if (count != 0) {
Brian Osman3e29f1d2019-05-28 09:35:05 -04001215 this->write(vector_instruction(ByteCodeInstruction::kPop, count));
1216 }
1217 discard = false;
1218 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001219}
1220
Ethan Nicholas91164d12019-05-15 15:29:54 -04001221class ByteCodeExternalValueLValue : public ByteCodeGenerator::LValue {
1222public:
1223 ByteCodeExternalValueLValue(ByteCodeGenerator* generator, ExternalValue& value, int index)
1224 : INHERITED(*generator)
Brian Osman07c117b2019-05-23 12:51:06 -07001225 , fCount(ByteCodeGenerator::SlotCount(value.type()))
Ethan Nicholas91164d12019-05-15 15:29:54 -04001226 , fIndex(index) {}
1227
1228 void load() override {
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001229 fGenerator.write(vector_instruction(ByteCodeInstruction::kReadExternal, fCount));
Ethan Nicholas91164d12019-05-15 15:29:54 -04001230 fGenerator.write8(fIndex);
1231 }
1232
Brian Osman3e29f1d2019-05-28 09:35:05 -04001233 void store(bool discard) override {
1234 if (!discard) {
1235 fGenerator.write(vector_instruction(ByteCodeInstruction::kDup, fCount));
1236 }
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001237 fGenerator.write(vector_instruction(ByteCodeInstruction::kWriteExternal, fCount));
Ethan Nicholas91164d12019-05-15 15:29:54 -04001238 fGenerator.write8(fIndex);
1239 }
1240
1241private:
1242 typedef LValue INHERITED;
1243
1244 int fCount;
1245
1246 int fIndex;
1247};
1248
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001249class ByteCodeSwizzleLValue : public ByteCodeGenerator::LValue {
1250public:
1251 ByteCodeSwizzleLValue(ByteCodeGenerator* generator, const Swizzle& swizzle)
1252 : INHERITED(*generator)
Brian Osman07c117b2019-05-23 12:51:06 -07001253 , fSwizzle(swizzle) {}
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001254
1255 void load() override {
Brian Osman1091f022019-05-16 09:42:16 -04001256 fGenerator.writeSwizzle(fSwizzle);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001257 }
1258
Brian Osman3e29f1d2019-05-28 09:35:05 -04001259 void store(bool discard) override {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001260 int count = fSwizzle.fComponents.size();
Brian Osman3e29f1d2019-05-28 09:35:05 -04001261 if (!discard) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001262 fGenerator.write(vector_instruction(ByteCodeInstruction::kDup, count));
Brian Osman3e29f1d2019-05-28 09:35:05 -04001263 }
Brian Osman869a3e82019-07-18 17:00:34 -04001264 Variable::Storage storage = Variable::kLocal_Storage;
Brian Osman07c117b2019-05-23 12:51:06 -07001265 int location = fGenerator.getLocation(*fSwizzle.fBase, &storage);
1266 bool isGlobal = storage == Variable::kGlobal_Storage;
1267 if (location < 0) {
1268 fGenerator.write(isGlobal ? ByteCodeInstruction::kStoreSwizzleIndirectGlobal
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001269 : ByteCodeInstruction::kStoreSwizzleIndirect,
1270 count);
Brian Osman07c117b2019-05-23 12:51:06 -07001271 } else {
1272 fGenerator.write(isGlobal ? ByteCodeInstruction::kStoreSwizzleGlobal
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001273 : ByteCodeInstruction::kStoreSwizzle,
1274 count);
Brian Osman07c117b2019-05-23 12:51:06 -07001275 fGenerator.write8(location);
1276 }
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001277 fGenerator.write8(count);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001278 for (int c : fSwizzle.fComponents) {
1279 fGenerator.write8(c);
1280 }
1281 }
1282
1283private:
1284 const Swizzle& fSwizzle;
1285
1286 typedef LValue INHERITED;
1287};
1288
Brian Osman07c117b2019-05-23 12:51:06 -07001289class ByteCodeExpressionLValue : public ByteCodeGenerator::LValue {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001290public:
Brian Osman07c117b2019-05-23 12:51:06 -07001291 ByteCodeExpressionLValue(ByteCodeGenerator* generator, const Expression& expr)
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001292 : INHERITED(*generator)
Brian Osman07c117b2019-05-23 12:51:06 -07001293 , fExpression(expr) {}
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001294
1295 void load() override {
Brian Osman07c117b2019-05-23 12:51:06 -07001296 fGenerator.writeVariableExpression(fExpression);
Brian Osman1091f022019-05-16 09:42:16 -04001297 }
1298
Brian Osman3e29f1d2019-05-28 09:35:05 -04001299 void store(bool discard) override {
Brian Osman07c117b2019-05-23 12:51:06 -07001300 int count = ByteCodeGenerator::SlotCount(fExpression.fType);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001301 if (!discard) {
1302 if (count > 4) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001303 fGenerator.write(ByteCodeInstruction::kDupN, count);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001304 fGenerator.write8(count);
1305 } else {
1306 fGenerator.write(vector_instruction(ByteCodeInstruction::kDup, count));
1307 }
Brian Osman07c117b2019-05-23 12:51:06 -07001308 }
Brian Osman869a3e82019-07-18 17:00:34 -04001309 Variable::Storage storage = Variable::kLocal_Storage;
Brian Osman07c117b2019-05-23 12:51:06 -07001310 int location = fGenerator.getLocation(fExpression, &storage);
1311 bool isGlobal = storage == Variable::kGlobal_Storage;
1312 if (location < 0 || count > 4) {
1313 if (location >= 0) {
1314 fGenerator.write(ByteCodeInstruction::kPushImmediate);
1315 fGenerator.write32(location);
1316 }
1317 fGenerator.write(isGlobal ? ByteCodeInstruction::kStoreExtendedGlobal
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001318 : ByteCodeInstruction::kStoreExtended,
1319 count);
Brian Osman07c117b2019-05-23 12:51:06 -07001320 fGenerator.write8(count);
1321 } else {
1322 fGenerator.write(vector_instruction(isGlobal ? ByteCodeInstruction::kStoreGlobal
1323 : ByteCodeInstruction::kStore,
1324 count));
1325 fGenerator.write8(location);
1326 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001327 }
1328
1329private:
1330 typedef LValue INHERITED;
1331
Brian Osman07c117b2019-05-23 12:51:06 -07001332 const Expression& fExpression;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001333};
1334
1335std::unique_ptr<ByteCodeGenerator::LValue> ByteCodeGenerator::getLValue(const Expression& e) {
1336 switch (e.fKind) {
Ethan Nicholas91164d12019-05-15 15:29:54 -04001337 case Expression::kExternalValue_Kind: {
1338 ExternalValue* value = ((ExternalValueReference&) e).fValue;
1339 int index = fOutput->fExternalValues.size();
1340 fOutput->fExternalValues.push_back(value);
1341 SkASSERT(index <= 255);
1342 return std::unique_ptr<LValue>(new ByteCodeExternalValueLValue(this, *value, index));
1343 }
Brian Osman07c117b2019-05-23 12:51:06 -07001344 case Expression::kFieldAccess_Kind:
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001345 case Expression::kIndex_Kind:
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001346 case Expression::kVariableReference_Kind:
Brian Osman07c117b2019-05-23 12:51:06 -07001347 return std::unique_ptr<LValue>(new ByteCodeExpressionLValue(this, e));
Brian Osman0785db02019-05-24 14:19:11 -04001348 case Expression::kSwizzle_Kind: {
1349 const Swizzle& s = (const Swizzle&) e;
1350 return swizzle_is_simple(s)
1351 ? std::unique_ptr<LValue>(new ByteCodeExpressionLValue(this, e))
1352 : std::unique_ptr<LValue>(new ByteCodeSwizzleLValue(this, s));
1353 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001354 case Expression::kTernary_Kind:
1355 default:
1356 printf("unsupported lvalue %s\n", e.description().c_str());
1357 return nullptr;
1358 }
1359}
1360
1361void ByteCodeGenerator::writeBlock(const Block& b) {
1362 for (const auto& s : b.fStatements) {
1363 this->writeStatement(*s);
1364 }
1365}
1366
1367void ByteCodeGenerator::setBreakTargets() {
1368 std::vector<DeferredLocation>& breaks = fBreakTargets.top();
1369 for (DeferredLocation& b : breaks) {
1370 b.set();
1371 }
1372 fBreakTargets.pop();
1373}
1374
1375void ByteCodeGenerator::setContinueTargets() {
1376 std::vector<DeferredLocation>& continues = fContinueTargets.top();
1377 for (DeferredLocation& c : continues) {
1378 c.set();
1379 }
1380 fContinueTargets.pop();
1381}
1382
1383void ByteCodeGenerator::writeBreakStatement(const BreakStatement& b) {
Brian Osman569f12f2019-06-13 11:23:57 -04001384 // TODO: Include BranchIfAllFalse to top-most LoopNext
1385 this->write(ByteCodeInstruction::kLoopBreak);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001386}
1387
1388void ByteCodeGenerator::writeContinueStatement(const ContinueStatement& c) {
Brian Osman569f12f2019-06-13 11:23:57 -04001389 // TODO: Include BranchIfAllFalse to top-most LoopNext
1390 this->write(ByteCodeInstruction::kLoopContinue);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001391}
1392
1393void ByteCodeGenerator::writeDoStatement(const DoStatement& d) {
Brian Osman569f12f2019-06-13 11:23:57 -04001394 this->write(ByteCodeInstruction::kLoopBegin);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001395 size_t start = fCode->size();
1396 this->writeStatement(*d.fStatement);
Brian Osman569f12f2019-06-13 11:23:57 -04001397 this->write(ByteCodeInstruction::kLoopNext);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001398 this->writeExpression(*d.fTest);
Brian Osman569f12f2019-06-13 11:23:57 -04001399 this->write(ByteCodeInstruction::kLoopMask);
1400 // TODO: Could shorten this with kBranchIfAnyTrue
1401 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1402 DeferredLocation endLocation(this);
1403 this->write(ByteCodeInstruction::kBranch);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001404 this->write16(start);
Brian Osman569f12f2019-06-13 11:23:57 -04001405 endLocation.set();
1406 this->write(ByteCodeInstruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001407}
1408
1409void ByteCodeGenerator::writeForStatement(const ForStatement& f) {
1410 fContinueTargets.emplace();
1411 fBreakTargets.emplace();
1412 if (f.fInitializer) {
1413 this->writeStatement(*f.fInitializer);
1414 }
Brian Osman569f12f2019-06-13 11:23:57 -04001415 this->write(ByteCodeInstruction::kLoopBegin);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001416 size_t start = fCode->size();
1417 if (f.fTest) {
1418 this->writeExpression(*f.fTest);
Brian Osman569f12f2019-06-13 11:23:57 -04001419 this->write(ByteCodeInstruction::kLoopMask);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001420 }
Brian Osman569f12f2019-06-13 11:23:57 -04001421 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1422 DeferredLocation endLocation(this);
1423 this->writeStatement(*f.fStatement);
1424 this->write(ByteCodeInstruction::kLoopNext);
1425 if (f.fNext) {
1426 this->writeExpression(*f.fNext, true);
1427 }
1428 this->write(ByteCodeInstruction::kBranch);
1429 this->write16(start);
1430 endLocation.set();
1431 this->write(ByteCodeInstruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001432}
1433
1434void ByteCodeGenerator::writeIfStatement(const IfStatement& i) {
Brian Osman569f12f2019-06-13 11:23:57 -04001435 this->writeExpression(*i.fTest);
1436 this->write(ByteCodeInstruction::kMaskPush);
1437 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1438 DeferredLocation falseLocation(this);
1439 this->writeStatement(*i.fIfTrue);
1440 falseLocation.set();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001441 if (i.fIfFalse) {
Brian Osman569f12f2019-06-13 11:23:57 -04001442 this->write(ByteCodeInstruction::kMaskNegate);
1443 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1444 DeferredLocation endLocation(this);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001445 this->writeStatement(*i.fIfFalse);
Mike Kleinb45ee832019-05-17 11:11:11 -05001446 endLocation.set();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001447 }
Brian Osman569f12f2019-06-13 11:23:57 -04001448 this->write(ByteCodeInstruction::kMaskPop);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001449}
1450
1451void ByteCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
Brian Osman4a47da72019-07-12 11:30:32 -04001452 if (fLoopCount || fConditionCount) {
1453 fErrors.error(r.fOffset, "return not allowed inside conditional or loop");
1454 return;
1455 }
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001456 int count = SlotCount(r.fExpression->fType);
Ethan Nicholas746035a2019-04-23 13:31:09 -04001457 this->writeExpression(*r.fExpression);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001458
1459 // Technically, the kReturn also pops fOutput->fLocalCount values from the stack, too, but we
1460 // haven't counted pushing those (they're outside the scope of our stack tracking). Instead,
1461 // we account for those in writeFunction().
1462
1463 // This is all fine because we don't allow conditional returns, so we only return once anyway.
1464 this->write(ByteCodeInstruction::kReturn, -count);
1465 this->write8(count);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001466}
1467
1468void ByteCodeGenerator::writeSwitchStatement(const SwitchStatement& r) {
1469 // not yet implemented
1470 abort();
1471}
1472
1473void ByteCodeGenerator::writeVarDeclarations(const VarDeclarations& v) {
1474 for (const auto& declStatement : v.fVars) {
1475 const VarDeclaration& decl = (VarDeclaration&) *declStatement;
1476 // we need to grab the location even if we don't use it, to ensure it
1477 // has been allocated
1478 int location = getLocation(*decl.fVar);
1479 if (decl.fValue) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001480 this->writeExpression(*decl.fValue);
Brian Osman07c117b2019-05-23 12:51:06 -07001481 int count = SlotCount(decl.fValue->fType);
1482 if (count > 4) {
1483 this->write(ByteCodeInstruction::kPushImmediate);
1484 this->write32(location);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001485 this->write(ByteCodeInstruction::kStoreExtended, count);
Brian Osman07c117b2019-05-23 12:51:06 -07001486 this->write8(count);
1487 } else {
1488 this->write(vector_instruction(ByteCodeInstruction::kStore, count));
1489 this->write8(location);
1490 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001491 }
1492 }
1493}
1494
1495void ByteCodeGenerator::writeWhileStatement(const WhileStatement& w) {
Brian Osman569f12f2019-06-13 11:23:57 -04001496 this->write(ByteCodeInstruction::kLoopBegin);
1497 size_t cond = fCode->size();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001498 this->writeExpression(*w.fTest);
Brian Osman569f12f2019-06-13 11:23:57 -04001499 this->write(ByteCodeInstruction::kLoopMask);
1500 this->write(ByteCodeInstruction::kBranchIfAllFalse);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001501 DeferredLocation endLocation(this);
1502 this->writeStatement(*w.fStatement);
Brian Osman569f12f2019-06-13 11:23:57 -04001503 this->write(ByteCodeInstruction::kLoopNext);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001504 this->write(ByteCodeInstruction::kBranch);
Brian Osman569f12f2019-06-13 11:23:57 -04001505 this->write16(cond);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001506 endLocation.set();
Brian Osman569f12f2019-06-13 11:23:57 -04001507 this->write(ByteCodeInstruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001508}
1509
1510void ByteCodeGenerator::writeStatement(const Statement& s) {
1511 switch (s.fKind) {
1512 case Statement::kBlock_Kind:
1513 this->writeBlock((Block&) s);
1514 break;
1515 case Statement::kBreak_Kind:
1516 this->writeBreakStatement((BreakStatement&) s);
1517 break;
1518 case Statement::kContinue_Kind:
1519 this->writeContinueStatement((ContinueStatement&) s);
1520 break;
1521 case Statement::kDiscard_Kind:
1522 // not yet implemented
1523 abort();
1524 case Statement::kDo_Kind:
1525 this->writeDoStatement((DoStatement&) s);
1526 break;
Brian Osman3e29f1d2019-05-28 09:35:05 -04001527 case Statement::kExpression_Kind:
1528 this->writeExpression(*((ExpressionStatement&) s).fExpression, true);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001529 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001530 case Statement::kFor_Kind:
1531 this->writeForStatement((ForStatement&) s);
1532 break;
1533 case Statement::kIf_Kind:
1534 this->writeIfStatement((IfStatement&) s);
1535 break;
1536 case Statement::kNop_Kind:
1537 break;
1538 case Statement::kReturn_Kind:
1539 this->writeReturnStatement((ReturnStatement&) s);
1540 break;
1541 case Statement::kSwitch_Kind:
1542 this->writeSwitchStatement((SwitchStatement&) s);
1543 break;
1544 case Statement::kVarDeclarations_Kind:
1545 this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration);
1546 break;
1547 case Statement::kWhile_Kind:
1548 this->writeWhileStatement((WhileStatement&) s);
1549 break;
1550 default:
1551 SkASSERT(false);
1552 }
1553}
1554
Brian Osman80164412019-06-07 13:00:23 -04001555ByteCodeFunction::ByteCodeFunction(const FunctionDeclaration* declaration)
1556 : fName(declaration->fName) {
1557 fParameterCount = 0;
1558 for (const auto& p : declaration->fParameters) {
1559 int slots = ByteCodeGenerator::SlotCount(p->fType);
1560 fParameters.push_back({ slots, (bool)(p->fModifiers.fFlags & Modifiers::kOut_Flag) });
1561 fParameterCount += slots;
1562 }
1563}
1564
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001565}