blob: c484d7c611f93ab7a6f2db122790ebffb94c3994 [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);
Brian Osmanb08cc022020-04-02 11:38:40 -0400194
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 Osman5aaaeea2020-06-22 14:26:03 -0400209// If the expression is a reference to a builtin global variable, return the builtin ID.
210// Otherwise, return -1.
211static int expression_as_builtin(const Expression& e) {
212 if (e.fKind == Expression::kVariableReference_Kind) {
213 const Variable& var(((VariableReference&)e).fVariable);
214 if (var.fStorage == Variable::kGlobal_Storage) {
215 return var.fModifiers.fLayout.fBuiltin;
216 }
217 }
218 return -1;
219}
220
Brian Osman0785db02019-05-24 14:19:11 -0400221// A "simple" Swizzle is based on a variable (or a compound variable like a struct or array), and
222// that references consecutive values, such that it can be implemented using normal load/store ops
223// with an offset. Note that all single-component swizzles (of suitable base types) are simple.
224static bool swizzle_is_simple(const Swizzle& s) {
Brian Osman5aaaeea2020-06-22 14:26:03 -0400225 // Builtin variables use dedicated instructions that don't allow subset loads
226 if (expression_as_builtin(*s.fBase) >= 0) {
227 return false;
228 }
229
Brian Osman0785db02019-05-24 14:19:11 -0400230 switch (s.fBase->fKind) {
231 case Expression::kFieldAccess_Kind:
232 case Expression::kIndex_Kind:
233 case Expression::kVariableReference_Kind:
234 break;
235 default:
236 return false;
237 }
238
239 for (size_t i = 1; i < s.fComponents.size(); ++i) {
240 if (s.fComponents[i] != s.fComponents[i - 1] + 1) {
241 return false;
242 }
243 }
244 return true;
245}
246
Brian Osmanb08cc022020-04-02 11:38:40 -0400247int ByteCodeGenerator::StackUsage(ByteCodeInstruction inst, int count_) {
248 // Ensures that we use count iff we're passed a non-default value. Most instructions have an
249 // implicit count, so the caller shouldn't need to worry about it (or count makes no sense).
250 // The asserts avoids callers thinking they're supplying useful information in that scenario,
251 // or failing to supply necessary information for the ops that need a count.
252 struct CountValue {
253 operator int() {
254 SkASSERT(val != ByteCodeGenerator::kUnusedStackCount);
255 SkDEBUGCODE(used = true);
256 return val;
257 }
258 ~CountValue() {
259 SkASSERT(used || val == ByteCodeGenerator::kUnusedStackCount);
260 }
261 int val;
262 SkDEBUGCODE(bool used = false;)
263 } count = { count_ };
264
265 switch (inst) {
266 // Unary functions/operators that don't change stack depth at all:
Brian Osmanb08cc022020-04-02 11:38:40 -0400267
Brian Osman49b30f42020-06-26 17:22:27 -0400268#define VEC_UNARY(inst) case ByteCodeInstruction::inst: return count - count;
Brian Osmanb08cc022020-04-02 11:38:40 -0400269
Brian Osman49b30f42020-06-26 17:22:27 -0400270 VEC_UNARY(kConvertFtoI)
271 VEC_UNARY(kConvertStoF)
272 VEC_UNARY(kConvertUtoF)
Brian Osmanb08cc022020-04-02 11:38:40 -0400273
Brian Osman49b30f42020-06-26 17:22:27 -0400274 VEC_UNARY(kATan)
275 VEC_UNARY(kCeil)
276 VEC_UNARY(kCos)
277 VEC_UNARY(kFloor)
278 VEC_UNARY(kFract)
279 VEC_UNARY(kSin)
280 VEC_UNARY(kSqrt)
281 VEC_UNARY(kTan)
282
283 VEC_UNARY(kNegateF)
284 VEC_UNARY(kNegateI)
285 VEC_UNARY(kNotB)
286
287#undef VEC_UNARY
Brian Osmanb08cc022020-04-02 11:38:40 -0400288
289 case ByteCodeInstruction::kInverse2x2:
290 case ByteCodeInstruction::kInverse3x3:
291 case ByteCodeInstruction::kInverse4x4: return 0;
292
Brian Osman49b30f42020-06-26 17:22:27 -0400293 case ByteCodeInstruction::kClampIndex: return 0;
294 case ByteCodeInstruction::kShiftLeft: return 0;
Brian Osmanb08cc022020-04-02 11:38:40 -0400295 case ByteCodeInstruction::kShiftRightS: return 0;
296 case ByteCodeInstruction::kShiftRightU: return 0;
297
Brian Osman49b30f42020-06-26 17:22:27 -0400298 // Binary functions/operators that do a 2 -> 1 reduction, N times
299 case ByteCodeInstruction::kAndB: return -count;
300 case ByteCodeInstruction::kOrB: return -count;
301 case ByteCodeInstruction::kXorB: return -count;
Brian Osmanb08cc022020-04-02 11:38:40 -0400302
Brian Osman49b30f42020-06-26 17:22:27 -0400303 case ByteCodeInstruction::kAddI: return -count;
304 case ByteCodeInstruction::kAddF: return -count;
Brian Osmanb08cc022020-04-02 11:38:40 -0400305
Brian Osman49b30f42020-06-26 17:22:27 -0400306 case ByteCodeInstruction::kCompareIEQ: return -count;
307 case ByteCodeInstruction::kCompareFEQ: return -count;
308 case ByteCodeInstruction::kCompareINEQ: return -count;
309 case ByteCodeInstruction::kCompareFNEQ: return -count;
310 case ByteCodeInstruction::kCompareSGT: return -count;
311 case ByteCodeInstruction::kCompareUGT: return -count;
312 case ByteCodeInstruction::kCompareFGT: return -count;
313 case ByteCodeInstruction::kCompareSGTEQ: return -count;
314 case ByteCodeInstruction::kCompareUGTEQ: return -count;
315 case ByteCodeInstruction::kCompareFGTEQ: return -count;
316 case ByteCodeInstruction::kCompareSLT: return -count;
317 case ByteCodeInstruction::kCompareULT: return -count;
318 case ByteCodeInstruction::kCompareFLT: return -count;
319 case ByteCodeInstruction::kCompareSLTEQ: return -count;
320 case ByteCodeInstruction::kCompareULTEQ: return -count;
321 case ByteCodeInstruction::kCompareFLTEQ: return -count;
Brian Osmanb08cc022020-04-02 11:38:40 -0400322
Brian Osman49b30f42020-06-26 17:22:27 -0400323 case ByteCodeInstruction::kDivideS: return -count;
324 case ByteCodeInstruction::kDivideU: return -count;
325 case ByteCodeInstruction::kDivideF: return -count;
326 case ByteCodeInstruction::kMaxF: return -count;
327 case ByteCodeInstruction::kMaxS: return -count;
328 case ByteCodeInstruction::kMinF: return -count;
329 case ByteCodeInstruction::kMinS: return -count;
330 case ByteCodeInstruction::kMultiplyI: return -count;
331 case ByteCodeInstruction::kMultiplyF: return -count;
332 case ByteCodeInstruction::kPow: return -count;
333 case ByteCodeInstruction::kRemainderF: return -count;
334 case ByteCodeInstruction::kRemainderS: return -count;
335 case ByteCodeInstruction::kRemainderU: return -count;
336 case ByteCodeInstruction::kSubtractI: return -count;
337 case ByteCodeInstruction::kSubtractF: return -count;
Brian Osmanb08cc022020-04-02 11:38:40 -0400338
339 // Ops that push or load data to grow the stack:
Brian Osman49b30f42020-06-26 17:22:27 -0400340 case ByteCodeInstruction::kPushImmediate:
341 return 1;
342 case ByteCodeInstruction::kLoadFragCoord:
343 return 4;
344
Brian Osmanb08cc022020-04-02 11:38:40 -0400345 case ByteCodeInstruction::kDup:
346 case ByteCodeInstruction::kLoad:
347 case ByteCodeInstruction::kLoadGlobal:
348 case ByteCodeInstruction::kLoadUniform:
349 case ByteCodeInstruction::kReadExternal:
Brian Osman49b30f42020-06-26 17:22:27 -0400350 case ByteCodeInstruction::kReserve:
Brian Osmanb08cc022020-04-02 11:38:40 -0400351 return count;
352
353 // Pushes 'count' values, minus one for the 'address' that's consumed first
354 case ByteCodeInstruction::kLoadExtended:
355 case ByteCodeInstruction::kLoadExtendedGlobal:
356 case ByteCodeInstruction::kLoadExtendedUniform:
357 return count - 1;
358
359 // Ops that pop or store data to shrink the stack:
360 case ByteCodeInstruction::kPop:
Brian Osman49b30f42020-06-26 17:22:27 -0400361 case ByteCodeInstruction::kReturn:
Brian Osmanb08cc022020-04-02 11:38:40 -0400362 case ByteCodeInstruction::kStore:
363 case ByteCodeInstruction::kStoreGlobal:
364 case ByteCodeInstruction::kWriteExternal:
Brian Osmanb08cc022020-04-02 11:38:40 -0400365 return -count;
366
367 // Consumes 'count' values, plus one for the 'address'
368 case ByteCodeInstruction::kStoreExtended:
369 case ByteCodeInstruction::kStoreExtendedGlobal:
Brian Osmanb08cc022020-04-02 11:38:40 -0400370 return -count - 1;
371
372 // Strange ops where the caller computes the delta for us:
373 case ByteCodeInstruction::kCallExternal:
374 case ByteCodeInstruction::kMatrixToMatrix:
375 case ByteCodeInstruction::kMatrixMultiply:
Brian Osmanb08cc022020-04-02 11:38:40 -0400376 case ByteCodeInstruction::kScalarToMatrix:
377 case ByteCodeInstruction::kSwizzle:
378 return count;
379
380 // Miscellaneous
381
Brian Osmana43d8202020-06-17 16:50:39 -0400382 // (X, Y) -> (R, G, B, A)
383 case ByteCodeInstruction::kSampleExplicit: return 4 - 2;
384 // (float3x3) -> (R, G, B, A)
385 case ByteCodeInstruction::kSampleMatrix: return 4 - 9;
386
Brian Osman8842b372020-05-01 15:07:49 -0400387 // kMix does a 3 -> 1 reduction (A, B, M -> A -or- B) for each component
Brian Osman49b30f42020-06-26 17:22:27 -0400388 case ByteCodeInstruction::kMix: return -(2 * count);
Brian Osman8842b372020-05-01 15:07:49 -0400389
390 // kLerp works the same way (producing lerp(A, B, T) for each component)
Brian Osman49b30f42020-06-26 17:22:27 -0400391 case ByteCodeInstruction::kLerp: return -(2 * count);
Brian Osman8842b372020-05-01 15:07:49 -0400392
Brian Osmanb08cc022020-04-02 11:38:40 -0400393 // kCall is net-zero. Max stack depth is adjusted in writeFunctionCall.
394 case ByteCodeInstruction::kCall: return 0;
395 case ByteCodeInstruction::kBranch: return 0;
396 case ByteCodeInstruction::kBranchIfAllFalse: return 0;
397
398 case ByteCodeInstruction::kMaskPush: return -1;
399 case ByteCodeInstruction::kMaskPop: return 0;
400 case ByteCodeInstruction::kMaskNegate: return 0;
401 case ByteCodeInstruction::kMaskBlend: return -count;
402
403 case ByteCodeInstruction::kLoopBegin: return 0;
404 case ByteCodeInstruction::kLoopNext: return 0;
405 case ByteCodeInstruction::kLoopMask: return -1;
406 case ByteCodeInstruction::kLoopEnd: return 0;
407 case ByteCodeInstruction::kLoopBreak: return 0;
408 case ByteCodeInstruction::kLoopContinue: return 0;
Brian Osmanb08cc022020-04-02 11:38:40 -0400409 }
Brian Osmand5f937b2020-05-04 12:07:29 -0400410
411 SkUNREACHABLE;
Brian Osmanb08cc022020-04-02 11:38:40 -0400412}
413
414ByteCodeGenerator::Location ByteCodeGenerator::getLocation(const Variable& var) {
415 // given that we seldom have more than a couple of variables, linear search is probably the most
416 // efficient way to handle lookups
417 switch (var.fStorage) {
418 case Variable::kLocal_Storage: {
419 for (int i = fLocals.size() - 1; i >= 0; --i) {
420 if (fLocals[i] == &var) {
421 SkASSERT(fParameterCount + i <= 255);
422 return { fParameterCount + i, Storage::kLocal };
423 }
424 }
425 int result = fParameterCount + fLocals.size();
426 fLocals.push_back(&var);
427 for (int i = 0; i < SlotCount(var.fType) - 1; ++i) {
428 fLocals.push_back(nullptr);
429 }
430 SkASSERT(result <= 255);
431 return { result, Storage::kLocal };
432 }
433 case Variable::kParameter_Storage: {
434 int offset = 0;
435 for (const auto& p : fFunction->fDeclaration.fParameters) {
436 if (p == &var) {
437 SkASSERT(offset <= 255);
438 return { offset, Storage::kLocal };
439 }
440 offset += SlotCount(p->fType);
441 }
442 SkASSERT(false);
443 return Location::MakeInvalid();
444 }
445 case Variable::kGlobal_Storage: {
Brian Osmana43d8202020-06-17 16:50:39 -0400446 if (var.fType == *fContext.fFragmentProcessor_Type) {
447 int offset = 0;
448 for (const auto& e : fProgram) {
449 if (e.fKind == ProgramElement::kVar_Kind) {
450 VarDeclarations& decl = (VarDeclarations&) e;
451 for (const auto& v : decl.fVars) {
452 const Variable* declVar = ((VarDeclaration&) *v).fVar;
453 if (declVar->fType != *fContext.fFragmentProcessor_Type) {
454 continue;
455 }
456 if (declVar == &var) {
457 SkASSERT(offset <= 255);
458 return { offset, Storage::kChildFP };
459 }
460 offset++;
461 }
462 }
463 }
464 SkASSERT(false);
465 return Location::MakeInvalid();
466 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400467 if (is_in(var)) {
468 // If you see this error, it means the program is using raw 'in' variables. You
469 // should either specialize the program (Compiler::specialize) to bake in the final
470 // values of the 'in' variables, or not use 'in' variables (maybe you meant to use
471 // 'uniform' instead?).
472 fErrors.error(var.fOffset,
473 "'in' variable is not specialized or has unsupported type");
474 return Location::MakeInvalid();
475 }
476 int offset = 0;
477 bool isUniform = is_uniform(var);
478 for (const auto& e : fProgram) {
479 if (e.fKind == ProgramElement::kVar_Kind) {
480 VarDeclarations& decl = (VarDeclarations&) e;
481 for (const auto& v : decl.fVars) {
482 const Variable* declVar = ((VarDeclaration&) *v).fVar;
483 if (declVar->fModifiers.fLayout.fBuiltin >= 0 || is_in(*declVar)) {
484 continue;
485 }
486 if (isUniform != is_uniform(*declVar)) {
487 continue;
488 }
489 if (declVar == &var) {
490 SkASSERT(offset <= 255);
491 return { offset, isUniform ? Storage::kUniform : Storage::kGlobal };
492 }
493 offset += SlotCount(declVar->fType);
494 }
495 }
496 }
497 SkASSERT(false);
498 return Location::MakeInvalid();
499 }
500 default:
501 SkASSERT(false);
502 return Location::MakeInvalid();
503 }
504}
505
Brian Osman1c110a02019-10-01 14:53:32 -0400506ByteCodeGenerator::Location ByteCodeGenerator::getLocation(const Expression& expr) {
Brian Osman07c117b2019-05-23 12:51:06 -0700507 switch (expr.fKind) {
508 case Expression::kFieldAccess_Kind: {
Brian Osmanb08cc022020-04-02 11:38:40 -0400509 const FieldAccess& f = (const FieldAccess&)expr;
510 Location baseLoc = this->getLocation(*f.fBase);
Brian Osman07c117b2019-05-23 12:51:06 -0700511 int offset = 0;
512 for (int i = 0; i < f.fFieldIndex; ++i) {
513 offset += SlotCount(*f.fBase->fType.fields()[i].fType);
514 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400515 if (baseLoc.isOnStack()) {
516 if (offset != 0) {
517 this->write(ByteCodeInstruction::kPushImmediate);
518 this->write32(offset);
Brian Osman49b30f42020-06-26 17:22:27 -0400519 this->write(ByteCodeInstruction::kAddI, 1);
Ben Wagner470e0ac2020-01-22 16:59:21 -0500520 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400521 return baseLoc;
Ben Wagner470e0ac2020-01-22 16:59:21 -0500522 } else {
Brian Osmanb08cc022020-04-02 11:38:40 -0400523 return baseLoc + offset;
Ben Wagner470e0ac2020-01-22 16:59:21 -0500524 }
Ben Wagner470e0ac2020-01-22 16:59:21 -0500525 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400526 case Expression::kIndex_Kind: {
527 const IndexExpression& i = (const IndexExpression&)expr;
528 int stride = SlotCount(i.fType);
529 int length = i.fBase->fType.columns();
530 SkASSERT(length <= 255);
531 int offset = -1;
532 if (i.fIndex->isConstant()) {
533 int64_t index = i.fIndex->getConstantInt();
534 if (index < 0 || index >= length) {
535 fErrors.error(i.fIndex->fOffset, "Array index out of bounds.");
536 return Location::MakeInvalid();
537 }
538 offset = index * stride;
539 } else {
540 if (i.fIndex->hasSideEffects()) {
541 // Having a side-effect in an indexer is technically safe for an rvalue,
542 // but with lvalues we have to evaluate the indexer twice, so make it an error.
543 fErrors.error(i.fIndex->fOffset,
544 "Index expressions with side-effects not supported in byte code.");
545 return Location::MakeInvalid();
546 }
547 this->writeExpression(*i.fIndex);
548 this->write(ByteCodeInstruction::kClampIndex);
549 this->write8(length);
550 if (stride != 1) {
551 this->write(ByteCodeInstruction::kPushImmediate);
552 this->write32(stride);
Brian Osman49b30f42020-06-26 17:22:27 -0400553 this->write(ByteCodeInstruction::kMultiplyI, 1);
Brian Osmanb08cc022020-04-02 11:38:40 -0400554 }
555 }
556 Location baseLoc = this->getLocation(*i.fBase);
557
558 // Are both components known statically?
559 if (!baseLoc.isOnStack() && offset >= 0) {
560 return baseLoc + offset;
561 }
562
563 // At least one component is dynamic (and on the stack).
564
565 // If the other component is zero, we're done
566 if (baseLoc.fSlot == 0 || offset == 0) {
567 return baseLoc.makeOnStack();
568 }
569
570 // Push the non-dynamic component (if any) to the stack, then add the two
571 if (!baseLoc.isOnStack()) {
572 this->write(ByteCodeInstruction::kPushImmediate);
573 this->write32(baseLoc.fSlot);
574 }
575 if (offset >= 0) {
576 this->write(ByteCodeInstruction::kPushImmediate);
577 this->write32(offset);
578 }
Brian Osman49b30f42020-06-26 17:22:27 -0400579 this->write(ByteCodeInstruction::kAddI, 1);
Brian Osmanb08cc022020-04-02 11:38:40 -0400580 return baseLoc.makeOnStack();
581 }
Brian Osman0785db02019-05-24 14:19:11 -0400582 case Expression::kSwizzle_Kind: {
Brian Osmanb08cc022020-04-02 11:38:40 -0400583 const Swizzle& s = (const Swizzle&)expr;
Brian Osman0785db02019-05-24 14:19:11 -0400584 SkASSERT(swizzle_is_simple(s));
Brian Osmanb08cc022020-04-02 11:38:40 -0400585 Location baseLoc = this->getLocation(*s.fBase);
586 int offset = s.fComponents[0];
587 if (baseLoc.isOnStack()) {
588 if (offset != 0) {
589 this->write(ByteCodeInstruction::kPushImmediate);
590 this->write32(offset);
Brian Osman49b30f42020-06-26 17:22:27 -0400591 this->write(ByteCodeInstruction::kAddI, 1);
Brian Osmanb08cc022020-04-02 11:38:40 -0400592 }
593 return baseLoc;
594 } else {
595 return baseLoc + offset;
596 }
Brian Osman0785db02019-05-24 14:19:11 -0400597 }
Brian Osman07c117b2019-05-23 12:51:06 -0700598 case Expression::kVariableReference_Kind: {
Brian Osmanb08cc022020-04-02 11:38:40 -0400599 const Variable& var = ((const VariableReference&)expr).fVariable;
Brian Osman07c117b2019-05-23 12:51:06 -0700600 return this->getLocation(var);
601 }
602 default:
603 SkASSERT(false);
Brian Osmanb08cc022020-04-02 11:38:40 -0400604 return Location::MakeInvalid();
Brian Osman07c117b2019-05-23 12:51:06 -0700605 }
606}
607
Brian Osmanb08cc022020-04-02 11:38:40 -0400608void ByteCodeGenerator::write8(uint8_t b) {
609 fCode->push_back(b);
Ethan Nicholas2cde3a12020-01-21 09:23:13 -0500610}
611
Brian Osmanb08cc022020-04-02 11:38:40 -0400612void ByteCodeGenerator::write16(uint16_t i) {
613 size_t n = fCode->size();
614 fCode->resize(n+2);
615 memcpy(fCode->data() + n, &i, 2);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500616}
Ben Wagner470e0ac2020-01-22 16:59:21 -0500617
Brian Osmanb08cc022020-04-02 11:38:40 -0400618void ByteCodeGenerator::write32(uint32_t i) {
619 size_t n = fCode->size();
620 fCode->resize(n+4);
621 memcpy(fCode->data() + n, &i, 4);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500622}
623
Brian Osmanb08cc022020-04-02 11:38:40 -0400624void ByteCodeGenerator::write(ByteCodeInstruction i, int count) {
625 switch (i) {
626 case ByteCodeInstruction::kLoopBegin: this->enterLoop(); break;
627 case ByteCodeInstruction::kLoopEnd: this->exitLoop(); break;
Ethan Nicholas2329da02020-01-24 15:49:33 -0500628
Brian Osmanb08cc022020-04-02 11:38:40 -0400629 case ByteCodeInstruction::kMaskPush: this->enterCondition(); break;
630 case ByteCodeInstruction::kMaskPop:
631 case ByteCodeInstruction::kMaskBlend: this->exitCondition(); break;
632 default: /* Do nothing */ break;
Ben Wagner470e0ac2020-01-22 16:59:21 -0500633 }
Brian Osmanab8f3842020-04-07 09:30:44 -0400634 this->write16((uint16_t)i);
Brian Osmanb08cc022020-04-02 11:38:40 -0400635 fStackCount += StackUsage(i, count);
636 fMaxStackCount = std::max(fMaxStackCount, fStackCount);
Brian Osman49b30f42020-06-26 17:22:27 -0400637
638 // Most ops have an explicit count byte after them (passed here as 'count')
639 // Ops that don't have a count byte pass the default (kUnusedStackCount)
640 // There are a handful of strange ops that pass in a computed stack delta as count, but where
641 // that value should *not* be written as a count byte (it may even be negative!)
642 if (count != kUnusedStackCount) {
643 switch (i) {
644 // Odd instructions that have a non-default count, but we shouldn't write it
645 case ByteCodeInstruction::kCallExternal:
646 case ByteCodeInstruction::kMatrixToMatrix:
647 case ByteCodeInstruction::kMatrixMultiply:
648 case ByteCodeInstruction::kScalarToMatrix:
649 case ByteCodeInstruction::kSwizzle:
650 break;
651 default:
652 this->write8(count);
653 break;
654 }
655 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500656}
657
Brian Osman49b30f42020-06-26 17:22:27 -0400658void ByteCodeGenerator::writeTypedInstruction(const Type& type,
659 ByteCodeInstruction s,
660 ByteCodeInstruction u,
661 ByteCodeInstruction f,
Brian Osmanab8f3842020-04-07 09:30:44 -0400662 int count) {
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500663 switch (type_category(type)) {
Brian Osman8842b372020-05-01 15:07:49 -0400664 case TypeCategory::kBool:
Brian Osman49b30f42020-06-26 17:22:27 -0400665 case TypeCategory::kSigned: this->write(s, count); break;
666 case TypeCategory::kUnsigned: this->write(u, count); break;
667 case TypeCategory::kFloat: this->write(f, count); break;
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500668 default:
669 SkASSERT(false);
670 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500671}
672
Brian Osmanb08cc022020-04-02 11:38:40 -0400673bool ByteCodeGenerator::writeBinaryExpression(const BinaryExpression& b, bool discard) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400674 if (b.fOperator == Token::Kind::TK_EQ) {
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500675 std::unique_ptr<LValue> lvalue = this->getLValue(*b.fLeft);
Brian Osmanb08cc022020-04-02 11:38:40 -0400676 this->writeExpression(*b.fRight);
677 lvalue->store(discard);
678 discard = false;
679 return discard;
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500680 }
681 const Type& lType = b.fLeft->fType;
682 const Type& rType = b.fRight->fType;
683 bool lVecOrMtx = (lType.kind() == Type::kVector_Kind || lType.kind() == Type::kMatrix_Kind);
684 bool rVecOrMtx = (rType.kind() == Type::kVector_Kind || rType.kind() == Type::kMatrix_Kind);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500685 Token::Kind op;
686 std::unique_ptr<LValue> lvalue;
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500687 if (is_assignment(b.fOperator)) {
688 lvalue = this->getLValue(*b.fLeft);
Brian Osmanb08cc022020-04-02 11:38:40 -0400689 lvalue->load();
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500690 op = remove_assignment(b.fOperator);
691 } else {
Brian Osmanb08cc022020-04-02 11:38:40 -0400692 this->writeExpression(*b.fLeft);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500693 op = b.fOperator;
694 if (!lVecOrMtx && rVecOrMtx) {
Brian Osmanb08cc022020-04-02 11:38:40 -0400695 for (int i = SlotCount(rType); i > 1; --i) {
Brian Osman49b30f42020-06-26 17:22:27 -0400696 this->write(ByteCodeInstruction::kDup, 1);
Brian Osmanb08cc022020-04-02 11:38:40 -0400697 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500698 }
699 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500700 int count = std::max(SlotCount(lType), SlotCount(rType));
Brian Osmanb08cc022020-04-02 11:38:40 -0400701 SkDEBUGCODE(TypeCategory tc = type_category(lType));
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500702 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400703 case Token::Kind::TK_LOGICALAND: {
Brian Osmanb08cc022020-04-02 11:38:40 -0400704 SkASSERT(tc == SkSL::TypeCategory::kBool && count == 1);
Brian Osman49b30f42020-06-26 17:22:27 -0400705 this->write(ByteCodeInstruction::kDup, 1);
Brian Osmanb08cc022020-04-02 11:38:40 -0400706 this->write(ByteCodeInstruction::kMaskPush);
707 this->write(ByteCodeInstruction::kBranchIfAllFalse);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500708 DeferredLocation falseLocation(this);
Brian Osmanb08cc022020-04-02 11:38:40 -0400709 this->writeExpression(*b.fRight);
Brian Osman49b30f42020-06-26 17:22:27 -0400710 this->write(ByteCodeInstruction::kAndB, 1);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500711 falseLocation.set();
Brian Osmanb08cc022020-04-02 11:38:40 -0400712 this->write(ByteCodeInstruction::kMaskPop);
713 return false;
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500714 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400715 case Token::Kind::TK_LOGICALOR: {
Brian Osmanb08cc022020-04-02 11:38:40 -0400716 SkASSERT(tc == SkSL::TypeCategory::kBool && count == 1);
Brian Osman49b30f42020-06-26 17:22:27 -0400717 this->write(ByteCodeInstruction::kDup, 1);
718 this->write(ByteCodeInstruction::kNotB, 1);
Brian Osmanb08cc022020-04-02 11:38:40 -0400719 this->write(ByteCodeInstruction::kMaskPush);
720 this->write(ByteCodeInstruction::kBranchIfAllFalse);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500721 DeferredLocation falseLocation(this);
Brian Osmanb08cc022020-04-02 11:38:40 -0400722 this->writeExpression(*b.fRight);
Brian Osman49b30f42020-06-26 17:22:27 -0400723 this->write(ByteCodeInstruction::kOrB, 1);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500724 falseLocation.set();
Brian Osmanb08cc022020-04-02 11:38:40 -0400725 this->write(ByteCodeInstruction::kMaskPop);
726 return false;
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500727 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400728 case Token::Kind::TK_SHL:
729 case Token::Kind::TK_SHR: {
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500730 SkASSERT(count == 1 && (tc == SkSL::TypeCategory::kSigned ||
731 tc == SkSL::TypeCategory::kUnsigned));
732 if (!b.fRight->isConstant()) {
733 fErrors.error(b.fRight->fOffset, "Shift amounts must be constant");
Brian Osmanb08cc022020-04-02 11:38:40 -0400734 return false;
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500735 }
736 int64_t shift = b.fRight->getConstantInt();
737 if (shift < 0 || shift > 31) {
738 fErrors.error(b.fRight->fOffset, "Shift amount out of range");
Brian Osmanb08cc022020-04-02 11:38:40 -0400739 return false;
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500740 }
741
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400742 if (op == Token::Kind::TK_SHL) {
Brian Osmanb08cc022020-04-02 11:38:40 -0400743 this->write(ByteCodeInstruction::kShiftLeft);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500744 } else {
745 this->write(type_category(lType) == TypeCategory::kSigned
Brian Osmanb08cc022020-04-02 11:38:40 -0400746 ? ByteCodeInstruction::kShiftRightS
747 : ByteCodeInstruction::kShiftRightU);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500748 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400749 this->write8(shift);
750 return false;
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500751 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500752
753 default:
754 break;
755 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400756 this->writeExpression(*b.fRight);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500757 if (lVecOrMtx && !rVecOrMtx) {
Brian Osmanb08cc022020-04-02 11:38:40 -0400758 for (int i = SlotCount(lType); i > 1; --i) {
Brian Osman49b30f42020-06-26 17:22:27 -0400759 this->write(ByteCodeInstruction::kDup, 1);
Brian Osmanb08cc022020-04-02 11:38:40 -0400760 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500761 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400762 // Special case for M*V, V*M, M*M (but not V*V!)
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400763 if (op == Token::Kind::TK_STAR && lVecOrMtx && rVecOrMtx &&
Brian Osmanb08cc022020-04-02 11:38:40 -0400764 !(lType.kind() == Type::kVector_Kind && rType.kind() == Type::kVector_Kind)) {
765 this->write(ByteCodeInstruction::kMatrixMultiply,
766 SlotCount(b.fType) - (SlotCount(lType) + SlotCount(rType)));
767 int rCols = rType.columns(),
768 rRows = rType.rows(),
769 lCols = lType.columns(),
770 lRows = lType.rows();
771 // M*V treats the vector as a column
772 if (rType.kind() == Type::kVector_Kind) {
773 std::swap(rCols, rRows);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500774 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400775 SkASSERT(lCols == rRows);
776 SkASSERT(SlotCount(b.fType) == lRows * rCols);
777 this->write8(lCols);
778 this->write8(lRows);
779 this->write8(rCols);
780 } else {
781 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400782 case Token::Kind::TK_EQEQ:
Brian Osmanb08cc022020-04-02 11:38:40 -0400783 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareIEQ,
784 ByteCodeInstruction::kCompareIEQ,
785 ByteCodeInstruction::kCompareFEQ,
786 count);
787 // Collapse to a single bool
788 for (int i = count; i > 1; --i) {
Brian Osman49b30f42020-06-26 17:22:27 -0400789 this->write(ByteCodeInstruction::kAndB, 1);
Brian Osmanb08cc022020-04-02 11:38:40 -0400790 }
791 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400792 case Token::Kind::TK_GT:
Brian Osmanb08cc022020-04-02 11:38:40 -0400793 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSGT,
794 ByteCodeInstruction::kCompareUGT,
795 ByteCodeInstruction::kCompareFGT,
796 count);
797 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400798 case Token::Kind::TK_GTEQ:
Brian Osmanb08cc022020-04-02 11:38:40 -0400799 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSGTEQ,
800 ByteCodeInstruction::kCompareUGTEQ,
801 ByteCodeInstruction::kCompareFGTEQ,
802 count);
803 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400804 case Token::Kind::TK_LT:
Brian Osmanb08cc022020-04-02 11:38:40 -0400805 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSLT,
806 ByteCodeInstruction::kCompareULT,
807 ByteCodeInstruction::kCompareFLT,
808 count);
809 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400810 case Token::Kind::TK_LTEQ:
Brian Osmanb08cc022020-04-02 11:38:40 -0400811 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSLTEQ,
812 ByteCodeInstruction::kCompareULTEQ,
813 ByteCodeInstruction::kCompareFLTEQ,
814 count);
815 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400816 case Token::Kind::TK_MINUS:
Brian Osmanb08cc022020-04-02 11:38:40 -0400817 this->writeTypedInstruction(lType, ByteCodeInstruction::kSubtractI,
818 ByteCodeInstruction::kSubtractI,
819 ByteCodeInstruction::kSubtractF,
820 count);
821 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400822 case Token::Kind::TK_NEQ:
Brian Osmanb08cc022020-04-02 11:38:40 -0400823 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareINEQ,
824 ByteCodeInstruction::kCompareINEQ,
825 ByteCodeInstruction::kCompareFNEQ,
826 count);
827 // Collapse to a single bool
828 for (int i = count; i > 1; --i) {
Brian Osman49b30f42020-06-26 17:22:27 -0400829 this->write(ByteCodeInstruction::kOrB, 1);
Brian Osmanb08cc022020-04-02 11:38:40 -0400830 }
831 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400832 case Token::Kind::TK_PERCENT:
Brian Osmanb08cc022020-04-02 11:38:40 -0400833 this->writeTypedInstruction(lType, ByteCodeInstruction::kRemainderS,
834 ByteCodeInstruction::kRemainderU,
835 ByteCodeInstruction::kRemainderF,
836 count);
837 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400838 case Token::Kind::TK_PLUS:
Brian Osmanb08cc022020-04-02 11:38:40 -0400839 this->writeTypedInstruction(lType, ByteCodeInstruction::kAddI,
840 ByteCodeInstruction::kAddI,
841 ByteCodeInstruction::kAddF,
842 count);
843 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400844 case Token::Kind::TK_SLASH:
Brian Osmanb08cc022020-04-02 11:38:40 -0400845 this->writeTypedInstruction(lType, ByteCodeInstruction::kDivideS,
846 ByteCodeInstruction::kDivideU,
847 ByteCodeInstruction::kDivideF,
848 count);
849 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400850 case Token::Kind::TK_STAR:
Brian Osmanb08cc022020-04-02 11:38:40 -0400851 this->writeTypedInstruction(lType, ByteCodeInstruction::kMultiplyI,
852 ByteCodeInstruction::kMultiplyI,
853 ByteCodeInstruction::kMultiplyF,
854 count);
855 break;
856
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400857 case Token::Kind::TK_LOGICALXOR:
Brian Osman49b30f42020-06-26 17:22:27 -0400858 SkASSERT(tc == SkSL::TypeCategory::kBool);
859 this->write(ByteCodeInstruction::kXorB, count);
Brian Osmanb08cc022020-04-02 11:38:40 -0400860 break;
861
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400862 case Token::Kind::TK_BITWISEAND:
Brian Osman49b30f42020-06-26 17:22:27 -0400863 SkASSERT(tc == SkSL::TypeCategory::kSigned || tc == SkSL::TypeCategory::kUnsigned);
864 this->write(ByteCodeInstruction::kAndB, count);
Brian Osmanb08cc022020-04-02 11:38:40 -0400865 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400866 case Token::Kind::TK_BITWISEOR:
Brian Osman49b30f42020-06-26 17:22:27 -0400867 SkASSERT(tc == SkSL::TypeCategory::kSigned || tc == SkSL::TypeCategory::kUnsigned);
868 this->write(ByteCodeInstruction::kOrB, count);
Brian Osmanb08cc022020-04-02 11:38:40 -0400869 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400870 case Token::Kind::TK_BITWISEXOR:
Brian Osman49b30f42020-06-26 17:22:27 -0400871 SkASSERT(tc == SkSL::TypeCategory::kSigned || tc == SkSL::TypeCategory::kUnsigned);
872 this->write(ByteCodeInstruction::kXorB, count);
Brian Osmanb08cc022020-04-02 11:38:40 -0400873 break;
874
875 default:
876 fErrors.error(b.fOffset, SkSL::String::printf("Unsupported binary operator '%s'",
877 Compiler::OperatorName(op)));
878 break;
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500879 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500880 }
881 if (lvalue) {
Brian Osmanb08cc022020-04-02 11:38:40 -0400882 lvalue->store(discard);
883 discard = false;
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500884 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400885 return discard;
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500886}
887
Brian Osmanb08cc022020-04-02 11:38:40 -0400888void ByteCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
889 this->write(ByteCodeInstruction::kPushImmediate);
890 this->write32(b.fValue ? ~0 : 0);
891}
892
893void ByteCodeGenerator::writeConstructor(const Constructor& c) {
894 for (const auto& arg : c.fArguments) {
895 this->writeExpression(*arg);
896 }
897 if (c.fArguments.size() == 1) {
898 const Type& inType = c.fArguments[0]->fType;
899 const Type& outType = c.fType;
900 TypeCategory inCategory = type_category(inType);
901 TypeCategory outCategory = type_category(outType);
902 int inCount = SlotCount(inType);
903 int outCount = SlotCount(outType);
904 if (inCategory != outCategory) {
905 SkASSERT(inCount == outCount);
906 if (inCategory == TypeCategory::kFloat) {
907 SkASSERT(outCategory == TypeCategory::kSigned ||
908 outCategory == TypeCategory::kUnsigned);
Brian Osman49b30f42020-06-26 17:22:27 -0400909 this->write(ByteCodeInstruction::kConvertFtoI, outCount);
Brian Osmanb08cc022020-04-02 11:38:40 -0400910 } else if (outCategory == TypeCategory::kFloat) {
911 if (inCategory == TypeCategory::kSigned) {
Brian Osman49b30f42020-06-26 17:22:27 -0400912 this->write(ByteCodeInstruction::kConvertStoF, outCount);
Brian Osmanb08cc022020-04-02 11:38:40 -0400913 } else {
914 SkASSERT(inCategory == TypeCategory::kUnsigned);
Brian Osman49b30f42020-06-26 17:22:27 -0400915 this->write(ByteCodeInstruction::kConvertUtoF, outCount);
Brian Osmanb08cc022020-04-02 11:38:40 -0400916 }
917 } else {
918 SkASSERT(false);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500919 }
920 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400921 if (inType.kind() == Type::kMatrix_Kind && outType.kind() == Type::kMatrix_Kind) {
922 this->write(ByteCodeInstruction::kMatrixToMatrix,
923 SlotCount(outType) - SlotCount(inType));
924 this->write8(inType.columns());
925 this->write8(inType.rows());
926 this->write8(outType.columns());
927 this->write8(outType.rows());
928 } else if (inCount != outCount) {
929 SkASSERT(inCount == 1);
930 if (outType.kind() == Type::kMatrix_Kind) {
931 this->write(ByteCodeInstruction::kScalarToMatrix, SlotCount(outType) - 1);
932 this->write8(outType.columns());
933 this->write8(outType.rows());
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500934 } else {
Brian Osmanb08cc022020-04-02 11:38:40 -0400935 SkASSERT(outType.kind() == Type::kVector_Kind);
936 for (; inCount != outCount; ++inCount) {
Brian Osman49b30f42020-06-26 17:22:27 -0400937 this->write(ByteCodeInstruction::kDup, 1);
Brian Osmanb08cc022020-04-02 11:38:40 -0400938 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500939 }
940 }
941 }
942}
943
Brian Osmanb08cc022020-04-02 11:38:40 -0400944void ByteCodeGenerator::writeExternalFunctionCall(const ExternalFunctionCall& f) {
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500945 int argumentCount = 0;
946 for (const auto& arg : f.fArguments) {
Brian Osmanb08cc022020-04-02 11:38:40 -0400947 this->writeExpression(*arg);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500948 argumentCount += SlotCount(arg->fType);
949 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400950 this->write(ByteCodeInstruction::kCallExternal, SlotCount(f.fType) - argumentCount);
951 SkASSERT(argumentCount <= 255);
952 this->write8(argumentCount);
953 this->write8(SlotCount(f.fType));
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500954 int index = fOutput->fExternalValues.size();
955 fOutput->fExternalValues.push_back(f.fFunction);
956 SkASSERT(index <= 255);
Brian Osmanb08cc022020-04-02 11:38:40 -0400957 this->write8(index);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500958}
959
Brian Osmanb08cc022020-04-02 11:38:40 -0400960void ByteCodeGenerator::writeExternalValue(const ExternalValueReference& e) {
961 int count = SlotCount(e.fValue->type());
Brian Osman49b30f42020-06-26 17:22:27 -0400962 this->write(ByteCodeInstruction::kReadExternal, count);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500963 int index = fOutput->fExternalValues.size();
964 fOutput->fExternalValues.push_back(e.fValue);
965 SkASSERT(index <= 255);
Brian Osmanb08cc022020-04-02 11:38:40 -0400966 this->write8(index);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500967}
968
Brian Osmanb08cc022020-04-02 11:38:40 -0400969void ByteCodeGenerator::writeVariableExpression(const Expression& expr) {
Brian Osman5aaaeea2020-06-22 14:26:03 -0400970 if (int builtin = expression_as_builtin(expr); builtin >= 0) {
971 switch (builtin) {
972 case SK_FRAGCOORD_BUILTIN:
973 this->write(ByteCodeInstruction::kLoadFragCoord);
974 fOutput->fUsesFragCoord = true;
975 break;
976 default:
977 fErrors.error(expr.fOffset, "Unsupported builtin");
978 break;
979 }
980 return;
981 }
982
Brian Osmanb08cc022020-04-02 11:38:40 -0400983 Location location = this->getLocation(expr);
984 int count = SlotCount(expr.fType);
Brian Osmanefb08402020-04-13 16:30:44 -0400985 if (count == 0) {
986 return;
987 }
Brian Osman02f8b072020-06-19 14:04:48 -0400988 if (location.isOnStack()) {
Brian Osmanb08cc022020-04-02 11:38:40 -0400989 this->write(location.selectLoad(ByteCodeInstruction::kLoadExtended,
990 ByteCodeInstruction::kLoadExtendedGlobal,
991 ByteCodeInstruction::kLoadExtendedUniform),
992 count);
Brian Osmanb08cc022020-04-02 11:38:40 -0400993 } else {
Brian Osman49b30f42020-06-26 17:22:27 -0400994 this->write(location.selectLoad(ByteCodeInstruction::kLoad,
995 ByteCodeInstruction::kLoadGlobal,
996 ByteCodeInstruction::kLoadUniform),
997 count);
998 this->write8(location.fSlot);
Brian Osmanb08cc022020-04-02 11:38:40 -0400999 }
1000}
1001
1002static inline uint32_t float_to_bits(float x) {
1003 uint32_t u;
1004 memcpy(&u, &x, sizeof(uint32_t));
1005 return u;
1006}
1007
1008void ByteCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
1009 this->write(ByteCodeInstruction::kPushImmediate);
1010 this->write32(float_to_bits(f.fValue));
1011}
1012
Brian Osman8842b372020-05-01 15:07:49 -04001013static bool is_generic_type(const Type* type, const Type* generic) {
1014 const std::vector<const Type*>& concrete(generic->coercibleTypes());
1015 return std::find(concrete.begin(), concrete.end(), type) != concrete.end();
1016}
1017
Brian Osmanb08cc022020-04-02 11:38:40 -04001018void ByteCodeGenerator::writeIntrinsicCall(const FunctionCall& c) {
1019 auto found = fIntrinsics.find(c.fFunction.fName);
1020 if (found == fIntrinsics.end()) {
1021 fErrors.error(c.fOffset, String::printf("Unsupported intrinsic: '%s'",
1022 String(c.fFunction.fName).c_str()));
1023 return;
1024 }
Mike Klein45be0772020-05-01 09:13:18 -05001025 Intrinsic intrin = found->second;
Brian Osmanb08cc022020-04-02 11:38:40 -04001026 int count = SlotCount(c.fArguments[0]->fType);
Brian Osmand5f937b2020-05-04 12:07:29 -04001027
1028 // Several intrinsics have variants where one argument is either scalar, or the same size as
1029 // the first argument. Call dupSmallerType(SlotCount(argType)) to ensure equal component count.
1030 auto dupSmallerType = [count, this](int smallCount) {
1031 SkASSERT(smallCount == 1 || smallCount == count);
1032 for (int i = smallCount; i < count; ++i) {
Brian Osman49b30f42020-06-26 17:22:27 -04001033 this->write(ByteCodeInstruction::kDup, 1);
Brian Osmand5f937b2020-05-04 12:07:29 -04001034 }
1035 };
1036
Brian Osmana43d8202020-06-17 16:50:39 -04001037 if (intrin.is_special && intrin.special == SpecialIntrinsic::kSample) {
1038 // Sample is very special, the first argument is an FP, which can't be pushed to the stack
1039 if (c.fArguments.size() != 2 ||
1040 c.fArguments[0]->fType != *fContext.fFragmentProcessor_Type ||
1041 (c.fArguments[1]->fType != *fContext.fFloat2_Type &&
1042 c.fArguments[1]->fType != *fContext.fFloat3x3_Type)) {
1043 fErrors.error(c.fOffset, "Unsupported form of sample");
1044 return;
1045 }
1046
1047 // Write our coords or matrix
1048 this->writeExpression(*c.fArguments[1]);
1049
1050 this->write(c.fArguments[1]->fType == *fContext.fFloat3x3_Type
1051 ? ByteCodeInstruction::kSampleMatrix
1052 : ByteCodeInstruction::kSampleExplicit);
1053
1054 Location childLoc = this->getLocation(*c.fArguments[0]);
1055 SkASSERT(childLoc.fStorage == Storage::kChildFP);
1056 this->write8(childLoc.fSlot);
1057 return;
1058 }
1059
Brian Osmand5f937b2020-05-04 12:07:29 -04001060 if (intrin.is_special && (intrin.special == SpecialIntrinsic::kClamp ||
1061 intrin.special == SpecialIntrinsic::kSaturate)) {
1062 // These intrinsics are extra-special, we need instructions interleaved with arguments
1063 bool saturate = (intrin.special == SpecialIntrinsic::kSaturate);
1064 SkASSERT(c.fArguments.size() == (saturate ? 1 : 3));
1065 int limitCount = saturate ? 1 : SlotCount(c.fArguments[1]->fType);
1066
1067 // 'x'
1068 this->writeExpression(*c.fArguments[0]);
1069
1070 // 'minVal'
1071 if (saturate) {
1072 this->write(ByteCodeInstruction::kPushImmediate);
1073 this->write32(float_to_bits(0.0f));
1074 } else {
1075 this->writeExpression(*c.fArguments[1]);
1076 }
1077 dupSmallerType(limitCount);
1078 this->writeTypedInstruction(c.fArguments[0]->fType,
1079 ByteCodeInstruction::kMaxS,
1080 ByteCodeInstruction::kMaxS,
1081 ByteCodeInstruction::kMaxF,
1082 count);
1083
1084 // 'maxVal'
1085 if (saturate) {
1086 this->write(ByteCodeInstruction::kPushImmediate);
1087 this->write32(float_to_bits(1.0f));
1088 } else {
1089 SkASSERT(limitCount == SlotCount(c.fArguments[2]->fType));
1090 this->writeExpression(*c.fArguments[2]);
1091 }
1092 dupSmallerType(limitCount);
1093 this->writeTypedInstruction(c.fArguments[0]->fType,
1094 ByteCodeInstruction::kMinS,
1095 ByteCodeInstruction::kMinS,
1096 ByteCodeInstruction::kMinF,
1097 count);
1098 return;
1099 }
1100
1101 // All other intrinsics can handle their arguments being on the stack in order
1102 for (const auto& arg : c.fArguments) {
1103 this->writeExpression(*arg);
1104 }
1105
Mike Klein45be0772020-05-01 09:13:18 -05001106 if (intrin.is_special) {
1107 switch (intrin.special) {
Brian Osman8842b372020-05-01 15:07:49 -04001108 case SpecialIntrinsic::kAll: {
1109 for (int i = count-1; i --> 0;) {
Brian Osman49b30f42020-06-26 17:22:27 -04001110 this->write(ByteCodeInstruction::kAndB, 1);
Brian Osman8842b372020-05-01 15:07:49 -04001111 }
1112 } break;
1113
1114 case SpecialIntrinsic::kAny: {
1115 for (int i = count-1; i --> 0;) {
Brian Osman49b30f42020-06-26 17:22:27 -04001116 this->write(ByteCodeInstruction::kOrB, 1);
Brian Osman8842b372020-05-01 15:07:49 -04001117 }
1118 } break;
1119
Brian Osman15c98cb2020-02-27 18:36:57 +00001120 case SpecialIntrinsic::kDot: {
1121 SkASSERT(c.fArguments.size() == 2);
Brian Osmanb08cc022020-04-02 11:38:40 -04001122 SkASSERT(count == SlotCount(c.fArguments[1]->fType));
Brian Osman49b30f42020-06-26 17:22:27 -04001123 this->write(ByteCodeInstruction::kMultiplyF, count);
Mike Klein45be0772020-05-01 09:13:18 -05001124 for (int i = count-1; i --> 0;) {
Brian Osman49b30f42020-06-26 17:22:27 -04001125 this->write(ByteCodeInstruction::kAddF, 1);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001126 }
Mike Klein45be0772020-05-01 09:13:18 -05001127 } break;
1128
1129 case SpecialIntrinsic::kLength: {
1130 SkASSERT(c.fArguments.size() == 1);
Brian Osman49b30f42020-06-26 17:22:27 -04001131 this->write(ByteCodeInstruction::kDup, count);
1132 this->write(ByteCodeInstruction::kMultiplyF, count);
Mike Klein45be0772020-05-01 09:13:18 -05001133 for (int i = count-1; i --> 0;) {
Brian Osman49b30f42020-06-26 17:22:27 -04001134 this->write(ByteCodeInstruction::kAddF, 1);
Mike Klein45be0772020-05-01 09:13:18 -05001135 }
Brian Osman49b30f42020-06-26 17:22:27 -04001136 this->write(ByteCodeInstruction::kSqrt, 1);
Mike Klein45be0772020-05-01 09:13:18 -05001137 } break;
1138
Brian Osmand5f937b2020-05-04 12:07:29 -04001139 case SpecialIntrinsic::kMax:
1140 case SpecialIntrinsic::kMin: {
1141 SkASSERT(c.fArguments.size() == 2);
1142 // There are variants where the second argument is scalar
1143 dupSmallerType(SlotCount(c.fArguments[1]->fType));
1144 if (intrin.special == SpecialIntrinsic::kMax) {
1145 this->writeTypedInstruction(c.fArguments[0]->fType,
1146 ByteCodeInstruction::kMaxS,
1147 ByteCodeInstruction::kMaxS,
1148 ByteCodeInstruction::kMaxF,
1149 count);
1150 } else {
1151 this->writeTypedInstruction(c.fArguments[0]->fType,
1152 ByteCodeInstruction::kMinS,
1153 ByteCodeInstruction::kMinS,
1154 ByteCodeInstruction::kMinF,
1155 count);
1156 }
1157 } break;
1158
Brian Osman8842b372020-05-01 15:07:49 -04001159 case SpecialIntrinsic::kMix: {
1160 // Two main variants of mix to handle
1161 SkASSERT(c.fArguments.size() == 3);
1162 SkASSERT(count == SlotCount(c.fArguments[1]->fType));
1163 int selectorCount = SlotCount(c.fArguments[2]->fType);
1164
1165 if (is_generic_type(&c.fArguments[2]->fType, fContext.fGenBType_Type.get())) {
1166 // mix(genType, genType, genBoolType)
1167 SkASSERT(selectorCount == count);
Brian Osman49b30f42020-06-26 17:22:27 -04001168 this->write(ByteCodeInstruction::kMix, count);
Brian Osman8842b372020-05-01 15:07:49 -04001169 } else {
1170 // mix(genType, genType, genType) or mix(genType, genType, float)
Brian Osmand5f937b2020-05-04 12:07:29 -04001171 dupSmallerType(selectorCount);
Brian Osman49b30f42020-06-26 17:22:27 -04001172 this->write(ByteCodeInstruction::kLerp, count);
Brian Osman8842b372020-05-01 15:07:49 -04001173 }
1174 } break;
1175
Brian Osman2a4871b2020-06-19 11:29:58 -04001176 case SpecialIntrinsic::kNormalize: {
1177 SkASSERT(c.fArguments.size() == 1);
Brian Osman49b30f42020-06-26 17:22:27 -04001178 this->write(ByteCodeInstruction::kDup, count);
1179 this->write(ByteCodeInstruction::kDup, count);
1180 this->write(ByteCodeInstruction::kMultiplyF, count);
Brian Osman2a4871b2020-06-19 11:29:58 -04001181 for (int i = count-1; i --> 0;) {
Brian Osman49b30f42020-06-26 17:22:27 -04001182 this->write(ByteCodeInstruction::kAddF, 1);
Brian Osman2a4871b2020-06-19 11:29:58 -04001183 }
Brian Osman49b30f42020-06-26 17:22:27 -04001184 this->write(ByteCodeInstruction::kSqrt, 1);
Brian Osman2a4871b2020-06-19 11:29:58 -04001185 dupSmallerType(1);
Brian Osman49b30f42020-06-26 17:22:27 -04001186 this->write(ByteCodeInstruction::kDivideF, count);
Brian Osman2a4871b2020-06-19 11:29:58 -04001187 } break;
1188
Brian Osmanb08cc022020-04-02 11:38:40 -04001189 default:
1190 SkASSERT(false);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001191 }
1192 } else {
Brian Osman8842b372020-05-01 15:07:49 -04001193 switch (intrin.inst_f) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001194 case ByteCodeInstruction::kInverse2x2: {
1195 SkASSERT(c.fArguments.size() > 0);
1196 auto op = ByteCodeInstruction::kInverse2x2;
1197 switch (count) {
1198 case 4: break; // float2x2
1199 case 9: op = ByteCodeInstruction::kInverse3x3; break;
1200 case 16: op = ByteCodeInstruction::kInverse4x4; break;
1201 default: SkASSERT(false);
1202 }
1203 this->write(op);
1204 break;
Brian Osman15c98cb2020-02-27 18:36:57 +00001205 }
Mike Klein45be0772020-05-01 09:13:18 -05001206
Brian Osmanb08cc022020-04-02 11:38:40 -04001207 default:
Brian Osman49b30f42020-06-26 17:22:27 -04001208 this->writeTypedInstruction(c.fArguments[0]->fType,
1209 intrin.inst_s,
1210 intrin.inst_u,
1211 intrin.inst_f,
1212 count);
Brian Osman8842b372020-05-01 15:07:49 -04001213 break;
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001214 }
1215 }
1216}
1217
Brian Osmanb08cc022020-04-02 11:38:40 -04001218void ByteCodeGenerator::writeFunctionCall(const FunctionCall& f) {
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001219 // Find the index of the function we're calling. We explicitly do not allow calls to functions
1220 // before they're defined. This is an easy-to-understand rule that prevents recursion.
Brian Osmanb08cc022020-04-02 11:38:40 -04001221 int idx = -1;
1222 for (size_t i = 0; i < fFunctions.size(); ++i) {
1223 if (f.fFunction.matches(fFunctions[i]->fDeclaration)) {
1224 idx = i;
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001225 break;
1226 }
1227 }
Brian Osmanb08cc022020-04-02 11:38:40 -04001228 if (idx == -1) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001229 this->writeIntrinsicCall(f);
1230 return;
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001231 }
Brian Osmanb08cc022020-04-02 11:38:40 -04001232
1233
1234 if (idx > 255) {
1235 fErrors.error(f.fOffset, "Function count limit exceeded");
1236 return;
1237 } else if (idx >= (int) fFunctions.size()) {
1238 fErrors.error(f.fOffset, "Call to undefined function");
1239 return;
1240 }
1241
1242 // We may need to deal with out parameters, so the sequence is tricky
1243 if (int returnCount = SlotCount(f.fType)) {
1244 this->write(ByteCodeInstruction::kReserve, returnCount);
Brian Osmanb08cc022020-04-02 11:38:40 -04001245 }
1246
1247 int argCount = f.fArguments.size();
1248 std::vector<std::unique_ptr<LValue>> lvalues;
1249 for (int i = 0; i < argCount; ++i) {
1250 const auto& param = f.fFunction.fParameters[i];
1251 const auto& arg = f.fArguments[i];
1252 if (param->fModifiers.fFlags & Modifiers::kOut_Flag) {
1253 lvalues.emplace_back(this->getLValue(*arg));
1254 lvalues.back()->load();
1255 } else {
1256 this->writeExpression(*arg);
1257 }
1258 }
1259
1260 // The space used by the call is based on the callee, but it also unwinds all of that before
1261 // we continue execution. We adjust our max stack depths below.
1262 this->write(ByteCodeInstruction::kCall);
1263 this->write8(idx);
1264
1265 const ByteCodeFunction* callee = fOutput->fFunctions[idx].get();
1266 fMaxLoopCount = std::max(fMaxLoopCount, fLoopCount + callee->fLoopCount);
1267 fMaxConditionCount = std::max(fMaxConditionCount, fConditionCount + callee->fConditionCount);
1268 fMaxStackCount = std::max(fMaxStackCount, fStackCount + callee->fLocalCount
1269 + callee->fStackCount);
1270
1271 // After the called function returns, the stack will still contain our arguments. We have to
1272 // pop them (storing any out parameters back to their lvalues as we go). We glob together slot
1273 // counts for all parameters that aren't out-params, so we can pop them in one big chunk.
1274 int popCount = 0;
1275 auto pop = [&]() {
Brian Osman49b30f42020-06-26 17:22:27 -04001276 if (popCount > 0) {
1277 this->write(ByteCodeInstruction::kPop, popCount);
Brian Osmanb08cc022020-04-02 11:38:40 -04001278 }
1279 popCount = 0;
1280 };
1281
1282 for (int i = argCount - 1; i >= 0; --i) {
1283 const auto& param = f.fFunction.fParameters[i];
1284 const auto& arg = f.fArguments[i];
1285 if (param->fModifiers.fFlags & Modifiers::kOut_Flag) {
1286 pop();
1287 lvalues.back()->store(true);
1288 lvalues.pop_back();
1289 } else {
1290 popCount += SlotCount(arg->fType);
1291 }
1292 }
1293 pop();
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001294}
1295
Brian Osmanb08cc022020-04-02 11:38:40 -04001296void ByteCodeGenerator::writeIntLiteral(const IntLiteral& i) {
1297 this->write(ByteCodeInstruction::kPushImmediate);
1298 this->write32(i.fValue);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001299}
1300
Brian Osmanb08cc022020-04-02 11:38:40 -04001301void ByteCodeGenerator::writeNullLiteral(const NullLiteral& n) {
1302 // not yet implemented
1303 abort();
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001304}
1305
Brian Osmanb08cc022020-04-02 11:38:40 -04001306bool ByteCodeGenerator::writePrefixExpression(const PrefixExpression& p, bool discard) {
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001307 switch (p.fOperator) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001308 case Token::Kind::TK_PLUSPLUS: // fall through
1309 case Token::Kind::TK_MINUSMINUS: {
Brian Osmanb08cc022020-04-02 11:38:40 -04001310 SkASSERT(SlotCount(p.fOperand->fType) == 1);
1311 std::unique_ptr<LValue> lvalue = this->getLValue(*p.fOperand);
1312 lvalue->load();
1313 this->write(ByteCodeInstruction::kPushImmediate);
1314 this->write32(type_category(p.fType) == TypeCategory::kFloat ? float_to_bits(1.0f) : 1);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001315 if (p.fOperator == Token::Kind::TK_PLUSPLUS) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001316 this->writeTypedInstruction(p.fType,
1317 ByteCodeInstruction::kAddI,
1318 ByteCodeInstruction::kAddI,
1319 ByteCodeInstruction::kAddF,
1320 1);
1321 } else {
1322 this->writeTypedInstruction(p.fType,
1323 ByteCodeInstruction::kSubtractI,
1324 ByteCodeInstruction::kSubtractI,
1325 ByteCodeInstruction::kSubtractF,
1326 1);
1327 }
1328 lvalue->store(discard);
1329 discard = false;
1330 break;
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001331 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001332 case Token::Kind::TK_MINUS: {
Brian Osmanb08cc022020-04-02 11:38:40 -04001333 this->writeExpression(*p.fOperand);
1334 this->writeTypedInstruction(p.fType,
1335 ByteCodeInstruction::kNegateI,
1336 ByteCodeInstruction::kNegateI,
1337 ByteCodeInstruction::kNegateF,
Brian Osmanab8f3842020-04-07 09:30:44 -04001338 SlotCount(p.fOperand->fType));
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001339 break;
1340 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001341 case Token::Kind::TK_LOGICALNOT:
1342 case Token::Kind::TK_BITWISENOT: {
Brian Osmanb08cc022020-04-02 11:38:40 -04001343 SkASSERT(SlotCount(p.fOperand->fType) == 1);
1344 SkDEBUGCODE(TypeCategory tc = type_category(p.fOperand->fType));
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001345 SkASSERT((p.fOperator == Token::Kind::TK_LOGICALNOT && tc == TypeCategory::kBool) ||
1346 (p.fOperator == Token::Kind::TK_BITWISENOT && (tc == TypeCategory::kSigned ||
Brian Osmanb08cc022020-04-02 11:38:40 -04001347 tc == TypeCategory::kUnsigned)));
1348 this->writeExpression(*p.fOperand);
Brian Osman49b30f42020-06-26 17:22:27 -04001349 this->write(ByteCodeInstruction::kNotB, 1);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001350 break;
1351 }
1352 default:
1353 SkASSERT(false);
1354 }
Brian Osmanb08cc022020-04-02 11:38:40 -04001355 return discard;
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001356}
1357
Brian Osmanb08cc022020-04-02 11:38:40 -04001358bool ByteCodeGenerator::writePostfixExpression(const PostfixExpression& p, bool discard) {
1359 switch (p.fOperator) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001360 case Token::Kind::TK_PLUSPLUS: // fall through
1361 case Token::Kind::TK_MINUSMINUS: {
Brian Osmanb08cc022020-04-02 11:38:40 -04001362 SkASSERT(SlotCount(p.fOperand->fType) == 1);
1363 std::unique_ptr<LValue> lvalue = this->getLValue(*p.fOperand);
1364 lvalue->load();
1365 // If we're not supposed to discard the result, then make a copy *before* the +/-
1366 if (!discard) {
Brian Osman49b30f42020-06-26 17:22:27 -04001367 this->write(ByteCodeInstruction::kDup, 1);
Brian Osmanb08cc022020-04-02 11:38:40 -04001368 }
1369 this->write(ByteCodeInstruction::kPushImmediate);
1370 this->write32(type_category(p.fType) == TypeCategory::kFloat ? float_to_bits(1.0f) : 1);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001371 if (p.fOperator == Token::Kind::TK_PLUSPLUS) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001372 this->writeTypedInstruction(p.fType,
1373 ByteCodeInstruction::kAddI,
1374 ByteCodeInstruction::kAddI,
1375 ByteCodeInstruction::kAddF,
1376 1);
1377 } else {
1378 this->writeTypedInstruction(p.fType,
1379 ByteCodeInstruction::kSubtractI,
1380 ByteCodeInstruction::kSubtractI,
1381 ByteCodeInstruction::kSubtractF,
1382 1);
1383 }
1384 // Always consume the result as part of the store
1385 lvalue->store(true);
1386 discard = false;
1387 break;
1388 }
1389 default:
1390 SkASSERT(false);
1391 }
1392 return discard;
1393}
1394
1395void ByteCodeGenerator::writeSwizzle(const Swizzle& s) {
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001396 if (swizzle_is_simple(s)) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001397 this->writeVariableExpression(s);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001398 return;
1399 }
Brian Osmanb08cc022020-04-02 11:38:40 -04001400
Brian Osman3711c662020-06-18 14:42:21 -04001401 this->writeExpression(*s.fBase);
1402 this->write(ByteCodeInstruction::kSwizzle, s.fComponents.size() - s.fBase->fType.columns());
1403 this->write8(s.fBase->fType.columns());
1404 this->write8(s.fComponents.size());
1405 for (int c : s.fComponents) {
1406 this->write8(c);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001407 }
1408}
1409
Brian Osmanb08cc022020-04-02 11:38:40 -04001410void ByteCodeGenerator::writeTernaryExpression(const TernaryExpression& t) {
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001411 int count = SlotCount(t.fType);
1412 SkASSERT(count == SlotCount(t.fIfTrue->fType));
1413 SkASSERT(count == SlotCount(t.fIfFalse->fType));
1414
Brian Osmanb08cc022020-04-02 11:38:40 -04001415 this->writeExpression(*t.fTest);
1416 this->write(ByteCodeInstruction::kMaskPush);
1417 this->writeExpression(*t.fIfTrue);
1418 this->write(ByteCodeInstruction::kMaskNegate);
1419 this->writeExpression(*t.fIfFalse);
1420 this->write(ByteCodeInstruction::kMaskBlend, count);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001421}
1422
Brian Osmanb08cc022020-04-02 11:38:40 -04001423void ByteCodeGenerator::writeExpression(const Expression& e, bool discard) {
1424 switch (e.fKind) {
1425 case Expression::kBinary_Kind:
1426 discard = this->writeBinaryExpression((BinaryExpression&) e, discard);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001427 break;
Brian Osmanb08cc022020-04-02 11:38:40 -04001428 case Expression::kBoolLiteral_Kind:
1429 this->writeBoolLiteral((BoolLiteral&) e);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001430 break;
Brian Osmanb08cc022020-04-02 11:38:40 -04001431 case Expression::kConstructor_Kind:
1432 this->writeConstructor((Constructor&) e);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001433 break;
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001434 case Expression::kExternalFunctionCall_Kind:
Brian Osmanb08cc022020-04-02 11:38:40 -04001435 this->writeExternalFunctionCall((ExternalFunctionCall&) e);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001436 break;
1437 case Expression::kExternalValue_Kind:
Brian Osmanb08cc022020-04-02 11:38:40 -04001438 this->writeExternalValue((ExternalValueReference&) e);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001439 break;
1440 case Expression::kFieldAccess_Kind:
1441 case Expression::kIndex_Kind:
1442 case Expression::kVariableReference_Kind:
Brian Osmanb08cc022020-04-02 11:38:40 -04001443 this->writeVariableExpression(e);
1444 break;
1445 case Expression::kFloatLiteral_Kind:
1446 this->writeFloatLiteral((FloatLiteral&) e);
1447 break;
1448 case Expression::kFunctionCall_Kind:
1449 this->writeFunctionCall((FunctionCall&) e);
1450 break;
1451 case Expression::kIntLiteral_Kind:
1452 this->writeIntLiteral((IntLiteral&) e);
1453 break;
1454 case Expression::kNullLiteral_Kind:
1455 this->writeNullLiteral((NullLiteral&) e);
1456 break;
1457 case Expression::kPrefix_Kind:
1458 discard = this->writePrefixExpression((PrefixExpression&) e, discard);
1459 break;
1460 case Expression::kPostfix_Kind:
1461 discard = this->writePostfixExpression((PostfixExpression&) e, discard);
1462 break;
1463 case Expression::kSwizzle_Kind:
1464 this->writeSwizzle((Swizzle&) e);
1465 break;
1466 case Expression::kTernary_Kind:
1467 this->writeTernaryExpression((TernaryExpression&) e);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001468 break;
Ben Wagner470e0ac2020-01-22 16:59:21 -05001469 default:
1470#ifdef SK_DEBUG
Brian Osmanb08cc022020-04-02 11:38:40 -04001471 printf("unsupported expression %s\n", e.description().c_str());
Ben Wagner470e0ac2020-01-22 16:59:21 -05001472#endif
Brian Osmanb08cc022020-04-02 11:38:40 -04001473 SkASSERT(false);
1474 }
1475 if (discard) {
1476 int count = SlotCount(e.fType);
Brian Osman49b30f42020-06-26 17:22:27 -04001477 if (count > 0) {
1478 this->write(ByteCodeInstruction::kPop, count);
Brian Osmanb08cc022020-04-02 11:38:40 -04001479 }
1480 discard = false;
Ben Wagner470e0ac2020-01-22 16:59:21 -05001481 }
Ethan Nicholas7deb1c22020-01-22 10:31:55 -05001482}
1483
Brian Osmanb08cc022020-04-02 11:38:40 -04001484class ByteCodeExternalValueLValue : public ByteCodeGenerator::LValue {
1485public:
1486 ByteCodeExternalValueLValue(ByteCodeGenerator* generator, ExternalValue& value, int index)
1487 : INHERITED(*generator)
1488 , fCount(ByteCodeGenerator::SlotCount(value.type()))
1489 , fIndex(index) {}
1490
1491 void load() override {
Brian Osman49b30f42020-06-26 17:22:27 -04001492 fGenerator.write(ByteCodeInstruction::kReadExternal, fCount);
Brian Osmanb08cc022020-04-02 11:38:40 -04001493 fGenerator.write8(fIndex);
1494 }
1495
1496 void store(bool discard) override {
1497 if (!discard) {
Brian Osman49b30f42020-06-26 17:22:27 -04001498 fGenerator.write(ByteCodeInstruction::kDup, fCount);
Brian Osmanb08cc022020-04-02 11:38:40 -04001499 }
Brian Osman49b30f42020-06-26 17:22:27 -04001500 fGenerator.write(ByteCodeInstruction::kWriteExternal, fCount);
Brian Osmanb08cc022020-04-02 11:38:40 -04001501 fGenerator.write8(fIndex);
1502 }
1503
1504private:
1505 typedef LValue INHERITED;
1506
1507 int fCount;
Brian Osmanb08cc022020-04-02 11:38:40 -04001508 int fIndex;
1509};
1510
1511class ByteCodeSwizzleLValue : public ByteCodeGenerator::LValue {
1512public:
1513 ByteCodeSwizzleLValue(ByteCodeGenerator* generator, const Swizzle& swizzle)
1514 : INHERITED(*generator)
1515 , fSwizzle(swizzle) {}
1516
1517 void load() override {
1518 fGenerator.writeSwizzle(fSwizzle);
1519 }
1520
1521 void store(bool discard) override {
1522 int count = fSwizzle.fComponents.size();
1523 if (!discard) {
Brian Osman49b30f42020-06-26 17:22:27 -04001524 fGenerator.write(ByteCodeInstruction::kDup, count);
Brian Osmanb08cc022020-04-02 11:38:40 -04001525 }
Brian Osman304dfa32020-06-18 15:53:51 -04001526 // We already have the correct number of values on the stack, thanks to type checking.
1527 // The algorithm: Walk down the values on the stack, doing 'count' single-element stores.
1528 // For each value, use the corresponding swizzle component to offset the store location.
1529 //
1530 // Static locations: We (wastefully) call getLocation every time, but get good byte code.
1531 // Note that we could (but don't) store adjacent/sequential values with fewer instructions.
1532 //
1533 // Dynamic locations: ... are bad. We have to recompute the base address on each iteration,
1534 // because the stack doesn't let us retain that address between stores. Dynamic locations
1535 // are rare though, and swizzled writes to those are even rarer, so we just live with this.
1536 for (int i = count; i-- > 0;) {
1537 ByteCodeGenerator::Location location = fGenerator.getLocation(*fSwizzle.fBase);
1538 if (!location.isOnStack()) {
1539 fGenerator.write(location.selectStore(ByteCodeInstruction::kStore,
Brian Osman49b30f42020-06-26 17:22:27 -04001540 ByteCodeInstruction::kStoreGlobal),
1541 1);
Brian Osman304dfa32020-06-18 15:53:51 -04001542 fGenerator.write8(location.fSlot + fSwizzle.fComponents[i]);
1543 } else {
1544 fGenerator.write(ByteCodeInstruction::kPushImmediate);
1545 fGenerator.write32(fSwizzle.fComponents[i]);
Brian Osman49b30f42020-06-26 17:22:27 -04001546 fGenerator.write(ByteCodeInstruction::kAddI, 1);
Brian Osman304dfa32020-06-18 15:53:51 -04001547 fGenerator.write(location.selectStore(ByteCodeInstruction::kStoreExtended,
1548 ByteCodeInstruction::kStoreExtendedGlobal),
1549 1);
Brian Osman304dfa32020-06-18 15:53:51 -04001550 }
Brian Osmanb08cc022020-04-02 11:38:40 -04001551 }
1552 }
1553
1554private:
1555 const Swizzle& fSwizzle;
1556
1557 typedef LValue INHERITED;
1558};
1559
1560class ByteCodeExpressionLValue : public ByteCodeGenerator::LValue {
1561public:
1562 ByteCodeExpressionLValue(ByteCodeGenerator* generator, const Expression& expr)
1563 : INHERITED(*generator)
1564 , fExpression(expr) {}
1565
1566 void load() override {
1567 fGenerator.writeVariableExpression(fExpression);
1568 }
1569
1570 void store(bool discard) override {
1571 int count = ByteCodeGenerator::SlotCount(fExpression.fType);
1572 if (!discard) {
Brian Osman49b30f42020-06-26 17:22:27 -04001573 fGenerator.write(ByteCodeInstruction::kDup, count);
Brian Osmanb08cc022020-04-02 11:38:40 -04001574 }
1575 ByteCodeGenerator::Location location = fGenerator.getLocation(fExpression);
Brian Osman49b30f42020-06-26 17:22:27 -04001576 if (location.isOnStack()) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001577 fGenerator.write(location.selectStore(ByteCodeInstruction::kStoreExtended,
1578 ByteCodeInstruction::kStoreExtendedGlobal),
1579 count);
Brian Osmanb08cc022020-04-02 11:38:40 -04001580 } else {
Brian Osman49b30f42020-06-26 17:22:27 -04001581 fGenerator.write(location.selectStore(ByteCodeInstruction::kStore,
1582 ByteCodeInstruction::kStoreGlobal),
1583 count);
Brian Osmanb08cc022020-04-02 11:38:40 -04001584 fGenerator.write8(location.fSlot);
1585 }
1586 }
1587
1588private:
1589 typedef LValue INHERITED;
1590
1591 const Expression& fExpression;
1592};
1593
1594std::unique_ptr<ByteCodeGenerator::LValue> ByteCodeGenerator::getLValue(const Expression& e) {
1595 switch (e.fKind) {
1596 case Expression::kExternalValue_Kind: {
1597 ExternalValue* value = ((ExternalValueReference&) e).fValue;
1598 int index = fOutput->fExternalValues.size();
1599 fOutput->fExternalValues.push_back(value);
1600 SkASSERT(index <= 255);
1601 return std::unique_ptr<LValue>(new ByteCodeExternalValueLValue(this, *value, index));
1602 }
1603 case Expression::kFieldAccess_Kind:
1604 case Expression::kIndex_Kind:
1605 case Expression::kVariableReference_Kind:
1606 return std::unique_ptr<LValue>(new ByteCodeExpressionLValue(this, e));
1607 case Expression::kSwizzle_Kind: {
1608 const Swizzle& s = (const Swizzle&) e;
1609 return swizzle_is_simple(s)
1610 ? std::unique_ptr<LValue>(new ByteCodeExpressionLValue(this, e))
1611 : std::unique_ptr<LValue>(new ByteCodeSwizzleLValue(this, s));
1612 }
1613 case Expression::kTernary_Kind:
1614 default:
1615#ifdef SK_DEBUG
1616 ABORT("unsupported lvalue %s\n", e.description().c_str());
1617#endif
1618 return nullptr;
1619 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001620}
1621
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001622void ByteCodeGenerator::writeBlock(const Block& b) {
1623 for (const auto& s : b.fStatements) {
1624 this->writeStatement(*s);
1625 }
1626}
1627
Brian Osmanb08cc022020-04-02 11:38:40 -04001628void ByteCodeGenerator::setBreakTargets() {
1629 std::vector<DeferredLocation>& breaks = fBreakTargets.top();
1630 for (DeferredLocation& b : breaks) {
1631 b.set();
1632 }
1633 fBreakTargets.pop();
1634}
1635
1636void ByteCodeGenerator::setContinueTargets() {
1637 std::vector<DeferredLocation>& continues = fContinueTargets.top();
1638 for (DeferredLocation& c : continues) {
1639 c.set();
1640 }
1641 fContinueTargets.pop();
1642}
1643
1644void ByteCodeGenerator::writeBreakStatement(const BreakStatement& b) {
1645 // TODO: Include BranchIfAllFalse to top-most LoopNext
1646 this->write(ByteCodeInstruction::kLoopBreak);
1647}
1648
1649void ByteCodeGenerator::writeContinueStatement(const ContinueStatement& c) {
1650 // TODO: Include BranchIfAllFalse to top-most LoopNext
1651 this->write(ByteCodeInstruction::kLoopContinue);
1652}
1653
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001654void ByteCodeGenerator::writeDoStatement(const DoStatement& d) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001655 this->write(ByteCodeInstruction::kLoopBegin);
1656 size_t start = fCode->size();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001657 this->writeStatement(*d.fStatement);
Brian Osmanb08cc022020-04-02 11:38:40 -04001658 this->write(ByteCodeInstruction::kLoopNext);
1659 this->writeExpression(*d.fTest);
1660 this->write(ByteCodeInstruction::kLoopMask);
1661 // TODO: Could shorten this with kBranchIfAnyTrue
1662 this->write(ByteCodeInstruction::kBranchIfAllFalse);
Brian Osman569f12f2019-06-13 11:23:57 -04001663 DeferredLocation endLocation(this);
Brian Osmanb08cc022020-04-02 11:38:40 -04001664 this->write(ByteCodeInstruction::kBranch);
1665 this->write16(start);
Brian Osman569f12f2019-06-13 11:23:57 -04001666 endLocation.set();
Brian Osmanb08cc022020-04-02 11:38:40 -04001667 this->write(ByteCodeInstruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001668}
1669
1670void ByteCodeGenerator::writeForStatement(const ForStatement& f) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001671 fContinueTargets.emplace();
1672 fBreakTargets.emplace();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001673 if (f.fInitializer) {
1674 this->writeStatement(*f.fInitializer);
1675 }
Brian Osmanb08cc022020-04-02 11:38:40 -04001676 this->write(ByteCodeInstruction::kLoopBegin);
1677 size_t start = fCode->size();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001678 if (f.fTest) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001679 this->writeExpression(*f.fTest);
1680 this->write(ByteCodeInstruction::kLoopMask);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001681 }
Brian Osmanb08cc022020-04-02 11:38:40 -04001682 this->write(ByteCodeInstruction::kBranchIfAllFalse);
Brian Osman569f12f2019-06-13 11:23:57 -04001683 DeferredLocation endLocation(this);
1684 this->writeStatement(*f.fStatement);
Brian Osmanb08cc022020-04-02 11:38:40 -04001685 this->write(ByteCodeInstruction::kLoopNext);
Brian Osman569f12f2019-06-13 11:23:57 -04001686 if (f.fNext) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001687 this->writeExpression(*f.fNext, true);
Brian Osman569f12f2019-06-13 11:23:57 -04001688 }
Brian Osmanb08cc022020-04-02 11:38:40 -04001689 this->write(ByteCodeInstruction::kBranch);
1690 this->write16(start);
Brian Osman569f12f2019-06-13 11:23:57 -04001691 endLocation.set();
Brian Osmanb08cc022020-04-02 11:38:40 -04001692 this->write(ByteCodeInstruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001693}
1694
1695void ByteCodeGenerator::writeIfStatement(const IfStatement& i) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001696 this->writeExpression(*i.fTest);
1697 this->write(ByteCodeInstruction::kMaskPush);
1698 this->write(ByteCodeInstruction::kBranchIfAllFalse);
Brian Osman569f12f2019-06-13 11:23:57 -04001699 DeferredLocation falseLocation(this);
1700 this->writeStatement(*i.fIfTrue);
1701 falseLocation.set();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001702 if (i.fIfFalse) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001703 this->write(ByteCodeInstruction::kMaskNegate);
1704 this->write(ByteCodeInstruction::kBranchIfAllFalse);
Brian Osman569f12f2019-06-13 11:23:57 -04001705 DeferredLocation endLocation(this);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001706 this->writeStatement(*i.fIfFalse);
Mike Kleinb45ee832019-05-17 11:11:11 -05001707 endLocation.set();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001708 }
Brian Osmanb08cc022020-04-02 11:38:40 -04001709 this->write(ByteCodeInstruction::kMaskPop);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001710}
1711
Brian Osmanb08cc022020-04-02 11:38:40 -04001712void ByteCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
1713 if (fLoopCount || fConditionCount) {
Brian Osman4a47da72019-07-12 11:30:32 -04001714 fErrors.error(r.fOffset, "return not allowed inside conditional or loop");
1715 return;
1716 }
Brian Osmanb08cc022020-04-02 11:38:40 -04001717 int count = SlotCount(r.fExpression->fType);
1718 this->writeExpression(*r.fExpression);
1719
1720 // Technically, the kReturn also pops fOutput->fLocalCount values from the stack, too, but we
1721 // haven't counted pushing those (they're outside the scope of our stack tracking). Instead,
1722 // we account for those in writeFunction().
1723
1724 // This is all fine because we don't allow conditional returns, so we only return once anyway.
Brian Osman49b30f42020-06-26 17:22:27 -04001725 this->write(ByteCodeInstruction::kReturn, count);
Brian Osmanb08cc022020-04-02 11:38:40 -04001726}
1727
1728void ByteCodeGenerator::writeSwitchStatement(const SwitchStatement& r) {
1729 // not yet implemented
1730 abort();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001731}
1732
1733void ByteCodeGenerator::writeVarDeclarations(const VarDeclarations& v) {
1734 for (const auto& declStatement : v.fVars) {
1735 const VarDeclaration& decl = (VarDeclaration&) *declStatement;
Brian Osmanb08cc022020-04-02 11:38:40 -04001736 // we need to grab the location even if we don't use it, to ensure it has been allocated
1737 Location location = this->getLocation(*decl.fVar);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001738 if (decl.fValue) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001739 this->writeExpression(*decl.fValue);
1740 int count = SlotCount(decl.fValue->fType);
Brian Osman49b30f42020-06-26 17:22:27 -04001741 this->write(ByteCodeInstruction::kStore, count);
1742 this->write8(location.fSlot);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001743 }
1744 }
1745}
1746
1747void ByteCodeGenerator::writeWhileStatement(const WhileStatement& w) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001748 this->write(ByteCodeInstruction::kLoopBegin);
1749 size_t cond = fCode->size();
1750 this->writeExpression(*w.fTest);
1751 this->write(ByteCodeInstruction::kLoopMask);
1752 this->write(ByteCodeInstruction::kBranchIfAllFalse);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001753 DeferredLocation endLocation(this);
1754 this->writeStatement(*w.fStatement);
Brian Osmanb08cc022020-04-02 11:38:40 -04001755 this->write(ByteCodeInstruction::kLoopNext);
1756 this->write(ByteCodeInstruction::kBranch);
1757 this->write16(cond);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001758 endLocation.set();
Brian Osmanb08cc022020-04-02 11:38:40 -04001759 this->write(ByteCodeInstruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001760}
1761
1762void ByteCodeGenerator::writeStatement(const Statement& s) {
1763 switch (s.fKind) {
1764 case Statement::kBlock_Kind:
1765 this->writeBlock((Block&) s);
1766 break;
1767 case Statement::kBreak_Kind:
Brian Osmanb08cc022020-04-02 11:38:40 -04001768 this->writeBreakStatement((BreakStatement&) s);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001769 break;
1770 case Statement::kContinue_Kind:
Brian Osmanb08cc022020-04-02 11:38:40 -04001771 this->writeContinueStatement((ContinueStatement&) s);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001772 break;
Brian Osmanb08cc022020-04-02 11:38:40 -04001773 case Statement::kDiscard_Kind:
1774 // not yet implemented
1775 abort();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001776 case Statement::kDo_Kind:
1777 this->writeDoStatement((DoStatement&) s);
1778 break;
Brian Osman3e29f1d2019-05-28 09:35:05 -04001779 case Statement::kExpression_Kind:
Brian Osmanb08cc022020-04-02 11:38:40 -04001780 this->writeExpression(*((ExpressionStatement&) s).fExpression, true);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001781 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001782 case Statement::kFor_Kind:
1783 this->writeForStatement((ForStatement&) s);
1784 break;
1785 case Statement::kIf_Kind:
1786 this->writeIfStatement((IfStatement&) s);
1787 break;
1788 case Statement::kNop_Kind:
1789 break;
1790 case Statement::kReturn_Kind:
Brian Osmanb08cc022020-04-02 11:38:40 -04001791 this->writeReturnStatement((ReturnStatement&) s);
1792 break;
1793 case Statement::kSwitch_Kind:
1794 this->writeSwitchStatement((SwitchStatement&) s);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001795 break;
1796 case Statement::kVarDeclarations_Kind:
1797 this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration);
1798 break;
1799 case Statement::kWhile_Kind:
1800 this->writeWhileStatement((WhileStatement&) s);
1801 break;
1802 default:
Brian Osmanb08cc022020-04-02 11:38:40 -04001803 SkASSERT(false);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001804 }
1805}
1806
Brian Osmanb08cc022020-04-02 11:38:40 -04001807ByteCodeFunction::ByteCodeFunction(const FunctionDeclaration* declaration)
1808 : fName(declaration->fName) {
Brian Osman80164412019-06-07 13:00:23 -04001809 fParameterCount = 0;
Brian Osmanb08cc022020-04-02 11:38:40 -04001810 for (const auto& p : declaration->fParameters) {
1811 int slots = ByteCodeGenerator::SlotCount(p->fType);
1812 fParameters.push_back({ slots, (bool)(p->fModifiers.fFlags & Modifiers::kOut_Flag) });
1813 fParameterCount += slots;
Brian Osman80164412019-06-07 13:00:23 -04001814 }
1815}
1816
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001817}