1/*
2 * Copyright 2019 Google LLC
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "src/sksl/SkSLByteCodeGenerator.h"
9
10#include <algorithm>
11
12namespace SkSL {
13
14static TypeCategory type_category(const Type& type) {
15 switch (type.kind()) {
16 case Type::Kind::kVector_Kind:
17 case Type::Kind::kMatrix_Kind:
18 return type_category(type.componentType());
19 default:
20 if (type.fName == "bool") {
21 return TypeCategory::kBool;
22 } else if (type.fName == "int" ||
23 type.fName == "short" ||
24 type.fName == "$intLiteral") {
25 return TypeCategory::kSigned;
26 } else if (type.fName == "uint" ||
27 type.fName == "ushort") {
28 return TypeCategory::kUnsigned;
29 } else {
30 SkASSERT(type.fName == "float" ||
31 type.fName == "half" ||
32 type.fName == "$floatLiteral");
33 return TypeCategory::kFloat;
34 }
35 ABORT("unsupported type: %s\n", type.displayName().c_str());
36 }
37}
38
39
40ByteCodeGenerator::ByteCodeGenerator(const Context* context, const Program* program, ErrorReporter* errors,
41 ByteCode* output)
42 : INHERITED(program, errors, nullptr)
43 , fContext(*context)
44 , fOutput(output)
45 // If you're adding new intrinsics here, ensure that they're declared in sksl_interp.inc, so
46 // they're available to "generic" interpreter programs (eg particles).
47 // You can probably copy the declarations from sksl_gpu.inc.
48 , fIntrinsics {
49 { "atan", ByteCodeInstruction::kATan },
50 { "ceil", ByteCodeInstruction::kCeil },
51 { "clamp", SpecialIntrinsic::kClamp },
52 { "cos", ByteCodeInstruction::kCos },
53 { "dot", SpecialIntrinsic::kDot },
54 { "floor", ByteCodeInstruction::kFloor },
55 { "fract", ByteCodeInstruction::kFract },
56 { "inverse", ByteCodeInstruction::kInverse2x2 },
57 { "length", SpecialIntrinsic::kLength },
58 { "max", SpecialIntrinsic::kMax },
59 { "min", SpecialIntrinsic::kMin },
60 { "mix", SpecialIntrinsic::kMix },
61 { "normalize", SpecialIntrinsic::kNormalize },
62 { "pow", ByteCodeInstruction::kPow },
63 { "sample", SpecialIntrinsic::kSample },
64 { "saturate", SpecialIntrinsic::kSaturate },
65 { "sin", ByteCodeInstruction::kSin },
66 { "sqrt", ByteCodeInstruction::kSqrt },
67 { "tan", ByteCodeInstruction::kTan },
68
69 { "lessThan", { ByteCodeInstruction::kCompareFLT,
70 ByteCodeInstruction::kCompareSLT,
71 ByteCodeInstruction::kCompareULT } },
72 { "lessThanEqual", { ByteCodeInstruction::kCompareFLTEQ,
73 ByteCodeInstruction::kCompareSLTEQ,
74 ByteCodeInstruction::kCompareULTEQ } },
75 { "greaterThan", { ByteCodeInstruction::kCompareFGT,
76 ByteCodeInstruction::kCompareSGT,
77 ByteCodeInstruction::kCompareUGT } },
78 { "greaterThanEqual", { ByteCodeInstruction::kCompareFGTEQ,
79 ByteCodeInstruction::kCompareSGTEQ,
80 ByteCodeInstruction::kCompareUGTEQ } },
81 { "equal", { ByteCodeInstruction::kCompareFEQ,
82 ByteCodeInstruction::kCompareIEQ,
83 ByteCodeInstruction::kCompareIEQ } },
84 { "notEqual", { ByteCodeInstruction::kCompareFNEQ,
85 ByteCodeInstruction::kCompareINEQ,
86 ByteCodeInstruction::kCompareINEQ } },
87
88 { "any", SpecialIntrinsic::kAny },
89 { "all", SpecialIntrinsic::kAll },
90 { "not", ByteCodeInstruction::kNotB },
91 } {}
92
93
94int ByteCodeGenerator::SlotCount(const Type& type) {
95 if (type.kind() == Type::kOther_Kind) {
96 return 0;
97 } else if (type.kind() == Type::kStruct_Kind) {
98 int slots = 0;
99 for (const auto& f : type.fields()) {
100 slots += SlotCount(*f.fType);
101 }
102 SkASSERT(slots <= 255);
103 return slots;
104 } else if (type.kind() == Type::kArray_Kind) {
105 int columns = type.columns();
106 SkASSERT(columns >= 0);
107 int slots = columns * SlotCount(type.componentType());
108 SkASSERT(slots <= 255);
109 return slots;
110 } else {
111 return type.columns() * type.rows();
112 }
113}
114
115static inline bool is_uniform(const SkSL::Variable& var) {
116 return var.fModifiers.fFlags & Modifiers::kUniform_Flag;
117}
118
119static inline bool is_in(const SkSL::Variable& var) {
120 return var.fModifiers.fFlags & Modifiers::kIn_Flag;
121}
122
123void ByteCodeGenerator::gatherUniforms(const Type& type, const String& name) {
124 if (type.kind() == Type::kOther_Kind) {
125 return;
126 } else if (type.kind() == Type::kStruct_Kind) {
127 for (const auto& f : type.fields()) {
128 this->gatherUniforms(*f.fType, name + "." + f.fName);
129 }
130 } else if (type.kind() == Type::kArray_Kind) {
131 for (int i = 0; i < type.columns(); ++i) {
132 this->gatherUniforms(type.componentType(), String::printf("%s[%d]", name.c_str(), i));
133 }
134 } else {
135 fOutput->fUniforms.push_back({ name, type_category(type), type.rows(), type.columns(),
136 fOutput->fUniformSlotCount });
137 fOutput->fUniformSlotCount += type.columns() * type.rows();
138 }
139}
140
141bool ByteCodeGenerator::generateCode() {
142 for (const auto& e : fProgram) {
143 switch (e.fKind) {
144 case ProgramElement::kFunction_Kind: {
145 std::unique_ptr<ByteCodeFunction> f = this->writeFunction((FunctionDefinition&) e);
146 if (!f) {
147 return false;
148 }
149 fOutput->fFunctions.push_back(std::move(f));
150 fFunctions.push_back(&(FunctionDefinition&)e);
151 break;
152 }
153 case ProgramElement::kVar_Kind: {
154 VarDeclarations& decl = (VarDeclarations&) e;
155 for (const auto& v : decl.fVars) {
156 const Variable* declVar = ((VarDeclaration&) *v).fVar;
157 if (declVar->fType == *fContext.fFragmentProcessor_Type) {
158 fOutput->fChildFPCount++;
159 }
160 if (declVar->fModifiers.fLayout.fBuiltin >= 0 || is_in(*declVar)) {
161 continue;
162 }
163 if (is_uniform(*declVar)) {
164 this->gatherUniforms(declVar->fType, declVar->fName);
165 } else {
166 fOutput->fGlobalSlotCount += SlotCount(declVar->fType);
167 }
168 }
169 break;
170 }
171 default:
172 ; // ignore
173 }
174 }
175 return 0 == fErrors.errorCount();
176}
177
178std::unique_ptr<ByteCodeFunction> ByteCodeGenerator::writeFunction(const FunctionDefinition& f) {
179 fFunction = &f;
180 std::unique_ptr<ByteCodeFunction> result(new ByteCodeFunction(&f.fDeclaration));
181 fParameterCount = result->fParameterCount;
182 fLoopCount = fMaxLoopCount = 0;
183 fConditionCount = fMaxConditionCount = 0;
184 fStackCount = fMaxStackCount = 0;
185 fCode = &result->fCode;
186
187 this->writeStatement(*f.fBody);
188 if (0 == fErrors.errorCount()) {
189 SkASSERT(fLoopCount == 0);
190 SkASSERT(fConditionCount == 0);
191 SkASSERT(fStackCount == 0);
192 }
193 this->write(ByteCodeInstruction::kReturn, 0);
194
195 result->fLocalCount = fLocals.size();
196 result->fConditionCount = fMaxConditionCount;
197 result->fLoopCount = fMaxLoopCount;
198 result->fStackCount = fMaxStackCount;
199
200 const Type& returnType = f.fDeclaration.fReturnType;
201 if (returnType != *fContext.fVoid_Type) {
202 result->fReturnCount = SlotCount(returnType);
203 }
204 fLocals.clear();
205 fFunction = nullptr;
206 return result;
207}
208
209// If the expression is a reference to a builtin global variable, return the builtin ID.
210// Otherwise, return -1.
211static int expression_as_builtin(const Expression& e) {
212 if (e.fKind == Expression::kVariableReference_Kind) {
213 const Variable& var(((VariableReference&)e).fVariable);
214 if (var.fStorage == Variable::kGlobal_Storage) {
215 return var.fModifiers.fLayout.fBuiltin;
216 }
217 }
218 return -1;
219}
220
221// A "simple" Swizzle is based on a variable (or a compound variable like a struct or array), and
222// that references consecutive values, such that it can be implemented using normal load/store ops
223// with an offset. Note that all single-component swizzles (of suitable base types) are simple.
224static bool swizzle_is_simple(const Swizzle& s) {
225 // Builtin variables use dedicated instructions that don't allow subset loads
226 if (expression_as_builtin(*s.fBase) >= 0) {
227 return false;
228 }
229
230 switch (s.fBase->fKind) {
231 case Expression::kFieldAccess_Kind:
232 case Expression::kIndex_Kind:
233 case Expression::kVariableReference_Kind:
234 break;
235 default:
236 return false;
237 }
238
239 for (size_t i = 1; i < s.fComponents.size(); ++i) {
240 if (s.fComponents[i] != s.fComponents[i - 1] + 1) {
241 return false;
242 }
243 }
244 return true;
245}
246
247int ByteCodeGenerator::StackUsage(ByteCodeInstruction inst, int count_) {
248 // Ensures that we use count iff we're passed a non-default value. Most instructions have an
249 // implicit count, so the caller shouldn't need to worry about it (or count makes no sense).
250 // The asserts avoids callers thinking they're supplying useful information in that scenario,
251 // or failing to supply necessary information for the ops that need a count.
252 struct CountValue {
253 operator int() {
254 SkASSERT(val != ByteCodeGenerator::kUnusedStackCount);
255 SkDEBUGCODE(used = true);
256 return val;
257 }
258 ~CountValue() {
259 SkASSERT(used || val == ByteCodeGenerator::kUnusedStackCount);
260 }
261 int val;
262 SkDEBUGCODE(bool used = false;)
263 } count = { count_ };
264
265 switch (inst) {
266 // Unary functions/operators that don't change stack depth at all:
267
268#define VEC_UNARY(inst) case ByteCodeInstruction::inst: return count - count;
269
270 VEC_UNARY(kConvertFtoI)
271 VEC_UNARY(kConvertStoF)
272 VEC_UNARY(kConvertUtoF)
273
274 VEC_UNARY(kATan)
275 VEC_UNARY(kCeil)
276 VEC_UNARY(kCos)
277 VEC_UNARY(kFloor)
278 VEC_UNARY(kFract)
279 VEC_UNARY(kSin)
280 VEC_UNARY(kSqrt)
281 VEC_UNARY(kTan)
282
283 VEC_UNARY(kNegateF)
284 VEC_UNARY(kNegateI)
285 VEC_UNARY(kNotB)
286
287#undef VEC_UNARY
288
289 case ByteCodeInstruction::kInverse2x2:
290 case ByteCodeInstruction::kInverse3x3:
291 case ByteCodeInstruction::kInverse4x4: return 0;
292
293 case ByteCodeInstruction::kClampIndex: return 0;
294 case ByteCodeInstruction::kShiftLeft: return 0;
295 case ByteCodeInstruction::kShiftRightS: return 0;
296 case ByteCodeInstruction::kShiftRightU: return 0;
297
298 // Binary functions/operators that do a 2 -> 1 reduction, N times
299 case ByteCodeInstruction::kAndB: return -count;
300 case ByteCodeInstruction::kOrB: return -count;
301 case ByteCodeInstruction::kXorB: return -count;
302
303 case ByteCodeInstruction::kAddI: return -count;
304 case ByteCodeInstruction::kAddF: return -count;
305
306 case ByteCodeInstruction::kCompareIEQ: return -count;
307 case ByteCodeInstruction::kCompareFEQ: return -count;
308 case ByteCodeInstruction::kCompareINEQ: return -count;
309 case ByteCodeInstruction::kCompareFNEQ: return -count;
310 case ByteCodeInstruction::kCompareSGT: return -count;
311 case ByteCodeInstruction::kCompareUGT: return -count;
312 case ByteCodeInstruction::kCompareFGT: return -count;
313 case ByteCodeInstruction::kCompareSGTEQ: return -count;
314 case ByteCodeInstruction::kCompareUGTEQ: return -count;
315 case ByteCodeInstruction::kCompareFGTEQ: return -count;
316 case ByteCodeInstruction::kCompareSLT: return -count;
317 case ByteCodeInstruction::kCompareULT: return -count;
318 case ByteCodeInstruction::kCompareFLT: return -count;
319 case ByteCodeInstruction::kCompareSLTEQ: return -count;
320 case ByteCodeInstruction::kCompareULTEQ: return -count;
321 case ByteCodeInstruction::kCompareFLTEQ: return -count;
322
323 case ByteCodeInstruction::kDivideS: return -count;
324 case ByteCodeInstruction::kDivideU: return -count;
325 case ByteCodeInstruction::kDivideF: return -count;
326 case ByteCodeInstruction::kMaxF: return -count;
327 case ByteCodeInstruction::kMaxS: return -count;
328 case ByteCodeInstruction::kMinF: return -count;
329 case ByteCodeInstruction::kMinS: return -count;
330 case ByteCodeInstruction::kMultiplyI: return -count;
331 case ByteCodeInstruction::kMultiplyF: return -count;
332 case ByteCodeInstruction::kPow: return -count;
333 case ByteCodeInstruction::kRemainderF: return -count;
334 case ByteCodeInstruction::kRemainderS: return -count;
335 case ByteCodeInstruction::kRemainderU: return -count;
336 case ByteCodeInstruction::kSubtractI: return -count;
337 case ByteCodeInstruction::kSubtractF: return -count;
338
339 // Ops that push or load data to grow the stack:
340 case ByteCodeInstruction::kPushImmediate:
341 return 1;
342 case ByteCodeInstruction::kLoadFragCoord:
343 return 4;
344
345 case ByteCodeInstruction::kDup:
346 case ByteCodeInstruction::kLoad:
347 case ByteCodeInstruction::kLoadGlobal:
348 case ByteCodeInstruction::kLoadUniform:
349 case ByteCodeInstruction::kReadExternal:
350 case ByteCodeInstruction::kReserve:
351 return count;
352
353 // Pushes 'count' values, minus one for the 'address' that's consumed first
354 case ByteCodeInstruction::kLoadExtended:
355 case ByteCodeInstruction::kLoadExtendedGlobal:
356 case ByteCodeInstruction::kLoadExtendedUniform:
357 return count - 1;
358
359 // Ops that pop or store data to shrink the stack:
360 case ByteCodeInstruction::kPop:
361 case ByteCodeInstruction::kReturn:
362 case ByteCodeInstruction::kStore:
363 case ByteCodeInstruction::kStoreGlobal:
364 case ByteCodeInstruction::kWriteExternal:
365 return -count;
366
367 // Consumes 'count' values, plus one for the 'address'
368 case ByteCodeInstruction::kStoreExtended:
369 case ByteCodeInstruction::kStoreExtendedGlobal:
370 return -count - 1;
371
372 // Strange ops where the caller computes the delta for us:
373 case ByteCodeInstruction::kCallExternal:
374 case ByteCodeInstruction::kMatrixToMatrix:
375 case ByteCodeInstruction::kMatrixMultiply:
376 case ByteCodeInstruction::kScalarToMatrix:
377 case ByteCodeInstruction::kSwizzle:
378 return count;
379
380 // Miscellaneous
381
382 // () -> (R, G, B, A)
383 case ByteCodeInstruction::kSample: return 4;
384 // (X, Y) -> (R, G, B, A)
385 case ByteCodeInstruction::kSampleExplicit: return 4 - 2;
386 // (float3x3) -> (R, G, B, A)
387 case ByteCodeInstruction::kSampleMatrix: return 4 - 9;
388
389 // kMix does a 3 -> 1 reduction (A, B, M -> A -or- B) for each component
390 case ByteCodeInstruction::kMix: return -(2 * count);
391
392 // kLerp works the same way (producing lerp(A, B, T) for each component)
393 case ByteCodeInstruction::kLerp: return -(2 * count);
394
395 // kCall is net-zero. Max stack depth is adjusted in writeFunctionCall.
396 case ByteCodeInstruction::kCall: return 0;
397 case ByteCodeInstruction::kBranch: return 0;
398 case ByteCodeInstruction::kBranchIfAllFalse: return 0;
399
400 case ByteCodeInstruction::kMaskPush: return -1;
401 case ByteCodeInstruction::kMaskPop: return 0;
402 case ByteCodeInstruction::kMaskNegate: return 0;
403 case ByteCodeInstruction::kMaskBlend: return -count;
404
405 case ByteCodeInstruction::kLoopBegin: return 0;
406 case ByteCodeInstruction::kLoopNext: return 0;
407 case ByteCodeInstruction::kLoopMask: return -1;
408 case ByteCodeInstruction::kLoopEnd: return 0;
409 case ByteCodeInstruction::kLoopBreak: return 0;
410 case ByteCodeInstruction::kLoopContinue: return 0;
411 }
412
413 SkUNREACHABLE;
414}
415
416ByteCodeGenerator::Location ByteCodeGenerator::getLocation(const Variable& var) {
417 // given that we seldom have more than a couple of variables, linear search is probably the most
418 // efficient way to handle lookups
419 switch (var.fStorage) {
420 case Variable::kLocal_Storage: {
421 for (int i = fLocals.size() - 1; i >= 0; --i) {
422 if (fLocals[i] == &var) {
423 SkASSERT(fParameterCount + i <= 255);
424 return { fParameterCount + i, Storage::kLocal };
425 }
426 }
427 int result = fParameterCount + fLocals.size();
428 fLocals.push_back(&var);
429 for (int i = 0; i < SlotCount(var.fType) - 1; ++i) {
430 fLocals.push_back(nullptr);
431 }
432 SkASSERT(result <= 255);
433 return { result, Storage::kLocal };
434 }
435 case Variable::kParameter_Storage: {
436 int offset = 0;
437 for (const auto& p : fFunction->fDeclaration.fParameters) {
438 if (p == &var) {
439 SkASSERT(offset <= 255);
440 return { offset, Storage::kLocal };
441 }
442 offset += SlotCount(p->fType);
443 }
444 SkASSERT(false);
445 return Location::MakeInvalid();
446 }
447 case Variable::kGlobal_Storage: {
448 if (var.fType == *fContext.fFragmentProcessor_Type) {
449 int offset = 0;
450 for (const auto& e : fProgram) {
451 if (e.fKind == ProgramElement::kVar_Kind) {
452 VarDeclarations& decl = (VarDeclarations&) e;
453 for (const auto& v : decl.fVars) {
454 const Variable* declVar = ((VarDeclaration&) *v).fVar;
455 if (declVar->fType != *fContext.fFragmentProcessor_Type) {
456 continue;
457 }
458 if (declVar == &var) {
459 SkASSERT(offset <= 255);
460 return { offset, Storage::kChildFP };
461 }
462 offset++;
463 }
464 }
465 }
466 SkASSERT(false);
467 return Location::MakeInvalid();
468 }
469 if (is_in(var)) {
470 // If you see this error, it means the program is using raw 'in' variables. You
471 // should either specialize the program (Compiler::specialize) to bake in the final
472 // values of the 'in' variables, or not use 'in' variables (maybe you meant to use
473 // 'uniform' instead?).
474 fErrors.error(var.fOffset,
475 "'in' variable is not specialized or has unsupported type");
476 return Location::MakeInvalid();
477 }
478 int offset = 0;
479 bool isUniform = is_uniform(var);
480 for (const auto& e : fProgram) {
481 if (e.fKind == ProgramElement::kVar_Kind) {
482 VarDeclarations& decl = (VarDeclarations&) e;
483 for (const auto& v : decl.fVars) {
484 const Variable* declVar = ((VarDeclaration&) *v).fVar;
485 if (declVar->fModifiers.fLayout.fBuiltin >= 0 || is_in(*declVar)) {
486 continue;
487 }
488 if (isUniform != is_uniform(*declVar)) {
489 continue;
490 }
491 if (declVar == &var) {
492 SkASSERT(offset <= 255);
493 return { offset, isUniform ? Storage::kUniform : Storage::kGlobal };
494 }
495 offset += SlotCount(declVar->fType);
496 }
497 }
498 }
499 SkASSERT(false);
500 return Location::MakeInvalid();
501 }
502 default:
503 SkASSERT(false);
504 return Location::MakeInvalid();
505 }
506}
507
508ByteCodeGenerator::Location ByteCodeGenerator::getLocation(const Expression& expr) {
509 switch (expr.fKind) {
510 case Expression::kFieldAccess_Kind: {
511 const FieldAccess& f = (const FieldAccess&)expr;
512 Location baseLoc = this->getLocation(*f.fBase);
513 int offset = 0;
514 for (int i = 0; i < f.fFieldIndex; ++i) {
515 offset += SlotCount(*f.fBase->fType.fields()[i].fType);
516 }
517 if (baseLoc.isOnStack()) {
518 if (offset != 0) {
519 this->write(ByteCodeInstruction::kPushImmediate);
520 this->write32(offset);
521 this->write(ByteCodeInstruction::kAddI, 1);
522 }
523 return baseLoc;
524 } else {
525 return baseLoc + offset;
526 }
527 }
528 case Expression::kIndex_Kind: {
529 const IndexExpression& i = (const IndexExpression&)expr;
530 int stride = SlotCount(i.fType);
531 int length = i.fBase->fType.columns();
532 SkASSERT(length <= 255);
533 int offset = -1;
534 if (i.fIndex->isCompileTimeConstant()) {
535 int64_t index = i.fIndex->getConstantInt();
536 if (index < 0 || index >= length) {
537 fErrors.error(i.fIndex->fOffset, "Array index out of bounds.");
538 return Location::MakeInvalid();
539 }
540 offset = index * stride;
541 } else {
542 if (i.fIndex->hasSideEffects()) {
543 // Having a side-effect in an indexer is technically safe for an rvalue,
544 // but with lvalues we have to evaluate the indexer twice, so make it an error.
545 fErrors.error(i.fIndex->fOffset,
546 "Index expressions with side-effects not supported in byte code.");
547 return Location::MakeInvalid();
548 }
549 this->writeExpression(*i.fIndex);
550 this->write(ByteCodeInstruction::kClampIndex);
551 this->write8(length);
552 if (stride != 1) {
553 this->write(ByteCodeInstruction::kPushImmediate);
554 this->write32(stride);
555 this->write(ByteCodeInstruction::kMultiplyI, 1);
556 }
557 }
558 Location baseLoc = this->getLocation(*i.fBase);
559
560 // Are both components known statically?
561 if (!baseLoc.isOnStack() && offset >= 0) {
562 return baseLoc + offset;
563 }
564
565 // At least one component is dynamic (and on the stack).
566
567 // If the other component is zero, we're done
568 if (baseLoc.fSlot == 0 || offset == 0) {
569 return baseLoc.makeOnStack();
570 }
571
572 // Push the non-dynamic component (if any) to the stack, then add the two
573 if (!baseLoc.isOnStack()) {
574 this->write(ByteCodeInstruction::kPushImmediate);
575 this->write32(baseLoc.fSlot);
576 }
577 if (offset >= 0) {
578 this->write(ByteCodeInstruction::kPushImmediate);
579 this->write32(offset);
580 }
581 this->write(ByteCodeInstruction::kAddI, 1);
582 return baseLoc.makeOnStack();
583 }
584 case Expression::kSwizzle_Kind: {
585 const Swizzle& s = (const Swizzle&)expr;
586 SkASSERT(swizzle_is_simple(s));
587 Location baseLoc = this->getLocation(*s.fBase);
588 int offset = s.fComponents[0];
589 if (baseLoc.isOnStack()) {
590 if (offset != 0) {
591 this->write(ByteCodeInstruction::kPushImmediate);
592 this->write32(offset);
593 this->write(ByteCodeInstruction::kAddI, 1);
594 }
595 return baseLoc;
596 } else {
597 return baseLoc + offset;
598 }
599 }
600 case Expression::kVariableReference_Kind: {
601 const Variable& var = ((const VariableReference&)expr).fVariable;
602 return this->getLocation(var);
603 }
604 default:
605 SkASSERT(false);
606 return Location::MakeInvalid();
607 }
608}
609
610void ByteCodeGenerator::write8(uint8_t b) {
611 fCode->push_back(b);
612}
613
614void ByteCodeGenerator::write16(uint16_t i) {
615 size_t n = fCode->size();
616 fCode->resize(n+2);
617 memcpy(fCode->data() + n, &i, 2);
618}
619
620void ByteCodeGenerator::write32(uint32_t i) {
621 size_t n = fCode->size();
622 fCode->resize(n+4);
623 memcpy(fCode->data() + n, &i, 4);
624}
625
626void ByteCodeGenerator::write(ByteCodeInstruction i, int count) {
627 switch (i) {
628 case ByteCodeInstruction::kLoopBegin: this->enterLoop(); break;
629 case ByteCodeInstruction::kLoopEnd: this->exitLoop(); break;
630
631 case ByteCodeInstruction::kMaskPush: this->enterCondition(); break;
632 case ByteCodeInstruction::kMaskPop:
633 case ByteCodeInstruction::kMaskBlend: this->exitCondition(); break;
634 default: /* Do nothing */ break;
635 }
636 this->write8((uint8_t)i);
637 fStackCount += StackUsage(i, count);
638 fMaxStackCount = std::max(fMaxStackCount, fStackCount);
639
640 // Most ops have an explicit count byte after them (passed here as 'count')
641 // Ops that don't have a count byte pass the default (kUnusedStackCount)
642 // There are a handful of strange ops that pass in a computed stack delta as count, but where
643 // that value should *not* be written as a count byte (it may even be negative!)
644 if (count != kUnusedStackCount) {
645 switch (i) {
646 // Odd instructions that have a non-default count, but we shouldn't write it
647 case ByteCodeInstruction::kCallExternal:
648 case ByteCodeInstruction::kMatrixToMatrix:
649 case ByteCodeInstruction::kMatrixMultiply:
650 case ByteCodeInstruction::kScalarToMatrix:
651 case ByteCodeInstruction::kSwizzle:
652 break;
653 default:
654 this->write8(count);
655 break;
656 }
657 }
658}
659
660void ByteCodeGenerator::writeTypedInstruction(const Type& type,
661 ByteCodeInstruction s,
662 ByteCodeInstruction u,
663 ByteCodeInstruction f,
664 int count) {
665 switch (type_category(type)) {
666 case TypeCategory::kBool:
667 case TypeCategory::kSigned: this->write(s, count); break;
668 case TypeCategory::kUnsigned: this->write(u, count); break;
669 case TypeCategory::kFloat: this->write(f, count); break;
670 default:
671 SkASSERT(false);
672 }
673}
674
675bool ByteCodeGenerator::writeBinaryExpression(const BinaryExpression& b, bool discard) {
676 if (b.fOperator == Token::Kind::TK_EQ) {
677 std::unique_ptr<LValue> lvalue = this->getLValue(*b.fLeft);
678 this->writeExpression(*b.fRight);
679 lvalue->store(discard);
680 discard = false;
681 return discard;
682 }
683 const Type& lType = b.fLeft->fType;
684 const Type& rType = b.fRight->fType;
685 bool lVecOrMtx = (lType.kind() == Type::kVector_Kind || lType.kind() == Type::kMatrix_Kind);
686 bool rVecOrMtx = (rType.kind() == Type::kVector_Kind || rType.kind() == Type::kMatrix_Kind);
687 Token::Kind op;
688 std::unique_ptr<LValue> lvalue;
689 if (is_assignment(b.fOperator)) {
690 lvalue = this->getLValue(*b.fLeft);
691 lvalue->load();
692 op = remove_assignment(b.fOperator);
693 } else {
694 this->writeExpression(*b.fLeft);
695 op = b.fOperator;
696 if (!lVecOrMtx && rVecOrMtx) {
697 for (int i = SlotCount(rType); i > 1; --i) {
698 this->write(ByteCodeInstruction::kDup, 1);
699 }
700 }
701 }
702 int count = std::max(SlotCount(lType), SlotCount(rType));
703 SkDEBUGCODE(TypeCategory tc = type_category(lType));
704 switch (op) {
705 case Token::Kind::TK_LOGICALAND: {
706 SkASSERT(tc == SkSL::TypeCategory::kBool && count == 1);
707 this->write(ByteCodeInstruction::kDup, 1);
708 this->write(ByteCodeInstruction::kMaskPush);
709 this->write(ByteCodeInstruction::kBranchIfAllFalse);
710 DeferredLocation falseLocation(this);
711 this->writeExpression(*b.fRight);
712 this->write(ByteCodeInstruction::kAndB, 1);
713 falseLocation.set();
714 this->write(ByteCodeInstruction::kMaskPop);
715 return false;
716 }
717 case Token::Kind::TK_LOGICALOR: {
718 SkASSERT(tc == SkSL::TypeCategory::kBool && count == 1);
719 this->write(ByteCodeInstruction::kDup, 1);
720 this->write(ByteCodeInstruction::kNotB, 1);
721 this->write(ByteCodeInstruction::kMaskPush);
722 this->write(ByteCodeInstruction::kBranchIfAllFalse);
723 DeferredLocation falseLocation(this);
724 this->writeExpression(*b.fRight);
725 this->write(ByteCodeInstruction::kOrB, 1);
726 falseLocation.set();
727 this->write(ByteCodeInstruction::kMaskPop);
728 return false;
729 }
730 case Token::Kind::TK_SHL:
731 case Token::Kind::TK_SHR: {
732 SkASSERT(count == 1 && (tc == SkSL::TypeCategory::kSigned ||
733 tc == SkSL::TypeCategory::kUnsigned));
734 if (!b.fRight->isCompileTimeConstant()) {
735 fErrors.error(b.fRight->fOffset, "Shift amounts must be constant");
736 return false;
737 }
738 int64_t shift = b.fRight->getConstantInt();
739 if (shift < 0 || shift > 31) {
740 fErrors.error(b.fRight->fOffset, "Shift amount out of range");
741 return false;
742 }
743
744 if (op == Token::Kind::TK_SHL) {
745 this->write(ByteCodeInstruction::kShiftLeft);
746 } else {
747 this->write(type_category(lType) == TypeCategory::kSigned
748 ? ByteCodeInstruction::kShiftRightS
749 : ByteCodeInstruction::kShiftRightU);
750 }
751 this->write8(shift);
752 return false;
753 }
754
755 default:
756 break;
757 }
758 this->writeExpression(*b.fRight);
759 if (lVecOrMtx && !rVecOrMtx) {
760 for (int i = SlotCount(lType); i > 1; --i) {
761 this->write(ByteCodeInstruction::kDup, 1);
762 }
763 }
764 // Special case for M*V, V*M, M*M (but not V*V!)
765 if (op == Token::Kind::TK_STAR && lVecOrMtx && rVecOrMtx &&
766 !(lType.kind() == Type::kVector_Kind && rType.kind() == Type::kVector_Kind)) {
767 this->write(ByteCodeInstruction::kMatrixMultiply,
768 SlotCount(b.fType) - (SlotCount(lType) + SlotCount(rType)));
769 int rCols = rType.columns(),
770 rRows = rType.rows(),
771 lCols = lType.columns(),
772 lRows = lType.rows();
773 // M*V treats the vector as a column
774 if (rType.kind() == Type::kVector_Kind) {
775 std::swap(rCols, rRows);
776 }
777 SkASSERT(lCols == rRows);
778 SkASSERT(SlotCount(b.fType) == lRows * rCols);
779 this->write8(lCols);
780 this->write8(lRows);
781 this->write8(rCols);
782 } else {
783 switch (op) {
784 case Token::Kind::TK_EQEQ:
785 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareIEQ,
786 ByteCodeInstruction::kCompareIEQ,
787 ByteCodeInstruction::kCompareFEQ,
788 count);
789 // Collapse to a single bool
790 for (int i = count; i > 1; --i) {
791 this->write(ByteCodeInstruction::kAndB, 1);
792 }
793 break;
794 case Token::Kind::TK_GT:
795 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSGT,
796 ByteCodeInstruction::kCompareUGT,
797 ByteCodeInstruction::kCompareFGT,
798 count);
799 break;
800 case Token::Kind::TK_GTEQ:
801 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSGTEQ,
802 ByteCodeInstruction::kCompareUGTEQ,
803 ByteCodeInstruction::kCompareFGTEQ,
804 count);
805 break;
806 case Token::Kind::TK_LT:
807 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSLT,
808 ByteCodeInstruction::kCompareULT,
809 ByteCodeInstruction::kCompareFLT,
810 count);
811 break;
812 case Token::Kind::TK_LTEQ:
813 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSLTEQ,
814 ByteCodeInstruction::kCompareULTEQ,
815 ByteCodeInstruction::kCompareFLTEQ,
816 count);
817 break;
818 case Token::Kind::TK_MINUS:
819 this->writeTypedInstruction(lType, ByteCodeInstruction::kSubtractI,
820 ByteCodeInstruction::kSubtractI,
821 ByteCodeInstruction::kSubtractF,
822 count);
823 break;
824 case Token::Kind::TK_NEQ:
825 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareINEQ,
826 ByteCodeInstruction::kCompareINEQ,
827 ByteCodeInstruction::kCompareFNEQ,
828 count);
829 // Collapse to a single bool
830 for (int i = count; i > 1; --i) {
831 this->write(ByteCodeInstruction::kOrB, 1);
832 }
833 break;
834 case Token::Kind::TK_PERCENT:
835 this->writeTypedInstruction(lType, ByteCodeInstruction::kRemainderS,
836 ByteCodeInstruction::kRemainderU,
837 ByteCodeInstruction::kRemainderF,
838 count);
839 break;
840 case Token::Kind::TK_PLUS:
841 this->writeTypedInstruction(lType, ByteCodeInstruction::kAddI,
842 ByteCodeInstruction::kAddI,
843 ByteCodeInstruction::kAddF,
844 count);
845 break;
846 case Token::Kind::TK_SLASH:
847 this->writeTypedInstruction(lType, ByteCodeInstruction::kDivideS,
848 ByteCodeInstruction::kDivideU,
849 ByteCodeInstruction::kDivideF,
850 count);
851 break;
852 case Token::Kind::TK_STAR:
853 this->writeTypedInstruction(lType, ByteCodeInstruction::kMultiplyI,
854 ByteCodeInstruction::kMultiplyI,
855 ByteCodeInstruction::kMultiplyF,
856 count);
857 break;
858
859 case Token::Kind::TK_LOGICALXOR:
860 SkASSERT(tc == SkSL::TypeCategory::kBool);
861 this->write(ByteCodeInstruction::kXorB, count);
862 break;
863
864 case Token::Kind::TK_BITWISEAND:
865 SkASSERT(tc == SkSL::TypeCategory::kSigned || tc == SkSL::TypeCategory::kUnsigned);
866 this->write(ByteCodeInstruction::kAndB, count);
867 break;
868 case Token::Kind::TK_BITWISEOR:
869 SkASSERT(tc == SkSL::TypeCategory::kSigned || tc == SkSL::TypeCategory::kUnsigned);
870 this->write(ByteCodeInstruction::kOrB, count);
871 break;
872 case Token::Kind::TK_BITWISEXOR:
873 SkASSERT(tc == SkSL::TypeCategory::kSigned || tc == SkSL::TypeCategory::kUnsigned);
874 this->write(ByteCodeInstruction::kXorB, count);
875 break;
876
877 default:
878 fErrors.error(b.fOffset, SkSL::String::printf("Unsupported binary operator '%s'",
879 Compiler::OperatorName(op)));
880 break;
881 }
882 }
883 if (lvalue) {
884 lvalue->store(discard);
885 discard = false;
886 }
887 return discard;
888}
889
890void ByteCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
891 this->write(ByteCodeInstruction::kPushImmediate);
892 this->write32(b.fValue ? ~0 : 0);
893}
894
895void ByteCodeGenerator::writeConstructor(const Constructor& c) {
896 for (const auto& arg : c.fArguments) {
897 this->writeExpression(*arg);
898 }
899 if (c.fArguments.size() == 1) {
900 const Type& inType = c.fArguments[0]->fType;
901 const Type& outType = c.fType;
902 TypeCategory inCategory = type_category(inType);
903 TypeCategory outCategory = type_category(outType);
904 int inCount = SlotCount(inType);
905 int outCount = SlotCount(outType);
906 if (inCategory != outCategory) {
907 SkASSERT(inCount == outCount);
908 if (inCategory == TypeCategory::kFloat) {
909 SkASSERT(outCategory == TypeCategory::kSigned ||
910 outCategory == TypeCategory::kUnsigned);
911 this->write(ByteCodeInstruction::kConvertFtoI, outCount);
912 } else if (outCategory == TypeCategory::kFloat) {
913 if (inCategory == TypeCategory::kSigned) {
914 this->write(ByteCodeInstruction::kConvertStoF, outCount);
915 } else {
916 SkASSERT(inCategory == TypeCategory::kUnsigned);
917 this->write(ByteCodeInstruction::kConvertUtoF, outCount);
918 }
919 } else {
920 SkASSERT(false);
921 }
922 }
923 if (inType.kind() == Type::kMatrix_Kind && outType.kind() == Type::kMatrix_Kind) {
924 this->write(ByteCodeInstruction::kMatrixToMatrix,
925 SlotCount(outType) - SlotCount(inType));
926 this->write8(inType.columns());
927 this->write8(inType.rows());
928 this->write8(outType.columns());
929 this->write8(outType.rows());
930 } else if (inCount != outCount) {
931 SkASSERT(inCount == 1);
932 if (outType.kind() == Type::kMatrix_Kind) {
933 this->write(ByteCodeInstruction::kScalarToMatrix, SlotCount(outType) - 1);
934 this->write8(outType.columns());
935 this->write8(outType.rows());
936 } else {
937 SkASSERT(outType.kind() == Type::kVector_Kind);
938 for (; inCount != outCount; ++inCount) {
939 this->write(ByteCodeInstruction::kDup, 1);
940 }
941 }
942 }
943 }
944}
945
946void ByteCodeGenerator::writeExternalFunctionCall(const ExternalFunctionCall& f) {
947 int argumentCount = 0;
948 for (const auto& arg : f.fArguments) {
949 this->writeExpression(*arg);
950 argumentCount += SlotCount(arg->fType);
951 }
952 this->write(ByteCodeInstruction::kCallExternal, SlotCount(f.fType) - argumentCount);
953 SkASSERT(argumentCount <= 255);
954 this->write8(argumentCount);
955 this->write8(SlotCount(f.fType));
956 int index = fOutput->fExternalValues.size();
957 fOutput->fExternalValues.push_back(f.fFunction);
958 SkASSERT(index <= 255);
959 this->write8(index);
960}
961
962void ByteCodeGenerator::writeExternalValue(const ExternalValueReference& e) {
963 int count = SlotCount(e.fValue->type());
964 this->write(ByteCodeInstruction::kReadExternal, count);
965 int index = fOutput->fExternalValues.size();
966 fOutput->fExternalValues.push_back(e.fValue);
967 SkASSERT(index <= 255);
968 this->write8(index);
969}
970
971void ByteCodeGenerator::writeVariableExpression(const Expression& expr) {
972 if (int builtin = expression_as_builtin(expr); builtin >= 0) {
973 switch (builtin) {
974 case SK_FRAGCOORD_BUILTIN:
975 this->write(ByteCodeInstruction::kLoadFragCoord);
976 fOutput->fUsesFragCoord = true;
977 break;
978 default:
979 fErrors.error(expr.fOffset, "Unsupported builtin");
980 break;
981 }
982 return;
983 }
984
985 Location location = this->getLocation(expr);
986 int count = SlotCount(expr.fType);
987 if (count == 0) {
988 return;
989 }
990 if (location.isOnStack()) {
991 this->write(location.selectLoad(ByteCodeInstruction::kLoadExtended,
992 ByteCodeInstruction::kLoadExtendedGlobal,
993 ByteCodeInstruction::kLoadExtendedUniform),
994 count);
995 } else {
996 this->write(location.selectLoad(ByteCodeInstruction::kLoad,
997 ByteCodeInstruction::kLoadGlobal,
998 ByteCodeInstruction::kLoadUniform),
999 count);
1000 this->write8(location.fSlot);
1001 }
1002}
1003
1004static inline uint32_t float_to_bits(float x) {
1005 uint32_t u;
1006 memcpy(&u, &x, sizeof(uint32_t));
1007 return u;
1008}
1009
1010void ByteCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
1011 this->write(ByteCodeInstruction::kPushImmediate);
1012 this->write32(float_to_bits(f.fValue));
1013}
1014
1015static bool is_generic_type(const Type* type, const Type* generic) {
1016 const std::vector<const Type*>& concrete(generic->coercibleTypes());
1017 return std::find(concrete.begin(), concrete.end(), type) != concrete.end();
1018}
1019
1020void ByteCodeGenerator::writeIntrinsicCall(const FunctionCall& c) {
1021 auto found = fIntrinsics.find(c.fFunction.fName);
1022 if (found == fIntrinsics.end()) {
1023 fErrors.error(c.fOffset, String::printf("Unsupported intrinsic: '%s'",
1024 String(c.fFunction.fName).c_str()));
1025 return;
1026 }
1027 Intrinsic intrin = found->second;
1028
1029 const auto& args = c.fArguments;
1030 const size_t nargs = args.size();
1031 SkASSERT(nargs >= 1);
1032
1033 int count = SlotCount(args[0]->fType);
1034
1035 // Several intrinsics have variants where one argument is either scalar, or the same size as
1036 // the first argument. Call dupSmallerType(SlotCount(argType)) to ensure equal component count.
1037 auto dupSmallerType = [count, this](int smallCount) {
1038 SkASSERT(smallCount == 1 || smallCount == count);
1039 for (int i = smallCount; i < count; ++i) {
1040 this->write(ByteCodeInstruction::kDup, 1);
1041 }
1042 };
1043
1044 if (intrin.is_special && intrin.special == SpecialIntrinsic::kSample) {
1045 // Sample is very special, the first argument is an FP, which can't be pushed to the stack.
1046 if (nargs > 2 || args[0]->fType != *fContext.fFragmentProcessor_Type ||
1047 (nargs == 2 && (args[1]->fType != *fContext.fFloat2_Type &&
1048 args[1]->fType != *fContext.fFloat3x3_Type))) {
1049 fErrors.error(c.fOffset, "Unsupported form of sample");
1050 return;
1051 }
1052
1053 if (nargs == 2) {
1054 // Write our coords or matrix
1055 this->writeExpression(*args[1]);
1056 this->write(args[1]->fType == *fContext.fFloat3x3_Type
1057 ? ByteCodeInstruction::kSampleMatrix
1058 : ByteCodeInstruction::kSampleExplicit);
1059 } else {
1060 this->write(ByteCodeInstruction::kSample);
1061 }
1062
1063 Location childLoc = this->getLocation(*args[0]);
1064 SkASSERT(childLoc.fStorage == Storage::kChildFP);
1065 this->write8(childLoc.fSlot);
1066 return;
1067 }
1068
1069 if (intrin.is_special && (intrin.special == SpecialIntrinsic::kClamp ||
1070 intrin.special == SpecialIntrinsic::kSaturate)) {
1071 // These intrinsics are extra-special, we need instructions interleaved with arguments
1072 bool saturate = (intrin.special == SpecialIntrinsic::kSaturate);
1073 SkASSERT(nargs == (saturate ? 1 : 3));
1074 int limitCount = saturate ? 1 : SlotCount(args[1]->fType);
1075
1076 // 'x'
1077 this->writeExpression(*args[0]);
1078
1079 // 'minVal'
1080 if (saturate) {
1081 this->write(ByteCodeInstruction::kPushImmediate);
1082 this->write32(float_to_bits(0.0f));
1083 } else {
1084 this->writeExpression(*args[1]);
1085 }
1086 dupSmallerType(limitCount);
1087 this->writeTypedInstruction(args[0]->fType,
1088 ByteCodeInstruction::kMaxS,
1089 ByteCodeInstruction::kMaxS,
1090 ByteCodeInstruction::kMaxF,
1091 count);
1092
1093 // 'maxVal'
1094 if (saturate) {
1095 this->write(ByteCodeInstruction::kPushImmediate);
1096 this->write32(float_to_bits(1.0f));
1097 } else {
1098 SkASSERT(limitCount == SlotCount(args[2]->fType));
1099 this->writeExpression(*args[2]);
1100 }
1101 dupSmallerType(limitCount);
1102 this->writeTypedInstruction(args[0]->fType,
1103 ByteCodeInstruction::kMinS,
1104 ByteCodeInstruction::kMinS,
1105 ByteCodeInstruction::kMinF,
1106 count);
1107 return;
1108 }
1109
1110 // All other intrinsics can handle their arguments being on the stack in order
1111 for (const auto& arg : args) {
1112 this->writeExpression(*arg);
1113 }
1114
1115 if (intrin.is_special) {
1116 switch (intrin.special) {
1117 case SpecialIntrinsic::kAll: {
1118 for (int i = count-1; i --> 0;) {
1119 this->write(ByteCodeInstruction::kAndB, 1);
1120 }
1121 } break;
1122
1123 case SpecialIntrinsic::kAny: {
1124 for (int i = count-1; i --> 0;) {
1125 this->write(ByteCodeInstruction::kOrB, 1);
1126 }
1127 } break;
1128
1129 case SpecialIntrinsic::kDot: {
1130 SkASSERT(nargs == 2);
1131 SkASSERT(count == SlotCount(args[1]->fType));
1132 this->write(ByteCodeInstruction::kMultiplyF, count);
1133 for (int i = count-1; i --> 0;) {
1134 this->write(ByteCodeInstruction::kAddF, 1);
1135 }
1136 } break;
1137
1138 case SpecialIntrinsic::kLength: {
1139 SkASSERT(nargs == 1);
1140 this->write(ByteCodeInstruction::kDup, count);
1141 this->write(ByteCodeInstruction::kMultiplyF, count);
1142 for (int i = count-1; i --> 0;) {
1143 this->write(ByteCodeInstruction::kAddF, 1);
1144 }
1145 this->write(ByteCodeInstruction::kSqrt, 1);
1146 } break;
1147
1148 case SpecialIntrinsic::kMax:
1149 case SpecialIntrinsic::kMin: {
1150 SkASSERT(nargs == 2);
1151 // There are variants where the second argument is scalar
1152 dupSmallerType(SlotCount(args[1]->fType));
1153 if (intrin.special == SpecialIntrinsic::kMax) {
1154 this->writeTypedInstruction(args[0]->fType,
1155 ByteCodeInstruction::kMaxS,
1156 ByteCodeInstruction::kMaxS,
1157 ByteCodeInstruction::kMaxF,
1158 count);
1159 } else {
1160 this->writeTypedInstruction(args[0]->fType,
1161 ByteCodeInstruction::kMinS,
1162 ByteCodeInstruction::kMinS,
1163 ByteCodeInstruction::kMinF,
1164 count);
1165 }
1166 } break;
1167
1168 case SpecialIntrinsic::kMix: {
1169 // Two main variants of mix to handle
1170 SkASSERT(nargs == 3);
1171 SkASSERT(count == SlotCount(args[1]->fType));
1172 int selectorCount = SlotCount(args[2]->fType);
1173
1174 if (is_generic_type(&args[2]->fType, fContext.fGenBType_Type.get())) {
1175 // mix(genType, genType, genBoolType)
1176 SkASSERT(selectorCount == count);
1177 this->write(ByteCodeInstruction::kMix, count);
1178 } else {
1179 // mix(genType, genType, genType) or mix(genType, genType, float)
1180 dupSmallerType(selectorCount);
1181 this->write(ByteCodeInstruction::kLerp, count);
1182 }
1183 } break;
1184
1185 case SpecialIntrinsic::kNormalize: {
1186 SkASSERT(nargs == 1);
1187 this->write(ByteCodeInstruction::kDup, count);
1188 this->write(ByteCodeInstruction::kDup, count);
1189 this->write(ByteCodeInstruction::kMultiplyF, count);
1190 for (int i = count-1; i --> 0;) {
1191 this->write(ByteCodeInstruction::kAddF, 1);
1192 }
1193 this->write(ByteCodeInstruction::kSqrt, 1);
1194 dupSmallerType(1);
1195 this->write(ByteCodeInstruction::kDivideF, count);
1196 } break;
1197
1198 default:
1199 SkASSERT(false);
1200 }
1201 } else {
1202 switch (intrin.inst_f) {
1203 case ByteCodeInstruction::kInverse2x2: {
1204 auto op = ByteCodeInstruction::kInverse2x2;
1205 switch (count) {
1206 case 4: break; // float2x2
1207 case 9: op = ByteCodeInstruction::kInverse3x3; break;
1208 case 16: op = ByteCodeInstruction::kInverse4x4; break;
1209 default: SkASSERT(false);
1210 }
1211 this->write(op);
1212 break;
1213 }
1214
1215 default:
1216 this->writeTypedInstruction(args[0]->fType,
1217 intrin.inst_s,
1218 intrin.inst_u,
1219 intrin.inst_f,
1220 count);
1221 break;
1222 }
1223 }
1224}
1225
1226void ByteCodeGenerator::writeFunctionCall(const FunctionCall& f) {
1227 // Find the index of the function we're calling. We explicitly do not allow calls to functions
1228 // before they're defined. This is an easy-to-understand rule that prevents recursion.
1229 int idx = -1;
1230 for (size_t i = 0; i < fFunctions.size(); ++i) {
1231 if (f.fFunction.matches(fFunctions[i]->fDeclaration)) {
1232 idx = i;
1233 break;
1234 }
1235 }
1236 if (idx == -1) {
1237 this->writeIntrinsicCall(f);
1238 return;
1239 }
1240
1241
1242 if (idx > 255) {
1243 fErrors.error(f.fOffset, "Function count limit exceeded");
1244 return;
1245 } else if (idx >= (int) fFunctions.size()) {
1246 fErrors.error(f.fOffset, "Call to undefined function");
1247 return;
1248 }
1249
1250 // We may need to deal with out parameters, so the sequence is tricky
1251 if (int returnCount = SlotCount(f.fType)) {
1252 this->write(ByteCodeInstruction::kReserve, returnCount);
1253 }
1254
1255 int argCount = f.fArguments.size();
1256 std::vector<std::unique_ptr<LValue>> lvalues;
1257 for (int i = 0; i < argCount; ++i) {
1258 const auto& param = f.fFunction.fParameters[i];
1259 const auto& arg = f.fArguments[i];
1260 if (param->fModifiers.fFlags & Modifiers::kOut_Flag) {
1261 lvalues.emplace_back(this->getLValue(*arg));
1262 lvalues.back()->load();
1263 } else {
1264 this->writeExpression(*arg);
1265 }
1266 }
1267
1268 // The space used by the call is based on the callee, but it also unwinds all of that before
1269 // we continue execution. We adjust our max stack depths below.
1270 this->write(ByteCodeInstruction::kCall);
1271 this->write8(idx);
1272
1273 const ByteCodeFunction* callee = fOutput->fFunctions[idx].get();
1274 fMaxLoopCount = std::max(fMaxLoopCount, fLoopCount + callee->fLoopCount);
1275 fMaxConditionCount = std::max(fMaxConditionCount, fConditionCount + callee->fConditionCount);
1276 fMaxStackCount = std::max(fMaxStackCount, fStackCount + callee->fLocalCount
1277 + callee->fStackCount);
1278
1279 // After the called function returns, the stack will still contain our arguments. We have to
1280 // pop them (storing any out parameters back to their lvalues as we go). We glob together slot
1281 // counts for all parameters that aren't out-params, so we can pop them in one big chunk.
1282 int popCount = 0;
1283 auto pop = [&]() {
1284 if (popCount > 0) {
1285 this->write(ByteCodeInstruction::kPop, popCount);
1286 }
1287 popCount = 0;
1288 };
1289
1290 for (int i = argCount - 1; i >= 0; --i) {
1291 const auto& param = f.fFunction.fParameters[i];
1292 const auto& arg = f.fArguments[i];
1293 if (param->fModifiers.fFlags & Modifiers::kOut_Flag) {
1294 pop();
1295 lvalues.back()->store(true);
1296 lvalues.pop_back();
1297 } else {
1298 popCount += SlotCount(arg->fType);
1299 }
1300 }
1301 pop();
1302}
1303
1304void ByteCodeGenerator::writeIntLiteral(const IntLiteral& i) {
1305 this->write(ByteCodeInstruction::kPushImmediate);
1306 this->write32(i.fValue);
1307}
1308
1309void ByteCodeGenerator::writeNullLiteral(const NullLiteral& n) {
1310 // not yet implemented
1311 abort();
1312}
1313
1314bool ByteCodeGenerator::writePrefixExpression(const PrefixExpression& p, bool discard) {
1315 switch (p.fOperator) {
1316 case Token::Kind::TK_PLUSPLUS: // fall through
1317 case Token::Kind::TK_MINUSMINUS: {
1318 SkASSERT(SlotCount(p.fOperand->fType) == 1);
1319 std::unique_ptr<LValue> lvalue = this->getLValue(*p.fOperand);
1320 lvalue->load();
1321 this->write(ByteCodeInstruction::kPushImmediate);
1322 this->write32(type_category(p.fType) == TypeCategory::kFloat ? float_to_bits(1.0f) : 1);
1323 if (p.fOperator == Token::Kind::TK_PLUSPLUS) {
1324 this->writeTypedInstruction(p.fType,
1325 ByteCodeInstruction::kAddI,
1326 ByteCodeInstruction::kAddI,
1327 ByteCodeInstruction::kAddF,
1328 1);
1329 } else {
1330 this->writeTypedInstruction(p.fType,
1331 ByteCodeInstruction::kSubtractI,
1332 ByteCodeInstruction::kSubtractI,
1333 ByteCodeInstruction::kSubtractF,
1334 1);
1335 }
1336 lvalue->store(discard);
1337 discard = false;
1338 break;
1339 }
1340 case Token::Kind::TK_MINUS: {
1341 this->writeExpression(*p.fOperand);
1342 this->writeTypedInstruction(p.fType,
1343 ByteCodeInstruction::kNegateI,
1344 ByteCodeInstruction::kNegateI,
1345 ByteCodeInstruction::kNegateF,
1346 SlotCount(p.fOperand->fType));
1347 break;
1348 }
1349 case Token::Kind::TK_LOGICALNOT:
1350 case Token::Kind::TK_BITWISENOT: {
1351 SkASSERT(SlotCount(p.fOperand->fType) == 1);
1352 SkDEBUGCODE(TypeCategory tc = type_category(p.fOperand->fType));
1353 SkASSERT((p.fOperator == Token::Kind::TK_LOGICALNOT && tc == TypeCategory::kBool) ||
1354 (p.fOperator == Token::Kind::TK_BITWISENOT && (tc == TypeCategory::kSigned ||
1355 tc == TypeCategory::kUnsigned)));
1356 this->writeExpression(*p.fOperand);
1357 this->write(ByteCodeInstruction::kNotB, 1);
1358 break;
1359 }
1360 default:
1361 SkASSERT(false);
1362 }
1363 return discard;
1364}
1365
1366bool ByteCodeGenerator::writePostfixExpression(const PostfixExpression& p, bool discard) {
1367 switch (p.fOperator) {
1368 case Token::Kind::TK_PLUSPLUS: // fall through
1369 case Token::Kind::TK_MINUSMINUS: {
1370 SkASSERT(SlotCount(p.fOperand->fType) == 1);
1371 std::unique_ptr<LValue> lvalue = this->getLValue(*p.fOperand);
1372 lvalue->load();
1373 // If we're not supposed to discard the result, then make a copy *before* the +/-
1374 if (!discard) {
1375 this->write(ByteCodeInstruction::kDup, 1);
1376 }
1377 this->write(ByteCodeInstruction::kPushImmediate);
1378 this->write32(type_category(p.fType) == TypeCategory::kFloat ? float_to_bits(1.0f) : 1);
1379 if (p.fOperator == Token::Kind::TK_PLUSPLUS) {
1380 this->writeTypedInstruction(p.fType,
1381 ByteCodeInstruction::kAddI,
1382 ByteCodeInstruction::kAddI,
1383 ByteCodeInstruction::kAddF,
1384 1);
1385 } else {
1386 this->writeTypedInstruction(p.fType,
1387 ByteCodeInstruction::kSubtractI,
1388 ByteCodeInstruction::kSubtractI,
1389 ByteCodeInstruction::kSubtractF,
1390 1);
1391 }
1392 // Always consume the result as part of the store
1393 lvalue->store(true);
1394 discard = false;
1395 break;
1396 }
1397 default:
1398 SkASSERT(false);
1399 }
1400 return discard;
1401}
1402
1403void ByteCodeGenerator::writeSwizzle(const Swizzle& s) {
1404 if (swizzle_is_simple(s)) {
1405 this->writeVariableExpression(s);
1406 return;
1407 }
1408
1409 this->writeExpression(*s.fBase);
1410 this->write(ByteCodeInstruction::kSwizzle, s.fComponents.size() - s.fBase->fType.columns());
1411 this->write8(s.fBase->fType.columns());
1412 this->write8(s.fComponents.size());
1413 for (int c : s.fComponents) {
1414 this->write8(c);
1415 }
1416}
1417
1418void ByteCodeGenerator::writeTernaryExpression(const TernaryExpression& t) {
1419 int count = SlotCount(t.fType);
1420 SkASSERT(count == SlotCount(t.fIfTrue->fType));
1421 SkASSERT(count == SlotCount(t.fIfFalse->fType));
1422
1423 this->writeExpression(*t.fTest);
1424 this->write(ByteCodeInstruction::kMaskPush);
1425 this->writeExpression(*t.fIfTrue);
1426 this->write(ByteCodeInstruction::kMaskNegate);
1427 this->writeExpression(*t.fIfFalse);
1428 this->write(ByteCodeInstruction::kMaskBlend, count);
1429}
1430
1431void ByteCodeGenerator::writeExpression(const Expression& e, bool discard) {
1432 switch (e.fKind) {
1433 case Expression::kBinary_Kind:
1434 discard = this->writeBinaryExpression((BinaryExpression&) e, discard);
1435 break;
1436 case Expression::kBoolLiteral_Kind:
1437 this->writeBoolLiteral((BoolLiteral&) e);
1438 break;
1439 case Expression::kConstructor_Kind:
1440 this->writeConstructor((Constructor&) e);
1441 break;
1442 case Expression::kExternalFunctionCall_Kind:
1443 this->writeExternalFunctionCall((ExternalFunctionCall&) e);
1444 break;
1445 case Expression::kExternalValue_Kind:
1446 this->writeExternalValue((ExternalValueReference&) e);
1447 break;
1448 case Expression::kFieldAccess_Kind:
1449 case Expression::kIndex_Kind:
1450 case Expression::kVariableReference_Kind:
1451 this->writeVariableExpression(e);
1452 break;
1453 case Expression::kFloatLiteral_Kind:
1454 this->writeFloatLiteral((FloatLiteral&) e);
1455 break;
1456 case Expression::kFunctionCall_Kind:
1457 this->writeFunctionCall((FunctionCall&) e);
1458 break;
1459 case Expression::kIntLiteral_Kind:
1460 this->writeIntLiteral((IntLiteral&) e);
1461 break;
1462 case Expression::kNullLiteral_Kind:
1463 this->writeNullLiteral((NullLiteral&) e);
1464 break;
1465 case Expression::kPrefix_Kind:
1466 discard = this->writePrefixExpression((PrefixExpression&) e, discard);
1467 break;
1468 case Expression::kPostfix_Kind:
1469 discard = this->writePostfixExpression((PostfixExpression&) e, discard);
1470 break;
1471 case Expression::kSwizzle_Kind:
1472 this->writeSwizzle((Swizzle&) e);
1473 break;
1474 case Expression::kTernary_Kind:
1475 this->writeTernaryExpression((TernaryExpression&) e);
1476 break;
1477 default:
1478#ifdef SK_DEBUG
1479 printf("unsupported expression %s\n", e.description().c_str());
1480#endif
1481 SkASSERT(false);
1482 }
1483 if (discard) {
1484 int count = SlotCount(e.fType);
1485 if (count > 0) {
1486 this->write(ByteCodeInstruction::kPop, count);
1487 }
1488 discard = false;
1489 }
1490}
1491
1492class ByteCodeExternalValueLValue : public ByteCodeGenerator::LValue {
1493public:
1494 ByteCodeExternalValueLValue(ByteCodeGenerator* generator, ExternalValue& value, int index)
1495 : INHERITED(*generator)
1496 , fCount(ByteCodeGenerator::SlotCount(value.type()))
1497 , fIndex(index) {}
1498
1499 void load() override {
1500 fGenerator.write(ByteCodeInstruction::kReadExternal, fCount);
1501 fGenerator.write8(fIndex);
1502 }
1503
1504 void store(bool discard) override {
1505 if (!discard) {
1506 fGenerator.write(ByteCodeInstruction::kDup, fCount);
1507 }
1508 fGenerator.write(ByteCodeInstruction::kWriteExternal, fCount);
1509 fGenerator.write8(fIndex);
1510 }
1511
1512private:
1513 typedef LValue INHERITED;
1514
1515 int fCount;
1516 int fIndex;
1517};
1518
1519class ByteCodeSwizzleLValue : public ByteCodeGenerator::LValue {
1520public:
1521 ByteCodeSwizzleLValue(ByteCodeGenerator* generator, const Swizzle& swizzle)
1522 : INHERITED(*generator)
1523 , fSwizzle(swizzle) {}
1524
1525 void load() override {
1526 fGenerator.writeSwizzle(fSwizzle);
1527 }
1528
1529 void store(bool discard) override {
1530 int count = fSwizzle.fComponents.size();
1531 if (!discard) {
1532 fGenerator.write(ByteCodeInstruction::kDup, count);
1533 }
1534 // We already have the correct number of values on the stack, thanks to type checking.
1535 // The algorithm: Walk down the values on the stack, doing 'count' single-element stores.
1536 // For each value, use the corresponding swizzle component to offset the store location.
1537 //
1538 // Static locations: We (wastefully) call getLocation every time, but get good byte code.
1539 // Note that we could (but don't) store adjacent/sequential values with fewer instructions.
1540 //
1541 // Dynamic locations: ... are bad. We have to recompute the base address on each iteration,
1542 // because the stack doesn't let us retain that address between stores. Dynamic locations
1543 // are rare though, and swizzled writes to those are even rarer, so we just live with this.
1544 for (int i = count; i-- > 0;) {
1545 ByteCodeGenerator::Location location = fGenerator.getLocation(*fSwizzle.fBase);
1546 if (!location.isOnStack()) {
1547 fGenerator.write(location.selectStore(ByteCodeInstruction::kStore,
1548 ByteCodeInstruction::kStoreGlobal),
1549 1);
1550 fGenerator.write8(location.fSlot + fSwizzle.fComponents[i]);
1551 } else {
1552 fGenerator.write(ByteCodeInstruction::kPushImmediate);
1553 fGenerator.write32(fSwizzle.fComponents[i]);
1554 fGenerator.write(ByteCodeInstruction::kAddI, 1);
1555 fGenerator.write(location.selectStore(ByteCodeInstruction::kStoreExtended,
1556 ByteCodeInstruction::kStoreExtendedGlobal),
1557 1);
1558 }
1559 }
1560 }
1561
1562private:
1563 const Swizzle& fSwizzle;
1564
1565 typedef LValue INHERITED;
1566};
1567
1568class ByteCodeExpressionLValue : public ByteCodeGenerator::LValue {
1569public:
1570 ByteCodeExpressionLValue(ByteCodeGenerator* generator, const Expression& expr)
1571 : INHERITED(*generator)
1572 , fExpression(expr) {}
1573
1574 void load() override {
1575 fGenerator.writeVariableExpression(fExpression);
1576 }
1577
1578 void store(bool discard) override {
1579 int count = ByteCodeGenerator::SlotCount(fExpression.fType);
1580 if (!discard) {
1581 fGenerator.write(ByteCodeInstruction::kDup, count);
1582 }
1583 ByteCodeGenerator::Location location = fGenerator.getLocation(fExpression);
1584 if (location.isOnStack()) {
1585 fGenerator.write(location.selectStore(ByteCodeInstruction::kStoreExtended,
1586 ByteCodeInstruction::kStoreExtendedGlobal),
1587 count);
1588 } else {
1589 fGenerator.write(location.selectStore(ByteCodeInstruction::kStore,
1590 ByteCodeInstruction::kStoreGlobal),
1591 count);
1592 fGenerator.write8(location.fSlot);
1593 }
1594 }
1595
1596private:
1597 typedef LValue INHERITED;
1598
1599 const Expression& fExpression;
1600};
1601
1602std::unique_ptr<ByteCodeGenerator::LValue> ByteCodeGenerator::getLValue(const Expression& e) {
1603 switch (e.fKind) {
1604 case Expression::kExternalValue_Kind: {
1605 ExternalValue* value = ((ExternalValueReference&) e).fValue;
1606 int index = fOutput->fExternalValues.size();
1607 fOutput->fExternalValues.push_back(value);
1608 SkASSERT(index <= 255);
1609 return std::unique_ptr<LValue>(new ByteCodeExternalValueLValue(this, *value, index));
1610 }
1611 case Expression::kFieldAccess_Kind:
1612 case Expression::kIndex_Kind:
1613 case Expression::kVariableReference_Kind:
1614 return std::unique_ptr<LValue>(new ByteCodeExpressionLValue(this, e));
1615 case Expression::kSwizzle_Kind: {
1616 const Swizzle& s = (const Swizzle&) e;
1617 return swizzle_is_simple(s)
1618 ? std::unique_ptr<LValue>(new ByteCodeExpressionLValue(this, e))
1619 : std::unique_ptr<LValue>(new ByteCodeSwizzleLValue(this, s));
1620 }
1621 case Expression::kTernary_Kind:
1622 default:
1623#ifdef SK_DEBUG
1624 ABORT("unsupported lvalue %s\n", e.description().c_str());
1625#endif
1626 return nullptr;
1627 }
1628}
1629
1630void ByteCodeGenerator::writeBlock(const Block& b) {
1631 for (const auto& s : b.fStatements) {
1632 this->writeStatement(*s);
1633 }
1634}
1635
1636void ByteCodeGenerator::setBreakTargets() {
1637 std::vector<DeferredLocation>& breaks = fBreakTargets.top();
1638 for (DeferredLocation& b : breaks) {
1639 b.set();
1640 }
1641 fBreakTargets.pop();
1642}
1643
1644void ByteCodeGenerator::setContinueTargets() {
1645 std::vector<DeferredLocation>& continues = fContinueTargets.top();
1646 for (DeferredLocation& c : continues) {
1647 c.set();
1648 }
1649 fContinueTargets.pop();
1650}
1651
1652void ByteCodeGenerator::writeBreakStatement(const BreakStatement& b) {
1653 // TODO: Include BranchIfAllFalse to top-most LoopNext
1654 this->write(ByteCodeInstruction::kLoopBreak);
1655}
1656
1657void ByteCodeGenerator::writeContinueStatement(const ContinueStatement& c) {
1658 // TODO: Include BranchIfAllFalse to top-most LoopNext
1659 this->write(ByteCodeInstruction::kLoopContinue);
1660}
1661
1662void ByteCodeGenerator::writeDoStatement(const DoStatement& d) {
1663 this->write(ByteCodeInstruction::kLoopBegin);
1664 size_t start = fCode->size();
1665 this->writeStatement(*d.fStatement);
1666 this->write(ByteCodeInstruction::kLoopNext);
1667 this->writeExpression(*d.fTest);
1668 this->write(ByteCodeInstruction::kLoopMask);
1669 // TODO: Could shorten this with kBranchIfAnyTrue
1670 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1671 DeferredLocation endLocation(this);
1672 this->write(ByteCodeInstruction::kBranch);
1673 this->write16(start);
1674 endLocation.set();
1675 this->write(ByteCodeInstruction::kLoopEnd);
1676}
1677
1678void ByteCodeGenerator::writeForStatement(const ForStatement& f) {
1679 fContinueTargets.emplace();
1680 fBreakTargets.emplace();
1681 if (f.fInitializer) {
1682 this->writeStatement(*f.fInitializer);
1683 }
1684 this->write(ByteCodeInstruction::kLoopBegin);
1685 size_t start = fCode->size();
1686 if (f.fTest) {
1687 this->writeExpression(*f.fTest);
1688 this->write(ByteCodeInstruction::kLoopMask);
1689 }
1690 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1691 DeferredLocation endLocation(this);
1692 this->writeStatement(*f.fStatement);
1693 this->write(ByteCodeInstruction::kLoopNext);
1694 if (f.fNext) {
1695 this->writeExpression(*f.fNext, true);
1696 }
1697 this->write(ByteCodeInstruction::kBranch);
1698 this->write16(start);
1699 endLocation.set();
1700 this->write(ByteCodeInstruction::kLoopEnd);
1701}
1702
1703void ByteCodeGenerator::writeIfStatement(const IfStatement& i) {
1704 this->writeExpression(*i.fTest);
1705 this->write(ByteCodeInstruction::kMaskPush);
1706 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1707 DeferredLocation falseLocation(this);
1708 this->writeStatement(*i.fIfTrue);
1709 falseLocation.set();
1710 if (i.fIfFalse) {
1711 this->write(ByteCodeInstruction::kMaskNegate);
1712 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1713 DeferredLocation endLocation(this);
1714 this->writeStatement(*i.fIfFalse);
1715 endLocation.set();
1716 }
1717 this->write(ByteCodeInstruction::kMaskPop);
1718}
1719
1720void ByteCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
1721 if (fLoopCount || fConditionCount) {
1722 fErrors.error(r.fOffset, "return not allowed inside conditional or loop");
1723 return;
1724 }
1725 int count = SlotCount(r.fExpression->fType);
1726 this->writeExpression(*r.fExpression);
1727
1728 // Technically, the kReturn also pops fOutput->fLocalCount values from the stack, too, but we
1729 // haven't counted pushing those (they're outside the scope of our stack tracking). Instead,
1730 // we account for those in writeFunction().
1731
1732 // This is all fine because we don't allow conditional returns, so we only return once anyway.
1733 this->write(ByteCodeInstruction::kReturn, count);
1734}
1735
1736void ByteCodeGenerator::writeSwitchStatement(const SwitchStatement& r) {
1737 // not yet implemented
1738 abort();
1739}
1740
1741void ByteCodeGenerator::writeVarDeclarations(const VarDeclarations& v) {
1742 for (const auto& declStatement : v.fVars) {
1743 const VarDeclaration& decl = (VarDeclaration&) *declStatement;
1744 // we need to grab the location even if we don't use it, to ensure it has been allocated
1745 Location location = this->getLocation(*decl.fVar);
1746 if (decl.fValue) {
1747 this->writeExpression(*decl.fValue);
1748 int count = SlotCount(decl.fValue->fType);
1749 this->write(ByteCodeInstruction::kStore, count);
1750 this->write8(location.fSlot);
1751 }
1752 }
1753}
1754
1755void ByteCodeGenerator::writeWhileStatement(const WhileStatement& w) {
1756 this->write(ByteCodeInstruction::kLoopBegin);
1757 size_t cond = fCode->size();
1758 this->writeExpression(*w.fTest);
1759 this->write(ByteCodeInstruction::kLoopMask);
1760 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1761 DeferredLocation endLocation(this);
1762 this->writeStatement(*w.fStatement);
1763 this->write(ByteCodeInstruction::kLoopNext);
1764 this->write(ByteCodeInstruction::kBranch);
1765 this->write16(cond);
1766 endLocation.set();
1767 this->write(ByteCodeInstruction::kLoopEnd);
1768}
1769
1770void ByteCodeGenerator::writeStatement(const Statement& s) {
1771 switch (s.fKind) {
1772 case Statement::kBlock_Kind:
1773 this->writeBlock((Block&) s);
1774 break;
1775 case Statement::kBreak_Kind:
1776 this->writeBreakStatement((BreakStatement&) s);
1777 break;
1778 case Statement::kContinue_Kind:
1779 this->writeContinueStatement((ContinueStatement&) s);
1780 break;
1781 case Statement::kDiscard_Kind:
1782 // not yet implemented
1783 abort();
1784 case Statement::kDo_Kind:
1785 this->writeDoStatement((DoStatement&) s);
1786 break;
1787 case Statement::kExpression_Kind:
1788 this->writeExpression(*((ExpressionStatement&) s).fExpression, true);
1789 break;
1790 case Statement::kFor_Kind:
1791 this->writeForStatement((ForStatement&) s);
1792 break;
1793 case Statement::kIf_Kind:
1794 this->writeIfStatement((IfStatement&) s);
1795 break;
1796 case Statement::kNop_Kind:
1797 break;
1798 case Statement::kReturn_Kind:
1799 this->writeReturnStatement((ReturnStatement&) s);
1800 break;
1801 case Statement::kSwitch_Kind:
1802 this->writeSwitchStatement((SwitchStatement&) s);
1803 break;
1804 case Statement::kVarDeclarations_Kind:
1805 this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration);
1806 break;
1807 case Statement::kWhile_Kind:
1808 this->writeWhileStatement((WhileStatement&) s);
1809 break;
1810 default:
1811 SkASSERT(false);
1812 }
1813}
1814
1815ByteCodeFunction::ByteCodeFunction(const FunctionDeclaration* declaration)
1816 : fName(declaration->fName) {
1817 fParameterCount = 0;
1818 for (const auto& p : declaration->fParameters) {
1819 int slots = ByteCodeGenerator::SlotCount(p->fType);
1820 fParameters.push_back({ slots, (bool)(p->fModifiers.fFlags & Modifiers::kOut_Flag) });
1821 fParameterCount += slots;
1822 }
1823}
1824
1825} // namespace SkSL
1826