blob: e5ab5afaed8f41e3e2ae4dc0f010a1ac4b072455 [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 Osmand5f937b2020-05-04 12:07:29 -040049 { "atan", ByteCodeInstruction::kATan },
Brian Osman89bf7342020-06-18 17:11:16 -040050 { "ceil", ByteCodeInstruction::kCeil },
Brian Osmand5f937b2020-05-04 12:07:29 -040051 { "clamp", SpecialIntrinsic::kClamp },
52 { "cos", ByteCodeInstruction::kCos },
53 { "dot", SpecialIntrinsic::kDot },
Brian Osman89bf7342020-06-18 17:11:16 -040054 { "floor", ByteCodeInstruction::kFloor },
Brian Osmand5f937b2020-05-04 12:07:29 -040055 { "fract", ByteCodeInstruction::kFract },
56 { "inverse", ByteCodeInstruction::kInverse2x2 },
57 { "length", SpecialIntrinsic::kLength },
58 { "max", SpecialIntrinsic::kMax },
59 { "min", SpecialIntrinsic::kMin },
60 { "mix", SpecialIntrinsic::kMix },
61 { "pow", ByteCodeInstruction::kPow },
Brian Osmana43d8202020-06-17 16:50:39 -040062 { "sample", SpecialIntrinsic::kSample },
Brian Osmand5f937b2020-05-04 12:07:29 -040063 { "saturate", SpecialIntrinsic::kSaturate },
64 { "sin", ByteCodeInstruction::kSin },
65 { "sqrt", ByteCodeInstruction::kSqrt },
66 { "tan", ByteCodeInstruction::kTan },
Brian Osman8842b372020-05-01 15:07:49 -040067
68 { "lessThan", { ByteCodeInstruction::kCompareFLT,
69 ByteCodeInstruction::kCompareSLT,
70 ByteCodeInstruction::kCompareULT } },
71 { "lessThanEqual", { ByteCodeInstruction::kCompareFLTEQ,
72 ByteCodeInstruction::kCompareSLTEQ,
73 ByteCodeInstruction::kCompareULTEQ } },
74 { "greaterThan", { ByteCodeInstruction::kCompareFGT,
75 ByteCodeInstruction::kCompareSGT,
76 ByteCodeInstruction::kCompareUGT } },
77 { "greaterThanEqual", { ByteCodeInstruction::kCompareFGTEQ,
78 ByteCodeInstruction::kCompareSGTEQ,
79 ByteCodeInstruction::kCompareUGTEQ } },
80 { "equal", { ByteCodeInstruction::kCompareFEQ,
81 ByteCodeInstruction::kCompareIEQ,
82 ByteCodeInstruction::kCompareIEQ } },
83 { "notEqual", { ByteCodeInstruction::kCompareFNEQ,
84 ByteCodeInstruction::kCompareINEQ,
85 ByteCodeInstruction::kCompareINEQ } },
86
87 { "any", SpecialIntrinsic::kAny },
88 { "all", SpecialIntrinsic::kAll },
89 { "not", ByteCodeInstruction::kNotB },
90 } {}
Brian Osmanb08cc022020-04-02 11:38:40 -040091
Ethan Nicholas82162ee2019-05-21 16:05:08 -040092
Brian Osman07c117b2019-05-23 12:51:06 -070093int ByteCodeGenerator::SlotCount(const Type& type) {
Brian Osmanfba386b2019-06-20 14:54:15 -040094 if (type.kind() == Type::kOther_Kind) {
95 return 0;
96 } else if (type.kind() == Type::kStruct_Kind) {
Brian Osman07c117b2019-05-23 12:51:06 -070097 int slots = 0;
98 for (const auto& f : type.fields()) {
99 slots += SlotCount(*f.fType);
100 }
101 SkASSERT(slots <= 255);
102 return slots;
103 } else if (type.kind() == Type::kArray_Kind) {
104 int columns = type.columns();
105 SkASSERT(columns >= 0);
106 int slots = columns * SlotCount(type.componentType());
107 SkASSERT(slots <= 255);
108 return slots;
109 } else {
110 return type.columns() * type.rows();
111 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400112}
113
Brian Osman1c110a02019-10-01 14:53:32 -0400114static inline bool is_uniform(const SkSL::Variable& var) {
115 return var.fModifiers.fFlags & Modifiers::kUniform_Flag;
116}
117
Brian Osmaneadfeb92020-01-09 12:43:03 -0500118static inline bool is_in(const SkSL::Variable& var) {
119 return var.fModifiers.fFlags & Modifiers::kIn_Flag;
120}
Brian Osmanb08cc022020-04-02 11:38:40 -0400121
122void ByteCodeGenerator::gatherUniforms(const Type& type, const String& name) {
123 if (type.kind() == Type::kOther_Kind) {
124 return;
125 } else if (type.kind() == Type::kStruct_Kind) {
126 for (const auto& f : type.fields()) {
127 this->gatherUniforms(*f.fType, name + "." + f.fName);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500128 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400129 } else if (type.kind() == Type::kArray_Kind) {
130 for (int i = 0; i < type.columns(); ++i) {
131 this->gatherUniforms(type.componentType(), String::printf("%s[%d]", name.c_str(), i));
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500132 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400133 } else {
134 fOutput->fUniforms.push_back({ name, type_category(type), type.rows(), type.columns(),
135 fOutput->fUniformSlotCount });
136 fOutput->fUniformSlotCount += type.columns() * type.rows();
137 }
138}
139
140bool ByteCodeGenerator::generateCode() {
141 for (const auto& e : fProgram) {
142 switch (e.fKind) {
143 case ProgramElement::kFunction_Kind: {
144 std::unique_ptr<ByteCodeFunction> f = this->writeFunction((FunctionDefinition&) e);
145 if (!f) {
146 return false;
147 }
148 fOutput->fFunctions.push_back(std::move(f));
149 fFunctions.push_back(&(FunctionDefinition&)e);
150 break;
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500151 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400152 case ProgramElement::kVar_Kind: {
153 VarDeclarations& decl = (VarDeclarations&) e;
154 for (const auto& v : decl.fVars) {
155 const Variable* declVar = ((VarDeclaration&) *v).fVar;
Brian Osmana43d8202020-06-17 16:50:39 -0400156 if (declVar->fType == *fContext.fFragmentProcessor_Type) {
157 fOutput->fChildFPCount++;
158 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400159 if (declVar->fModifiers.fLayout.fBuiltin >= 0 || is_in(*declVar)) {
160 continue;
161 }
162 if (is_uniform(*declVar)) {
163 this->gatherUniforms(declVar->fType, declVar->fName);
164 } else {
165 fOutput->fGlobalSlotCount += SlotCount(declVar->fType);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400166 }
167 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400168 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400169 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400170 default:
171 ; // ignore
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400172 }
173 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400174 return 0 == fErrors.errorCount();
175}
176
177std::unique_ptr<ByteCodeFunction> ByteCodeGenerator::writeFunction(const FunctionDefinition& f) {
178 fFunction = &f;
179 std::unique_ptr<ByteCodeFunction> result(new ByteCodeFunction(&f.fDeclaration));
180 fParameterCount = result->fParameterCount;
181 fLoopCount = fMaxLoopCount = 0;
182 fConditionCount = fMaxConditionCount = 0;
183 fStackCount = fMaxStackCount = 0;
184 fCode = &result->fCode;
185
186 this->writeStatement(*f.fBody);
187 if (0 == fErrors.errorCount()) {
188 SkASSERT(fLoopCount == 0);
189 SkASSERT(fConditionCount == 0);
190 SkASSERT(fStackCount == 0);
191 }
192 this->write(ByteCodeInstruction::kReturn, 0);
193 this->write8(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;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400207}
208
Brian Osman0785db02019-05-24 14:19:11 -0400209// A "simple" Swizzle is based on a variable (or a compound variable like a struct or array), and
210// that references consecutive values, such that it can be implemented using normal load/store ops
211// with an offset. Note that all single-component swizzles (of suitable base types) are simple.
212static bool swizzle_is_simple(const Swizzle& s) {
213 switch (s.fBase->fKind) {
214 case Expression::kFieldAccess_Kind:
215 case Expression::kIndex_Kind:
216 case Expression::kVariableReference_Kind:
217 break;
218 default:
219 return false;
220 }
221
222 for (size_t i = 1; i < s.fComponents.size(); ++i) {
223 if (s.fComponents[i] != s.fComponents[i - 1] + 1) {
224 return false;
225 }
226 }
227 return true;
228}
229
Brian Osmanb08cc022020-04-02 11:38:40 -0400230int ByteCodeGenerator::StackUsage(ByteCodeInstruction inst, int count_) {
231 // Ensures that we use count iff we're passed a non-default value. Most instructions have an
232 // implicit count, so the caller shouldn't need to worry about it (or count makes no sense).
233 // The asserts avoids callers thinking they're supplying useful information in that scenario,
234 // or failing to supply necessary information for the ops that need a count.
235 struct CountValue {
236 operator int() {
237 SkASSERT(val != ByteCodeGenerator::kUnusedStackCount);
238 SkDEBUGCODE(used = true);
239 return val;
240 }
241 ~CountValue() {
242 SkASSERT(used || val == ByteCodeGenerator::kUnusedStackCount);
243 }
244 int val;
245 SkDEBUGCODE(bool used = false;)
246 } count = { count_ };
247
248 switch (inst) {
249 // Unary functions/operators that don't change stack depth at all:
250#define VECTOR_UNARY_OP(base) \
251 case ByteCodeInstruction::base: \
252 case ByteCodeInstruction::base ## 2: \
253 case ByteCodeInstruction::base ## 3: \
254 case ByteCodeInstruction::base ## 4: \
255 return 0;
256
257 VECTOR_UNARY_OP(kConvertFtoI)
258 VECTOR_UNARY_OP(kConvertStoF)
259 VECTOR_UNARY_OP(kConvertUtoF)
260
Mike Reed8520e762020-04-30 12:06:23 -0400261 VECTOR_UNARY_OP(kATan)
Brian Osman89bf7342020-06-18 17:11:16 -0400262 VECTOR_UNARY_OP(kCeil)
Brian Osmanb08cc022020-04-02 11:38:40 -0400263 VECTOR_UNARY_OP(kCos)
Brian Osman89bf7342020-06-18 17:11:16 -0400264 VECTOR_UNARY_OP(kFloor)
Mike Reed8520e762020-04-30 12:06:23 -0400265 VECTOR_UNARY_OP(kFract)
Brian Osmanb08cc022020-04-02 11:38:40 -0400266 VECTOR_UNARY_OP(kSin)
267 VECTOR_UNARY_OP(kSqrt)
268 VECTOR_UNARY_OP(kTan)
269
270 VECTOR_UNARY_OP(kNegateF)
271 VECTOR_UNARY_OP(kNegateI)
Brian Osman8842b372020-05-01 15:07:49 -0400272 VECTOR_UNARY_OP(kNotB)
Brian Osmanb08cc022020-04-02 11:38:40 -0400273
274 case ByteCodeInstruction::kInverse2x2:
275 case ByteCodeInstruction::kInverse3x3:
276 case ByteCodeInstruction::kInverse4x4: return 0;
277
278 case ByteCodeInstruction::kClampIndex: return 0;
Brian Osmanb08cc022020-04-02 11:38:40 -0400279 case ByteCodeInstruction::kNegateFN: return 0;
280 case ByteCodeInstruction::kShiftLeft: return 0;
281 case ByteCodeInstruction::kShiftRightS: return 0;
282 case ByteCodeInstruction::kShiftRightU: return 0;
283
284#undef VECTOR_UNARY_OP
285
286 // Binary functions/operators that do a 2 -> 1 reduction (possibly N times)
287#define VECTOR_BINARY_OP(base) \
288 case ByteCodeInstruction::base: return -1; \
289 case ByteCodeInstruction::base ## 2: return -2; \
290 case ByteCodeInstruction::base ## 3: return -3; \
291 case ByteCodeInstruction::base ## 4: return -4;
292
293#define VECTOR_MATRIX_BINARY_OP(base) \
294 VECTOR_BINARY_OP(base) \
295 case ByteCodeInstruction::base ## N: return -count;
296
297 case ByteCodeInstruction::kAndB: return -1;
298 case ByteCodeInstruction::kOrB: return -1;
299 case ByteCodeInstruction::kXorB: return -1;
300
301 VECTOR_BINARY_OP(kAddI)
302 VECTOR_MATRIX_BINARY_OP(kAddF)
303
304 VECTOR_BINARY_OP(kCompareIEQ)
305 VECTOR_MATRIX_BINARY_OP(kCompareFEQ)
306 VECTOR_BINARY_OP(kCompareINEQ)
307 VECTOR_MATRIX_BINARY_OP(kCompareFNEQ)
308 VECTOR_BINARY_OP(kCompareSGT)
309 VECTOR_BINARY_OP(kCompareUGT)
310 VECTOR_BINARY_OP(kCompareFGT)
311 VECTOR_BINARY_OP(kCompareSGTEQ)
312 VECTOR_BINARY_OP(kCompareUGTEQ)
313 VECTOR_BINARY_OP(kCompareFGTEQ)
314 VECTOR_BINARY_OP(kCompareSLT)
315 VECTOR_BINARY_OP(kCompareULT)
316 VECTOR_BINARY_OP(kCompareFLT)
317 VECTOR_BINARY_OP(kCompareSLTEQ)
318 VECTOR_BINARY_OP(kCompareULTEQ)
319 VECTOR_BINARY_OP(kCompareFLTEQ)
320
321 VECTOR_BINARY_OP(kDivideS)
322 VECTOR_BINARY_OP(kDivideU)
323 VECTOR_MATRIX_BINARY_OP(kDivideF)
Brian Osmand5f937b2020-05-04 12:07:29 -0400324 VECTOR_BINARY_OP(kMaxF)
325 VECTOR_BINARY_OP(kMaxS)
326 VECTOR_BINARY_OP(kMinF)
327 VECTOR_BINARY_OP(kMinS)
Brian Osmanb08cc022020-04-02 11:38:40 -0400328 VECTOR_BINARY_OP(kMultiplyI)
329 VECTOR_MATRIX_BINARY_OP(kMultiplyF)
Florin Malita3facc9c2020-05-04 09:26:15 -0400330 VECTOR_BINARY_OP(kPow)
Brian Osmanb08cc022020-04-02 11:38:40 -0400331 VECTOR_BINARY_OP(kRemainderF)
332 VECTOR_BINARY_OP(kRemainderS)
333 VECTOR_BINARY_OP(kRemainderU)
334 VECTOR_BINARY_OP(kSubtractI)
335 VECTOR_MATRIX_BINARY_OP(kSubtractF)
336
337#undef VECTOR_BINARY_OP
338#undef VECTOR_MATRIX_BINARY_OP
339
340 // Ops that push or load data to grow the stack:
341 case ByteCodeInstruction::kDup:
342 case ByteCodeInstruction::kLoad:
343 case ByteCodeInstruction::kLoadGlobal:
344 case ByteCodeInstruction::kLoadUniform:
345 case ByteCodeInstruction::kReadExternal:
346 case ByteCodeInstruction::kPushImmediate:
347 return 1;
348
349 case ByteCodeInstruction::kDup2:
350 case ByteCodeInstruction::kLoad2:
351 case ByteCodeInstruction::kLoadGlobal2:
352 case ByteCodeInstruction::kLoadUniform2:
353 case ByteCodeInstruction::kReadExternal2:
354 return 2;
355
356 case ByteCodeInstruction::kDup3:
357 case ByteCodeInstruction::kLoad3:
358 case ByteCodeInstruction::kLoadGlobal3:
359 case ByteCodeInstruction::kLoadUniform3:
360 case ByteCodeInstruction::kReadExternal3:
361 return 3;
362
363 case ByteCodeInstruction::kDup4:
364 case ByteCodeInstruction::kLoad4:
365 case ByteCodeInstruction::kLoadGlobal4:
366 case ByteCodeInstruction::kLoadUniform4:
367 case ByteCodeInstruction::kReadExternal4:
368 return 4;
369
370 case ByteCodeInstruction::kDupN:
Brian Osmanb08cc022020-04-02 11:38:40 -0400371 return count;
372
373 // Pushes 'count' values, minus one for the 'address' that's consumed first
374 case ByteCodeInstruction::kLoadExtended:
375 case ByteCodeInstruction::kLoadExtendedGlobal:
376 case ByteCodeInstruction::kLoadExtendedUniform:
377 return count - 1;
378
379 // Ops that pop or store data to shrink the stack:
380 case ByteCodeInstruction::kPop:
381 case ByteCodeInstruction::kStore:
382 case ByteCodeInstruction::kStoreGlobal:
383 case ByteCodeInstruction::kWriteExternal:
384 return -1;
385
386 case ByteCodeInstruction::kPop2:
387 case ByteCodeInstruction::kStore2:
388 case ByteCodeInstruction::kStoreGlobal2:
389 case ByteCodeInstruction::kWriteExternal2:
390 return -2;
391
392 case ByteCodeInstruction::kPop3:
393 case ByteCodeInstruction::kStore3:
394 case ByteCodeInstruction::kStoreGlobal3:
395 case ByteCodeInstruction::kWriteExternal3:
396 return -3;
397
398 case ByteCodeInstruction::kPop4:
399 case ByteCodeInstruction::kStore4:
400 case ByteCodeInstruction::kStoreGlobal4:
401 case ByteCodeInstruction::kWriteExternal4:
402 return -4;
403
404 case ByteCodeInstruction::kPopN:
Brian Osmanb08cc022020-04-02 11:38:40 -0400405 return -count;
406
407 // Consumes 'count' values, plus one for the 'address'
408 case ByteCodeInstruction::kStoreExtended:
409 case ByteCodeInstruction::kStoreExtendedGlobal:
Brian Osmanb08cc022020-04-02 11:38:40 -0400410 return -count - 1;
411
412 // Strange ops where the caller computes the delta for us:
413 case ByteCodeInstruction::kCallExternal:
414 case ByteCodeInstruction::kMatrixToMatrix:
415 case ByteCodeInstruction::kMatrixMultiply:
416 case ByteCodeInstruction::kReserve:
417 case ByteCodeInstruction::kReturn:
418 case ByteCodeInstruction::kScalarToMatrix:
419 case ByteCodeInstruction::kSwizzle:
420 return count;
421
422 // Miscellaneous
423
Brian Osmana43d8202020-06-17 16:50:39 -0400424 // (X, Y) -> (R, G, B, A)
425 case ByteCodeInstruction::kSampleExplicit: return 4 - 2;
426 // (float3x3) -> (R, G, B, A)
427 case ByteCodeInstruction::kSampleMatrix: return 4 - 9;
428
Brian Osman8842b372020-05-01 15:07:49 -0400429 // kMix does a 3 -> 1 reduction (A, B, M -> A -or- B) for each component
430 case ByteCodeInstruction::kMix: return -2;
431 case ByteCodeInstruction::kMix2: return -4;
432 case ByteCodeInstruction::kMix3: return -6;
433 case ByteCodeInstruction::kMix4: return -8;
434
435 // kLerp works the same way (producing lerp(A, B, T) for each component)
436 case ByteCodeInstruction::kLerp: return -2;
437 case ByteCodeInstruction::kLerp2: return -4;
438 case ByteCodeInstruction::kLerp3: return -6;
439 case ByteCodeInstruction::kLerp4: return -8;
440
Brian Osmanb08cc022020-04-02 11:38:40 -0400441 // kCall is net-zero. Max stack depth is adjusted in writeFunctionCall.
442 case ByteCodeInstruction::kCall: return 0;
443 case ByteCodeInstruction::kBranch: return 0;
444 case ByteCodeInstruction::kBranchIfAllFalse: return 0;
445
446 case ByteCodeInstruction::kMaskPush: return -1;
447 case ByteCodeInstruction::kMaskPop: return 0;
448 case ByteCodeInstruction::kMaskNegate: return 0;
449 case ByteCodeInstruction::kMaskBlend: return -count;
450
451 case ByteCodeInstruction::kLoopBegin: return 0;
452 case ByteCodeInstruction::kLoopNext: return 0;
453 case ByteCodeInstruction::kLoopMask: return -1;
454 case ByteCodeInstruction::kLoopEnd: return 0;
455 case ByteCodeInstruction::kLoopBreak: return 0;
456 case ByteCodeInstruction::kLoopContinue: return 0;
Brian Osmanb08cc022020-04-02 11:38:40 -0400457 }
Brian Osmand5f937b2020-05-04 12:07:29 -0400458
459 SkUNREACHABLE;
Brian Osmanb08cc022020-04-02 11:38:40 -0400460}
461
462ByteCodeGenerator::Location ByteCodeGenerator::getLocation(const Variable& var) {
463 // given that we seldom have more than a couple of variables, linear search is probably the most
464 // efficient way to handle lookups
465 switch (var.fStorage) {
466 case Variable::kLocal_Storage: {
467 for (int i = fLocals.size() - 1; i >= 0; --i) {
468 if (fLocals[i] == &var) {
469 SkASSERT(fParameterCount + i <= 255);
470 return { fParameterCount + i, Storage::kLocal };
471 }
472 }
473 int result = fParameterCount + fLocals.size();
474 fLocals.push_back(&var);
475 for (int i = 0; i < SlotCount(var.fType) - 1; ++i) {
476 fLocals.push_back(nullptr);
477 }
478 SkASSERT(result <= 255);
479 return { result, Storage::kLocal };
480 }
481 case Variable::kParameter_Storage: {
482 int offset = 0;
483 for (const auto& p : fFunction->fDeclaration.fParameters) {
484 if (p == &var) {
485 SkASSERT(offset <= 255);
486 return { offset, Storage::kLocal };
487 }
488 offset += SlotCount(p->fType);
489 }
490 SkASSERT(false);
491 return Location::MakeInvalid();
492 }
493 case Variable::kGlobal_Storage: {
Brian Osmana43d8202020-06-17 16:50:39 -0400494 if (var.fType == *fContext.fFragmentProcessor_Type) {
495 int offset = 0;
496 for (const auto& e : fProgram) {
497 if (e.fKind == ProgramElement::kVar_Kind) {
498 VarDeclarations& decl = (VarDeclarations&) e;
499 for (const auto& v : decl.fVars) {
500 const Variable* declVar = ((VarDeclaration&) *v).fVar;
501 if (declVar->fType != *fContext.fFragmentProcessor_Type) {
502 continue;
503 }
504 if (declVar == &var) {
505 SkASSERT(offset <= 255);
506 return { offset, Storage::kChildFP };
507 }
508 offset++;
509 }
510 }
511 }
512 SkASSERT(false);
513 return Location::MakeInvalid();
514 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400515 if (is_in(var)) {
516 // If you see this error, it means the program is using raw 'in' variables. You
517 // should either specialize the program (Compiler::specialize) to bake in the final
518 // values of the 'in' variables, or not use 'in' variables (maybe you meant to use
519 // 'uniform' instead?).
520 fErrors.error(var.fOffset,
521 "'in' variable is not specialized or has unsupported type");
522 return Location::MakeInvalid();
523 }
524 int offset = 0;
525 bool isUniform = is_uniform(var);
526 for (const auto& e : fProgram) {
527 if (e.fKind == ProgramElement::kVar_Kind) {
528 VarDeclarations& decl = (VarDeclarations&) e;
529 for (const auto& v : decl.fVars) {
530 const Variable* declVar = ((VarDeclaration&) *v).fVar;
531 if (declVar->fModifiers.fLayout.fBuiltin >= 0 || is_in(*declVar)) {
532 continue;
533 }
534 if (isUniform != is_uniform(*declVar)) {
535 continue;
536 }
537 if (declVar == &var) {
538 SkASSERT(offset <= 255);
539 return { offset, isUniform ? Storage::kUniform : Storage::kGlobal };
540 }
541 offset += SlotCount(declVar->fType);
542 }
543 }
544 }
545 SkASSERT(false);
546 return Location::MakeInvalid();
547 }
548 default:
549 SkASSERT(false);
550 return Location::MakeInvalid();
551 }
552}
553
Brian Osman1c110a02019-10-01 14:53:32 -0400554ByteCodeGenerator::Location ByteCodeGenerator::getLocation(const Expression& expr) {
Brian Osman07c117b2019-05-23 12:51:06 -0700555 switch (expr.fKind) {
556 case Expression::kFieldAccess_Kind: {
Brian Osmanb08cc022020-04-02 11:38:40 -0400557 const FieldAccess& f = (const FieldAccess&)expr;
558 Location baseLoc = this->getLocation(*f.fBase);
Brian Osman07c117b2019-05-23 12:51:06 -0700559 int offset = 0;
560 for (int i = 0; i < f.fFieldIndex; ++i) {
561 offset += SlotCount(*f.fBase->fType.fields()[i].fType);
562 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400563 if (baseLoc.isOnStack()) {
564 if (offset != 0) {
565 this->write(ByteCodeInstruction::kPushImmediate);
566 this->write32(offset);
567 this->write(ByteCodeInstruction::kAddI);
Ben Wagner470e0ac2020-01-22 16:59:21 -0500568 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400569 return baseLoc;
Ben Wagner470e0ac2020-01-22 16:59:21 -0500570 } else {
Brian Osmanb08cc022020-04-02 11:38:40 -0400571 return baseLoc + offset;
Ben Wagner470e0ac2020-01-22 16:59:21 -0500572 }
Ben Wagner470e0ac2020-01-22 16:59:21 -0500573 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400574 case Expression::kIndex_Kind: {
575 const IndexExpression& i = (const IndexExpression&)expr;
576 int stride = SlotCount(i.fType);
577 int length = i.fBase->fType.columns();
578 SkASSERT(length <= 255);
579 int offset = -1;
580 if (i.fIndex->isConstant()) {
581 int64_t index = i.fIndex->getConstantInt();
582 if (index < 0 || index >= length) {
583 fErrors.error(i.fIndex->fOffset, "Array index out of bounds.");
584 return Location::MakeInvalid();
585 }
586 offset = index * stride;
587 } else {
588 if (i.fIndex->hasSideEffects()) {
589 // Having a side-effect in an indexer is technically safe for an rvalue,
590 // but with lvalues we have to evaluate the indexer twice, so make it an error.
591 fErrors.error(i.fIndex->fOffset,
592 "Index expressions with side-effects not supported in byte code.");
593 return Location::MakeInvalid();
594 }
595 this->writeExpression(*i.fIndex);
596 this->write(ByteCodeInstruction::kClampIndex);
597 this->write8(length);
598 if (stride != 1) {
599 this->write(ByteCodeInstruction::kPushImmediate);
600 this->write32(stride);
601 this->write(ByteCodeInstruction::kMultiplyI);
Brian Osmanb08cc022020-04-02 11:38:40 -0400602 }
603 }
604 Location baseLoc = this->getLocation(*i.fBase);
605
606 // Are both components known statically?
607 if (!baseLoc.isOnStack() && offset >= 0) {
608 return baseLoc + offset;
609 }
610
611 // At least one component is dynamic (and on the stack).
612
613 // If the other component is zero, we're done
614 if (baseLoc.fSlot == 0 || offset == 0) {
615 return baseLoc.makeOnStack();
616 }
617
618 // Push the non-dynamic component (if any) to the stack, then add the two
619 if (!baseLoc.isOnStack()) {
620 this->write(ByteCodeInstruction::kPushImmediate);
621 this->write32(baseLoc.fSlot);
622 }
623 if (offset >= 0) {
624 this->write(ByteCodeInstruction::kPushImmediate);
625 this->write32(offset);
626 }
627 this->write(ByteCodeInstruction::kAddI);
Brian Osmanb08cc022020-04-02 11:38:40 -0400628 return baseLoc.makeOnStack();
629 }
Brian Osman0785db02019-05-24 14:19:11 -0400630 case Expression::kSwizzle_Kind: {
Brian Osmanb08cc022020-04-02 11:38:40 -0400631 const Swizzle& s = (const Swizzle&)expr;
Brian Osman0785db02019-05-24 14:19:11 -0400632 SkASSERT(swizzle_is_simple(s));
Brian Osmanb08cc022020-04-02 11:38:40 -0400633 Location baseLoc = this->getLocation(*s.fBase);
634 int offset = s.fComponents[0];
635 if (baseLoc.isOnStack()) {
636 if (offset != 0) {
637 this->write(ByteCodeInstruction::kPushImmediate);
638 this->write32(offset);
639 this->write(ByteCodeInstruction::kAddI);
Brian Osmanb08cc022020-04-02 11:38:40 -0400640 }
641 return baseLoc;
642 } else {
643 return baseLoc + offset;
644 }
Brian Osman0785db02019-05-24 14:19:11 -0400645 }
Brian Osman07c117b2019-05-23 12:51:06 -0700646 case Expression::kVariableReference_Kind: {
Brian Osmanb08cc022020-04-02 11:38:40 -0400647 const Variable& var = ((const VariableReference&)expr).fVariable;
Brian Osman07c117b2019-05-23 12:51:06 -0700648 return this->getLocation(var);
649 }
650 default:
651 SkASSERT(false);
Brian Osmanb08cc022020-04-02 11:38:40 -0400652 return Location::MakeInvalid();
Brian Osman07c117b2019-05-23 12:51:06 -0700653 }
654}
655
Brian Osmanb08cc022020-04-02 11:38:40 -0400656void ByteCodeGenerator::write8(uint8_t b) {
657 fCode->push_back(b);
Ethan Nicholas2cde3a12020-01-21 09:23:13 -0500658}
659
Brian Osmanb08cc022020-04-02 11:38:40 -0400660void ByteCodeGenerator::write16(uint16_t i) {
661 size_t n = fCode->size();
662 fCode->resize(n+2);
663 memcpy(fCode->data() + n, &i, 2);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500664}
Ben Wagner470e0ac2020-01-22 16:59:21 -0500665
Brian Osmanb08cc022020-04-02 11:38:40 -0400666void ByteCodeGenerator::write32(uint32_t i) {
667 size_t n = fCode->size();
668 fCode->resize(n+4);
669 memcpy(fCode->data() + n, &i, 4);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500670}
671
Brian Osmanb08cc022020-04-02 11:38:40 -0400672void ByteCodeGenerator::write(ByteCodeInstruction i, int count) {
673 switch (i) {
674 case ByteCodeInstruction::kLoopBegin: this->enterLoop(); break;
675 case ByteCodeInstruction::kLoopEnd: this->exitLoop(); break;
Ethan Nicholas2329da02020-01-24 15:49:33 -0500676
Brian Osmanb08cc022020-04-02 11:38:40 -0400677 case ByteCodeInstruction::kMaskPush: this->enterCondition(); break;
678 case ByteCodeInstruction::kMaskPop:
679 case ByteCodeInstruction::kMaskBlend: this->exitCondition(); break;
680 default: /* Do nothing */ break;
Ben Wagner470e0ac2020-01-22 16:59:21 -0500681 }
Brian Osmanab8f3842020-04-07 09:30:44 -0400682 this->write16((uint16_t)i);
Brian Osmanb08cc022020-04-02 11:38:40 -0400683 fStackCount += StackUsage(i, count);
684 fMaxStackCount = std::max(fMaxStackCount, fStackCount);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500685}
686
Brian Osmanb08cc022020-04-02 11:38:40 -0400687static ByteCodeInstruction vector_instruction(ByteCodeInstruction base, int count) {
688 SkASSERT(count >= 1 && count <= 4);
689 return ((ByteCodeInstruction) ((int) base + 1 - count));
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500690}
691
Brian Osmanb08cc022020-04-02 11:38:40 -0400692void ByteCodeGenerator::writeTypedInstruction(const Type& type, ByteCodeInstruction s,
693 ByteCodeInstruction u, ByteCodeInstruction f,
Brian Osmanab8f3842020-04-07 09:30:44 -0400694 int count) {
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500695 switch (type_category(type)) {
Brian Osman8842b372020-05-01 15:07:49 -0400696 case TypeCategory::kBool:
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500697 case TypeCategory::kSigned:
Brian Osmanb08cc022020-04-02 11:38:40 -0400698 this->write(vector_instruction(s, count));
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500699 break;
700 case TypeCategory::kUnsigned:
Brian Osmanb08cc022020-04-02 11:38:40 -0400701 this->write(vector_instruction(u, count));
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500702 break;
703 case TypeCategory::kFloat: {
Brian Osmanb08cc022020-04-02 11:38:40 -0400704 if (count > 4) {
705 this->write((ByteCodeInstruction)((int)f + 1), count);
Brian Osmanab8f3842020-04-07 09:30:44 -0400706 this->write8(count);
Brian Osmanb08cc022020-04-02 11:38:40 -0400707 } else {
708 this->write(vector_instruction(f, count));
709 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500710 break;
711 }
712 default:
713 SkASSERT(false);
714 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500715}
716
Brian Osmanb08cc022020-04-02 11:38:40 -0400717bool ByteCodeGenerator::writeBinaryExpression(const BinaryExpression& b, bool discard) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400718 if (b.fOperator == Token::Kind::TK_EQ) {
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500719 std::unique_ptr<LValue> lvalue = this->getLValue(*b.fLeft);
Brian Osmanb08cc022020-04-02 11:38:40 -0400720 this->writeExpression(*b.fRight);
721 lvalue->store(discard);
722 discard = false;
723 return discard;
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500724 }
725 const Type& lType = b.fLeft->fType;
726 const Type& rType = b.fRight->fType;
727 bool lVecOrMtx = (lType.kind() == Type::kVector_Kind || lType.kind() == Type::kMatrix_Kind);
728 bool rVecOrMtx = (rType.kind() == Type::kVector_Kind || rType.kind() == Type::kMatrix_Kind);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500729 Token::Kind op;
730 std::unique_ptr<LValue> lvalue;
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500731 if (is_assignment(b.fOperator)) {
732 lvalue = this->getLValue(*b.fLeft);
Brian Osmanb08cc022020-04-02 11:38:40 -0400733 lvalue->load();
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500734 op = remove_assignment(b.fOperator);
735 } else {
Brian Osmanb08cc022020-04-02 11:38:40 -0400736 this->writeExpression(*b.fLeft);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500737 op = b.fOperator;
738 if (!lVecOrMtx && rVecOrMtx) {
Brian Osmanb08cc022020-04-02 11:38:40 -0400739 for (int i = SlotCount(rType); i > 1; --i) {
740 this->write(ByteCodeInstruction::kDup);
Brian Osmanb08cc022020-04-02 11:38:40 -0400741 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500742 }
743 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500744 int count = std::max(SlotCount(lType), SlotCount(rType));
Brian Osmanb08cc022020-04-02 11:38:40 -0400745 SkDEBUGCODE(TypeCategory tc = type_category(lType));
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500746 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400747 case Token::Kind::TK_LOGICALAND: {
Brian Osmanb08cc022020-04-02 11:38:40 -0400748 SkASSERT(tc == SkSL::TypeCategory::kBool && count == 1);
749 this->write(ByteCodeInstruction::kDup);
Brian Osmanb08cc022020-04-02 11:38:40 -0400750 this->write(ByteCodeInstruction::kMaskPush);
751 this->write(ByteCodeInstruction::kBranchIfAllFalse);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500752 DeferredLocation falseLocation(this);
Brian Osmanb08cc022020-04-02 11:38:40 -0400753 this->writeExpression(*b.fRight);
754 this->write(ByteCodeInstruction::kAndB);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500755 falseLocation.set();
Brian Osmanb08cc022020-04-02 11:38:40 -0400756 this->write(ByteCodeInstruction::kMaskPop);
757 return false;
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500758 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400759 case Token::Kind::TK_LOGICALOR: {
Brian Osmanb08cc022020-04-02 11:38:40 -0400760 SkASSERT(tc == SkSL::TypeCategory::kBool && count == 1);
761 this->write(ByteCodeInstruction::kDup);
Brian Osmanb08cc022020-04-02 11:38:40 -0400762 this->write(ByteCodeInstruction::kNotB);
763 this->write(ByteCodeInstruction::kMaskPush);
764 this->write(ByteCodeInstruction::kBranchIfAllFalse);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500765 DeferredLocation falseLocation(this);
Brian Osmanb08cc022020-04-02 11:38:40 -0400766 this->writeExpression(*b.fRight);
767 this->write(ByteCodeInstruction::kOrB);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500768 falseLocation.set();
Brian Osmanb08cc022020-04-02 11:38:40 -0400769 this->write(ByteCodeInstruction::kMaskPop);
770 return false;
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500771 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400772 case Token::Kind::TK_SHL:
773 case Token::Kind::TK_SHR: {
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500774 SkASSERT(count == 1 && (tc == SkSL::TypeCategory::kSigned ||
775 tc == SkSL::TypeCategory::kUnsigned));
776 if (!b.fRight->isConstant()) {
777 fErrors.error(b.fRight->fOffset, "Shift amounts must be constant");
Brian Osmanb08cc022020-04-02 11:38:40 -0400778 return false;
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500779 }
780 int64_t shift = b.fRight->getConstantInt();
781 if (shift < 0 || shift > 31) {
782 fErrors.error(b.fRight->fOffset, "Shift amount out of range");
Brian Osmanb08cc022020-04-02 11:38:40 -0400783 return false;
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500784 }
785
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400786 if (op == Token::Kind::TK_SHL) {
Brian Osmanb08cc022020-04-02 11:38:40 -0400787 this->write(ByteCodeInstruction::kShiftLeft);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500788 } else {
789 this->write(type_category(lType) == TypeCategory::kSigned
Brian Osmanb08cc022020-04-02 11:38:40 -0400790 ? ByteCodeInstruction::kShiftRightS
791 : ByteCodeInstruction::kShiftRightU);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500792 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400793 this->write8(shift);
794 return false;
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500795 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500796
797 default:
798 break;
799 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400800 this->writeExpression(*b.fRight);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500801 if (lVecOrMtx && !rVecOrMtx) {
Brian Osmanb08cc022020-04-02 11:38:40 -0400802 for (int i = SlotCount(lType); i > 1; --i) {
803 this->write(ByteCodeInstruction::kDup);
Brian Osmanb08cc022020-04-02 11:38:40 -0400804 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500805 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400806 // Special case for M*V, V*M, M*M (but not V*V!)
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400807 if (op == Token::Kind::TK_STAR && lVecOrMtx && rVecOrMtx &&
Brian Osmanb08cc022020-04-02 11:38:40 -0400808 !(lType.kind() == Type::kVector_Kind && rType.kind() == Type::kVector_Kind)) {
809 this->write(ByteCodeInstruction::kMatrixMultiply,
810 SlotCount(b.fType) - (SlotCount(lType) + SlotCount(rType)));
811 int rCols = rType.columns(),
812 rRows = rType.rows(),
813 lCols = lType.columns(),
814 lRows = lType.rows();
815 // M*V treats the vector as a column
816 if (rType.kind() == Type::kVector_Kind) {
817 std::swap(rCols, rRows);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500818 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400819 SkASSERT(lCols == rRows);
820 SkASSERT(SlotCount(b.fType) == lRows * rCols);
821 this->write8(lCols);
822 this->write8(lRows);
823 this->write8(rCols);
824 } else {
825 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400826 case Token::Kind::TK_EQEQ:
Brian Osmanb08cc022020-04-02 11:38:40 -0400827 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareIEQ,
828 ByteCodeInstruction::kCompareIEQ,
829 ByteCodeInstruction::kCompareFEQ,
830 count);
831 // Collapse to a single bool
832 for (int i = count; i > 1; --i) {
833 this->write(ByteCodeInstruction::kAndB);
834 }
835 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400836 case Token::Kind::TK_GT:
Brian Osmanb08cc022020-04-02 11:38:40 -0400837 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSGT,
838 ByteCodeInstruction::kCompareUGT,
839 ByteCodeInstruction::kCompareFGT,
840 count);
841 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400842 case Token::Kind::TK_GTEQ:
Brian Osmanb08cc022020-04-02 11:38:40 -0400843 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSGTEQ,
844 ByteCodeInstruction::kCompareUGTEQ,
845 ByteCodeInstruction::kCompareFGTEQ,
846 count);
847 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400848 case Token::Kind::TK_LT:
Brian Osmanb08cc022020-04-02 11:38:40 -0400849 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSLT,
850 ByteCodeInstruction::kCompareULT,
851 ByteCodeInstruction::kCompareFLT,
852 count);
853 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400854 case Token::Kind::TK_LTEQ:
Brian Osmanb08cc022020-04-02 11:38:40 -0400855 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSLTEQ,
856 ByteCodeInstruction::kCompareULTEQ,
857 ByteCodeInstruction::kCompareFLTEQ,
858 count);
859 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400860 case Token::Kind::TK_MINUS:
Brian Osmanb08cc022020-04-02 11:38:40 -0400861 this->writeTypedInstruction(lType, ByteCodeInstruction::kSubtractI,
862 ByteCodeInstruction::kSubtractI,
863 ByteCodeInstruction::kSubtractF,
864 count);
865 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400866 case Token::Kind::TK_NEQ:
Brian Osmanb08cc022020-04-02 11:38:40 -0400867 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareINEQ,
868 ByteCodeInstruction::kCompareINEQ,
869 ByteCodeInstruction::kCompareFNEQ,
870 count);
871 // Collapse to a single bool
872 for (int i = count; i > 1; --i) {
873 this->write(ByteCodeInstruction::kOrB);
874 }
875 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400876 case Token::Kind::TK_PERCENT:
Brian Osmanb08cc022020-04-02 11:38:40 -0400877 this->writeTypedInstruction(lType, ByteCodeInstruction::kRemainderS,
878 ByteCodeInstruction::kRemainderU,
879 ByteCodeInstruction::kRemainderF,
880 count);
881 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400882 case Token::Kind::TK_PLUS:
Brian Osmanb08cc022020-04-02 11:38:40 -0400883 this->writeTypedInstruction(lType, ByteCodeInstruction::kAddI,
884 ByteCodeInstruction::kAddI,
885 ByteCodeInstruction::kAddF,
886 count);
887 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400888 case Token::Kind::TK_SLASH:
Brian Osmanb08cc022020-04-02 11:38:40 -0400889 this->writeTypedInstruction(lType, ByteCodeInstruction::kDivideS,
890 ByteCodeInstruction::kDivideU,
891 ByteCodeInstruction::kDivideF,
892 count);
893 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400894 case Token::Kind::TK_STAR:
Brian Osmanb08cc022020-04-02 11:38:40 -0400895 this->writeTypedInstruction(lType, ByteCodeInstruction::kMultiplyI,
896 ByteCodeInstruction::kMultiplyI,
897 ByteCodeInstruction::kMultiplyF,
898 count);
899 break;
900
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400901 case Token::Kind::TK_LOGICALXOR:
Brian Osmanb08cc022020-04-02 11:38:40 -0400902 SkASSERT(tc == SkSL::TypeCategory::kBool && count == 1);
903 this->write(ByteCodeInstruction::kXorB);
904 break;
905
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400906 case Token::Kind::TK_BITWISEAND:
Brian Osmanb08cc022020-04-02 11:38:40 -0400907 SkASSERT(count == 1 && (tc == SkSL::TypeCategory::kSigned ||
908 tc == SkSL::TypeCategory::kUnsigned));
909 this->write(ByteCodeInstruction::kAndB);
910 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400911 case Token::Kind::TK_BITWISEOR:
Brian Osmanb08cc022020-04-02 11:38:40 -0400912 SkASSERT(count == 1 && (tc == SkSL::TypeCategory::kSigned ||
913 tc == SkSL::TypeCategory::kUnsigned));
914 this->write(ByteCodeInstruction::kOrB);
915 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400916 case Token::Kind::TK_BITWISEXOR:
Brian Osmanb08cc022020-04-02 11:38:40 -0400917 SkASSERT(count == 1 && (tc == SkSL::TypeCategory::kSigned ||
918 tc == SkSL::TypeCategory::kUnsigned));
919 this->write(ByteCodeInstruction::kXorB);
920 break;
921
922 default:
923 fErrors.error(b.fOffset, SkSL::String::printf("Unsupported binary operator '%s'",
924 Compiler::OperatorName(op)));
925 break;
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500926 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500927 }
928 if (lvalue) {
Brian Osmanb08cc022020-04-02 11:38:40 -0400929 lvalue->store(discard);
930 discard = false;
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500931 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400932 return discard;
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500933}
934
Brian Osmanb08cc022020-04-02 11:38:40 -0400935void ByteCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
936 this->write(ByteCodeInstruction::kPushImmediate);
937 this->write32(b.fValue ? ~0 : 0);
938}
939
940void ByteCodeGenerator::writeConstructor(const Constructor& c) {
941 for (const auto& arg : c.fArguments) {
942 this->writeExpression(*arg);
943 }
944 if (c.fArguments.size() == 1) {
945 const Type& inType = c.fArguments[0]->fType;
946 const Type& outType = c.fType;
947 TypeCategory inCategory = type_category(inType);
948 TypeCategory outCategory = type_category(outType);
949 int inCount = SlotCount(inType);
950 int outCount = SlotCount(outType);
951 if (inCategory != outCategory) {
952 SkASSERT(inCount == outCount);
953 if (inCategory == TypeCategory::kFloat) {
954 SkASSERT(outCategory == TypeCategory::kSigned ||
955 outCategory == TypeCategory::kUnsigned);
956 this->write(vector_instruction(ByteCodeInstruction::kConvertFtoI, outCount));
957 } else if (outCategory == TypeCategory::kFloat) {
958 if (inCategory == TypeCategory::kSigned) {
959 this->write(vector_instruction(ByteCodeInstruction::kConvertStoF, outCount));
960 } else {
961 SkASSERT(inCategory == TypeCategory::kUnsigned);
962 this->write(vector_instruction(ByteCodeInstruction::kConvertUtoF, outCount));
963 }
964 } else {
965 SkASSERT(false);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500966 }
967 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400968 if (inType.kind() == Type::kMatrix_Kind && outType.kind() == Type::kMatrix_Kind) {
969 this->write(ByteCodeInstruction::kMatrixToMatrix,
970 SlotCount(outType) - SlotCount(inType));
971 this->write8(inType.columns());
972 this->write8(inType.rows());
973 this->write8(outType.columns());
974 this->write8(outType.rows());
975 } else if (inCount != outCount) {
976 SkASSERT(inCount == 1);
977 if (outType.kind() == Type::kMatrix_Kind) {
978 this->write(ByteCodeInstruction::kScalarToMatrix, SlotCount(outType) - 1);
979 this->write8(outType.columns());
980 this->write8(outType.rows());
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500981 } else {
Brian Osmanb08cc022020-04-02 11:38:40 -0400982 SkASSERT(outType.kind() == Type::kVector_Kind);
983 for (; inCount != outCount; ++inCount) {
984 this->write(ByteCodeInstruction::kDup);
Brian Osmanb08cc022020-04-02 11:38:40 -0400985 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500986 }
987 }
988 }
989}
990
Brian Osmanb08cc022020-04-02 11:38:40 -0400991void ByteCodeGenerator::writeExternalFunctionCall(const ExternalFunctionCall& f) {
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500992 int argumentCount = 0;
993 for (const auto& arg : f.fArguments) {
Brian Osmanb08cc022020-04-02 11:38:40 -0400994 this->writeExpression(*arg);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500995 argumentCount += SlotCount(arg->fType);
996 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400997 this->write(ByteCodeInstruction::kCallExternal, SlotCount(f.fType) - argumentCount);
998 SkASSERT(argumentCount <= 255);
999 this->write8(argumentCount);
1000 this->write8(SlotCount(f.fType));
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001001 int index = fOutput->fExternalValues.size();
1002 fOutput->fExternalValues.push_back(f.fFunction);
1003 SkASSERT(index <= 255);
Brian Osmanb08cc022020-04-02 11:38:40 -04001004 this->write8(index);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001005}
1006
Brian Osmanb08cc022020-04-02 11:38:40 -04001007void ByteCodeGenerator::writeExternalValue(const ExternalValueReference& e) {
1008 int count = SlotCount(e.fValue->type());
1009 this->write(vector_instruction(ByteCodeInstruction::kReadExternal, count));
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001010 int index = fOutput->fExternalValues.size();
1011 fOutput->fExternalValues.push_back(e.fValue);
1012 SkASSERT(index <= 255);
Brian Osmanb08cc022020-04-02 11:38:40 -04001013 this->write8(index);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001014}
1015
Brian Osmanb08cc022020-04-02 11:38:40 -04001016void ByteCodeGenerator::writeVariableExpression(const Expression& expr) {
1017 Location location = this->getLocation(expr);
1018 int count = SlotCount(expr.fType);
Brian Osmanefb08402020-04-13 16:30:44 -04001019 if (count == 0) {
1020 return;
1021 }
Brian Osmanb08cc022020-04-02 11:38:40 -04001022 if (location.isOnStack() || count > 4) {
1023 if (!location.isOnStack()) {
1024 this->write(ByteCodeInstruction::kPushImmediate);
1025 this->write32(location.fSlot);
1026 }
1027 this->write(location.selectLoad(ByteCodeInstruction::kLoadExtended,
1028 ByteCodeInstruction::kLoadExtendedGlobal,
1029 ByteCodeInstruction::kLoadExtendedUniform),
1030 count);
1031 this->write8(count);
1032 } else {
1033 this->write(vector_instruction(location.selectLoad(ByteCodeInstruction::kLoad,
1034 ByteCodeInstruction::kLoadGlobal,
1035 ByteCodeInstruction::kLoadUniform),
1036 count));
Brian Osmanb08cc022020-04-02 11:38:40 -04001037 this->write8(location.fSlot);
1038 }
1039}
1040
1041static inline uint32_t float_to_bits(float x) {
1042 uint32_t u;
1043 memcpy(&u, &x, sizeof(uint32_t));
1044 return u;
1045}
1046
1047void ByteCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
1048 this->write(ByteCodeInstruction::kPushImmediate);
1049 this->write32(float_to_bits(f.fValue));
1050}
1051
Brian Osman8842b372020-05-01 15:07:49 -04001052static bool is_generic_type(const Type* type, const Type* generic) {
1053 const std::vector<const Type*>& concrete(generic->coercibleTypes());
1054 return std::find(concrete.begin(), concrete.end(), type) != concrete.end();
1055}
1056
Brian Osmanb08cc022020-04-02 11:38:40 -04001057void ByteCodeGenerator::writeIntrinsicCall(const FunctionCall& c) {
1058 auto found = fIntrinsics.find(c.fFunction.fName);
1059 if (found == fIntrinsics.end()) {
1060 fErrors.error(c.fOffset, String::printf("Unsupported intrinsic: '%s'",
1061 String(c.fFunction.fName).c_str()));
1062 return;
1063 }
Mike Klein45be0772020-05-01 09:13:18 -05001064 Intrinsic intrin = found->second;
Brian Osmanb08cc022020-04-02 11:38:40 -04001065 int count = SlotCount(c.fArguments[0]->fType);
Brian Osmand5f937b2020-05-04 12:07:29 -04001066
1067 // Several intrinsics have variants where one argument is either scalar, or the same size as
1068 // the first argument. Call dupSmallerType(SlotCount(argType)) to ensure equal component count.
1069 auto dupSmallerType = [count, this](int smallCount) {
1070 SkASSERT(smallCount == 1 || smallCount == count);
1071 for (int i = smallCount; i < count; ++i) {
1072 this->write(ByteCodeInstruction::kDup);
1073 }
1074 };
1075
Brian Osmana43d8202020-06-17 16:50:39 -04001076 if (intrin.is_special && intrin.special == SpecialIntrinsic::kSample) {
1077 // Sample is very special, the first argument is an FP, which can't be pushed to the stack
1078 if (c.fArguments.size() != 2 ||
1079 c.fArguments[0]->fType != *fContext.fFragmentProcessor_Type ||
1080 (c.fArguments[1]->fType != *fContext.fFloat2_Type &&
1081 c.fArguments[1]->fType != *fContext.fFloat3x3_Type)) {
1082 fErrors.error(c.fOffset, "Unsupported form of sample");
1083 return;
1084 }
1085
1086 // Write our coords or matrix
1087 this->writeExpression(*c.fArguments[1]);
1088
1089 this->write(c.fArguments[1]->fType == *fContext.fFloat3x3_Type
1090 ? ByteCodeInstruction::kSampleMatrix
1091 : ByteCodeInstruction::kSampleExplicit);
1092
1093 Location childLoc = this->getLocation(*c.fArguments[0]);
1094 SkASSERT(childLoc.fStorage == Storage::kChildFP);
1095 this->write8(childLoc.fSlot);
1096 return;
1097 }
1098
Brian Osmand5f937b2020-05-04 12:07:29 -04001099 if (intrin.is_special && (intrin.special == SpecialIntrinsic::kClamp ||
1100 intrin.special == SpecialIntrinsic::kSaturate)) {
1101 // These intrinsics are extra-special, we need instructions interleaved with arguments
1102 bool saturate = (intrin.special == SpecialIntrinsic::kSaturate);
1103 SkASSERT(c.fArguments.size() == (saturate ? 1 : 3));
1104 int limitCount = saturate ? 1 : SlotCount(c.fArguments[1]->fType);
1105
1106 // 'x'
1107 this->writeExpression(*c.fArguments[0]);
1108
1109 // 'minVal'
1110 if (saturate) {
1111 this->write(ByteCodeInstruction::kPushImmediate);
1112 this->write32(float_to_bits(0.0f));
1113 } else {
1114 this->writeExpression(*c.fArguments[1]);
1115 }
1116 dupSmallerType(limitCount);
1117 this->writeTypedInstruction(c.fArguments[0]->fType,
1118 ByteCodeInstruction::kMaxS,
1119 ByteCodeInstruction::kMaxS,
1120 ByteCodeInstruction::kMaxF,
1121 count);
1122
1123 // 'maxVal'
1124 if (saturate) {
1125 this->write(ByteCodeInstruction::kPushImmediate);
1126 this->write32(float_to_bits(1.0f));
1127 } else {
1128 SkASSERT(limitCount == SlotCount(c.fArguments[2]->fType));
1129 this->writeExpression(*c.fArguments[2]);
1130 }
1131 dupSmallerType(limitCount);
1132 this->writeTypedInstruction(c.fArguments[0]->fType,
1133 ByteCodeInstruction::kMinS,
1134 ByteCodeInstruction::kMinS,
1135 ByteCodeInstruction::kMinF,
1136 count);
1137 return;
1138 }
1139
1140 // All other intrinsics can handle their arguments being on the stack in order
1141 for (const auto& arg : c.fArguments) {
1142 this->writeExpression(*arg);
1143 }
1144
Mike Klein45be0772020-05-01 09:13:18 -05001145 if (intrin.is_special) {
1146 switch (intrin.special) {
Brian Osman8842b372020-05-01 15:07:49 -04001147 case SpecialIntrinsic::kAll: {
1148 for (int i = count-1; i --> 0;) {
1149 this->write(ByteCodeInstruction::kAndB);
1150 }
1151 } break;
1152
1153 case SpecialIntrinsic::kAny: {
1154 for (int i = count-1; i --> 0;) {
1155 this->write(ByteCodeInstruction::kOrB);
1156 }
1157 } break;
1158
Brian Osman15c98cb2020-02-27 18:36:57 +00001159 case SpecialIntrinsic::kDot: {
1160 SkASSERT(c.fArguments.size() == 2);
Brian Osmanb08cc022020-04-02 11:38:40 -04001161 SkASSERT(count == SlotCount(c.fArguments[1]->fType));
1162 this->write(vector_instruction(ByteCodeInstruction::kMultiplyF, count));
Mike Klein45be0772020-05-01 09:13:18 -05001163 for (int i = count-1; i --> 0;) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001164 this->write(ByteCodeInstruction::kAddF);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001165 }
Mike Klein45be0772020-05-01 09:13:18 -05001166 } break;
1167
1168 case SpecialIntrinsic::kLength: {
1169 SkASSERT(c.fArguments.size() == 1);
1170 this->write(vector_instruction(ByteCodeInstruction::kDup , count));
1171 this->write(vector_instruction(ByteCodeInstruction::kMultiplyF, count));
1172 for (int i = count-1; i --> 0;) {
1173 this->write(ByteCodeInstruction::kAddF);
1174 }
1175 this->write(ByteCodeInstruction::kSqrt);
1176 } break;
1177
Brian Osmand5f937b2020-05-04 12:07:29 -04001178 case SpecialIntrinsic::kMax:
1179 case SpecialIntrinsic::kMin: {
1180 SkASSERT(c.fArguments.size() == 2);
1181 // There are variants where the second argument is scalar
1182 dupSmallerType(SlotCount(c.fArguments[1]->fType));
1183 if (intrin.special == SpecialIntrinsic::kMax) {
1184 this->writeTypedInstruction(c.fArguments[0]->fType,
1185 ByteCodeInstruction::kMaxS,
1186 ByteCodeInstruction::kMaxS,
1187 ByteCodeInstruction::kMaxF,
1188 count);
1189 } else {
1190 this->writeTypedInstruction(c.fArguments[0]->fType,
1191 ByteCodeInstruction::kMinS,
1192 ByteCodeInstruction::kMinS,
1193 ByteCodeInstruction::kMinF,
1194 count);
1195 }
1196 } break;
1197
Brian Osman8842b372020-05-01 15:07:49 -04001198 case SpecialIntrinsic::kMix: {
1199 // Two main variants of mix to handle
1200 SkASSERT(c.fArguments.size() == 3);
1201 SkASSERT(count == SlotCount(c.fArguments[1]->fType));
1202 int selectorCount = SlotCount(c.fArguments[2]->fType);
1203
1204 if (is_generic_type(&c.fArguments[2]->fType, fContext.fGenBType_Type.get())) {
1205 // mix(genType, genType, genBoolType)
1206 SkASSERT(selectorCount == count);
1207 this->write(vector_instruction(ByteCodeInstruction::kMix, count));
1208 } else {
1209 // mix(genType, genType, genType) or mix(genType, genType, float)
Brian Osmand5f937b2020-05-04 12:07:29 -04001210 dupSmallerType(selectorCount);
Brian Osman8842b372020-05-01 15:07:49 -04001211 this->write(vector_instruction(ByteCodeInstruction::kLerp, count));
1212 }
1213 } break;
1214
Brian Osmanb08cc022020-04-02 11:38:40 -04001215 default:
1216 SkASSERT(false);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001217 }
1218 } else {
Brian Osman8842b372020-05-01 15:07:49 -04001219 switch (intrin.inst_f) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001220 case ByteCodeInstruction::kInverse2x2: {
1221 SkASSERT(c.fArguments.size() > 0);
1222 auto op = ByteCodeInstruction::kInverse2x2;
1223 switch (count) {
1224 case 4: break; // float2x2
1225 case 9: op = ByteCodeInstruction::kInverse3x3; break;
1226 case 16: op = ByteCodeInstruction::kInverse4x4; break;
1227 default: SkASSERT(false);
1228 }
1229 this->write(op);
1230 break;
Brian Osman15c98cb2020-02-27 18:36:57 +00001231 }
Mike Klein45be0772020-05-01 09:13:18 -05001232
Brian Osmanb08cc022020-04-02 11:38:40 -04001233 default:
Brian Osman8842b372020-05-01 15:07:49 -04001234 this->writeTypedInstruction(c.fArguments[0]->fType, intrin.inst_s, intrin.inst_u,
1235 intrin.inst_f, count);
1236 break;
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001237 }
1238 }
1239}
1240
Brian Osmanb08cc022020-04-02 11:38:40 -04001241void ByteCodeGenerator::writeFunctionCall(const FunctionCall& f) {
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001242 // Find the index of the function we're calling. We explicitly do not allow calls to functions
1243 // before they're defined. This is an easy-to-understand rule that prevents recursion.
Brian Osmanb08cc022020-04-02 11:38:40 -04001244 int idx = -1;
1245 for (size_t i = 0; i < fFunctions.size(); ++i) {
1246 if (f.fFunction.matches(fFunctions[i]->fDeclaration)) {
1247 idx = i;
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001248 break;
1249 }
1250 }
Brian Osmanb08cc022020-04-02 11:38:40 -04001251 if (idx == -1) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001252 this->writeIntrinsicCall(f);
1253 return;
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001254 }
Brian Osmanb08cc022020-04-02 11:38:40 -04001255
1256
1257 if (idx > 255) {
1258 fErrors.error(f.fOffset, "Function count limit exceeded");
1259 return;
1260 } else if (idx >= (int) fFunctions.size()) {
1261 fErrors.error(f.fOffset, "Call to undefined function");
1262 return;
1263 }
1264
1265 // We may need to deal with out parameters, so the sequence is tricky
1266 if (int returnCount = SlotCount(f.fType)) {
1267 this->write(ByteCodeInstruction::kReserve, returnCount);
1268 this->write8(returnCount);
1269 }
1270
1271 int argCount = f.fArguments.size();
1272 std::vector<std::unique_ptr<LValue>> lvalues;
1273 for (int i = 0; i < argCount; ++i) {
1274 const auto& param = f.fFunction.fParameters[i];
1275 const auto& arg = f.fArguments[i];
1276 if (param->fModifiers.fFlags & Modifiers::kOut_Flag) {
1277 lvalues.emplace_back(this->getLValue(*arg));
1278 lvalues.back()->load();
1279 } else {
1280 this->writeExpression(*arg);
1281 }
1282 }
1283
1284 // The space used by the call is based on the callee, but it also unwinds all of that before
1285 // we continue execution. We adjust our max stack depths below.
1286 this->write(ByteCodeInstruction::kCall);
1287 this->write8(idx);
1288
1289 const ByteCodeFunction* callee = fOutput->fFunctions[idx].get();
1290 fMaxLoopCount = std::max(fMaxLoopCount, fLoopCount + callee->fLoopCount);
1291 fMaxConditionCount = std::max(fMaxConditionCount, fConditionCount + callee->fConditionCount);
1292 fMaxStackCount = std::max(fMaxStackCount, fStackCount + callee->fLocalCount
1293 + callee->fStackCount);
1294
1295 // After the called function returns, the stack will still contain our arguments. We have to
1296 // pop them (storing any out parameters back to their lvalues as we go). We glob together slot
1297 // counts for all parameters that aren't out-params, so we can pop them in one big chunk.
1298 int popCount = 0;
1299 auto pop = [&]() {
1300 if (popCount > 4) {
1301 this->write(ByteCodeInstruction::kPopN, popCount);
1302 this->write8(popCount);
1303 } else if (popCount > 0) {
1304 this->write(vector_instruction(ByteCodeInstruction::kPop, popCount));
1305 }
1306 popCount = 0;
1307 };
1308
1309 for (int i = argCount - 1; i >= 0; --i) {
1310 const auto& param = f.fFunction.fParameters[i];
1311 const auto& arg = f.fArguments[i];
1312 if (param->fModifiers.fFlags & Modifiers::kOut_Flag) {
1313 pop();
1314 lvalues.back()->store(true);
1315 lvalues.pop_back();
1316 } else {
1317 popCount += SlotCount(arg->fType);
1318 }
1319 }
1320 pop();
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001321}
1322
Brian Osmanb08cc022020-04-02 11:38:40 -04001323void ByteCodeGenerator::writeIntLiteral(const IntLiteral& i) {
1324 this->write(ByteCodeInstruction::kPushImmediate);
1325 this->write32(i.fValue);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001326}
1327
Brian Osmanb08cc022020-04-02 11:38:40 -04001328void ByteCodeGenerator::writeNullLiteral(const NullLiteral& n) {
1329 // not yet implemented
1330 abort();
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001331}
1332
Brian Osmanb08cc022020-04-02 11:38:40 -04001333bool ByteCodeGenerator::writePrefixExpression(const PrefixExpression& p, bool discard) {
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001334 switch (p.fOperator) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001335 case Token::Kind::TK_PLUSPLUS: // fall through
1336 case Token::Kind::TK_MINUSMINUS: {
Brian Osmanb08cc022020-04-02 11:38:40 -04001337 SkASSERT(SlotCount(p.fOperand->fType) == 1);
1338 std::unique_ptr<LValue> lvalue = this->getLValue(*p.fOperand);
1339 lvalue->load();
1340 this->write(ByteCodeInstruction::kPushImmediate);
1341 this->write32(type_category(p.fType) == TypeCategory::kFloat ? float_to_bits(1.0f) : 1);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001342 if (p.fOperator == Token::Kind::TK_PLUSPLUS) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001343 this->writeTypedInstruction(p.fType,
1344 ByteCodeInstruction::kAddI,
1345 ByteCodeInstruction::kAddI,
1346 ByteCodeInstruction::kAddF,
1347 1);
1348 } else {
1349 this->writeTypedInstruction(p.fType,
1350 ByteCodeInstruction::kSubtractI,
1351 ByteCodeInstruction::kSubtractI,
1352 ByteCodeInstruction::kSubtractF,
1353 1);
1354 }
1355 lvalue->store(discard);
1356 discard = false;
1357 break;
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001358 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001359 case Token::Kind::TK_MINUS: {
Brian Osmanb08cc022020-04-02 11:38:40 -04001360 this->writeExpression(*p.fOperand);
1361 this->writeTypedInstruction(p.fType,
1362 ByteCodeInstruction::kNegateI,
1363 ByteCodeInstruction::kNegateI,
1364 ByteCodeInstruction::kNegateF,
Brian Osmanab8f3842020-04-07 09:30:44 -04001365 SlotCount(p.fOperand->fType));
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001366 break;
1367 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001368 case Token::Kind::TK_LOGICALNOT:
1369 case Token::Kind::TK_BITWISENOT: {
Brian Osmanb08cc022020-04-02 11:38:40 -04001370 SkASSERT(SlotCount(p.fOperand->fType) == 1);
1371 SkDEBUGCODE(TypeCategory tc = type_category(p.fOperand->fType));
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001372 SkASSERT((p.fOperator == Token::Kind::TK_LOGICALNOT && tc == TypeCategory::kBool) ||
1373 (p.fOperator == Token::Kind::TK_BITWISENOT && (tc == TypeCategory::kSigned ||
Brian Osmanb08cc022020-04-02 11:38:40 -04001374 tc == TypeCategory::kUnsigned)));
1375 this->writeExpression(*p.fOperand);
1376 this->write(ByteCodeInstruction::kNotB);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001377 break;
1378 }
1379 default:
1380 SkASSERT(false);
1381 }
Brian Osmanb08cc022020-04-02 11:38:40 -04001382 return discard;
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001383}
1384
Brian Osmanb08cc022020-04-02 11:38:40 -04001385bool ByteCodeGenerator::writePostfixExpression(const PostfixExpression& p, bool discard) {
1386 switch (p.fOperator) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001387 case Token::Kind::TK_PLUSPLUS: // fall through
1388 case Token::Kind::TK_MINUSMINUS: {
Brian Osmanb08cc022020-04-02 11:38:40 -04001389 SkASSERT(SlotCount(p.fOperand->fType) == 1);
1390 std::unique_ptr<LValue> lvalue = this->getLValue(*p.fOperand);
1391 lvalue->load();
1392 // If we're not supposed to discard the result, then make a copy *before* the +/-
1393 if (!discard) {
1394 this->write(ByteCodeInstruction::kDup);
Brian Osmanb08cc022020-04-02 11:38:40 -04001395 }
1396 this->write(ByteCodeInstruction::kPushImmediate);
1397 this->write32(type_category(p.fType) == TypeCategory::kFloat ? float_to_bits(1.0f) : 1);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001398 if (p.fOperator == Token::Kind::TK_PLUSPLUS) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001399 this->writeTypedInstruction(p.fType,
1400 ByteCodeInstruction::kAddI,
1401 ByteCodeInstruction::kAddI,
1402 ByteCodeInstruction::kAddF,
1403 1);
1404 } else {
1405 this->writeTypedInstruction(p.fType,
1406 ByteCodeInstruction::kSubtractI,
1407 ByteCodeInstruction::kSubtractI,
1408 ByteCodeInstruction::kSubtractF,
1409 1);
1410 }
1411 // Always consume the result as part of the store
1412 lvalue->store(true);
1413 discard = false;
1414 break;
1415 }
1416 default:
1417 SkASSERT(false);
1418 }
1419 return discard;
1420}
1421
1422void ByteCodeGenerator::writeSwizzle(const Swizzle& s) {
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001423 if (swizzle_is_simple(s)) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001424 this->writeVariableExpression(s);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001425 return;
1426 }
Brian Osmanb08cc022020-04-02 11:38:40 -04001427
Brian Osman3711c662020-06-18 14:42:21 -04001428 this->writeExpression(*s.fBase);
1429 this->write(ByteCodeInstruction::kSwizzle, s.fComponents.size() - s.fBase->fType.columns());
1430 this->write8(s.fBase->fType.columns());
1431 this->write8(s.fComponents.size());
1432 for (int c : s.fComponents) {
1433 this->write8(c);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001434 }
1435}
1436
Brian Osmanb08cc022020-04-02 11:38:40 -04001437void ByteCodeGenerator::writeTernaryExpression(const TernaryExpression& t) {
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001438 int count = SlotCount(t.fType);
1439 SkASSERT(count == SlotCount(t.fIfTrue->fType));
1440 SkASSERT(count == SlotCount(t.fIfFalse->fType));
1441
Brian Osmanb08cc022020-04-02 11:38:40 -04001442 this->writeExpression(*t.fTest);
1443 this->write(ByteCodeInstruction::kMaskPush);
1444 this->writeExpression(*t.fIfTrue);
1445 this->write(ByteCodeInstruction::kMaskNegate);
1446 this->writeExpression(*t.fIfFalse);
1447 this->write(ByteCodeInstruction::kMaskBlend, count);
1448 this->write8(count);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001449}
1450
Brian Osmanb08cc022020-04-02 11:38:40 -04001451void ByteCodeGenerator::writeExpression(const Expression& e, bool discard) {
1452 switch (e.fKind) {
1453 case Expression::kBinary_Kind:
1454 discard = this->writeBinaryExpression((BinaryExpression&) e, discard);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001455 break;
Brian Osmanb08cc022020-04-02 11:38:40 -04001456 case Expression::kBoolLiteral_Kind:
1457 this->writeBoolLiteral((BoolLiteral&) e);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001458 break;
Brian Osmanb08cc022020-04-02 11:38:40 -04001459 case Expression::kConstructor_Kind:
1460 this->writeConstructor((Constructor&) e);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001461 break;
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001462 case Expression::kExternalFunctionCall_Kind:
Brian Osmanb08cc022020-04-02 11:38:40 -04001463 this->writeExternalFunctionCall((ExternalFunctionCall&) e);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001464 break;
1465 case Expression::kExternalValue_Kind:
Brian Osmanb08cc022020-04-02 11:38:40 -04001466 this->writeExternalValue((ExternalValueReference&) e);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001467 break;
1468 case Expression::kFieldAccess_Kind:
1469 case Expression::kIndex_Kind:
1470 case Expression::kVariableReference_Kind:
Brian Osmanb08cc022020-04-02 11:38:40 -04001471 this->writeVariableExpression(e);
1472 break;
1473 case Expression::kFloatLiteral_Kind:
1474 this->writeFloatLiteral((FloatLiteral&) e);
1475 break;
1476 case Expression::kFunctionCall_Kind:
1477 this->writeFunctionCall((FunctionCall&) e);
1478 break;
1479 case Expression::kIntLiteral_Kind:
1480 this->writeIntLiteral((IntLiteral&) e);
1481 break;
1482 case Expression::kNullLiteral_Kind:
1483 this->writeNullLiteral((NullLiteral&) e);
1484 break;
1485 case Expression::kPrefix_Kind:
1486 discard = this->writePrefixExpression((PrefixExpression&) e, discard);
1487 break;
1488 case Expression::kPostfix_Kind:
1489 discard = this->writePostfixExpression((PostfixExpression&) e, discard);
1490 break;
1491 case Expression::kSwizzle_Kind:
1492 this->writeSwizzle((Swizzle&) e);
1493 break;
1494 case Expression::kTernary_Kind:
1495 this->writeTernaryExpression((TernaryExpression&) e);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001496 break;
Ben Wagner470e0ac2020-01-22 16:59:21 -05001497 default:
1498#ifdef SK_DEBUG
Brian Osmanb08cc022020-04-02 11:38:40 -04001499 printf("unsupported expression %s\n", e.description().c_str());
Ben Wagner470e0ac2020-01-22 16:59:21 -05001500#endif
Brian Osmanb08cc022020-04-02 11:38:40 -04001501 SkASSERT(false);
1502 }
1503 if (discard) {
1504 int count = SlotCount(e.fType);
1505 if (count > 4) {
1506 this->write(ByteCodeInstruction::kPopN, count);
1507 this->write8(count);
1508 } else if (count != 0) {
1509 this->write(vector_instruction(ByteCodeInstruction::kPop, count));
1510 }
1511 discard = false;
Ben Wagner470e0ac2020-01-22 16:59:21 -05001512 }
Ethan Nicholas7deb1c22020-01-22 10:31:55 -05001513}
1514
Brian Osmanb08cc022020-04-02 11:38:40 -04001515class ByteCodeExternalValueLValue : public ByteCodeGenerator::LValue {
1516public:
1517 ByteCodeExternalValueLValue(ByteCodeGenerator* generator, ExternalValue& value, int index)
1518 : INHERITED(*generator)
1519 , fCount(ByteCodeGenerator::SlotCount(value.type()))
1520 , fIndex(index) {}
1521
1522 void load() override {
1523 fGenerator.write(vector_instruction(ByteCodeInstruction::kReadExternal, fCount));
Brian Osmanb08cc022020-04-02 11:38:40 -04001524 fGenerator.write8(fIndex);
1525 }
1526
1527 void store(bool discard) override {
1528 if (!discard) {
1529 fGenerator.write(vector_instruction(ByteCodeInstruction::kDup, fCount));
Brian Osmanb08cc022020-04-02 11:38:40 -04001530 }
1531 fGenerator.write(vector_instruction(ByteCodeInstruction::kWriteExternal, fCount));
Brian Osmanb08cc022020-04-02 11:38:40 -04001532 fGenerator.write8(fIndex);
1533 }
1534
1535private:
1536 typedef LValue INHERITED;
1537
1538 int fCount;
1539
1540 int fIndex;
1541};
1542
1543class ByteCodeSwizzleLValue : public ByteCodeGenerator::LValue {
1544public:
1545 ByteCodeSwizzleLValue(ByteCodeGenerator* generator, const Swizzle& swizzle)
1546 : INHERITED(*generator)
1547 , fSwizzle(swizzle) {}
1548
1549 void load() override {
1550 fGenerator.writeSwizzle(fSwizzle);
1551 }
1552
1553 void store(bool discard) override {
1554 int count = fSwizzle.fComponents.size();
1555 if (!discard) {
1556 fGenerator.write(vector_instruction(ByteCodeInstruction::kDup, count));
Brian Osmanb08cc022020-04-02 11:38:40 -04001557 }
Brian Osman304dfa32020-06-18 15:53:51 -04001558 // We already have the correct number of values on the stack, thanks to type checking.
1559 // The algorithm: Walk down the values on the stack, doing 'count' single-element stores.
1560 // For each value, use the corresponding swizzle component to offset the store location.
1561 //
1562 // Static locations: We (wastefully) call getLocation every time, but get good byte code.
1563 // Note that we could (but don't) store adjacent/sequential values with fewer instructions.
1564 //
1565 // Dynamic locations: ... are bad. We have to recompute the base address on each iteration,
1566 // because the stack doesn't let us retain that address between stores. Dynamic locations
1567 // are rare though, and swizzled writes to those are even rarer, so we just live with this.
1568 for (int i = count; i-- > 0;) {
1569 ByteCodeGenerator::Location location = fGenerator.getLocation(*fSwizzle.fBase);
1570 if (!location.isOnStack()) {
1571 fGenerator.write(location.selectStore(ByteCodeInstruction::kStore,
1572 ByteCodeInstruction::kStoreGlobal));
1573 fGenerator.write8(location.fSlot + fSwizzle.fComponents[i]);
1574 } else {
1575 fGenerator.write(ByteCodeInstruction::kPushImmediate);
1576 fGenerator.write32(fSwizzle.fComponents[i]);
1577 fGenerator.write(ByteCodeInstruction::kAddI);
1578 fGenerator.write(location.selectStore(ByteCodeInstruction::kStoreExtended,
1579 ByteCodeInstruction::kStoreExtendedGlobal),
1580 1);
1581 fGenerator.write8(1);
1582 }
Brian Osmanb08cc022020-04-02 11:38:40 -04001583 }
1584 }
1585
1586private:
1587 const Swizzle& fSwizzle;
1588
1589 typedef LValue INHERITED;
1590};
1591
1592class ByteCodeExpressionLValue : public ByteCodeGenerator::LValue {
1593public:
1594 ByteCodeExpressionLValue(ByteCodeGenerator* generator, const Expression& expr)
1595 : INHERITED(*generator)
1596 , fExpression(expr) {}
1597
1598 void load() override {
1599 fGenerator.writeVariableExpression(fExpression);
1600 }
1601
1602 void store(bool discard) override {
1603 int count = ByteCodeGenerator::SlotCount(fExpression.fType);
1604 if (!discard) {
1605 if (count > 4) {
1606 fGenerator.write(ByteCodeInstruction::kDupN, count);
1607 fGenerator.write8(count);
1608 } else {
1609 fGenerator.write(vector_instruction(ByteCodeInstruction::kDup, count));
Brian Osmanb08cc022020-04-02 11:38:40 -04001610 }
1611 }
1612 ByteCodeGenerator::Location location = fGenerator.getLocation(fExpression);
1613 if (location.isOnStack() || count > 4) {
1614 if (!location.isOnStack()) {
1615 fGenerator.write(ByteCodeInstruction::kPushImmediate);
1616 fGenerator.write32(location.fSlot);
1617 }
1618 fGenerator.write(location.selectStore(ByteCodeInstruction::kStoreExtended,
1619 ByteCodeInstruction::kStoreExtendedGlobal),
1620 count);
1621 fGenerator.write8(count);
1622 } else {
1623 fGenerator.write(
1624 vector_instruction(location.selectStore(ByteCodeInstruction::kStore,
1625 ByteCodeInstruction::kStoreGlobal),
1626 count));
1627 fGenerator.write8(location.fSlot);
1628 }
1629 }
1630
1631private:
1632 typedef LValue INHERITED;
1633
1634 const Expression& fExpression;
1635};
1636
1637std::unique_ptr<ByteCodeGenerator::LValue> ByteCodeGenerator::getLValue(const Expression& e) {
1638 switch (e.fKind) {
1639 case Expression::kExternalValue_Kind: {
1640 ExternalValue* value = ((ExternalValueReference&) e).fValue;
1641 int index = fOutput->fExternalValues.size();
1642 fOutput->fExternalValues.push_back(value);
1643 SkASSERT(index <= 255);
1644 return std::unique_ptr<LValue>(new ByteCodeExternalValueLValue(this, *value, index));
1645 }
1646 case Expression::kFieldAccess_Kind:
1647 case Expression::kIndex_Kind:
1648 case Expression::kVariableReference_Kind:
1649 return std::unique_ptr<LValue>(new ByteCodeExpressionLValue(this, e));
1650 case Expression::kSwizzle_Kind: {
1651 const Swizzle& s = (const Swizzle&) e;
1652 return swizzle_is_simple(s)
1653 ? std::unique_ptr<LValue>(new ByteCodeExpressionLValue(this, e))
1654 : std::unique_ptr<LValue>(new ByteCodeSwizzleLValue(this, s));
1655 }
1656 case Expression::kTernary_Kind:
1657 default:
1658#ifdef SK_DEBUG
1659 ABORT("unsupported lvalue %s\n", e.description().c_str());
1660#endif
1661 return nullptr;
1662 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001663}
1664
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001665void ByteCodeGenerator::writeBlock(const Block& b) {
1666 for (const auto& s : b.fStatements) {
1667 this->writeStatement(*s);
1668 }
1669}
1670
Brian Osmanb08cc022020-04-02 11:38:40 -04001671void ByteCodeGenerator::setBreakTargets() {
1672 std::vector<DeferredLocation>& breaks = fBreakTargets.top();
1673 for (DeferredLocation& b : breaks) {
1674 b.set();
1675 }
1676 fBreakTargets.pop();
1677}
1678
1679void ByteCodeGenerator::setContinueTargets() {
1680 std::vector<DeferredLocation>& continues = fContinueTargets.top();
1681 for (DeferredLocation& c : continues) {
1682 c.set();
1683 }
1684 fContinueTargets.pop();
1685}
1686
1687void ByteCodeGenerator::writeBreakStatement(const BreakStatement& b) {
1688 // TODO: Include BranchIfAllFalse to top-most LoopNext
1689 this->write(ByteCodeInstruction::kLoopBreak);
1690}
1691
1692void ByteCodeGenerator::writeContinueStatement(const ContinueStatement& c) {
1693 // TODO: Include BranchIfAllFalse to top-most LoopNext
1694 this->write(ByteCodeInstruction::kLoopContinue);
1695}
1696
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001697void ByteCodeGenerator::writeDoStatement(const DoStatement& d) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001698 this->write(ByteCodeInstruction::kLoopBegin);
1699 size_t start = fCode->size();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001700 this->writeStatement(*d.fStatement);
Brian Osmanb08cc022020-04-02 11:38:40 -04001701 this->write(ByteCodeInstruction::kLoopNext);
1702 this->writeExpression(*d.fTest);
1703 this->write(ByteCodeInstruction::kLoopMask);
1704 // TODO: Could shorten this with kBranchIfAnyTrue
1705 this->write(ByteCodeInstruction::kBranchIfAllFalse);
Brian Osman569f12f2019-06-13 11:23:57 -04001706 DeferredLocation endLocation(this);
Brian Osmanb08cc022020-04-02 11:38:40 -04001707 this->write(ByteCodeInstruction::kBranch);
1708 this->write16(start);
Brian Osman569f12f2019-06-13 11:23:57 -04001709 endLocation.set();
Brian Osmanb08cc022020-04-02 11:38:40 -04001710 this->write(ByteCodeInstruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001711}
1712
1713void ByteCodeGenerator::writeForStatement(const ForStatement& f) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001714 fContinueTargets.emplace();
1715 fBreakTargets.emplace();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001716 if (f.fInitializer) {
1717 this->writeStatement(*f.fInitializer);
1718 }
Brian Osmanb08cc022020-04-02 11:38:40 -04001719 this->write(ByteCodeInstruction::kLoopBegin);
1720 size_t start = fCode->size();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001721 if (f.fTest) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001722 this->writeExpression(*f.fTest);
1723 this->write(ByteCodeInstruction::kLoopMask);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001724 }
Brian Osmanb08cc022020-04-02 11:38:40 -04001725 this->write(ByteCodeInstruction::kBranchIfAllFalse);
Brian Osman569f12f2019-06-13 11:23:57 -04001726 DeferredLocation endLocation(this);
1727 this->writeStatement(*f.fStatement);
Brian Osmanb08cc022020-04-02 11:38:40 -04001728 this->write(ByteCodeInstruction::kLoopNext);
Brian Osman569f12f2019-06-13 11:23:57 -04001729 if (f.fNext) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001730 this->writeExpression(*f.fNext, true);
Brian Osman569f12f2019-06-13 11:23:57 -04001731 }
Brian Osmanb08cc022020-04-02 11:38:40 -04001732 this->write(ByteCodeInstruction::kBranch);
1733 this->write16(start);
Brian Osman569f12f2019-06-13 11:23:57 -04001734 endLocation.set();
Brian Osmanb08cc022020-04-02 11:38:40 -04001735 this->write(ByteCodeInstruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001736}
1737
1738void ByteCodeGenerator::writeIfStatement(const IfStatement& i) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001739 this->writeExpression(*i.fTest);
1740 this->write(ByteCodeInstruction::kMaskPush);
1741 this->write(ByteCodeInstruction::kBranchIfAllFalse);
Brian Osman569f12f2019-06-13 11:23:57 -04001742 DeferredLocation falseLocation(this);
1743 this->writeStatement(*i.fIfTrue);
1744 falseLocation.set();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001745 if (i.fIfFalse) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001746 this->write(ByteCodeInstruction::kMaskNegate);
1747 this->write(ByteCodeInstruction::kBranchIfAllFalse);
Brian Osman569f12f2019-06-13 11:23:57 -04001748 DeferredLocation endLocation(this);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001749 this->writeStatement(*i.fIfFalse);
Mike Kleinb45ee832019-05-17 11:11:11 -05001750 endLocation.set();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001751 }
Brian Osmanb08cc022020-04-02 11:38:40 -04001752 this->write(ByteCodeInstruction::kMaskPop);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001753}
1754
Brian Osmanb08cc022020-04-02 11:38:40 -04001755void ByteCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
1756 if (fLoopCount || fConditionCount) {
Brian Osman4a47da72019-07-12 11:30:32 -04001757 fErrors.error(r.fOffset, "return not allowed inside conditional or loop");
1758 return;
1759 }
Brian Osmanb08cc022020-04-02 11:38:40 -04001760 int count = SlotCount(r.fExpression->fType);
1761 this->writeExpression(*r.fExpression);
1762
1763 // Technically, the kReturn also pops fOutput->fLocalCount values from the stack, too, but we
1764 // haven't counted pushing those (they're outside the scope of our stack tracking). Instead,
1765 // we account for those in writeFunction().
1766
1767 // This is all fine because we don't allow conditional returns, so we only return once anyway.
1768 this->write(ByteCodeInstruction::kReturn, -count);
1769 this->write8(count);
1770}
1771
1772void ByteCodeGenerator::writeSwitchStatement(const SwitchStatement& r) {
1773 // not yet implemented
1774 abort();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001775}
1776
1777void ByteCodeGenerator::writeVarDeclarations(const VarDeclarations& v) {
1778 for (const auto& declStatement : v.fVars) {
1779 const VarDeclaration& decl = (VarDeclaration&) *declStatement;
Brian Osmanb08cc022020-04-02 11:38:40 -04001780 // we need to grab the location even if we don't use it, to ensure it has been allocated
1781 Location location = this->getLocation(*decl.fVar);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001782 if (decl.fValue) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001783 this->writeExpression(*decl.fValue);
1784 int count = SlotCount(decl.fValue->fType);
1785 if (count > 4) {
1786 this->write(ByteCodeInstruction::kPushImmediate);
1787 this->write32(location.fSlot);
1788 this->write(ByteCodeInstruction::kStoreExtended, count);
1789 this->write8(count);
1790 } else {
1791 this->write(vector_instruction(ByteCodeInstruction::kStore, count));
1792 this->write8(location.fSlot);
1793 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001794 }
1795 }
1796}
1797
1798void ByteCodeGenerator::writeWhileStatement(const WhileStatement& w) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001799 this->write(ByteCodeInstruction::kLoopBegin);
1800 size_t cond = fCode->size();
1801 this->writeExpression(*w.fTest);
1802 this->write(ByteCodeInstruction::kLoopMask);
1803 this->write(ByteCodeInstruction::kBranchIfAllFalse);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001804 DeferredLocation endLocation(this);
1805 this->writeStatement(*w.fStatement);
Brian Osmanb08cc022020-04-02 11:38:40 -04001806 this->write(ByteCodeInstruction::kLoopNext);
1807 this->write(ByteCodeInstruction::kBranch);
1808 this->write16(cond);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001809 endLocation.set();
Brian Osmanb08cc022020-04-02 11:38:40 -04001810 this->write(ByteCodeInstruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001811}
1812
1813void ByteCodeGenerator::writeStatement(const Statement& s) {
1814 switch (s.fKind) {
1815 case Statement::kBlock_Kind:
1816 this->writeBlock((Block&) s);
1817 break;
1818 case Statement::kBreak_Kind:
Brian Osmanb08cc022020-04-02 11:38:40 -04001819 this->writeBreakStatement((BreakStatement&) s);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001820 break;
1821 case Statement::kContinue_Kind:
Brian Osmanb08cc022020-04-02 11:38:40 -04001822 this->writeContinueStatement((ContinueStatement&) s);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001823 break;
Brian Osmanb08cc022020-04-02 11:38:40 -04001824 case Statement::kDiscard_Kind:
1825 // not yet implemented
1826 abort();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001827 case Statement::kDo_Kind:
1828 this->writeDoStatement((DoStatement&) s);
1829 break;
Brian Osman3e29f1d2019-05-28 09:35:05 -04001830 case Statement::kExpression_Kind:
Brian Osmanb08cc022020-04-02 11:38:40 -04001831 this->writeExpression(*((ExpressionStatement&) s).fExpression, true);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001832 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001833 case Statement::kFor_Kind:
1834 this->writeForStatement((ForStatement&) s);
1835 break;
1836 case Statement::kIf_Kind:
1837 this->writeIfStatement((IfStatement&) s);
1838 break;
1839 case Statement::kNop_Kind:
1840 break;
1841 case Statement::kReturn_Kind:
Brian Osmanb08cc022020-04-02 11:38:40 -04001842 this->writeReturnStatement((ReturnStatement&) s);
1843 break;
1844 case Statement::kSwitch_Kind:
1845 this->writeSwitchStatement((SwitchStatement&) s);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001846 break;
1847 case Statement::kVarDeclarations_Kind:
1848 this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration);
1849 break;
1850 case Statement::kWhile_Kind:
1851 this->writeWhileStatement((WhileStatement&) s);
1852 break;
1853 default:
Brian Osmanb08cc022020-04-02 11:38:40 -04001854 SkASSERT(false);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001855 }
1856}
1857
Brian Osmanb08cc022020-04-02 11:38:40 -04001858ByteCodeFunction::ByteCodeFunction(const FunctionDeclaration* declaration)
1859 : fName(declaration->fName) {
Brian Osman80164412019-06-07 13:00:23 -04001860 fParameterCount = 0;
Brian Osmanb08cc022020-04-02 11:38:40 -04001861 for (const auto& p : declaration->fParameters) {
1862 int slots = ByteCodeGenerator::SlotCount(p->fType);
1863 fParameters.push_back({ slots, (bool)(p->fModifiers.fFlags & Modifiers::kOut_Flag) });
1864 fParameterCount += slots;
Brian Osman80164412019-06-07 13:00:23 -04001865 }
1866}
1867
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001868}