blob: c28a982ea813445351e881d75ac525095dd698f9 [file] [log] [blame]
Mike Reed8520e762020-04-30 12:06:23 -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 Osmanb08cc022020-04-02 11:38:40 -040010#include <algorithm>
11
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040012namespace SkSL {
13
Brian Osmanb08cc022020-04-02 11:38:40 -040014static 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)
Ethan Nicholas82162ee2019-05-21 16:05:08 -040042 : INHERITED(program, errors, nullptr)
Brian Osmanb08cc022020-04-02 11:38:40 -040043 , fContext(*context)
Ethan Nicholasae9633b2019-05-24 12:46:34 -040044 , fOutput(output)
Brian Osman3479a952020-05-04 10:22:53 -040045 // 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.
Ethan Nicholasae9633b2019-05-24 12:46:34 -040048 , fIntrinsics {
Brian Osman2a4871b2020-06-19 11:29:58 -040049 { "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 },
Brian Osman8842b372020-05-01 15:07:49 -040068
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 } {}
Brian Osmanb08cc022020-04-02 11:38:40 -040092
Ethan Nicholas82162ee2019-05-21 16:05:08 -040093
Brian Osman07c117b2019-05-23 12:51:06 -070094int ByteCodeGenerator::SlotCount(const Type& type) {
Brian Osmanfba386b2019-06-20 14:54:15 -040095 if (type.kind() == Type::kOther_Kind) {
96 return 0;
97 } else if (type.kind() == Type::kStruct_Kind) {
Brian Osman07c117b2019-05-23 12:51:06 -070098 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 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400113}
114
Brian Osman1c110a02019-10-01 14:53:32 -0400115static inline bool is_uniform(const SkSL::Variable& var) {
116 return var.fModifiers.fFlags & Modifiers::kUniform_Flag;
117}
118
Brian Osmaneadfeb92020-01-09 12:43:03 -0500119static inline bool is_in(const SkSL::Variable& var) {
120 return var.fModifiers.fFlags & Modifiers::kIn_Flag;
121}
Brian Osmanb08cc022020-04-02 11:38:40 -0400122
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);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500129 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400130 } 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));
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500133 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400134 } 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;
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500152 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400153 case ProgramElement::kVar_Kind: {
154 VarDeclarations& decl = (VarDeclarations&) e;
155 for (const auto& v : decl.fVars) {
156 const Variable* declVar = ((VarDeclaration&) *v).fVar;
Brian Osmana43d8202020-06-17 16:50:39 -0400157 if (declVar->fType == *fContext.fFragmentProcessor_Type) {
158 fOutput->fChildFPCount++;
159 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400160 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);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400167 }
168 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400169 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400170 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400171 default:
172 ; // ignore
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400173 }
174 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400175 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 this->write8(0);
195
196 result->fLocalCount = fLocals.size();
197 result->fConditionCount = fMaxConditionCount;
198 result->fLoopCount = fMaxLoopCount;
199 result->fStackCount = fMaxStackCount;
200
201 const Type& returnType = f.fDeclaration.fReturnType;
202 if (returnType != *fContext.fVoid_Type) {
203 result->fReturnCount = SlotCount(returnType);
204 }
205 fLocals.clear();
206 fFunction = nullptr;
207 return result;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400208}
209
Brian Osman5aaaeea2020-06-22 14:26:03 -0400210// If the expression is a reference to a builtin global variable, return the builtin ID.
211// Otherwise, return -1.
212static int expression_as_builtin(const Expression& e) {
213 if (e.fKind == Expression::kVariableReference_Kind) {
214 const Variable& var(((VariableReference&)e).fVariable);
215 if (var.fStorage == Variable::kGlobal_Storage) {
216 return var.fModifiers.fLayout.fBuiltin;
217 }
218 }
219 return -1;
220}
221
Brian Osman0785db02019-05-24 14:19:11 -0400222// A "simple" Swizzle is based on a variable (or a compound variable like a struct or array), and
223// that references consecutive values, such that it can be implemented using normal load/store ops
224// with an offset. Note that all single-component swizzles (of suitable base types) are simple.
225static bool swizzle_is_simple(const Swizzle& s) {
Brian Osman5aaaeea2020-06-22 14:26:03 -0400226 // Builtin variables use dedicated instructions that don't allow subset loads
227 if (expression_as_builtin(*s.fBase) >= 0) {
228 return false;
229 }
230
Brian Osman0785db02019-05-24 14:19:11 -0400231 switch (s.fBase->fKind) {
232 case Expression::kFieldAccess_Kind:
233 case Expression::kIndex_Kind:
234 case Expression::kVariableReference_Kind:
235 break;
236 default:
237 return false;
238 }
239
240 for (size_t i = 1; i < s.fComponents.size(); ++i) {
241 if (s.fComponents[i] != s.fComponents[i - 1] + 1) {
242 return false;
243 }
244 }
245 return true;
246}
247
Brian Osmanb08cc022020-04-02 11:38:40 -0400248int ByteCodeGenerator::StackUsage(ByteCodeInstruction inst, int count_) {
249 // Ensures that we use count iff we're passed a non-default value. Most instructions have an
250 // implicit count, so the caller shouldn't need to worry about it (or count makes no sense).
251 // The asserts avoids callers thinking they're supplying useful information in that scenario,
252 // or failing to supply necessary information for the ops that need a count.
253 struct CountValue {
254 operator int() {
255 SkASSERT(val != ByteCodeGenerator::kUnusedStackCount);
256 SkDEBUGCODE(used = true);
257 return val;
258 }
259 ~CountValue() {
260 SkASSERT(used || val == ByteCodeGenerator::kUnusedStackCount);
261 }
262 int val;
263 SkDEBUGCODE(bool used = false;)
264 } count = { count_ };
265
266 switch (inst) {
267 // Unary functions/operators that don't change stack depth at all:
268#define VECTOR_UNARY_OP(base) \
269 case ByteCodeInstruction::base: \
270 case ByteCodeInstruction::base ## 2: \
271 case ByteCodeInstruction::base ## 3: \
272 case ByteCodeInstruction::base ## 4: \
273 return 0;
274
275 VECTOR_UNARY_OP(kConvertFtoI)
276 VECTOR_UNARY_OP(kConvertStoF)
277 VECTOR_UNARY_OP(kConvertUtoF)
278
Mike Reed8520e762020-04-30 12:06:23 -0400279 VECTOR_UNARY_OP(kATan)
Brian Osman89bf7342020-06-18 17:11:16 -0400280 VECTOR_UNARY_OP(kCeil)
Brian Osmanb08cc022020-04-02 11:38:40 -0400281 VECTOR_UNARY_OP(kCos)
Brian Osman89bf7342020-06-18 17:11:16 -0400282 VECTOR_UNARY_OP(kFloor)
Mike Reed8520e762020-04-30 12:06:23 -0400283 VECTOR_UNARY_OP(kFract)
Brian Osmanb08cc022020-04-02 11:38:40 -0400284 VECTOR_UNARY_OP(kSin)
285 VECTOR_UNARY_OP(kSqrt)
286 VECTOR_UNARY_OP(kTan)
287
288 VECTOR_UNARY_OP(kNegateF)
289 VECTOR_UNARY_OP(kNegateI)
Brian Osman8842b372020-05-01 15:07:49 -0400290 VECTOR_UNARY_OP(kNotB)
Brian Osmanb08cc022020-04-02 11:38:40 -0400291
292 case ByteCodeInstruction::kInverse2x2:
293 case ByteCodeInstruction::kInverse3x3:
294 case ByteCodeInstruction::kInverse4x4: return 0;
295
296 case ByteCodeInstruction::kClampIndex: return 0;
Brian Osmanb08cc022020-04-02 11:38:40 -0400297 case ByteCodeInstruction::kNegateFN: return 0;
298 case ByteCodeInstruction::kShiftLeft: return 0;
299 case ByteCodeInstruction::kShiftRightS: return 0;
300 case ByteCodeInstruction::kShiftRightU: return 0;
301
302#undef VECTOR_UNARY_OP
303
304 // Binary functions/operators that do a 2 -> 1 reduction (possibly N times)
305#define VECTOR_BINARY_OP(base) \
306 case ByteCodeInstruction::base: return -1; \
307 case ByteCodeInstruction::base ## 2: return -2; \
308 case ByteCodeInstruction::base ## 3: return -3; \
309 case ByteCodeInstruction::base ## 4: return -4;
310
311#define VECTOR_MATRIX_BINARY_OP(base) \
312 VECTOR_BINARY_OP(base) \
313 case ByteCodeInstruction::base ## N: return -count;
314
315 case ByteCodeInstruction::kAndB: return -1;
316 case ByteCodeInstruction::kOrB: return -1;
317 case ByteCodeInstruction::kXorB: return -1;
318
319 VECTOR_BINARY_OP(kAddI)
320 VECTOR_MATRIX_BINARY_OP(kAddF)
321
322 VECTOR_BINARY_OP(kCompareIEQ)
323 VECTOR_MATRIX_BINARY_OP(kCompareFEQ)
324 VECTOR_BINARY_OP(kCompareINEQ)
325 VECTOR_MATRIX_BINARY_OP(kCompareFNEQ)
326 VECTOR_BINARY_OP(kCompareSGT)
327 VECTOR_BINARY_OP(kCompareUGT)
328 VECTOR_BINARY_OP(kCompareFGT)
329 VECTOR_BINARY_OP(kCompareSGTEQ)
330 VECTOR_BINARY_OP(kCompareUGTEQ)
331 VECTOR_BINARY_OP(kCompareFGTEQ)
332 VECTOR_BINARY_OP(kCompareSLT)
333 VECTOR_BINARY_OP(kCompareULT)
334 VECTOR_BINARY_OP(kCompareFLT)
335 VECTOR_BINARY_OP(kCompareSLTEQ)
336 VECTOR_BINARY_OP(kCompareULTEQ)
337 VECTOR_BINARY_OP(kCompareFLTEQ)
338
339 VECTOR_BINARY_OP(kDivideS)
340 VECTOR_BINARY_OP(kDivideU)
341 VECTOR_MATRIX_BINARY_OP(kDivideF)
Brian Osmand5f937b2020-05-04 12:07:29 -0400342 VECTOR_BINARY_OP(kMaxF)
343 VECTOR_BINARY_OP(kMaxS)
344 VECTOR_BINARY_OP(kMinF)
345 VECTOR_BINARY_OP(kMinS)
Brian Osmanb08cc022020-04-02 11:38:40 -0400346 VECTOR_BINARY_OP(kMultiplyI)
347 VECTOR_MATRIX_BINARY_OP(kMultiplyF)
Florin Malita3facc9c2020-05-04 09:26:15 -0400348 VECTOR_BINARY_OP(kPow)
Brian Osmanb08cc022020-04-02 11:38:40 -0400349 VECTOR_BINARY_OP(kRemainderF)
350 VECTOR_BINARY_OP(kRemainderS)
351 VECTOR_BINARY_OP(kRemainderU)
352 VECTOR_BINARY_OP(kSubtractI)
353 VECTOR_MATRIX_BINARY_OP(kSubtractF)
354
355#undef VECTOR_BINARY_OP
356#undef VECTOR_MATRIX_BINARY_OP
357
358 // Ops that push or load data to grow the stack:
359 case ByteCodeInstruction::kDup:
360 case ByteCodeInstruction::kLoad:
361 case ByteCodeInstruction::kLoadGlobal:
362 case ByteCodeInstruction::kLoadUniform:
363 case ByteCodeInstruction::kReadExternal:
364 case ByteCodeInstruction::kPushImmediate:
365 return 1;
366
367 case ByteCodeInstruction::kDup2:
368 case ByteCodeInstruction::kLoad2:
369 case ByteCodeInstruction::kLoadGlobal2:
370 case ByteCodeInstruction::kLoadUniform2:
371 case ByteCodeInstruction::kReadExternal2:
372 return 2;
373
374 case ByteCodeInstruction::kDup3:
375 case ByteCodeInstruction::kLoad3:
376 case ByteCodeInstruction::kLoadGlobal3:
377 case ByteCodeInstruction::kLoadUniform3:
378 case ByteCodeInstruction::kReadExternal3:
379 return 3;
380
381 case ByteCodeInstruction::kDup4:
382 case ByteCodeInstruction::kLoad4:
383 case ByteCodeInstruction::kLoadGlobal4:
384 case ByteCodeInstruction::kLoadUniform4:
385 case ByteCodeInstruction::kReadExternal4:
Brian Osman5aaaeea2020-06-22 14:26:03 -0400386 case ByteCodeInstruction::kLoadFragCoord:
Brian Osmanb08cc022020-04-02 11:38:40 -0400387 return 4;
388
389 case ByteCodeInstruction::kDupN:
Brian Osmanb08cc022020-04-02 11:38:40 -0400390 return count;
391
392 // Pushes 'count' values, minus one for the 'address' that's consumed first
393 case ByteCodeInstruction::kLoadExtended:
394 case ByteCodeInstruction::kLoadExtendedGlobal:
395 case ByteCodeInstruction::kLoadExtendedUniform:
396 return count - 1;
397
398 // Ops that pop or store data to shrink the stack:
399 case ByteCodeInstruction::kPop:
400 case ByteCodeInstruction::kStore:
401 case ByteCodeInstruction::kStoreGlobal:
402 case ByteCodeInstruction::kWriteExternal:
403 return -1;
404
405 case ByteCodeInstruction::kPop2:
406 case ByteCodeInstruction::kStore2:
407 case ByteCodeInstruction::kStoreGlobal2:
408 case ByteCodeInstruction::kWriteExternal2:
409 return -2;
410
411 case ByteCodeInstruction::kPop3:
412 case ByteCodeInstruction::kStore3:
413 case ByteCodeInstruction::kStoreGlobal3:
414 case ByteCodeInstruction::kWriteExternal3:
415 return -3;
416
417 case ByteCodeInstruction::kPop4:
418 case ByteCodeInstruction::kStore4:
419 case ByteCodeInstruction::kStoreGlobal4:
420 case ByteCodeInstruction::kWriteExternal4:
421 return -4;
422
423 case ByteCodeInstruction::kPopN:
Brian Osmanb08cc022020-04-02 11:38:40 -0400424 return -count;
425
426 // Consumes 'count' values, plus one for the 'address'
427 case ByteCodeInstruction::kStoreExtended:
428 case ByteCodeInstruction::kStoreExtendedGlobal:
Brian Osmanb08cc022020-04-02 11:38:40 -0400429 return -count - 1;
430
431 // Strange ops where the caller computes the delta for us:
432 case ByteCodeInstruction::kCallExternal:
433 case ByteCodeInstruction::kMatrixToMatrix:
434 case ByteCodeInstruction::kMatrixMultiply:
435 case ByteCodeInstruction::kReserve:
436 case ByteCodeInstruction::kReturn:
437 case ByteCodeInstruction::kScalarToMatrix:
438 case ByteCodeInstruction::kSwizzle:
439 return count;
440
441 // Miscellaneous
442
Brian Osmana43d8202020-06-17 16:50:39 -0400443 // (X, Y) -> (R, G, B, A)
444 case ByteCodeInstruction::kSampleExplicit: return 4 - 2;
445 // (float3x3) -> (R, G, B, A)
446 case ByteCodeInstruction::kSampleMatrix: return 4 - 9;
447
Brian Osman8842b372020-05-01 15:07:49 -0400448 // kMix does a 3 -> 1 reduction (A, B, M -> A -or- B) for each component
449 case ByteCodeInstruction::kMix: return -2;
450 case ByteCodeInstruction::kMix2: return -4;
451 case ByteCodeInstruction::kMix3: return -6;
452 case ByteCodeInstruction::kMix4: return -8;
453
454 // kLerp works the same way (producing lerp(A, B, T) for each component)
455 case ByteCodeInstruction::kLerp: return -2;
456 case ByteCodeInstruction::kLerp2: return -4;
457 case ByteCodeInstruction::kLerp3: return -6;
458 case ByteCodeInstruction::kLerp4: return -8;
459
Brian Osmanb08cc022020-04-02 11:38:40 -0400460 // kCall is net-zero. Max stack depth is adjusted in writeFunctionCall.
461 case ByteCodeInstruction::kCall: return 0;
462 case ByteCodeInstruction::kBranch: return 0;
463 case ByteCodeInstruction::kBranchIfAllFalse: return 0;
464
465 case ByteCodeInstruction::kMaskPush: return -1;
466 case ByteCodeInstruction::kMaskPop: return 0;
467 case ByteCodeInstruction::kMaskNegate: return 0;
468 case ByteCodeInstruction::kMaskBlend: return -count;
469
470 case ByteCodeInstruction::kLoopBegin: return 0;
471 case ByteCodeInstruction::kLoopNext: return 0;
472 case ByteCodeInstruction::kLoopMask: return -1;
473 case ByteCodeInstruction::kLoopEnd: return 0;
474 case ByteCodeInstruction::kLoopBreak: return 0;
475 case ByteCodeInstruction::kLoopContinue: return 0;
Brian Osmanb08cc022020-04-02 11:38:40 -0400476 }
Brian Osmand5f937b2020-05-04 12:07:29 -0400477
478 SkUNREACHABLE;
Brian Osmanb08cc022020-04-02 11:38:40 -0400479}
480
481ByteCodeGenerator::Location ByteCodeGenerator::getLocation(const Variable& var) {
482 // given that we seldom have more than a couple of variables, linear search is probably the most
483 // efficient way to handle lookups
484 switch (var.fStorage) {
485 case Variable::kLocal_Storage: {
486 for (int i = fLocals.size() - 1; i >= 0; --i) {
487 if (fLocals[i] == &var) {
488 SkASSERT(fParameterCount + i <= 255);
489 return { fParameterCount + i, Storage::kLocal };
490 }
491 }
492 int result = fParameterCount + fLocals.size();
493 fLocals.push_back(&var);
494 for (int i = 0; i < SlotCount(var.fType) - 1; ++i) {
495 fLocals.push_back(nullptr);
496 }
497 SkASSERT(result <= 255);
498 return { result, Storage::kLocal };
499 }
500 case Variable::kParameter_Storage: {
501 int offset = 0;
502 for (const auto& p : fFunction->fDeclaration.fParameters) {
503 if (p == &var) {
504 SkASSERT(offset <= 255);
505 return { offset, Storage::kLocal };
506 }
507 offset += SlotCount(p->fType);
508 }
509 SkASSERT(false);
510 return Location::MakeInvalid();
511 }
512 case Variable::kGlobal_Storage: {
Brian Osmana43d8202020-06-17 16:50:39 -0400513 if (var.fType == *fContext.fFragmentProcessor_Type) {
514 int offset = 0;
515 for (const auto& e : fProgram) {
516 if (e.fKind == ProgramElement::kVar_Kind) {
517 VarDeclarations& decl = (VarDeclarations&) e;
518 for (const auto& v : decl.fVars) {
519 const Variable* declVar = ((VarDeclaration&) *v).fVar;
520 if (declVar->fType != *fContext.fFragmentProcessor_Type) {
521 continue;
522 }
523 if (declVar == &var) {
524 SkASSERT(offset <= 255);
525 return { offset, Storage::kChildFP };
526 }
527 offset++;
528 }
529 }
530 }
531 SkASSERT(false);
532 return Location::MakeInvalid();
533 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400534 if (is_in(var)) {
535 // If you see this error, it means the program is using raw 'in' variables. You
536 // should either specialize the program (Compiler::specialize) to bake in the final
537 // values of the 'in' variables, or not use 'in' variables (maybe you meant to use
538 // 'uniform' instead?).
539 fErrors.error(var.fOffset,
540 "'in' variable is not specialized or has unsupported type");
541 return Location::MakeInvalid();
542 }
543 int offset = 0;
544 bool isUniform = is_uniform(var);
545 for (const auto& e : fProgram) {
546 if (e.fKind == ProgramElement::kVar_Kind) {
547 VarDeclarations& decl = (VarDeclarations&) e;
548 for (const auto& v : decl.fVars) {
549 const Variable* declVar = ((VarDeclaration&) *v).fVar;
550 if (declVar->fModifiers.fLayout.fBuiltin >= 0 || is_in(*declVar)) {
551 continue;
552 }
553 if (isUniform != is_uniform(*declVar)) {
554 continue;
555 }
556 if (declVar == &var) {
557 SkASSERT(offset <= 255);
558 return { offset, isUniform ? Storage::kUniform : Storage::kGlobal };
559 }
560 offset += SlotCount(declVar->fType);
561 }
562 }
563 }
564 SkASSERT(false);
565 return Location::MakeInvalid();
566 }
567 default:
568 SkASSERT(false);
569 return Location::MakeInvalid();
570 }
571}
572
Brian Osman1c110a02019-10-01 14:53:32 -0400573ByteCodeGenerator::Location ByteCodeGenerator::getLocation(const Expression& expr) {
Brian Osman07c117b2019-05-23 12:51:06 -0700574 switch (expr.fKind) {
575 case Expression::kFieldAccess_Kind: {
Brian Osmanb08cc022020-04-02 11:38:40 -0400576 const FieldAccess& f = (const FieldAccess&)expr;
577 Location baseLoc = this->getLocation(*f.fBase);
Brian Osman07c117b2019-05-23 12:51:06 -0700578 int offset = 0;
579 for (int i = 0; i < f.fFieldIndex; ++i) {
580 offset += SlotCount(*f.fBase->fType.fields()[i].fType);
581 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400582 if (baseLoc.isOnStack()) {
583 if (offset != 0) {
584 this->write(ByteCodeInstruction::kPushImmediate);
585 this->write32(offset);
586 this->write(ByteCodeInstruction::kAddI);
Ben Wagner470e0ac2020-01-22 16:59:21 -0500587 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400588 return baseLoc;
Ben Wagner470e0ac2020-01-22 16:59:21 -0500589 } else {
Brian Osmanb08cc022020-04-02 11:38:40 -0400590 return baseLoc + offset;
Ben Wagner470e0ac2020-01-22 16:59:21 -0500591 }
Ben Wagner470e0ac2020-01-22 16:59:21 -0500592 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400593 case Expression::kIndex_Kind: {
594 const IndexExpression& i = (const IndexExpression&)expr;
595 int stride = SlotCount(i.fType);
596 int length = i.fBase->fType.columns();
597 SkASSERT(length <= 255);
598 int offset = -1;
599 if (i.fIndex->isConstant()) {
600 int64_t index = i.fIndex->getConstantInt();
601 if (index < 0 || index >= length) {
602 fErrors.error(i.fIndex->fOffset, "Array index out of bounds.");
603 return Location::MakeInvalid();
604 }
605 offset = index * stride;
606 } else {
607 if (i.fIndex->hasSideEffects()) {
608 // Having a side-effect in an indexer is technically safe for an rvalue,
609 // but with lvalues we have to evaluate the indexer twice, so make it an error.
610 fErrors.error(i.fIndex->fOffset,
611 "Index expressions with side-effects not supported in byte code.");
612 return Location::MakeInvalid();
613 }
614 this->writeExpression(*i.fIndex);
615 this->write(ByteCodeInstruction::kClampIndex);
616 this->write8(length);
617 if (stride != 1) {
618 this->write(ByteCodeInstruction::kPushImmediate);
619 this->write32(stride);
620 this->write(ByteCodeInstruction::kMultiplyI);
Brian Osmanb08cc022020-04-02 11:38:40 -0400621 }
622 }
623 Location baseLoc = this->getLocation(*i.fBase);
624
625 // Are both components known statically?
626 if (!baseLoc.isOnStack() && offset >= 0) {
627 return baseLoc + offset;
628 }
629
630 // At least one component is dynamic (and on the stack).
631
632 // If the other component is zero, we're done
633 if (baseLoc.fSlot == 0 || offset == 0) {
634 return baseLoc.makeOnStack();
635 }
636
637 // Push the non-dynamic component (if any) to the stack, then add the two
638 if (!baseLoc.isOnStack()) {
639 this->write(ByteCodeInstruction::kPushImmediate);
640 this->write32(baseLoc.fSlot);
641 }
642 if (offset >= 0) {
643 this->write(ByteCodeInstruction::kPushImmediate);
644 this->write32(offset);
645 }
646 this->write(ByteCodeInstruction::kAddI);
Brian Osmanb08cc022020-04-02 11:38:40 -0400647 return baseLoc.makeOnStack();
648 }
Brian Osman0785db02019-05-24 14:19:11 -0400649 case Expression::kSwizzle_Kind: {
Brian Osmanb08cc022020-04-02 11:38:40 -0400650 const Swizzle& s = (const Swizzle&)expr;
Brian Osman0785db02019-05-24 14:19:11 -0400651 SkASSERT(swizzle_is_simple(s));
Brian Osmanb08cc022020-04-02 11:38:40 -0400652 Location baseLoc = this->getLocation(*s.fBase);
653 int offset = s.fComponents[0];
654 if (baseLoc.isOnStack()) {
655 if (offset != 0) {
656 this->write(ByteCodeInstruction::kPushImmediate);
657 this->write32(offset);
658 this->write(ByteCodeInstruction::kAddI);
Brian Osmanb08cc022020-04-02 11:38:40 -0400659 }
660 return baseLoc;
661 } else {
662 return baseLoc + offset;
663 }
Brian Osman0785db02019-05-24 14:19:11 -0400664 }
Brian Osman07c117b2019-05-23 12:51:06 -0700665 case Expression::kVariableReference_Kind: {
Brian Osmanb08cc022020-04-02 11:38:40 -0400666 const Variable& var = ((const VariableReference&)expr).fVariable;
Brian Osman07c117b2019-05-23 12:51:06 -0700667 return this->getLocation(var);
668 }
669 default:
670 SkASSERT(false);
Brian Osmanb08cc022020-04-02 11:38:40 -0400671 return Location::MakeInvalid();
Brian Osman07c117b2019-05-23 12:51:06 -0700672 }
673}
674
Brian Osmanb08cc022020-04-02 11:38:40 -0400675void ByteCodeGenerator::write8(uint8_t b) {
676 fCode->push_back(b);
Ethan Nicholas2cde3a12020-01-21 09:23:13 -0500677}
678
Brian Osmanb08cc022020-04-02 11:38:40 -0400679void ByteCodeGenerator::write16(uint16_t i) {
680 size_t n = fCode->size();
681 fCode->resize(n+2);
682 memcpy(fCode->data() + n, &i, 2);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500683}
Ben Wagner470e0ac2020-01-22 16:59:21 -0500684
Brian Osmanb08cc022020-04-02 11:38:40 -0400685void ByteCodeGenerator::write32(uint32_t i) {
686 size_t n = fCode->size();
687 fCode->resize(n+4);
688 memcpy(fCode->data() + n, &i, 4);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500689}
690
Brian Osmanb08cc022020-04-02 11:38:40 -0400691void ByteCodeGenerator::write(ByteCodeInstruction i, int count) {
692 switch (i) {
693 case ByteCodeInstruction::kLoopBegin: this->enterLoop(); break;
694 case ByteCodeInstruction::kLoopEnd: this->exitLoop(); break;
Ethan Nicholas2329da02020-01-24 15:49:33 -0500695
Brian Osmanb08cc022020-04-02 11:38:40 -0400696 case ByteCodeInstruction::kMaskPush: this->enterCondition(); break;
697 case ByteCodeInstruction::kMaskPop:
698 case ByteCodeInstruction::kMaskBlend: this->exitCondition(); break;
699 default: /* Do nothing */ break;
Ben Wagner470e0ac2020-01-22 16:59:21 -0500700 }
Brian Osmanab8f3842020-04-07 09:30:44 -0400701 this->write16((uint16_t)i);
Brian Osmanb08cc022020-04-02 11:38:40 -0400702 fStackCount += StackUsage(i, count);
703 fMaxStackCount = std::max(fMaxStackCount, fStackCount);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500704}
705
Brian Osmanb08cc022020-04-02 11:38:40 -0400706static ByteCodeInstruction vector_instruction(ByteCodeInstruction base, int count) {
707 SkASSERT(count >= 1 && count <= 4);
708 return ((ByteCodeInstruction) ((int) base + 1 - count));
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500709}
710
Brian Osmanb08cc022020-04-02 11:38:40 -0400711void ByteCodeGenerator::writeTypedInstruction(const Type& type, ByteCodeInstruction s,
712 ByteCodeInstruction u, ByteCodeInstruction f,
Brian Osmanab8f3842020-04-07 09:30:44 -0400713 int count) {
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500714 switch (type_category(type)) {
Brian Osman8842b372020-05-01 15:07:49 -0400715 case TypeCategory::kBool:
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500716 case TypeCategory::kSigned:
Brian Osmanb08cc022020-04-02 11:38:40 -0400717 this->write(vector_instruction(s, count));
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500718 break;
719 case TypeCategory::kUnsigned:
Brian Osmanb08cc022020-04-02 11:38:40 -0400720 this->write(vector_instruction(u, count));
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500721 break;
722 case TypeCategory::kFloat: {
Brian Osmanb08cc022020-04-02 11:38:40 -0400723 if (count > 4) {
Brian Osman56079c42020-06-26 11:31:59 -0400724 this->write((ByteCodeInstruction)((int)f + 1 - 5), count);
Brian Osmanab8f3842020-04-07 09:30:44 -0400725 this->write8(count);
Brian Osmanb08cc022020-04-02 11:38:40 -0400726 } else {
727 this->write(vector_instruction(f, count));
728 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500729 break;
730 }
731 default:
732 SkASSERT(false);
733 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500734}
735
Brian Osmanb08cc022020-04-02 11:38:40 -0400736bool ByteCodeGenerator::writeBinaryExpression(const BinaryExpression& b, bool discard) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400737 if (b.fOperator == Token::Kind::TK_EQ) {
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500738 std::unique_ptr<LValue> lvalue = this->getLValue(*b.fLeft);
Brian Osmanb08cc022020-04-02 11:38:40 -0400739 this->writeExpression(*b.fRight);
740 lvalue->store(discard);
741 discard = false;
742 return discard;
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500743 }
744 const Type& lType = b.fLeft->fType;
745 const Type& rType = b.fRight->fType;
746 bool lVecOrMtx = (lType.kind() == Type::kVector_Kind || lType.kind() == Type::kMatrix_Kind);
747 bool rVecOrMtx = (rType.kind() == Type::kVector_Kind || rType.kind() == Type::kMatrix_Kind);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500748 Token::Kind op;
749 std::unique_ptr<LValue> lvalue;
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500750 if (is_assignment(b.fOperator)) {
751 lvalue = this->getLValue(*b.fLeft);
Brian Osmanb08cc022020-04-02 11:38:40 -0400752 lvalue->load();
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500753 op = remove_assignment(b.fOperator);
754 } else {
Brian Osmanb08cc022020-04-02 11:38:40 -0400755 this->writeExpression(*b.fLeft);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500756 op = b.fOperator;
757 if (!lVecOrMtx && rVecOrMtx) {
Brian Osmanb08cc022020-04-02 11:38:40 -0400758 for (int i = SlotCount(rType); i > 1; --i) {
759 this->write(ByteCodeInstruction::kDup);
Brian Osmanb08cc022020-04-02 11:38:40 -0400760 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500761 }
762 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500763 int count = std::max(SlotCount(lType), SlotCount(rType));
Brian Osmanb08cc022020-04-02 11:38:40 -0400764 SkDEBUGCODE(TypeCategory tc = type_category(lType));
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500765 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400766 case Token::Kind::TK_LOGICALAND: {
Brian Osmanb08cc022020-04-02 11:38:40 -0400767 SkASSERT(tc == SkSL::TypeCategory::kBool && count == 1);
768 this->write(ByteCodeInstruction::kDup);
Brian Osmanb08cc022020-04-02 11:38:40 -0400769 this->write(ByteCodeInstruction::kMaskPush);
770 this->write(ByteCodeInstruction::kBranchIfAllFalse);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500771 DeferredLocation falseLocation(this);
Brian Osmanb08cc022020-04-02 11:38:40 -0400772 this->writeExpression(*b.fRight);
773 this->write(ByteCodeInstruction::kAndB);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500774 falseLocation.set();
Brian Osmanb08cc022020-04-02 11:38:40 -0400775 this->write(ByteCodeInstruction::kMaskPop);
776 return false;
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500777 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400778 case Token::Kind::TK_LOGICALOR: {
Brian Osmanb08cc022020-04-02 11:38:40 -0400779 SkASSERT(tc == SkSL::TypeCategory::kBool && count == 1);
780 this->write(ByteCodeInstruction::kDup);
Brian Osmanb08cc022020-04-02 11:38:40 -0400781 this->write(ByteCodeInstruction::kNotB);
782 this->write(ByteCodeInstruction::kMaskPush);
783 this->write(ByteCodeInstruction::kBranchIfAllFalse);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500784 DeferredLocation falseLocation(this);
Brian Osmanb08cc022020-04-02 11:38:40 -0400785 this->writeExpression(*b.fRight);
786 this->write(ByteCodeInstruction::kOrB);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500787 falseLocation.set();
Brian Osmanb08cc022020-04-02 11:38:40 -0400788 this->write(ByteCodeInstruction::kMaskPop);
789 return false;
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500790 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400791 case Token::Kind::TK_SHL:
792 case Token::Kind::TK_SHR: {
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500793 SkASSERT(count == 1 && (tc == SkSL::TypeCategory::kSigned ||
794 tc == SkSL::TypeCategory::kUnsigned));
795 if (!b.fRight->isConstant()) {
796 fErrors.error(b.fRight->fOffset, "Shift amounts must be constant");
Brian Osmanb08cc022020-04-02 11:38:40 -0400797 return false;
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500798 }
799 int64_t shift = b.fRight->getConstantInt();
800 if (shift < 0 || shift > 31) {
801 fErrors.error(b.fRight->fOffset, "Shift amount out of range");
Brian Osmanb08cc022020-04-02 11:38:40 -0400802 return false;
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500803 }
804
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400805 if (op == Token::Kind::TK_SHL) {
Brian Osmanb08cc022020-04-02 11:38:40 -0400806 this->write(ByteCodeInstruction::kShiftLeft);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500807 } else {
808 this->write(type_category(lType) == TypeCategory::kSigned
Brian Osmanb08cc022020-04-02 11:38:40 -0400809 ? ByteCodeInstruction::kShiftRightS
810 : ByteCodeInstruction::kShiftRightU);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500811 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400812 this->write8(shift);
813 return false;
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500814 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500815
816 default:
817 break;
818 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400819 this->writeExpression(*b.fRight);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500820 if (lVecOrMtx && !rVecOrMtx) {
Brian Osmanb08cc022020-04-02 11:38:40 -0400821 for (int i = SlotCount(lType); i > 1; --i) {
822 this->write(ByteCodeInstruction::kDup);
Brian Osmanb08cc022020-04-02 11:38:40 -0400823 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500824 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400825 // Special case for M*V, V*M, M*M (but not V*V!)
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400826 if (op == Token::Kind::TK_STAR && lVecOrMtx && rVecOrMtx &&
Brian Osmanb08cc022020-04-02 11:38:40 -0400827 !(lType.kind() == Type::kVector_Kind && rType.kind() == Type::kVector_Kind)) {
828 this->write(ByteCodeInstruction::kMatrixMultiply,
829 SlotCount(b.fType) - (SlotCount(lType) + SlotCount(rType)));
830 int rCols = rType.columns(),
831 rRows = rType.rows(),
832 lCols = lType.columns(),
833 lRows = lType.rows();
834 // M*V treats the vector as a column
835 if (rType.kind() == Type::kVector_Kind) {
836 std::swap(rCols, rRows);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500837 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400838 SkASSERT(lCols == rRows);
839 SkASSERT(SlotCount(b.fType) == lRows * rCols);
840 this->write8(lCols);
841 this->write8(lRows);
842 this->write8(rCols);
843 } else {
844 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400845 case Token::Kind::TK_EQEQ:
Brian Osmanb08cc022020-04-02 11:38:40 -0400846 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareIEQ,
847 ByteCodeInstruction::kCompareIEQ,
848 ByteCodeInstruction::kCompareFEQ,
849 count);
850 // Collapse to a single bool
851 for (int i = count; i > 1; --i) {
852 this->write(ByteCodeInstruction::kAndB);
853 }
854 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400855 case Token::Kind::TK_GT:
Brian Osmanb08cc022020-04-02 11:38:40 -0400856 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSGT,
857 ByteCodeInstruction::kCompareUGT,
858 ByteCodeInstruction::kCompareFGT,
859 count);
860 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400861 case Token::Kind::TK_GTEQ:
Brian Osmanb08cc022020-04-02 11:38:40 -0400862 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSGTEQ,
863 ByteCodeInstruction::kCompareUGTEQ,
864 ByteCodeInstruction::kCompareFGTEQ,
865 count);
866 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400867 case Token::Kind::TK_LT:
Brian Osmanb08cc022020-04-02 11:38:40 -0400868 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSLT,
869 ByteCodeInstruction::kCompareULT,
870 ByteCodeInstruction::kCompareFLT,
871 count);
872 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400873 case Token::Kind::TK_LTEQ:
Brian Osmanb08cc022020-04-02 11:38:40 -0400874 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSLTEQ,
875 ByteCodeInstruction::kCompareULTEQ,
876 ByteCodeInstruction::kCompareFLTEQ,
877 count);
878 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400879 case Token::Kind::TK_MINUS:
Brian Osmanb08cc022020-04-02 11:38:40 -0400880 this->writeTypedInstruction(lType, ByteCodeInstruction::kSubtractI,
881 ByteCodeInstruction::kSubtractI,
882 ByteCodeInstruction::kSubtractF,
883 count);
884 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400885 case Token::Kind::TK_NEQ:
Brian Osmanb08cc022020-04-02 11:38:40 -0400886 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareINEQ,
887 ByteCodeInstruction::kCompareINEQ,
888 ByteCodeInstruction::kCompareFNEQ,
889 count);
890 // Collapse to a single bool
891 for (int i = count; i > 1; --i) {
892 this->write(ByteCodeInstruction::kOrB);
893 }
894 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400895 case Token::Kind::TK_PERCENT:
Brian Osmanb08cc022020-04-02 11:38:40 -0400896 this->writeTypedInstruction(lType, ByteCodeInstruction::kRemainderS,
897 ByteCodeInstruction::kRemainderU,
898 ByteCodeInstruction::kRemainderF,
899 count);
900 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400901 case Token::Kind::TK_PLUS:
Brian Osmanb08cc022020-04-02 11:38:40 -0400902 this->writeTypedInstruction(lType, ByteCodeInstruction::kAddI,
903 ByteCodeInstruction::kAddI,
904 ByteCodeInstruction::kAddF,
905 count);
906 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400907 case Token::Kind::TK_SLASH:
Brian Osmanb08cc022020-04-02 11:38:40 -0400908 this->writeTypedInstruction(lType, ByteCodeInstruction::kDivideS,
909 ByteCodeInstruction::kDivideU,
910 ByteCodeInstruction::kDivideF,
911 count);
912 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400913 case Token::Kind::TK_STAR:
Brian Osmanb08cc022020-04-02 11:38:40 -0400914 this->writeTypedInstruction(lType, ByteCodeInstruction::kMultiplyI,
915 ByteCodeInstruction::kMultiplyI,
916 ByteCodeInstruction::kMultiplyF,
917 count);
918 break;
919
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400920 case Token::Kind::TK_LOGICALXOR:
Brian Osmanb08cc022020-04-02 11:38:40 -0400921 SkASSERT(tc == SkSL::TypeCategory::kBool && count == 1);
922 this->write(ByteCodeInstruction::kXorB);
923 break;
924
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400925 case Token::Kind::TK_BITWISEAND:
Brian Osmanb08cc022020-04-02 11:38:40 -0400926 SkASSERT(count == 1 && (tc == SkSL::TypeCategory::kSigned ||
927 tc == SkSL::TypeCategory::kUnsigned));
928 this->write(ByteCodeInstruction::kAndB);
929 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400930 case Token::Kind::TK_BITWISEOR:
Brian Osmanb08cc022020-04-02 11:38:40 -0400931 SkASSERT(count == 1 && (tc == SkSL::TypeCategory::kSigned ||
932 tc == SkSL::TypeCategory::kUnsigned));
933 this->write(ByteCodeInstruction::kOrB);
934 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400935 case Token::Kind::TK_BITWISEXOR:
Brian Osmanb08cc022020-04-02 11:38:40 -0400936 SkASSERT(count == 1 && (tc == SkSL::TypeCategory::kSigned ||
937 tc == SkSL::TypeCategory::kUnsigned));
938 this->write(ByteCodeInstruction::kXorB);
939 break;
940
941 default:
942 fErrors.error(b.fOffset, SkSL::String::printf("Unsupported binary operator '%s'",
943 Compiler::OperatorName(op)));
944 break;
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500945 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500946 }
947 if (lvalue) {
Brian Osmanb08cc022020-04-02 11:38:40 -0400948 lvalue->store(discard);
949 discard = false;
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500950 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400951 return discard;
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500952}
953
Brian Osmanb08cc022020-04-02 11:38:40 -0400954void ByteCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
955 this->write(ByteCodeInstruction::kPushImmediate);
956 this->write32(b.fValue ? ~0 : 0);
957}
958
959void ByteCodeGenerator::writeConstructor(const Constructor& c) {
960 for (const auto& arg : c.fArguments) {
961 this->writeExpression(*arg);
962 }
963 if (c.fArguments.size() == 1) {
964 const Type& inType = c.fArguments[0]->fType;
965 const Type& outType = c.fType;
966 TypeCategory inCategory = type_category(inType);
967 TypeCategory outCategory = type_category(outType);
968 int inCount = SlotCount(inType);
969 int outCount = SlotCount(outType);
970 if (inCategory != outCategory) {
971 SkASSERT(inCount == outCount);
972 if (inCategory == TypeCategory::kFloat) {
973 SkASSERT(outCategory == TypeCategory::kSigned ||
974 outCategory == TypeCategory::kUnsigned);
975 this->write(vector_instruction(ByteCodeInstruction::kConvertFtoI, outCount));
976 } else if (outCategory == TypeCategory::kFloat) {
977 if (inCategory == TypeCategory::kSigned) {
978 this->write(vector_instruction(ByteCodeInstruction::kConvertStoF, outCount));
979 } else {
980 SkASSERT(inCategory == TypeCategory::kUnsigned);
981 this->write(vector_instruction(ByteCodeInstruction::kConvertUtoF, outCount));
982 }
983 } else {
984 SkASSERT(false);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500985 }
986 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400987 if (inType.kind() == Type::kMatrix_Kind && outType.kind() == Type::kMatrix_Kind) {
988 this->write(ByteCodeInstruction::kMatrixToMatrix,
989 SlotCount(outType) - SlotCount(inType));
990 this->write8(inType.columns());
991 this->write8(inType.rows());
992 this->write8(outType.columns());
993 this->write8(outType.rows());
994 } else if (inCount != outCount) {
995 SkASSERT(inCount == 1);
996 if (outType.kind() == Type::kMatrix_Kind) {
997 this->write(ByteCodeInstruction::kScalarToMatrix, SlotCount(outType) - 1);
998 this->write8(outType.columns());
999 this->write8(outType.rows());
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001000 } else {
Brian Osmanb08cc022020-04-02 11:38:40 -04001001 SkASSERT(outType.kind() == Type::kVector_Kind);
1002 for (; inCount != outCount; ++inCount) {
1003 this->write(ByteCodeInstruction::kDup);
Brian Osmanb08cc022020-04-02 11:38:40 -04001004 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001005 }
1006 }
1007 }
1008}
1009
Brian Osmanb08cc022020-04-02 11:38:40 -04001010void ByteCodeGenerator::writeExternalFunctionCall(const ExternalFunctionCall& f) {
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001011 int argumentCount = 0;
1012 for (const auto& arg : f.fArguments) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001013 this->writeExpression(*arg);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001014 argumentCount += SlotCount(arg->fType);
1015 }
Brian Osmanb08cc022020-04-02 11:38:40 -04001016 this->write(ByteCodeInstruction::kCallExternal, SlotCount(f.fType) - argumentCount);
1017 SkASSERT(argumentCount <= 255);
1018 this->write8(argumentCount);
1019 this->write8(SlotCount(f.fType));
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001020 int index = fOutput->fExternalValues.size();
1021 fOutput->fExternalValues.push_back(f.fFunction);
1022 SkASSERT(index <= 255);
Brian Osmanb08cc022020-04-02 11:38:40 -04001023 this->write8(index);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001024}
1025
Brian Osmanb08cc022020-04-02 11:38:40 -04001026void ByteCodeGenerator::writeExternalValue(const ExternalValueReference& e) {
1027 int count = SlotCount(e.fValue->type());
1028 this->write(vector_instruction(ByteCodeInstruction::kReadExternal, count));
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001029 int index = fOutput->fExternalValues.size();
1030 fOutput->fExternalValues.push_back(e.fValue);
1031 SkASSERT(index <= 255);
Brian Osmanb08cc022020-04-02 11:38:40 -04001032 this->write8(index);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001033}
1034
Brian Osmanb08cc022020-04-02 11:38:40 -04001035void ByteCodeGenerator::writeVariableExpression(const Expression& expr) {
Brian Osman5aaaeea2020-06-22 14:26:03 -04001036 if (int builtin = expression_as_builtin(expr); builtin >= 0) {
1037 switch (builtin) {
1038 case SK_FRAGCOORD_BUILTIN:
1039 this->write(ByteCodeInstruction::kLoadFragCoord);
1040 fOutput->fUsesFragCoord = true;
1041 break;
1042 default:
1043 fErrors.error(expr.fOffset, "Unsupported builtin");
1044 break;
1045 }
1046 return;
1047 }
1048
Brian Osmanb08cc022020-04-02 11:38:40 -04001049 Location location = this->getLocation(expr);
1050 int count = SlotCount(expr.fType);
Brian Osmanefb08402020-04-13 16:30:44 -04001051 if (count == 0) {
1052 return;
1053 }
Brian Osman02f8b072020-06-19 14:04:48 -04001054 if (location.isOnStack()) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001055 this->write(location.selectLoad(ByteCodeInstruction::kLoadExtended,
1056 ByteCodeInstruction::kLoadExtendedGlobal,
1057 ByteCodeInstruction::kLoadExtendedUniform),
1058 count);
1059 this->write8(count);
1060 } else {
Brian Osman02f8b072020-06-19 14:04:48 -04001061 while (count) {
1062 int loadCount = std::min(count, 4);
1063 this->write(vector_instruction(location.selectLoad(ByteCodeInstruction::kLoad,
1064 ByteCodeInstruction::kLoadGlobal,
1065 ByteCodeInstruction::kLoadUniform),
1066 loadCount));
1067 this->write8(location.fSlot);
1068 count -= loadCount;
1069 location.fSlot += loadCount;
1070 }
Brian Osmanb08cc022020-04-02 11:38:40 -04001071 }
1072}
1073
1074static inline uint32_t float_to_bits(float x) {
1075 uint32_t u;
1076 memcpy(&u, &x, sizeof(uint32_t));
1077 return u;
1078}
1079
1080void ByteCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
1081 this->write(ByteCodeInstruction::kPushImmediate);
1082 this->write32(float_to_bits(f.fValue));
1083}
1084
Brian Osman8842b372020-05-01 15:07:49 -04001085static bool is_generic_type(const Type* type, const Type* generic) {
1086 const std::vector<const Type*>& concrete(generic->coercibleTypes());
1087 return std::find(concrete.begin(), concrete.end(), type) != concrete.end();
1088}
1089
Brian Osmanb08cc022020-04-02 11:38:40 -04001090void ByteCodeGenerator::writeIntrinsicCall(const FunctionCall& c) {
1091 auto found = fIntrinsics.find(c.fFunction.fName);
1092 if (found == fIntrinsics.end()) {
1093 fErrors.error(c.fOffset, String::printf("Unsupported intrinsic: '%s'",
1094 String(c.fFunction.fName).c_str()));
1095 return;
1096 }
Mike Klein45be0772020-05-01 09:13:18 -05001097 Intrinsic intrin = found->second;
Brian Osmanb08cc022020-04-02 11:38:40 -04001098 int count = SlotCount(c.fArguments[0]->fType);
Brian Osmand5f937b2020-05-04 12:07:29 -04001099
1100 // Several intrinsics have variants where one argument is either scalar, or the same size as
1101 // the first argument. Call dupSmallerType(SlotCount(argType)) to ensure equal component count.
1102 auto dupSmallerType = [count, this](int smallCount) {
1103 SkASSERT(smallCount == 1 || smallCount == count);
1104 for (int i = smallCount; i < count; ++i) {
1105 this->write(ByteCodeInstruction::kDup);
1106 }
1107 };
1108
Brian Osmana43d8202020-06-17 16:50:39 -04001109 if (intrin.is_special && intrin.special == SpecialIntrinsic::kSample) {
1110 // Sample is very special, the first argument is an FP, which can't be pushed to the stack
1111 if (c.fArguments.size() != 2 ||
1112 c.fArguments[0]->fType != *fContext.fFragmentProcessor_Type ||
1113 (c.fArguments[1]->fType != *fContext.fFloat2_Type &&
1114 c.fArguments[1]->fType != *fContext.fFloat3x3_Type)) {
1115 fErrors.error(c.fOffset, "Unsupported form of sample");
1116 return;
1117 }
1118
1119 // Write our coords or matrix
1120 this->writeExpression(*c.fArguments[1]);
1121
1122 this->write(c.fArguments[1]->fType == *fContext.fFloat3x3_Type
1123 ? ByteCodeInstruction::kSampleMatrix
1124 : ByteCodeInstruction::kSampleExplicit);
1125
1126 Location childLoc = this->getLocation(*c.fArguments[0]);
1127 SkASSERT(childLoc.fStorage == Storage::kChildFP);
1128 this->write8(childLoc.fSlot);
1129 return;
1130 }
1131
Brian Osmand5f937b2020-05-04 12:07:29 -04001132 if (intrin.is_special && (intrin.special == SpecialIntrinsic::kClamp ||
1133 intrin.special == SpecialIntrinsic::kSaturate)) {
1134 // These intrinsics are extra-special, we need instructions interleaved with arguments
1135 bool saturate = (intrin.special == SpecialIntrinsic::kSaturate);
1136 SkASSERT(c.fArguments.size() == (saturate ? 1 : 3));
1137 int limitCount = saturate ? 1 : SlotCount(c.fArguments[1]->fType);
1138
1139 // 'x'
1140 this->writeExpression(*c.fArguments[0]);
1141
1142 // 'minVal'
1143 if (saturate) {
1144 this->write(ByteCodeInstruction::kPushImmediate);
1145 this->write32(float_to_bits(0.0f));
1146 } else {
1147 this->writeExpression(*c.fArguments[1]);
1148 }
1149 dupSmallerType(limitCount);
1150 this->writeTypedInstruction(c.fArguments[0]->fType,
1151 ByteCodeInstruction::kMaxS,
1152 ByteCodeInstruction::kMaxS,
1153 ByteCodeInstruction::kMaxF,
1154 count);
1155
1156 // 'maxVal'
1157 if (saturate) {
1158 this->write(ByteCodeInstruction::kPushImmediate);
1159 this->write32(float_to_bits(1.0f));
1160 } else {
1161 SkASSERT(limitCount == SlotCount(c.fArguments[2]->fType));
1162 this->writeExpression(*c.fArguments[2]);
1163 }
1164 dupSmallerType(limitCount);
1165 this->writeTypedInstruction(c.fArguments[0]->fType,
1166 ByteCodeInstruction::kMinS,
1167 ByteCodeInstruction::kMinS,
1168 ByteCodeInstruction::kMinF,
1169 count);
1170 return;
1171 }
1172
1173 // All other intrinsics can handle their arguments being on the stack in order
1174 for (const auto& arg : c.fArguments) {
1175 this->writeExpression(*arg);
1176 }
1177
Mike Klein45be0772020-05-01 09:13:18 -05001178 if (intrin.is_special) {
1179 switch (intrin.special) {
Brian Osman8842b372020-05-01 15:07:49 -04001180 case SpecialIntrinsic::kAll: {
1181 for (int i = count-1; i --> 0;) {
1182 this->write(ByteCodeInstruction::kAndB);
1183 }
1184 } break;
1185
1186 case SpecialIntrinsic::kAny: {
1187 for (int i = count-1; i --> 0;) {
1188 this->write(ByteCodeInstruction::kOrB);
1189 }
1190 } break;
1191
Brian Osman15c98cb2020-02-27 18:36:57 +00001192 case SpecialIntrinsic::kDot: {
1193 SkASSERT(c.fArguments.size() == 2);
Brian Osmanb08cc022020-04-02 11:38:40 -04001194 SkASSERT(count == SlotCount(c.fArguments[1]->fType));
1195 this->write(vector_instruction(ByteCodeInstruction::kMultiplyF, count));
Mike Klein45be0772020-05-01 09:13:18 -05001196 for (int i = count-1; i --> 0;) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001197 this->write(ByteCodeInstruction::kAddF);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001198 }
Mike Klein45be0772020-05-01 09:13:18 -05001199 } break;
1200
1201 case SpecialIntrinsic::kLength: {
1202 SkASSERT(c.fArguments.size() == 1);
1203 this->write(vector_instruction(ByteCodeInstruction::kDup , count));
1204 this->write(vector_instruction(ByteCodeInstruction::kMultiplyF, count));
1205 for (int i = count-1; i --> 0;) {
1206 this->write(ByteCodeInstruction::kAddF);
1207 }
1208 this->write(ByteCodeInstruction::kSqrt);
1209 } break;
1210
Brian Osmand5f937b2020-05-04 12:07:29 -04001211 case SpecialIntrinsic::kMax:
1212 case SpecialIntrinsic::kMin: {
1213 SkASSERT(c.fArguments.size() == 2);
1214 // There are variants where the second argument is scalar
1215 dupSmallerType(SlotCount(c.fArguments[1]->fType));
1216 if (intrin.special == SpecialIntrinsic::kMax) {
1217 this->writeTypedInstruction(c.fArguments[0]->fType,
1218 ByteCodeInstruction::kMaxS,
1219 ByteCodeInstruction::kMaxS,
1220 ByteCodeInstruction::kMaxF,
1221 count);
1222 } else {
1223 this->writeTypedInstruction(c.fArguments[0]->fType,
1224 ByteCodeInstruction::kMinS,
1225 ByteCodeInstruction::kMinS,
1226 ByteCodeInstruction::kMinF,
1227 count);
1228 }
1229 } break;
1230
Brian Osman8842b372020-05-01 15:07:49 -04001231 case SpecialIntrinsic::kMix: {
1232 // Two main variants of mix to handle
1233 SkASSERT(c.fArguments.size() == 3);
1234 SkASSERT(count == SlotCount(c.fArguments[1]->fType));
1235 int selectorCount = SlotCount(c.fArguments[2]->fType);
1236
1237 if (is_generic_type(&c.fArguments[2]->fType, fContext.fGenBType_Type.get())) {
1238 // mix(genType, genType, genBoolType)
1239 SkASSERT(selectorCount == count);
1240 this->write(vector_instruction(ByteCodeInstruction::kMix, count));
1241 } else {
1242 // mix(genType, genType, genType) or mix(genType, genType, float)
Brian Osmand5f937b2020-05-04 12:07:29 -04001243 dupSmallerType(selectorCount);
Brian Osman8842b372020-05-01 15:07:49 -04001244 this->write(vector_instruction(ByteCodeInstruction::kLerp, count));
1245 }
1246 } break;
1247
Brian Osman2a4871b2020-06-19 11:29:58 -04001248 case SpecialIntrinsic::kNormalize: {
1249 SkASSERT(c.fArguments.size() == 1);
1250 this->write(vector_instruction(ByteCodeInstruction::kDup , count));
1251 this->write(vector_instruction(ByteCodeInstruction::kDup , count));
1252 this->write(vector_instruction(ByteCodeInstruction::kMultiplyF, count));
1253 for (int i = count-1; i --> 0;) {
1254 this->write(ByteCodeInstruction::kAddF);
1255 }
1256 this->write(ByteCodeInstruction::kSqrt);
1257 dupSmallerType(1);
1258 this->write(vector_instruction(ByteCodeInstruction::kDivideF, count));
1259 } break;
1260
Brian Osmanb08cc022020-04-02 11:38:40 -04001261 default:
1262 SkASSERT(false);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001263 }
1264 } else {
Brian Osman8842b372020-05-01 15:07:49 -04001265 switch (intrin.inst_f) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001266 case ByteCodeInstruction::kInverse2x2: {
1267 SkASSERT(c.fArguments.size() > 0);
1268 auto op = ByteCodeInstruction::kInverse2x2;
1269 switch (count) {
1270 case 4: break; // float2x2
1271 case 9: op = ByteCodeInstruction::kInverse3x3; break;
1272 case 16: op = ByteCodeInstruction::kInverse4x4; break;
1273 default: SkASSERT(false);
1274 }
1275 this->write(op);
1276 break;
Brian Osman15c98cb2020-02-27 18:36:57 +00001277 }
Mike Klein45be0772020-05-01 09:13:18 -05001278
Brian Osmanb08cc022020-04-02 11:38:40 -04001279 default:
Brian Osman8842b372020-05-01 15:07:49 -04001280 this->writeTypedInstruction(c.fArguments[0]->fType, intrin.inst_s, intrin.inst_u,
1281 intrin.inst_f, count);
1282 break;
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001283 }
1284 }
1285}
1286
Brian Osmanb08cc022020-04-02 11:38:40 -04001287void ByteCodeGenerator::writeFunctionCall(const FunctionCall& f) {
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001288 // Find the index of the function we're calling. We explicitly do not allow calls to functions
1289 // before they're defined. This is an easy-to-understand rule that prevents recursion.
Brian Osmanb08cc022020-04-02 11:38:40 -04001290 int idx = -1;
1291 for (size_t i = 0; i < fFunctions.size(); ++i) {
1292 if (f.fFunction.matches(fFunctions[i]->fDeclaration)) {
1293 idx = i;
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001294 break;
1295 }
1296 }
Brian Osmanb08cc022020-04-02 11:38:40 -04001297 if (idx == -1) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001298 this->writeIntrinsicCall(f);
1299 return;
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001300 }
Brian Osmanb08cc022020-04-02 11:38:40 -04001301
1302
1303 if (idx > 255) {
1304 fErrors.error(f.fOffset, "Function count limit exceeded");
1305 return;
1306 } else if (idx >= (int) fFunctions.size()) {
1307 fErrors.error(f.fOffset, "Call to undefined function");
1308 return;
1309 }
1310
1311 // We may need to deal with out parameters, so the sequence is tricky
1312 if (int returnCount = SlotCount(f.fType)) {
1313 this->write(ByteCodeInstruction::kReserve, returnCount);
1314 this->write8(returnCount);
1315 }
1316
1317 int argCount = f.fArguments.size();
1318 std::vector<std::unique_ptr<LValue>> lvalues;
1319 for (int i = 0; i < argCount; ++i) {
1320 const auto& param = f.fFunction.fParameters[i];
1321 const auto& arg = f.fArguments[i];
1322 if (param->fModifiers.fFlags & Modifiers::kOut_Flag) {
1323 lvalues.emplace_back(this->getLValue(*arg));
1324 lvalues.back()->load();
1325 } else {
1326 this->writeExpression(*arg);
1327 }
1328 }
1329
1330 // The space used by the call is based on the callee, but it also unwinds all of that before
1331 // we continue execution. We adjust our max stack depths below.
1332 this->write(ByteCodeInstruction::kCall);
1333 this->write8(idx);
1334
1335 const ByteCodeFunction* callee = fOutput->fFunctions[idx].get();
1336 fMaxLoopCount = std::max(fMaxLoopCount, fLoopCount + callee->fLoopCount);
1337 fMaxConditionCount = std::max(fMaxConditionCount, fConditionCount + callee->fConditionCount);
1338 fMaxStackCount = std::max(fMaxStackCount, fStackCount + callee->fLocalCount
1339 + callee->fStackCount);
1340
1341 // After the called function returns, the stack will still contain our arguments. We have to
1342 // pop them (storing any out parameters back to their lvalues as we go). We glob together slot
1343 // counts for all parameters that aren't out-params, so we can pop them in one big chunk.
1344 int popCount = 0;
1345 auto pop = [&]() {
1346 if (popCount > 4) {
1347 this->write(ByteCodeInstruction::kPopN, popCount);
1348 this->write8(popCount);
1349 } else if (popCount > 0) {
1350 this->write(vector_instruction(ByteCodeInstruction::kPop, popCount));
1351 }
1352 popCount = 0;
1353 };
1354
1355 for (int i = argCount - 1; i >= 0; --i) {
1356 const auto& param = f.fFunction.fParameters[i];
1357 const auto& arg = f.fArguments[i];
1358 if (param->fModifiers.fFlags & Modifiers::kOut_Flag) {
1359 pop();
1360 lvalues.back()->store(true);
1361 lvalues.pop_back();
1362 } else {
1363 popCount += SlotCount(arg->fType);
1364 }
1365 }
1366 pop();
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001367}
1368
Brian Osmanb08cc022020-04-02 11:38:40 -04001369void ByteCodeGenerator::writeIntLiteral(const IntLiteral& i) {
1370 this->write(ByteCodeInstruction::kPushImmediate);
1371 this->write32(i.fValue);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001372}
1373
Brian Osmanb08cc022020-04-02 11:38:40 -04001374void ByteCodeGenerator::writeNullLiteral(const NullLiteral& n) {
1375 // not yet implemented
1376 abort();
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001377}
1378
Brian Osmanb08cc022020-04-02 11:38:40 -04001379bool ByteCodeGenerator::writePrefixExpression(const PrefixExpression& p, bool discard) {
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001380 switch (p.fOperator) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001381 case Token::Kind::TK_PLUSPLUS: // fall through
1382 case Token::Kind::TK_MINUSMINUS: {
Brian Osmanb08cc022020-04-02 11:38:40 -04001383 SkASSERT(SlotCount(p.fOperand->fType) == 1);
1384 std::unique_ptr<LValue> lvalue = this->getLValue(*p.fOperand);
1385 lvalue->load();
1386 this->write(ByteCodeInstruction::kPushImmediate);
1387 this->write32(type_category(p.fType) == TypeCategory::kFloat ? float_to_bits(1.0f) : 1);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001388 if (p.fOperator == Token::Kind::TK_PLUSPLUS) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001389 this->writeTypedInstruction(p.fType,
1390 ByteCodeInstruction::kAddI,
1391 ByteCodeInstruction::kAddI,
1392 ByteCodeInstruction::kAddF,
1393 1);
1394 } else {
1395 this->writeTypedInstruction(p.fType,
1396 ByteCodeInstruction::kSubtractI,
1397 ByteCodeInstruction::kSubtractI,
1398 ByteCodeInstruction::kSubtractF,
1399 1);
1400 }
1401 lvalue->store(discard);
1402 discard = false;
1403 break;
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001404 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001405 case Token::Kind::TK_MINUS: {
Brian Osmanb08cc022020-04-02 11:38:40 -04001406 this->writeExpression(*p.fOperand);
1407 this->writeTypedInstruction(p.fType,
1408 ByteCodeInstruction::kNegateI,
1409 ByteCodeInstruction::kNegateI,
1410 ByteCodeInstruction::kNegateF,
Brian Osmanab8f3842020-04-07 09:30:44 -04001411 SlotCount(p.fOperand->fType));
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001412 break;
1413 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001414 case Token::Kind::TK_LOGICALNOT:
1415 case Token::Kind::TK_BITWISENOT: {
Brian Osmanb08cc022020-04-02 11:38:40 -04001416 SkASSERT(SlotCount(p.fOperand->fType) == 1);
1417 SkDEBUGCODE(TypeCategory tc = type_category(p.fOperand->fType));
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001418 SkASSERT((p.fOperator == Token::Kind::TK_LOGICALNOT && tc == TypeCategory::kBool) ||
1419 (p.fOperator == Token::Kind::TK_BITWISENOT && (tc == TypeCategory::kSigned ||
Brian Osmanb08cc022020-04-02 11:38:40 -04001420 tc == TypeCategory::kUnsigned)));
1421 this->writeExpression(*p.fOperand);
1422 this->write(ByteCodeInstruction::kNotB);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001423 break;
1424 }
1425 default:
1426 SkASSERT(false);
1427 }
Brian Osmanb08cc022020-04-02 11:38:40 -04001428 return discard;
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001429}
1430
Brian Osmanb08cc022020-04-02 11:38:40 -04001431bool ByteCodeGenerator::writePostfixExpression(const PostfixExpression& p, bool discard) {
1432 switch (p.fOperator) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001433 case Token::Kind::TK_PLUSPLUS: // fall through
1434 case Token::Kind::TK_MINUSMINUS: {
Brian Osmanb08cc022020-04-02 11:38:40 -04001435 SkASSERT(SlotCount(p.fOperand->fType) == 1);
1436 std::unique_ptr<LValue> lvalue = this->getLValue(*p.fOperand);
1437 lvalue->load();
1438 // If we're not supposed to discard the result, then make a copy *before* the +/-
1439 if (!discard) {
1440 this->write(ByteCodeInstruction::kDup);
Brian Osmanb08cc022020-04-02 11:38:40 -04001441 }
1442 this->write(ByteCodeInstruction::kPushImmediate);
1443 this->write32(type_category(p.fType) == TypeCategory::kFloat ? float_to_bits(1.0f) : 1);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001444 if (p.fOperator == Token::Kind::TK_PLUSPLUS) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001445 this->writeTypedInstruction(p.fType,
1446 ByteCodeInstruction::kAddI,
1447 ByteCodeInstruction::kAddI,
1448 ByteCodeInstruction::kAddF,
1449 1);
1450 } else {
1451 this->writeTypedInstruction(p.fType,
1452 ByteCodeInstruction::kSubtractI,
1453 ByteCodeInstruction::kSubtractI,
1454 ByteCodeInstruction::kSubtractF,
1455 1);
1456 }
1457 // Always consume the result as part of the store
1458 lvalue->store(true);
1459 discard = false;
1460 break;
1461 }
1462 default:
1463 SkASSERT(false);
1464 }
1465 return discard;
1466}
1467
1468void ByteCodeGenerator::writeSwizzle(const Swizzle& s) {
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001469 if (swizzle_is_simple(s)) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001470 this->writeVariableExpression(s);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001471 return;
1472 }
Brian Osmanb08cc022020-04-02 11:38:40 -04001473
Brian Osman3711c662020-06-18 14:42:21 -04001474 this->writeExpression(*s.fBase);
1475 this->write(ByteCodeInstruction::kSwizzle, s.fComponents.size() - s.fBase->fType.columns());
1476 this->write8(s.fBase->fType.columns());
1477 this->write8(s.fComponents.size());
1478 for (int c : s.fComponents) {
1479 this->write8(c);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001480 }
1481}
1482
Brian Osmanb08cc022020-04-02 11:38:40 -04001483void ByteCodeGenerator::writeTernaryExpression(const TernaryExpression& t) {
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001484 int count = SlotCount(t.fType);
1485 SkASSERT(count == SlotCount(t.fIfTrue->fType));
1486 SkASSERT(count == SlotCount(t.fIfFalse->fType));
1487
Brian Osmanb08cc022020-04-02 11:38:40 -04001488 this->writeExpression(*t.fTest);
1489 this->write(ByteCodeInstruction::kMaskPush);
1490 this->writeExpression(*t.fIfTrue);
1491 this->write(ByteCodeInstruction::kMaskNegate);
1492 this->writeExpression(*t.fIfFalse);
1493 this->write(ByteCodeInstruction::kMaskBlend, count);
1494 this->write8(count);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001495}
1496
Brian Osmanb08cc022020-04-02 11:38:40 -04001497void ByteCodeGenerator::writeExpression(const Expression& e, bool discard) {
1498 switch (e.fKind) {
1499 case Expression::kBinary_Kind:
1500 discard = this->writeBinaryExpression((BinaryExpression&) e, discard);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001501 break;
Brian Osmanb08cc022020-04-02 11:38:40 -04001502 case Expression::kBoolLiteral_Kind:
1503 this->writeBoolLiteral((BoolLiteral&) e);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001504 break;
Brian Osmanb08cc022020-04-02 11:38:40 -04001505 case Expression::kConstructor_Kind:
1506 this->writeConstructor((Constructor&) e);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001507 break;
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001508 case Expression::kExternalFunctionCall_Kind:
Brian Osmanb08cc022020-04-02 11:38:40 -04001509 this->writeExternalFunctionCall((ExternalFunctionCall&) e);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001510 break;
1511 case Expression::kExternalValue_Kind:
Brian Osmanb08cc022020-04-02 11:38:40 -04001512 this->writeExternalValue((ExternalValueReference&) e);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001513 break;
1514 case Expression::kFieldAccess_Kind:
1515 case Expression::kIndex_Kind:
1516 case Expression::kVariableReference_Kind:
Brian Osmanb08cc022020-04-02 11:38:40 -04001517 this->writeVariableExpression(e);
1518 break;
1519 case Expression::kFloatLiteral_Kind:
1520 this->writeFloatLiteral((FloatLiteral&) e);
1521 break;
1522 case Expression::kFunctionCall_Kind:
1523 this->writeFunctionCall((FunctionCall&) e);
1524 break;
1525 case Expression::kIntLiteral_Kind:
1526 this->writeIntLiteral((IntLiteral&) e);
1527 break;
1528 case Expression::kNullLiteral_Kind:
1529 this->writeNullLiteral((NullLiteral&) e);
1530 break;
1531 case Expression::kPrefix_Kind:
1532 discard = this->writePrefixExpression((PrefixExpression&) e, discard);
1533 break;
1534 case Expression::kPostfix_Kind:
1535 discard = this->writePostfixExpression((PostfixExpression&) e, discard);
1536 break;
1537 case Expression::kSwizzle_Kind:
1538 this->writeSwizzle((Swizzle&) e);
1539 break;
1540 case Expression::kTernary_Kind:
1541 this->writeTernaryExpression((TernaryExpression&) e);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001542 break;
Ben Wagner470e0ac2020-01-22 16:59:21 -05001543 default:
1544#ifdef SK_DEBUG
Brian Osmanb08cc022020-04-02 11:38:40 -04001545 printf("unsupported expression %s\n", e.description().c_str());
Ben Wagner470e0ac2020-01-22 16:59:21 -05001546#endif
Brian Osmanb08cc022020-04-02 11:38:40 -04001547 SkASSERT(false);
1548 }
1549 if (discard) {
1550 int count = SlotCount(e.fType);
1551 if (count > 4) {
1552 this->write(ByteCodeInstruction::kPopN, count);
1553 this->write8(count);
1554 } else if (count != 0) {
1555 this->write(vector_instruction(ByteCodeInstruction::kPop, count));
1556 }
1557 discard = false;
Ben Wagner470e0ac2020-01-22 16:59:21 -05001558 }
Ethan Nicholas7deb1c22020-01-22 10:31:55 -05001559}
1560
Brian Osmanb08cc022020-04-02 11:38:40 -04001561class ByteCodeExternalValueLValue : public ByteCodeGenerator::LValue {
1562public:
1563 ByteCodeExternalValueLValue(ByteCodeGenerator* generator, ExternalValue& value, int index)
1564 : INHERITED(*generator)
1565 , fCount(ByteCodeGenerator::SlotCount(value.type()))
1566 , fIndex(index) {}
1567
1568 void load() override {
1569 fGenerator.write(vector_instruction(ByteCodeInstruction::kReadExternal, fCount));
Brian Osmanb08cc022020-04-02 11:38:40 -04001570 fGenerator.write8(fIndex);
1571 }
1572
1573 void store(bool discard) override {
1574 if (!discard) {
1575 fGenerator.write(vector_instruction(ByteCodeInstruction::kDup, fCount));
Brian Osmanb08cc022020-04-02 11:38:40 -04001576 }
1577 fGenerator.write(vector_instruction(ByteCodeInstruction::kWriteExternal, fCount));
Brian Osmanb08cc022020-04-02 11:38:40 -04001578 fGenerator.write8(fIndex);
1579 }
1580
1581private:
1582 typedef LValue INHERITED;
1583
1584 int fCount;
1585
1586 int fIndex;
1587};
1588
1589class ByteCodeSwizzleLValue : public ByteCodeGenerator::LValue {
1590public:
1591 ByteCodeSwizzleLValue(ByteCodeGenerator* generator, const Swizzle& swizzle)
1592 : INHERITED(*generator)
1593 , fSwizzle(swizzle) {}
1594
1595 void load() override {
1596 fGenerator.writeSwizzle(fSwizzle);
1597 }
1598
1599 void store(bool discard) override {
1600 int count = fSwizzle.fComponents.size();
1601 if (!discard) {
1602 fGenerator.write(vector_instruction(ByteCodeInstruction::kDup, count));
Brian Osmanb08cc022020-04-02 11:38:40 -04001603 }
Brian Osman304dfa32020-06-18 15:53:51 -04001604 // We already have the correct number of values on the stack, thanks to type checking.
1605 // The algorithm: Walk down the values on the stack, doing 'count' single-element stores.
1606 // For each value, use the corresponding swizzle component to offset the store location.
1607 //
1608 // Static locations: We (wastefully) call getLocation every time, but get good byte code.
1609 // Note that we could (but don't) store adjacent/sequential values with fewer instructions.
1610 //
1611 // Dynamic locations: ... are bad. We have to recompute the base address on each iteration,
1612 // because the stack doesn't let us retain that address between stores. Dynamic locations
1613 // are rare though, and swizzled writes to those are even rarer, so we just live with this.
1614 for (int i = count; i-- > 0;) {
1615 ByteCodeGenerator::Location location = fGenerator.getLocation(*fSwizzle.fBase);
1616 if (!location.isOnStack()) {
1617 fGenerator.write(location.selectStore(ByteCodeInstruction::kStore,
1618 ByteCodeInstruction::kStoreGlobal));
1619 fGenerator.write8(location.fSlot + fSwizzle.fComponents[i]);
1620 } else {
1621 fGenerator.write(ByteCodeInstruction::kPushImmediate);
1622 fGenerator.write32(fSwizzle.fComponents[i]);
1623 fGenerator.write(ByteCodeInstruction::kAddI);
1624 fGenerator.write(location.selectStore(ByteCodeInstruction::kStoreExtended,
1625 ByteCodeInstruction::kStoreExtendedGlobal),
1626 1);
1627 fGenerator.write8(1);
1628 }
Brian Osmanb08cc022020-04-02 11:38:40 -04001629 }
1630 }
1631
1632private:
1633 const Swizzle& fSwizzle;
1634
1635 typedef LValue INHERITED;
1636};
1637
1638class ByteCodeExpressionLValue : public ByteCodeGenerator::LValue {
1639public:
1640 ByteCodeExpressionLValue(ByteCodeGenerator* generator, const Expression& expr)
1641 : INHERITED(*generator)
1642 , fExpression(expr) {}
1643
1644 void load() override {
1645 fGenerator.writeVariableExpression(fExpression);
1646 }
1647
1648 void store(bool discard) override {
1649 int count = ByteCodeGenerator::SlotCount(fExpression.fType);
1650 if (!discard) {
1651 if (count > 4) {
1652 fGenerator.write(ByteCodeInstruction::kDupN, count);
1653 fGenerator.write8(count);
1654 } else {
1655 fGenerator.write(vector_instruction(ByteCodeInstruction::kDup, count));
Brian Osmanb08cc022020-04-02 11:38:40 -04001656 }
1657 }
1658 ByteCodeGenerator::Location location = fGenerator.getLocation(fExpression);
1659 if (location.isOnStack() || count > 4) {
1660 if (!location.isOnStack()) {
1661 fGenerator.write(ByteCodeInstruction::kPushImmediate);
1662 fGenerator.write32(location.fSlot);
1663 }
1664 fGenerator.write(location.selectStore(ByteCodeInstruction::kStoreExtended,
1665 ByteCodeInstruction::kStoreExtendedGlobal),
1666 count);
1667 fGenerator.write8(count);
1668 } else {
1669 fGenerator.write(
1670 vector_instruction(location.selectStore(ByteCodeInstruction::kStore,
1671 ByteCodeInstruction::kStoreGlobal),
1672 count));
1673 fGenerator.write8(location.fSlot);
1674 }
1675 }
1676
1677private:
1678 typedef LValue INHERITED;
1679
1680 const Expression& fExpression;
1681};
1682
1683std::unique_ptr<ByteCodeGenerator::LValue> ByteCodeGenerator::getLValue(const Expression& e) {
1684 switch (e.fKind) {
1685 case Expression::kExternalValue_Kind: {
1686 ExternalValue* value = ((ExternalValueReference&) e).fValue;
1687 int index = fOutput->fExternalValues.size();
1688 fOutput->fExternalValues.push_back(value);
1689 SkASSERT(index <= 255);
1690 return std::unique_ptr<LValue>(new ByteCodeExternalValueLValue(this, *value, index));
1691 }
1692 case Expression::kFieldAccess_Kind:
1693 case Expression::kIndex_Kind:
1694 case Expression::kVariableReference_Kind:
1695 return std::unique_ptr<LValue>(new ByteCodeExpressionLValue(this, e));
1696 case Expression::kSwizzle_Kind: {
1697 const Swizzle& s = (const Swizzle&) e;
1698 return swizzle_is_simple(s)
1699 ? std::unique_ptr<LValue>(new ByteCodeExpressionLValue(this, e))
1700 : std::unique_ptr<LValue>(new ByteCodeSwizzleLValue(this, s));
1701 }
1702 case Expression::kTernary_Kind:
1703 default:
1704#ifdef SK_DEBUG
1705 ABORT("unsupported lvalue %s\n", e.description().c_str());
1706#endif
1707 return nullptr;
1708 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001709}
1710
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001711void ByteCodeGenerator::writeBlock(const Block& b) {
1712 for (const auto& s : b.fStatements) {
1713 this->writeStatement(*s);
1714 }
1715}
1716
Brian Osmanb08cc022020-04-02 11:38:40 -04001717void ByteCodeGenerator::setBreakTargets() {
1718 std::vector<DeferredLocation>& breaks = fBreakTargets.top();
1719 for (DeferredLocation& b : breaks) {
1720 b.set();
1721 }
1722 fBreakTargets.pop();
1723}
1724
1725void ByteCodeGenerator::setContinueTargets() {
1726 std::vector<DeferredLocation>& continues = fContinueTargets.top();
1727 for (DeferredLocation& c : continues) {
1728 c.set();
1729 }
1730 fContinueTargets.pop();
1731}
1732
1733void ByteCodeGenerator::writeBreakStatement(const BreakStatement& b) {
1734 // TODO: Include BranchIfAllFalse to top-most LoopNext
1735 this->write(ByteCodeInstruction::kLoopBreak);
1736}
1737
1738void ByteCodeGenerator::writeContinueStatement(const ContinueStatement& c) {
1739 // TODO: Include BranchIfAllFalse to top-most LoopNext
1740 this->write(ByteCodeInstruction::kLoopContinue);
1741}
1742
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001743void ByteCodeGenerator::writeDoStatement(const DoStatement& d) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001744 this->write(ByteCodeInstruction::kLoopBegin);
1745 size_t start = fCode->size();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001746 this->writeStatement(*d.fStatement);
Brian Osmanb08cc022020-04-02 11:38:40 -04001747 this->write(ByteCodeInstruction::kLoopNext);
1748 this->writeExpression(*d.fTest);
1749 this->write(ByteCodeInstruction::kLoopMask);
1750 // TODO: Could shorten this with kBranchIfAnyTrue
1751 this->write(ByteCodeInstruction::kBranchIfAllFalse);
Brian Osman569f12f2019-06-13 11:23:57 -04001752 DeferredLocation endLocation(this);
Brian Osmanb08cc022020-04-02 11:38:40 -04001753 this->write(ByteCodeInstruction::kBranch);
1754 this->write16(start);
Brian Osman569f12f2019-06-13 11:23:57 -04001755 endLocation.set();
Brian Osmanb08cc022020-04-02 11:38:40 -04001756 this->write(ByteCodeInstruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001757}
1758
1759void ByteCodeGenerator::writeForStatement(const ForStatement& f) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001760 fContinueTargets.emplace();
1761 fBreakTargets.emplace();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001762 if (f.fInitializer) {
1763 this->writeStatement(*f.fInitializer);
1764 }
Brian Osmanb08cc022020-04-02 11:38:40 -04001765 this->write(ByteCodeInstruction::kLoopBegin);
1766 size_t start = fCode->size();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001767 if (f.fTest) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001768 this->writeExpression(*f.fTest);
1769 this->write(ByteCodeInstruction::kLoopMask);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001770 }
Brian Osmanb08cc022020-04-02 11:38:40 -04001771 this->write(ByteCodeInstruction::kBranchIfAllFalse);
Brian Osman569f12f2019-06-13 11:23:57 -04001772 DeferredLocation endLocation(this);
1773 this->writeStatement(*f.fStatement);
Brian Osmanb08cc022020-04-02 11:38:40 -04001774 this->write(ByteCodeInstruction::kLoopNext);
Brian Osman569f12f2019-06-13 11:23:57 -04001775 if (f.fNext) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001776 this->writeExpression(*f.fNext, true);
Brian Osman569f12f2019-06-13 11:23:57 -04001777 }
Brian Osmanb08cc022020-04-02 11:38:40 -04001778 this->write(ByteCodeInstruction::kBranch);
1779 this->write16(start);
Brian Osman569f12f2019-06-13 11:23:57 -04001780 endLocation.set();
Brian Osmanb08cc022020-04-02 11:38:40 -04001781 this->write(ByteCodeInstruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001782}
1783
1784void ByteCodeGenerator::writeIfStatement(const IfStatement& i) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001785 this->writeExpression(*i.fTest);
1786 this->write(ByteCodeInstruction::kMaskPush);
1787 this->write(ByteCodeInstruction::kBranchIfAllFalse);
Brian Osman569f12f2019-06-13 11:23:57 -04001788 DeferredLocation falseLocation(this);
1789 this->writeStatement(*i.fIfTrue);
1790 falseLocation.set();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001791 if (i.fIfFalse) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001792 this->write(ByteCodeInstruction::kMaskNegate);
1793 this->write(ByteCodeInstruction::kBranchIfAllFalse);
Brian Osman569f12f2019-06-13 11:23:57 -04001794 DeferredLocation endLocation(this);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001795 this->writeStatement(*i.fIfFalse);
Mike Kleinb45ee832019-05-17 11:11:11 -05001796 endLocation.set();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001797 }
Brian Osmanb08cc022020-04-02 11:38:40 -04001798 this->write(ByteCodeInstruction::kMaskPop);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001799}
1800
Brian Osmanb08cc022020-04-02 11:38:40 -04001801void ByteCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
1802 if (fLoopCount || fConditionCount) {
Brian Osman4a47da72019-07-12 11:30:32 -04001803 fErrors.error(r.fOffset, "return not allowed inside conditional or loop");
1804 return;
1805 }
Brian Osmanb08cc022020-04-02 11:38:40 -04001806 int count = SlotCount(r.fExpression->fType);
1807 this->writeExpression(*r.fExpression);
1808
1809 // Technically, the kReturn also pops fOutput->fLocalCount values from the stack, too, but we
1810 // haven't counted pushing those (they're outside the scope of our stack tracking). Instead,
1811 // we account for those in writeFunction().
1812
1813 // This is all fine because we don't allow conditional returns, so we only return once anyway.
1814 this->write(ByteCodeInstruction::kReturn, -count);
1815 this->write8(count);
1816}
1817
1818void ByteCodeGenerator::writeSwitchStatement(const SwitchStatement& r) {
1819 // not yet implemented
1820 abort();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001821}
1822
1823void ByteCodeGenerator::writeVarDeclarations(const VarDeclarations& v) {
1824 for (const auto& declStatement : v.fVars) {
1825 const VarDeclaration& decl = (VarDeclaration&) *declStatement;
Brian Osmanb08cc022020-04-02 11:38:40 -04001826 // we need to grab the location even if we don't use it, to ensure it has been allocated
1827 Location location = this->getLocation(*decl.fVar);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001828 if (decl.fValue) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001829 this->writeExpression(*decl.fValue);
1830 int count = SlotCount(decl.fValue->fType);
1831 if (count > 4) {
1832 this->write(ByteCodeInstruction::kPushImmediate);
1833 this->write32(location.fSlot);
1834 this->write(ByteCodeInstruction::kStoreExtended, count);
1835 this->write8(count);
1836 } else {
1837 this->write(vector_instruction(ByteCodeInstruction::kStore, count));
1838 this->write8(location.fSlot);
1839 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001840 }
1841 }
1842}
1843
1844void ByteCodeGenerator::writeWhileStatement(const WhileStatement& w) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001845 this->write(ByteCodeInstruction::kLoopBegin);
1846 size_t cond = fCode->size();
1847 this->writeExpression(*w.fTest);
1848 this->write(ByteCodeInstruction::kLoopMask);
1849 this->write(ByteCodeInstruction::kBranchIfAllFalse);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001850 DeferredLocation endLocation(this);
1851 this->writeStatement(*w.fStatement);
Brian Osmanb08cc022020-04-02 11:38:40 -04001852 this->write(ByteCodeInstruction::kLoopNext);
1853 this->write(ByteCodeInstruction::kBranch);
1854 this->write16(cond);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001855 endLocation.set();
Brian Osmanb08cc022020-04-02 11:38:40 -04001856 this->write(ByteCodeInstruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001857}
1858
1859void ByteCodeGenerator::writeStatement(const Statement& s) {
1860 switch (s.fKind) {
1861 case Statement::kBlock_Kind:
1862 this->writeBlock((Block&) s);
1863 break;
1864 case Statement::kBreak_Kind:
Brian Osmanb08cc022020-04-02 11:38:40 -04001865 this->writeBreakStatement((BreakStatement&) s);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001866 break;
1867 case Statement::kContinue_Kind:
Brian Osmanb08cc022020-04-02 11:38:40 -04001868 this->writeContinueStatement((ContinueStatement&) s);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001869 break;
Brian Osmanb08cc022020-04-02 11:38:40 -04001870 case Statement::kDiscard_Kind:
1871 // not yet implemented
1872 abort();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001873 case Statement::kDo_Kind:
1874 this->writeDoStatement((DoStatement&) s);
1875 break;
Brian Osman3e29f1d2019-05-28 09:35:05 -04001876 case Statement::kExpression_Kind:
Brian Osmanb08cc022020-04-02 11:38:40 -04001877 this->writeExpression(*((ExpressionStatement&) s).fExpression, true);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001878 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001879 case Statement::kFor_Kind:
1880 this->writeForStatement((ForStatement&) s);
1881 break;
1882 case Statement::kIf_Kind:
1883 this->writeIfStatement((IfStatement&) s);
1884 break;
1885 case Statement::kNop_Kind:
1886 break;
1887 case Statement::kReturn_Kind:
Brian Osmanb08cc022020-04-02 11:38:40 -04001888 this->writeReturnStatement((ReturnStatement&) s);
1889 break;
1890 case Statement::kSwitch_Kind:
1891 this->writeSwitchStatement((SwitchStatement&) s);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001892 break;
1893 case Statement::kVarDeclarations_Kind:
1894 this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration);
1895 break;
1896 case Statement::kWhile_Kind:
1897 this->writeWhileStatement((WhileStatement&) s);
1898 break;
1899 default:
Brian Osmanb08cc022020-04-02 11:38:40 -04001900 SkASSERT(false);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001901 }
1902}
1903
Brian Osmanb08cc022020-04-02 11:38:40 -04001904ByteCodeFunction::ByteCodeFunction(const FunctionDeclaration* declaration)
1905 : fName(declaration->fName) {
Brian Osman80164412019-06-07 13:00:23 -04001906 fParameterCount = 0;
Brian Osmanb08cc022020-04-02 11:38:40 -04001907 for (const auto& p : declaration->fParameters) {
1908 int slots = ByteCodeGenerator::SlotCount(p->fType);
1909 fParameters.push_back({ slots, (bool)(p->fModifiers.fFlags & Modifiers::kOut_Flag) });
1910 fParameterCount += slots;
Brian Osman80164412019-06-07 13:00:23 -04001911 }
1912}
1913
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001914}