blob: 6c8dab40f8b2978bf061a0be63d196e529ee6d34 [file] [log] [blame]
Brian Osmanb380e712019-07-24 17:02:39 -04001/*
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04002 * Copyright 2019 Google LLC
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "src/sksl/SkSLByteCodeGenerator.h"
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04009
Brian Osman95253bd2019-06-05 10:28:45 -040010#include <algorithm>
11
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040012namespace SkSL {
13
Ethan Nicholas82162ee2019-05-21 16:05:08 -040014ByteCodeGenerator::ByteCodeGenerator(const Context* context, const Program* program, ErrorReporter* errors,
15 ByteCode* output)
16 : INHERITED(program, errors, nullptr)
17 , fContext(*context)
Ethan Nicholasae9633b2019-05-24 12:46:34 -040018 , fOutput(output)
19 , fIntrinsics {
Brian Osman886af0d2019-07-26 15:12:56 -040020 { "cos", ByteCodeInstruction::kCos },
21 { "dot", SpecialIntrinsic::kDot },
22 { "inverse", ByteCodeInstruction::kInverse2x2 },
23 { "sin", ByteCodeInstruction::kSin },
24 { "sqrt", ByteCodeInstruction::kSqrt },
25 { "tan", ByteCodeInstruction::kTan },
Ethan Nicholasae9633b2019-05-24 12:46:34 -040026 } {}
27
Ethan Nicholas82162ee2019-05-21 16:05:08 -040028
Brian Osman07c117b2019-05-23 12:51:06 -070029int ByteCodeGenerator::SlotCount(const Type& type) {
Brian Osmanfba386b2019-06-20 14:54:15 -040030 if (type.kind() == Type::kOther_Kind) {
31 return 0;
32 } else if (type.kind() == Type::kStruct_Kind) {
Brian Osman07c117b2019-05-23 12:51:06 -070033 int slots = 0;
34 for (const auto& f : type.fields()) {
35 slots += SlotCount(*f.fType);
36 }
37 SkASSERT(slots <= 255);
38 return slots;
39 } else if (type.kind() == Type::kArray_Kind) {
40 int columns = type.columns();
41 SkASSERT(columns >= 0);
42 int slots = columns * SlotCount(type.componentType());
43 SkASSERT(slots <= 255);
44 return slots;
45 } else {
46 return type.columns() * type.rows();
47 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040048}
49
Brian Osman1c110a02019-10-01 14:53:32 -040050static inline bool is_uniform(const SkSL::Variable& var) {
51 return var.fModifiers.fFlags & Modifiers::kUniform_Flag;
52}
53
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040054bool ByteCodeGenerator::generateCode() {
55 for (const auto& e : fProgram) {
56 switch (e.fKind) {
57 case ProgramElement::kFunction_Kind: {
58 std::unique_ptr<ByteCodeFunction> f = this->writeFunction((FunctionDefinition&) e);
59 if (!f) {
60 return false;
61 }
62 fOutput->fFunctions.push_back(std::move(f));
Brian Osman80164412019-06-07 13:00:23 -040063 fFunctions.push_back(&(FunctionDefinition&)e);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040064 break;
65 }
66 case ProgramElement::kVar_Kind: {
67 VarDeclarations& decl = (VarDeclarations&) e;
68 for (const auto& v : decl.fVars) {
69 const Variable* declVar = ((VarDeclaration&) *v).fVar;
70 if (declVar->fModifiers.fLayout.fBuiltin >= 0) {
71 continue;
72 }
Ethan Nicholas31cff272019-09-26 13:04:48 -040073 // if you trip this assert, it means the program has raw 'in' variables. You
74 // should either specialize the program (Compiler::specialize) to bake in the
75 // final values of the 'in' variables, or not use 'in' variables (maybe you
76 // meant to use 'uniform' instead?).
77// SkASSERT(!(declVar->fModifiers.fFlags & Modifiers::kIn_Flag));
Brian Osman1c110a02019-10-01 14:53:32 -040078 if (is_uniform(*declVar)) {
79 fOutput->fUniformSlotCount += SlotCount(declVar->fType);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040080 } else {
Brian Osman1c110a02019-10-01 14:53:32 -040081 fOutput->fGlobalSlotCount += SlotCount(declVar->fType);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040082 }
83 }
84 break;
85 }
86 default:
87 ; // ignore
88 }
89 }
Brian Osman6f5358f2019-07-09 14:17:23 -040090 return 0 == fErrors.errorCount();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040091}
92
93std::unique_ptr<ByteCodeFunction> ByteCodeGenerator::writeFunction(const FunctionDefinition& f) {
94 fFunction = &f;
Brian Osman226668a2019-05-14 16:47:30 -040095 std::unique_ptr<ByteCodeFunction> result(new ByteCodeFunction(&f.fDeclaration));
Brian Osman80164412019-06-07 13:00:23 -040096 fParameterCount = result->fParameterCount;
Brian Osman4a47da72019-07-12 11:30:32 -040097 fLoopCount = fMaxLoopCount = 0;
98 fConditionCount = fMaxConditionCount = 0;
Brian Osmanaa2ca3f2019-07-15 13:24:48 -040099 fStackCount = fMaxStackCount = 0;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400100 fCode = &result->fCode;
Brian Osman4a47da72019-07-12 11:30:32 -0400101
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400102 this->writeStatement(*f.fBody);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400103 if (0 == fErrors.errorCount()) {
104 SkASSERT(fLoopCount == 0);
105 SkASSERT(fConditionCount == 0);
106 SkASSERT(fStackCount == 0);
107 }
108 this->write(ByteCodeInstruction::kReturn, 0);
Ethan Nicholas7e603db2019-05-03 12:57:47 -0400109 this->write8(0);
Brian Osman4a47da72019-07-12 11:30:32 -0400110
111 result->fLocalCount = fLocals.size();
112 result->fConditionCount = fMaxConditionCount;
113 result->fLoopCount = fMaxLoopCount;
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400114 result->fStackCount = fMaxStackCount;
Brian Osman4a47da72019-07-12 11:30:32 -0400115
Ethan Nicholasdfcad062019-05-07 12:53:34 -0400116 const Type& returnType = f.fDeclaration.fReturnType;
117 if (returnType != *fContext.fVoid_Type) {
Brian Osman07c117b2019-05-23 12:51:06 -0700118 result->fReturnCount = SlotCount(returnType);
Ethan Nicholasdfcad062019-05-07 12:53:34 -0400119 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400120 fLocals.clear();
121 fFunction = nullptr;
122 return result;
123}
124
125enum class TypeCategory {
126 kBool,
127 kSigned,
128 kUnsigned,
129 kFloat,
130};
131
132static TypeCategory type_category(const Type& type) {
133 switch (type.kind()) {
134 case Type::Kind::kVector_Kind:
135 case Type::Kind::kMatrix_Kind:
136 return type_category(type.componentType());
137 default:
138 if (type.fName == "bool") {
139 return TypeCategory::kBool;
140 } else if (type.fName == "int" || type.fName == "short") {
141 return TypeCategory::kSigned;
142 } else if (type.fName == "uint" || type.fName == "ushort") {
143 return TypeCategory::kUnsigned;
144 } else {
145 SkASSERT(type.fName == "float" || type.fName == "half");
146 return TypeCategory::kFloat;
147 }
148 ABORT("unsupported type: %s\n", type.description().c_str());
149 }
150}
151
Brian Osman0785db02019-05-24 14:19:11 -0400152// A "simple" Swizzle is based on a variable (or a compound variable like a struct or array), and
153// that references consecutive values, such that it can be implemented using normal load/store ops
154// with an offset. Note that all single-component swizzles (of suitable base types) are simple.
155static bool swizzle_is_simple(const Swizzle& s) {
156 switch (s.fBase->fKind) {
157 case Expression::kFieldAccess_Kind:
158 case Expression::kIndex_Kind:
159 case Expression::kVariableReference_Kind:
160 break;
161 default:
162 return false;
163 }
164
165 for (size_t i = 1; i < s.fComponents.size(); ++i) {
166 if (s.fComponents[i] != s.fComponents[i - 1] + 1) {
167 return false;
168 }
169 }
170 return true;
171}
172
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400173int ByteCodeGenerator::StackUsage(ByteCodeInstruction inst, int count_) {
174 // Ensures that we use count iff we're passed a non-default value. Most instructions have an
175 // implicit count, so the caller shouldn't need to worry about it (or count makes no sense).
176 // The asserts avoids callers thinking they're supplying useful information in that scenario,
177 // or failing to supply necessary information for the ops that need a count.
178 struct CountValue {
179 operator int() {
180 SkASSERT(val != ByteCodeGenerator::kUnusedStackCount);
181 SkDEBUGCODE(used = true);
182 return val;
183 }
184 ~CountValue() {
185 SkASSERT(used || val == ByteCodeGenerator::kUnusedStackCount);
186 }
187 int val;
188 SkDEBUGCODE(bool used = false;)
189 } count = { count_ };
190
191 switch (inst) {
192 // Unary functions/operators that don't change stack depth at all:
193#define VECTOR_UNARY_OP(base) \
194 case ByteCodeInstruction::base: \
195 case ByteCodeInstruction::base ## 2: \
196 case ByteCodeInstruction::base ## 3: \
197 case ByteCodeInstruction::base ## 4: \
198 return 0;
199
200 VECTOR_UNARY_OP(kConvertFtoI)
201 VECTOR_UNARY_OP(kConvertStoF)
202 VECTOR_UNARY_OP(kConvertUtoF)
203
204 VECTOR_UNARY_OP(kCos)
205 VECTOR_UNARY_OP(kSin)
206 VECTOR_UNARY_OP(kSqrt)
207 VECTOR_UNARY_OP(kTan)
208
209 VECTOR_UNARY_OP(kNegateF)
210 VECTOR_UNARY_OP(kNegateI)
211
Mike Reed634c9412019-07-18 13:20:04 -0400212 case ByteCodeInstruction::kInverse2x2:
213 case ByteCodeInstruction::kInverse3x3:
214 case ByteCodeInstruction::kInverse4x4: return 0;
215
Brian Osman869a3e82019-07-18 17:00:34 -0400216 case ByteCodeInstruction::kClampIndex: return 0;
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400217 case ByteCodeInstruction::kNotB: return 0;
218 case ByteCodeInstruction::kNegateFN: return 0;
Brian Osman4c2146f2019-09-24 09:39:38 -0400219 case ByteCodeInstruction::kShiftLeft: return 0;
220 case ByteCodeInstruction::kShiftRightS: return 0;
221 case ByteCodeInstruction::kShiftRightU: return 0;
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400222
223#undef VECTOR_UNARY_OP
224
225 // Binary functions/operators that do a 2 -> 1 reduction (possibly N times)
226#define VECTOR_BINARY_OP(base) \
227 case ByteCodeInstruction::base: return -1; \
228 case ByteCodeInstruction::base ## 2: return -2; \
229 case ByteCodeInstruction::base ## 3: return -3; \
230 case ByteCodeInstruction::base ## 4: return -4;
231
232#define VECTOR_MATRIX_BINARY_OP(base) \
233 VECTOR_BINARY_OP(base) \
234 case ByteCodeInstruction::base ## N: return -count;
235
236 case ByteCodeInstruction::kAndB: return -1;
237 case ByteCodeInstruction::kOrB: return -1;
238 case ByteCodeInstruction::kXorB: return -1;
239
240 VECTOR_BINARY_OP(kAddI)
241 VECTOR_MATRIX_BINARY_OP(kAddF)
242
243 VECTOR_BINARY_OP(kCompareIEQ)
244 VECTOR_MATRIX_BINARY_OP(kCompareFEQ)
245 VECTOR_BINARY_OP(kCompareINEQ)
246 VECTOR_MATRIX_BINARY_OP(kCompareFNEQ)
247 VECTOR_BINARY_OP(kCompareSGT)
248 VECTOR_BINARY_OP(kCompareUGT)
249 VECTOR_BINARY_OP(kCompareFGT)
250 VECTOR_BINARY_OP(kCompareSGTEQ)
251 VECTOR_BINARY_OP(kCompareUGTEQ)
252 VECTOR_BINARY_OP(kCompareFGTEQ)
253 VECTOR_BINARY_OP(kCompareSLT)
254 VECTOR_BINARY_OP(kCompareULT)
255 VECTOR_BINARY_OP(kCompareFLT)
256 VECTOR_BINARY_OP(kCompareSLTEQ)
257 VECTOR_BINARY_OP(kCompareULTEQ)
258 VECTOR_BINARY_OP(kCompareFLTEQ)
259
260 VECTOR_BINARY_OP(kDivideS)
261 VECTOR_BINARY_OP(kDivideU)
262 VECTOR_MATRIX_BINARY_OP(kDivideF)
263 VECTOR_BINARY_OP(kMultiplyI)
264 VECTOR_MATRIX_BINARY_OP(kMultiplyF)
265 VECTOR_BINARY_OP(kRemainderF)
266 VECTOR_BINARY_OP(kRemainderS)
267 VECTOR_BINARY_OP(kRemainderU)
268 VECTOR_BINARY_OP(kSubtractI)
269 VECTOR_MATRIX_BINARY_OP(kSubtractF)
270
271#undef VECTOR_BINARY_OP
272#undef VECTOR_MATRIX_BINARY_OP
273
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400274 // Ops that push or load data to grow the stack:
275 case ByteCodeInstruction::kDup:
276 case ByteCodeInstruction::kLoad:
277 case ByteCodeInstruction::kLoadGlobal:
Brian Osman1c110a02019-10-01 14:53:32 -0400278 case ByteCodeInstruction::kLoadUniform:
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400279 case ByteCodeInstruction::kReadExternal:
280 case ByteCodeInstruction::kPushImmediate:
281 return 1;
282
283 case ByteCodeInstruction::kDup2:
284 case ByteCodeInstruction::kLoad2:
285 case ByteCodeInstruction::kLoadGlobal2:
Brian Osman1c110a02019-10-01 14:53:32 -0400286 case ByteCodeInstruction::kLoadUniform2:
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400287 case ByteCodeInstruction::kReadExternal2:
288 return 2;
289
290 case ByteCodeInstruction::kDup3:
291 case ByteCodeInstruction::kLoad3:
292 case ByteCodeInstruction::kLoadGlobal3:
Brian Osman1c110a02019-10-01 14:53:32 -0400293 case ByteCodeInstruction::kLoadUniform3:
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400294 case ByteCodeInstruction::kReadExternal3:
295 return 3;
296
297 case ByteCodeInstruction::kDup4:
298 case ByteCodeInstruction::kLoad4:
299 case ByteCodeInstruction::kLoadGlobal4:
Brian Osman1c110a02019-10-01 14:53:32 -0400300 case ByteCodeInstruction::kLoadUniform4:
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400301 case ByteCodeInstruction::kReadExternal4:
302 return 4;
303
304 case ByteCodeInstruction::kDupN:
305 case ByteCodeInstruction::kLoadSwizzle:
306 case ByteCodeInstruction::kLoadSwizzleGlobal:
Brian Osman1c110a02019-10-01 14:53:32 -0400307 case ByteCodeInstruction::kLoadSwizzleUniform:
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400308 return count;
309
310 // Pushes 'count' values, minus one for the 'address' that's consumed first
311 case ByteCodeInstruction::kLoadExtended:
312 case ByteCodeInstruction::kLoadExtendedGlobal:
Brian Osman1c110a02019-10-01 14:53:32 -0400313 case ByteCodeInstruction::kLoadExtendedUniform:
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400314 return count - 1;
315
316 // Ops that pop or store data to shrink the stack:
317 case ByteCodeInstruction::kPop:
318 case ByteCodeInstruction::kStore:
319 case ByteCodeInstruction::kStoreGlobal:
320 case ByteCodeInstruction::kWriteExternal:
321 return -1;
322
323 case ByteCodeInstruction::kPop2:
324 case ByteCodeInstruction::kStore2:
325 case ByteCodeInstruction::kStoreGlobal2:
326 case ByteCodeInstruction::kWriteExternal2:
327 return -2;
328
329 case ByteCodeInstruction::kPop3:
330 case ByteCodeInstruction::kStore3:
331 case ByteCodeInstruction::kStoreGlobal3:
332 case ByteCodeInstruction::kWriteExternal3:
333 return -3;
334
335 case ByteCodeInstruction::kPop4:
336 case ByteCodeInstruction::kStore4:
337 case ByteCodeInstruction::kStoreGlobal4:
338 case ByteCodeInstruction::kWriteExternal4:
339 return -4;
340
341 case ByteCodeInstruction::kPopN:
342 case ByteCodeInstruction::kStoreSwizzle:
343 case ByteCodeInstruction::kStoreSwizzleGlobal:
344 return -count;
345
346 // Consumes 'count' values, plus one for the 'address'
347 case ByteCodeInstruction::kStoreExtended:
348 case ByteCodeInstruction::kStoreExtendedGlobal:
349 case ByteCodeInstruction::kStoreSwizzleIndirect:
350 case ByteCodeInstruction::kStoreSwizzleIndirectGlobal:
351 return -count - 1;
352
353 // Strange ops where the caller computes the delta for us:
354 case ByteCodeInstruction::kCallExternal:
355 case ByteCodeInstruction::kMatrixToMatrix:
356 case ByteCodeInstruction::kMatrixMultiply:
357 case ByteCodeInstruction::kReserve:
358 case ByteCodeInstruction::kReturn:
359 case ByteCodeInstruction::kScalarToMatrix:
360 case ByteCodeInstruction::kSwizzle:
361 return count;
362
363 // Miscellaneous
364
365 // kCall is net-zero. Max stack depth is adjusted in writeFunctionCall.
366 case ByteCodeInstruction::kCall: return 0;
367 case ByteCodeInstruction::kBranch: return 0;
368 case ByteCodeInstruction::kBranchIfAllFalse: return 0;
369
370 case ByteCodeInstruction::kMaskPush: return -1;
371 case ByteCodeInstruction::kMaskPop: return 0;
372 case ByteCodeInstruction::kMaskNegate: return 0;
373 case ByteCodeInstruction::kMaskBlend: return -count;
374
375 case ByteCodeInstruction::kLoopBegin: return 0;
376 case ByteCodeInstruction::kLoopNext: return 0;
377 case ByteCodeInstruction::kLoopMask: return -1;
378 case ByteCodeInstruction::kLoopEnd: return 0;
379 case ByteCodeInstruction::kLoopBreak: return 0;
380 case ByteCodeInstruction::kLoopContinue: return 0;
381
382 default:
Brian Osmanc7ec9e22019-07-16 08:49:11 -0400383 ABORT("unsupported instruction %d\n", (int)inst);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400384 return 0;
385 }
386}
387
Brian Osman1c110a02019-10-01 14:53:32 -0400388ByteCodeGenerator::Location ByteCodeGenerator::getLocation(const Variable& var) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400389 // given that we seldom have more than a couple of variables, linear search is probably the most
390 // efficient way to handle lookups
391 switch (var.fStorage) {
392 case Variable::kLocal_Storage: {
393 for (int i = fLocals.size() - 1; i >= 0; --i) {
394 if (fLocals[i] == &var) {
Brian Osman1091f022019-05-16 09:42:16 -0400395 SkASSERT(fParameterCount + i <= 255);
Brian Osman1c110a02019-10-01 14:53:32 -0400396 return { fParameterCount + i, Storage::kLocal };
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400397 }
398 }
399 int result = fParameterCount + fLocals.size();
400 fLocals.push_back(&var);
Brian Osman07c117b2019-05-23 12:51:06 -0700401 for (int i = 0; i < SlotCount(var.fType) - 1; ++i) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400402 fLocals.push_back(nullptr);
403 }
Brian Osman1091f022019-05-16 09:42:16 -0400404 SkASSERT(result <= 255);
Brian Osman1c110a02019-10-01 14:53:32 -0400405 return { result, Storage::kLocal };
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400406 }
407 case Variable::kParameter_Storage: {
408 int offset = 0;
409 for (const auto& p : fFunction->fDeclaration.fParameters) {
410 if (p == &var) {
Brian Osman1091f022019-05-16 09:42:16 -0400411 SkASSERT(offset <= 255);
Brian Osman1c110a02019-10-01 14:53:32 -0400412 return { offset, Storage::kLocal };
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400413 }
Brian Osman07c117b2019-05-23 12:51:06 -0700414 offset += SlotCount(p->fType);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400415 }
416 SkASSERT(false);
Brian Osman1c110a02019-10-01 14:53:32 -0400417 return Location::MakeInvalid();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400418 }
419 case Variable::kGlobal_Storage: {
420 int offset = 0;
Brian Osman1c110a02019-10-01 14:53:32 -0400421 bool isUniform = is_uniform(var);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400422 for (const auto& e : fProgram) {
423 if (e.fKind == ProgramElement::kVar_Kind) {
424 VarDeclarations& decl = (VarDeclarations&) e;
425 for (const auto& v : decl.fVars) {
426 const Variable* declVar = ((VarDeclaration&) *v).fVar;
427 if (declVar->fModifiers.fLayout.fBuiltin >= 0) {
428 continue;
429 }
Brian Osman1c110a02019-10-01 14:53:32 -0400430 if (isUniform != is_uniform(*declVar)) {
431 continue;
432 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400433 if (declVar == &var) {
Brian Osmanb7451292019-05-15 13:02:13 -0400434 SkASSERT(offset <= 255);
Brian Osman1c110a02019-10-01 14:53:32 -0400435 return { offset, isUniform ? Storage::kUniform : Storage::kGlobal };
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400436 }
Brian Osman07c117b2019-05-23 12:51:06 -0700437 offset += SlotCount(declVar->fType);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400438 }
439 }
440 }
441 SkASSERT(false);
Brian Osman1c110a02019-10-01 14:53:32 -0400442 return Location::MakeInvalid();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400443 }
444 default:
445 SkASSERT(false);
Brian Osman1c110a02019-10-01 14:53:32 -0400446 return Location::MakeInvalid();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400447 }
448}
449
Brian Osman1c110a02019-10-01 14:53:32 -0400450ByteCodeGenerator::Location ByteCodeGenerator::getLocation(const Expression& expr) {
Brian Osman07c117b2019-05-23 12:51:06 -0700451 switch (expr.fKind) {
452 case Expression::kFieldAccess_Kind: {
453 const FieldAccess& f = (const FieldAccess&)expr;
Brian Osman1c110a02019-10-01 14:53:32 -0400454 Location baseLoc = this->getLocation(*f.fBase);
Brian Osman07c117b2019-05-23 12:51:06 -0700455 int offset = 0;
456 for (int i = 0; i < f.fFieldIndex; ++i) {
457 offset += SlotCount(*f.fBase->fType.fields()[i].fType);
458 }
Brian Osman1c110a02019-10-01 14:53:32 -0400459 if (baseLoc.isOnStack()) {
Brian Osman86769292019-06-21 11:05:47 -0400460 if (offset != 0) {
461 this->write(ByteCodeInstruction::kPushImmediate);
462 this->write32(offset);
463 this->write(ByteCodeInstruction::kAddI);
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400464 this->write8(1);
Brian Osman86769292019-06-21 11:05:47 -0400465 }
Brian Osman1c110a02019-10-01 14:53:32 -0400466 return baseLoc;
Brian Osman07c117b2019-05-23 12:51:06 -0700467 } else {
Brian Osman1c110a02019-10-01 14:53:32 -0400468 return baseLoc + offset;
Brian Osman07c117b2019-05-23 12:51:06 -0700469 }
470 }
471 case Expression::kIndex_Kind: {
472 const IndexExpression& i = (const IndexExpression&)expr;
473 int stride = SlotCount(i.fType);
Brian Osman869a3e82019-07-18 17:00:34 -0400474 int length = i.fBase->fType.columns();
475 SkASSERT(length <= 255);
Brian Osman07c117b2019-05-23 12:51:06 -0700476 int offset = -1;
477 if (i.fIndex->isConstant()) {
Brian Osman869a3e82019-07-18 17:00:34 -0400478 int64_t index = i.fIndex->getConstantInt();
479 if (index < 0 || index >= length) {
480 fErrors.error(i.fIndex->fOffset, "Array index out of bounds.");
Brian Osman1c110a02019-10-01 14:53:32 -0400481 return Location::MakeInvalid();
Brian Osman869a3e82019-07-18 17:00:34 -0400482 }
483 offset = index * stride;
Brian Osman07c117b2019-05-23 12:51:06 -0700484 } else {
Brian Osman86769292019-06-21 11:05:47 -0400485 if (i.fIndex->hasSideEffects()) {
486 // Having a side-effect in an indexer is technically safe for an rvalue,
487 // but with lvalues we have to evaluate the indexer twice, so make it an error.
488 fErrors.error(i.fIndex->fOffset,
489 "Index expressions with side-effects not supported in byte code.");
Brian Osman1c110a02019-10-01 14:53:32 -0400490 return Location::MakeInvalid();
Brian Osman86769292019-06-21 11:05:47 -0400491 }
Brian Osman07c117b2019-05-23 12:51:06 -0700492 this->writeExpression(*i.fIndex);
Brian Osman869a3e82019-07-18 17:00:34 -0400493 this->write(ByteCodeInstruction::kClampIndex);
494 this->write8(length);
Brian Osman86769292019-06-21 11:05:47 -0400495 if (stride != 1) {
496 this->write(ByteCodeInstruction::kPushImmediate);
497 this->write32(stride);
498 this->write(ByteCodeInstruction::kMultiplyI);
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400499 this->write8(1);
Brian Osman86769292019-06-21 11:05:47 -0400500 }
Brian Osman07c117b2019-05-23 12:51:06 -0700501 }
Brian Osman1c110a02019-10-01 14:53:32 -0400502 Location baseLoc = this->getLocation(*i.fBase);
Brian Osman86769292019-06-21 11:05:47 -0400503
504 // Are both components known statically?
Brian Osman1c110a02019-10-01 14:53:32 -0400505 if (!baseLoc.isOnStack() && offset >= 0) {
506 return baseLoc + offset;
Brian Osman07c117b2019-05-23 12:51:06 -0700507 }
Brian Osman86769292019-06-21 11:05:47 -0400508
509 // At least one component is dynamic (and on the stack).
510
511 // If the other component is zero, we're done
Brian Osman1c110a02019-10-01 14:53:32 -0400512 if (baseLoc.fSlot == 0 || offset == 0) {
513 return baseLoc.makeOnStack();
Brian Osman86769292019-06-21 11:05:47 -0400514 }
515
516 // Push the non-dynamic component (if any) to the stack, then add the two
Brian Osman1c110a02019-10-01 14:53:32 -0400517 if (!baseLoc.isOnStack()) {
Brian Osman07c117b2019-05-23 12:51:06 -0700518 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osman1c110a02019-10-01 14:53:32 -0400519 this->write32(baseLoc.fSlot);
Brian Osman07c117b2019-05-23 12:51:06 -0700520 }
521 if (offset >= 0) {
522 this->write(ByteCodeInstruction::kPushImmediate);
523 this->write32(offset);
524 }
525 this->write(ByteCodeInstruction::kAddI);
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400526 this->write8(1);
Brian Osman1c110a02019-10-01 14:53:32 -0400527 return baseLoc.makeOnStack();
Brian Osman07c117b2019-05-23 12:51:06 -0700528 }
Brian Osman0785db02019-05-24 14:19:11 -0400529 case Expression::kSwizzle_Kind: {
530 const Swizzle& s = (const Swizzle&)expr;
531 SkASSERT(swizzle_is_simple(s));
Brian Osman1c110a02019-10-01 14:53:32 -0400532 Location baseLoc = this->getLocation(*s.fBase);
Brian Osman0785db02019-05-24 14:19:11 -0400533 int offset = s.fComponents[0];
Brian Osman1c110a02019-10-01 14:53:32 -0400534 if (baseLoc.isOnStack()) {
Brian Osman86769292019-06-21 11:05:47 -0400535 if (offset != 0) {
536 this->write(ByteCodeInstruction::kPushImmediate);
537 this->write32(offset);
538 this->write(ByteCodeInstruction::kAddI);
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400539 this->write8(1);
Brian Osman86769292019-06-21 11:05:47 -0400540 }
Brian Osman1c110a02019-10-01 14:53:32 -0400541 return baseLoc;
Brian Osman0785db02019-05-24 14:19:11 -0400542 } else {
Brian Osman1c110a02019-10-01 14:53:32 -0400543 return baseLoc + offset;
Brian Osman0785db02019-05-24 14:19:11 -0400544 }
545 }
Brian Osman07c117b2019-05-23 12:51:06 -0700546 case Expression::kVariableReference_Kind: {
547 const Variable& var = ((const VariableReference&)expr).fVariable;
Brian Osman07c117b2019-05-23 12:51:06 -0700548 return this->getLocation(var);
549 }
550 default:
551 SkASSERT(false);
Brian Osman1c110a02019-10-01 14:53:32 -0400552 return Location::MakeInvalid();
Brian Osman07c117b2019-05-23 12:51:06 -0700553 }
554}
555
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400556void ByteCodeGenerator::write8(uint8_t b) {
557 fCode->push_back(b);
558}
559
560void ByteCodeGenerator::write16(uint16_t i) {
Mike Klein76346ac2019-05-17 11:57:10 -0500561 size_t n = fCode->size();
562 fCode->resize(n+2);
563 memcpy(fCode->data() + n, &i, 2);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400564}
565
566void ByteCodeGenerator::write32(uint32_t i) {
Mike Klein76346ac2019-05-17 11:57:10 -0500567 size_t n = fCode->size();
568 fCode->resize(n+4);
569 memcpy(fCode->data() + n, &i, 4);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400570}
571
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400572void ByteCodeGenerator::write(ByteCodeInstruction i, int count) {
Brian Osman4a47da72019-07-12 11:30:32 -0400573 switch (i) {
574 case ByteCodeInstruction::kLoopBegin: this->enterLoop(); break;
575 case ByteCodeInstruction::kLoopEnd: this->exitLoop(); break;
576
577 case ByteCodeInstruction::kMaskPush: this->enterCondition(); break;
578 case ByteCodeInstruction::kMaskPop:
579 case ByteCodeInstruction::kMaskBlend: this->exitCondition(); break;
580 default: /* Do nothing */ break;
581 }
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400582 instruction val = (instruction) i;
583 size_t n = fCode->size();
584 fCode->resize(n + sizeof(val));
585 memcpy(fCode->data() + n, &val, sizeof(val));
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400586 fStackCount += StackUsage(i, count);
587 fMaxStackCount = std::max(fMaxStackCount, fStackCount);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400588}
589
Mike Klein76346ac2019-05-17 11:57:10 -0500590static ByteCodeInstruction vector_instruction(ByteCodeInstruction base, int count) {
Brian Osman07c117b2019-05-23 12:51:06 -0700591 SkASSERT(count >= 1 && count <= 4);
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400592 return ((ByteCodeInstruction) ((int) base + 1 - count));
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400593}
594
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400595void ByteCodeGenerator::writeTypedInstruction(const Type& type, ByteCodeInstruction s,
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400596 ByteCodeInstruction u, ByteCodeInstruction f,
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400597 int count, bool writeCount) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400598 switch (type_category(type)) {
599 case TypeCategory::kSigned:
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400600 this->write(vector_instruction(s, count));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400601 break;
602 case TypeCategory::kUnsigned:
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400603 this->write(vector_instruction(u, count));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400604 break;
Brian Osman1e855b22019-05-29 15:21:52 -0400605 case TypeCategory::kFloat: {
606 if (count > 4) {
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400607 this->write((ByteCodeInstruction)((int)f + 1), count);
Brian Osman1e855b22019-05-29 15:21:52 -0400608 } else {
609 this->write(vector_instruction(f, count));
610 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400611 break;
Brian Osman1e855b22019-05-29 15:21:52 -0400612 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400613 default:
614 SkASSERT(false);
615 }
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400616 if (writeCount) {
617 this->write8(count);
618 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400619}
620
Brian Osman3e29f1d2019-05-28 09:35:05 -0400621bool ByteCodeGenerator::writeBinaryExpression(const BinaryExpression& b, bool discard) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400622 if (b.fOperator == Token::Kind::EQ) {
623 std::unique_ptr<LValue> lvalue = this->getLValue(*b.fLeft);
624 this->writeExpression(*b.fRight);
Brian Osman3e29f1d2019-05-28 09:35:05 -0400625 lvalue->store(discard);
626 discard = false;
627 return discard;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400628 }
Brian Osman16e6fd52019-05-29 11:19:00 -0400629 const Type& lType = b.fLeft->fType;
630 const Type& rType = b.fRight->fType;
Brian Osman909231c2019-05-29 15:34:36 -0400631 bool lVecOrMtx = (lType.kind() == Type::kVector_Kind || lType.kind() == Type::kMatrix_Kind);
632 bool rVecOrMtx = (rType.kind() == Type::kVector_Kind || rType.kind() == Type::kMatrix_Kind);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400633 Token::Kind op;
634 std::unique_ptr<LValue> lvalue;
635 if (is_assignment(b.fOperator)) {
636 lvalue = this->getLValue(*b.fLeft);
637 lvalue->load();
638 op = remove_assignment(b.fOperator);
639 } else {
640 this->writeExpression(*b.fLeft);
641 op = b.fOperator;
Brian Osman909231c2019-05-29 15:34:36 -0400642 if (!lVecOrMtx && rVecOrMtx) {
Brian Osman16e6fd52019-05-29 11:19:00 -0400643 for (int i = SlotCount(rType); i > 1; --i) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400644 this->write(ByteCodeInstruction::kDup);
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400645 this->write8(1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400646 }
647 }
648 }
Ethan Nicholasd166d2e2019-09-23 11:43:45 -0400649 int count = std::max(SlotCount(lType), SlotCount(rType));
Brian Osmane5bbce22019-09-23 12:38:40 -0400650 SkDEBUGCODE(TypeCategory tc = type_category(lType));
Ethan Nicholasd166d2e2019-09-23 11:43:45 -0400651 switch (op) {
652 case Token::Kind::LOGICALAND: {
Brian Osmane5bbce22019-09-23 12:38:40 -0400653 SkASSERT(tc == SkSL::TypeCategory::kBool && count == 1);
Ethan Nicholasd166d2e2019-09-23 11:43:45 -0400654 this->write(ByteCodeInstruction::kDup);
655 this->write8(1);
656 this->write(ByteCodeInstruction::kMaskPush);
657 this->write(ByteCodeInstruction::kBranchIfAllFalse);
658 DeferredLocation falseLocation(this);
659 this->writeExpression(*b.fRight);
660 this->write(ByteCodeInstruction::kAndB);
661 falseLocation.set();
662 this->write(ByteCodeInstruction::kMaskPop);
663 return false;
664 }
665 case Token::Kind::LOGICALOR: {
Brian Osmane5bbce22019-09-23 12:38:40 -0400666 SkASSERT(tc == SkSL::TypeCategory::kBool && count == 1);
Ethan Nicholasd166d2e2019-09-23 11:43:45 -0400667 this->write(ByteCodeInstruction::kDup);
668 this->write8(1);
669 this->write(ByteCodeInstruction::kNotB);
670 this->write(ByteCodeInstruction::kMaskPush);
671 this->write(ByteCodeInstruction::kBranchIfAllFalse);
672 DeferredLocation falseLocation(this);
673 this->writeExpression(*b.fRight);
674 this->write(ByteCodeInstruction::kOrB);
675 falseLocation.set();
676 this->write(ByteCodeInstruction::kMaskPop);
677 return false;
678 }
Brian Osman4c2146f2019-09-24 09:39:38 -0400679 case Token::Kind::SHL:
680 case Token::Kind::SHR: {
681 SkASSERT(count == 1 && (tc == SkSL::TypeCategory::kSigned ||
682 tc == SkSL::TypeCategory::kUnsigned));
683 if (!b.fRight->isConstant()) {
684 fErrors.error(b.fRight->fOffset, "Shift amounts must be constant");
685 return false;
686 }
687 int64_t shift = b.fRight->getConstantInt();
688 if (shift < 0 || shift > 31) {
689 fErrors.error(b.fRight->fOffset, "Shift amount out of range");
690 return false;
691 }
692
693 if (op == Token::Kind::SHL) {
694 this->write(ByteCodeInstruction::kShiftLeft);
695 } else {
696 this->write(type_category(lType) == TypeCategory::kSigned
697 ? ByteCodeInstruction::kShiftRightS
698 : ByteCodeInstruction::kShiftRightU);
699 }
700 this->write8(shift);
701 return false;
702 }
703
Ethan Nicholasd166d2e2019-09-23 11:43:45 -0400704 default:
705 break;
706 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400707 this->writeExpression(*b.fRight);
Brian Osman909231c2019-05-29 15:34:36 -0400708 if (lVecOrMtx && !rVecOrMtx) {
Brian Osman16e6fd52019-05-29 11:19:00 -0400709 for (int i = SlotCount(lType); i > 1; --i) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400710 this->write(ByteCodeInstruction::kDup);
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400711 this->write8(1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400712 }
713 }
Brian Osman909231c2019-05-29 15:34:36 -0400714 // Special case for M*V, V*M, M*M (but not V*V!)
715 if (op == Token::Kind::STAR && lVecOrMtx && rVecOrMtx &&
716 !(lType.kind() == Type::kVector_Kind && rType.kind() == Type::kVector_Kind)) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400717 this->write(ByteCodeInstruction::kMatrixMultiply,
718 SlotCount(b.fType) - (SlotCount(lType) + SlotCount(rType)));
Brian Osman909231c2019-05-29 15:34:36 -0400719 int rCols = rType.columns(),
720 rRows = rType.rows(),
721 lCols = lType.columns(),
722 lRows = lType.rows();
723 // M*V treats the vector as a column
724 if (rType.kind() == Type::kVector_Kind) {
725 std::swap(rCols, rRows);
726 }
727 SkASSERT(lCols == rRows);
728 SkASSERT(SlotCount(b.fType) == lRows * rCols);
729 this->write8(lCols);
730 this->write8(lRows);
731 this->write8(rCols);
732 } else {
Brian Osman909231c2019-05-29 15:34:36 -0400733 switch (op) {
734 case Token::Kind::EQEQ:
735 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareIEQ,
736 ByteCodeInstruction::kCompareIEQ,
737 ByteCodeInstruction::kCompareFEQ,
738 count);
739 // Collapse to a single bool
740 for (int i = count; i > 1; --i) {
741 this->write(ByteCodeInstruction::kAndB);
742 }
743 break;
744 case Token::Kind::GT:
745 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSGT,
746 ByteCodeInstruction::kCompareUGT,
747 ByteCodeInstruction::kCompareFGT,
748 count);
749 break;
750 case Token::Kind::GTEQ:
751 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSGTEQ,
752 ByteCodeInstruction::kCompareUGTEQ,
753 ByteCodeInstruction::kCompareFGTEQ,
754 count);
755 break;
756 case Token::Kind::LT:
757 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSLT,
758 ByteCodeInstruction::kCompareULT,
759 ByteCodeInstruction::kCompareFLT,
760 count);
761 break;
762 case Token::Kind::LTEQ:
763 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSLTEQ,
764 ByteCodeInstruction::kCompareULTEQ,
765 ByteCodeInstruction::kCompareFLTEQ,
766 count);
767 break;
768 case Token::Kind::MINUS:
769 this->writeTypedInstruction(lType, ByteCodeInstruction::kSubtractI,
770 ByteCodeInstruction::kSubtractI,
771 ByteCodeInstruction::kSubtractF,
772 count);
773 break;
774 case Token::Kind::NEQ:
775 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareINEQ,
776 ByteCodeInstruction::kCompareINEQ,
777 ByteCodeInstruction::kCompareFNEQ,
778 count);
779 // Collapse to a single bool
780 for (int i = count; i > 1; --i) {
781 this->write(ByteCodeInstruction::kOrB);
782 }
783 break;
784 case Token::Kind::PERCENT:
785 this->writeTypedInstruction(lType, ByteCodeInstruction::kRemainderS,
786 ByteCodeInstruction::kRemainderU,
787 ByteCodeInstruction::kRemainderF,
788 count);
789 break;
790 case Token::Kind::PLUS:
791 this->writeTypedInstruction(lType, ByteCodeInstruction::kAddI,
792 ByteCodeInstruction::kAddI,
793 ByteCodeInstruction::kAddF,
794 count);
795 break;
796 case Token::Kind::SLASH:
797 this->writeTypedInstruction(lType, ByteCodeInstruction::kDivideS,
798 ByteCodeInstruction::kDivideU,
799 ByteCodeInstruction::kDivideF,
800 count);
801 break;
802 case Token::Kind::STAR:
803 this->writeTypedInstruction(lType, ByteCodeInstruction::kMultiplyI,
804 ByteCodeInstruction::kMultiplyI,
805 ByteCodeInstruction::kMultiplyF,
806 count);
807 break;
Brian Osman569f12f2019-06-13 11:23:57 -0400808
Brian Osman569f12f2019-06-13 11:23:57 -0400809 case Token::Kind::LOGICALXOR:
Brian Osmane5bbce22019-09-23 12:38:40 -0400810 SkASSERT(tc == SkSL::TypeCategory::kBool && count == 1);
811 this->write(ByteCodeInstruction::kXorB);
812 break;
813
814 case Token::Kind::BITWISEAND:
815 SkASSERT(count == 1 && (tc == SkSL::TypeCategory::kSigned ||
816 tc == SkSL::TypeCategory::kUnsigned));
817 this->write(ByteCodeInstruction::kAndB);
818 break;
819 case Token::Kind::BITWISEOR:
820 SkASSERT(count == 1 && (tc == SkSL::TypeCategory::kSigned ||
821 tc == SkSL::TypeCategory::kUnsigned));
822 this->write(ByteCodeInstruction::kOrB);
823 break;
824 case Token::Kind::BITWISEXOR:
825 SkASSERT(count == 1 && (tc == SkSL::TypeCategory::kSigned ||
826 tc == SkSL::TypeCategory::kUnsigned));
Brian Osman569f12f2019-06-13 11:23:57 -0400827 this->write(ByteCodeInstruction::kXorB);
828 break;
829
Brian Osman909231c2019-05-29 15:34:36 -0400830 default:
Brian Osmandb3dad22019-07-26 15:44:29 -0400831 fErrors.error(b.fOffset, SkSL::String::printf("Unsupported binary operator '%s'",
832 Compiler::OperatorName(op)));
833 break;
Brian Osman909231c2019-05-29 15:34:36 -0400834 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400835 }
836 if (lvalue) {
Brian Osman3e29f1d2019-05-28 09:35:05 -0400837 lvalue->store(discard);
838 discard = false;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400839 }
Brian Osman3e29f1d2019-05-28 09:35:05 -0400840 return discard;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400841}
842
843void ByteCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
844 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osman569f12f2019-06-13 11:23:57 -0400845 this->write32(b.fValue ? ~0 : 0);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400846}
847
848void ByteCodeGenerator::writeConstructor(const Constructor& c) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400849 for (const auto& arg : c.fArguments) {
850 this->writeExpression(*arg);
851 }
852 if (c.fArguments.size() == 1) {
Brian Osman29e013d2019-05-28 17:16:03 -0400853 const Type& inType = c.fArguments[0]->fType;
854 const Type& outType = c.fType;
855 TypeCategory inCategory = type_category(inType);
856 TypeCategory outCategory = type_category(outType);
857 int inCount = SlotCount(inType);
858 int outCount = SlotCount(outType);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400859 if (inCategory != outCategory) {
Brian Osmanc51d7912019-05-22 15:16:16 -0700860 SkASSERT(inCount == outCount);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400861 if (inCategory == TypeCategory::kFloat) {
862 SkASSERT(outCategory == TypeCategory::kSigned ||
863 outCategory == TypeCategory::kUnsigned);
Brian Osmanc51d7912019-05-22 15:16:16 -0700864 this->write(vector_instruction(ByteCodeInstruction::kConvertFtoI, outCount));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400865 } else if (outCategory == TypeCategory::kFloat) {
866 if (inCategory == TypeCategory::kSigned) {
Brian Osmanc51d7912019-05-22 15:16:16 -0700867 this->write(vector_instruction(ByteCodeInstruction::kConvertStoF, outCount));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400868 } else {
869 SkASSERT(inCategory == TypeCategory::kUnsigned);
Brian Osmanc51d7912019-05-22 15:16:16 -0700870 this->write(vector_instruction(ByteCodeInstruction::kConvertUtoF, outCount));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400871 }
872 } else {
873 SkASSERT(false);
874 }
875 }
Brian Osman29e013d2019-05-28 17:16:03 -0400876 if (inType.kind() == Type::kMatrix_Kind && outType.kind() == Type::kMatrix_Kind) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400877 this->write(ByteCodeInstruction::kMatrixToMatrix,
878 SlotCount(outType) - SlotCount(inType));
Brian Osman29e013d2019-05-28 17:16:03 -0400879 this->write8(inType.columns());
880 this->write8(inType.rows());
881 this->write8(outType.columns());
882 this->write8(outType.rows());
883 } else if (inCount != outCount) {
Brian Osmanc51d7912019-05-22 15:16:16 -0700884 SkASSERT(inCount == 1);
Brian Osman29e013d2019-05-28 17:16:03 -0400885 if (outType.kind() == Type::kMatrix_Kind) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400886 this->write(ByteCodeInstruction::kScalarToMatrix, SlotCount(outType) - 1);
Brian Osman29e013d2019-05-28 17:16:03 -0400887 this->write8(outType.columns());
888 this->write8(outType.rows());
889 } else {
890 SkASSERT(outType.kind() == Type::kVector_Kind);
891 for (; inCount != outCount; ++inCount) {
892 this->write(ByteCodeInstruction::kDup);
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400893 this->write8(1);
Brian Osman29e013d2019-05-28 17:16:03 -0400894 }
Brian Osmanc51d7912019-05-22 15:16:16 -0700895 }
896 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400897 }
898}
899
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400900void ByteCodeGenerator::writeExternalFunctionCall(const ExternalFunctionCall& f) {
901 int argumentCount = 0;
902 for (const auto& arg : f.fArguments) {
903 this->writeExpression(*arg);
Brian Osman07c117b2019-05-23 12:51:06 -0700904 argumentCount += SlotCount(arg->fType);
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400905 }
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400906 this->write(ByteCodeInstruction::kCallExternal, SlotCount(f.fType) - argumentCount);
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400907 SkASSERT(argumentCount <= 255);
908 this->write8(argumentCount);
Brian Osman07c117b2019-05-23 12:51:06 -0700909 this->write8(SlotCount(f.fType));
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400910 int index = fOutput->fExternalValues.size();
911 fOutput->fExternalValues.push_back(f.fFunction);
912 SkASSERT(index <= 255);
913 this->write8(index);
914}
915
Ethan Nicholas91164d12019-05-15 15:29:54 -0400916void ByteCodeGenerator::writeExternalValue(const ExternalValueReference& e) {
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400917 int count = SlotCount(e.fValue->type());
918 this->write(vector_instruction(ByteCodeInstruction::kReadExternal, count));
919 this->write8(count);
Ethan Nicholas91164d12019-05-15 15:29:54 -0400920 int index = fOutput->fExternalValues.size();
921 fOutput->fExternalValues.push_back(e.fValue);
922 SkASSERT(index <= 255);
923 this->write8(index);
924}
925
Brian Osman07c117b2019-05-23 12:51:06 -0700926void ByteCodeGenerator::writeVariableExpression(const Expression& expr) {
Brian Osman1c110a02019-10-01 14:53:32 -0400927 Location location = this->getLocation(expr);
Brian Osman07c117b2019-05-23 12:51:06 -0700928 int count = SlotCount(expr.fType);
Brian Osman1c110a02019-10-01 14:53:32 -0400929 if (location.isOnStack() || count > 4) {
930 if (!location.isOnStack()) {
Brian Osman07c117b2019-05-23 12:51:06 -0700931 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osman1c110a02019-10-01 14:53:32 -0400932 this->write32(location.fSlot);
Brian Osman07c117b2019-05-23 12:51:06 -0700933 }
Brian Osman1c110a02019-10-01 14:53:32 -0400934 this->write(location.selectLoad(ByteCodeInstruction::kLoadExtended,
935 ByteCodeInstruction::kLoadExtendedGlobal,
936 ByteCodeInstruction::kLoadExtendedUniform),
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400937 count);
Brian Osman07c117b2019-05-23 12:51:06 -0700938 this->write8(count);
939 } else {
Brian Osman1c110a02019-10-01 14:53:32 -0400940 this->write(vector_instruction(location.selectLoad(ByteCodeInstruction::kLoad,
941 ByteCodeInstruction::kLoadGlobal,
942 ByteCodeInstruction::kLoadUniform),
Brian Osman07c117b2019-05-23 12:51:06 -0700943 count));
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400944 this->write8(count);
Brian Osman1c110a02019-10-01 14:53:32 -0400945 this->write8(location.fSlot);
Brian Osman07c117b2019-05-23 12:51:06 -0700946 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400947}
948
Brian Osmand30e0392019-06-14 14:05:14 -0400949static inline uint32_t float_to_bits(float x) {
950 uint32_t u;
951 memcpy(&u, &x, sizeof(uint32_t));
952 return u;
953}
954
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400955void ByteCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
956 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osmand30e0392019-06-14 14:05:14 -0400957 this->write32(float_to_bits(f.fValue));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400958}
959
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400960void ByteCodeGenerator::writeIntrinsicCall(const FunctionCall& c) {
961 auto found = fIntrinsics.find(c.fFunction.fName);
962 if (found == fIntrinsics.end()) {
963 fErrors.error(c.fOffset, "unsupported intrinsic function");
964 return;
965 }
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400966 int count = SlotCount(c.fArguments[0]->fType);
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400967 if (found->second.fIsSpecial) {
Brian Osmanb380e712019-07-24 17:02:39 -0400968 SpecialIntrinsic special = found->second.fValue.fSpecial;
969 switch (special) {
970 case SpecialIntrinsic::kDot: {
971 SkASSERT(c.fArguments.size() == 2);
972 SkASSERT(count == SlotCount(c.fArguments[1]->fType));
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400973 this->write(vector_instruction(ByteCodeInstruction::kMultiplyF, count));
974 this->write8(count);
Brian Osmanb380e712019-07-24 17:02:39 -0400975 for (int i = count; i > 1; --i) {
976 this->write(ByteCodeInstruction::kAddF);
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400977 this->write8(1);
Brian Osmanb380e712019-07-24 17:02:39 -0400978 }
979 break;
980 }
Brian Osmanb380e712019-07-24 17:02:39 -0400981 default:
982 SkASSERT(false);
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400983 }
984 } else {
985 switch (found->second.fValue.fInstruction) {
986 case ByteCodeInstruction::kCos:
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400987 case ByteCodeInstruction::kSin:
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400988 case ByteCodeInstruction::kTan:
989 SkASSERT(c.fArguments.size() > 0);
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400990 this->write(vector_instruction(found->second.fValue.fInstruction, count));
991 this->write8(count);
992 break;
993 case ByteCodeInstruction::kSqrt:
994 SkASSERT(c.fArguments.size() > 0);
995 this->write(vector_instruction(found->second.fValue.fInstruction, count));
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400996 break;
Mike Reed634c9412019-07-18 13:20:04 -0400997 case ByteCodeInstruction::kInverse2x2: {
998 SkASSERT(c.fArguments.size() > 0);
999 auto op = ByteCodeInstruction::kInverse2x2;
1000 switch (count) {
1001 case 4: break; // float2x2
1002 case 9: op = ByteCodeInstruction::kInverse3x3; break;
1003 case 16: op = ByteCodeInstruction::kInverse4x4; break;
1004 default: SkASSERT(false);
1005 }
1006 this->write(op);
Brian Osmanb380e712019-07-24 17:02:39 -04001007 break;
1008 }
Ethan Nicholasae9633b2019-05-24 12:46:34 -04001009 default:
1010 SkASSERT(false);
1011 }
Ethan Nicholas82162ee2019-05-21 16:05:08 -04001012 }
1013}
1014
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001015void ByteCodeGenerator::writeFunctionCall(const FunctionCall& f) {
Brian Osmand3494ed2019-06-20 15:41:34 -04001016 // Builtins have simple signatures...
Ethan Nicholas82162ee2019-05-21 16:05:08 -04001017 if (f.fFunction.fBuiltin) {
Brian Osmand3494ed2019-06-20 15:41:34 -04001018 for (const auto& arg : f.fArguments) {
1019 this->writeExpression(*arg);
1020 }
Ethan Nicholas82162ee2019-05-21 16:05:08 -04001021 this->writeIntrinsicCall(f);
1022 return;
1023 }
Brian Osmand3494ed2019-06-20 15:41:34 -04001024
Brian Osman6f5358f2019-07-09 14:17:23 -04001025 // Find the index of the function we're calling. We explicitly do not allow calls to functions
1026 // before they're defined. This is an easy-to-understand rule that prevents recursion.
1027 size_t idx;
1028 for (idx = 0; idx < fFunctions.size(); ++idx) {
1029 if (f.fFunction.matches(fFunctions[idx]->fDeclaration)) {
1030 break;
1031 }
1032 }
1033 if (idx > 255) {
1034 fErrors.error(f.fOffset, "Function count limit exceeded");
1035 return;
1036 } else if (idx >= fFunctions.size()) {
1037 fErrors.error(f.fOffset, "Call to undefined function");
1038 return;
1039 }
1040
1041 // We may need to deal with out parameters, so the sequence is tricky
Brian Osmand3494ed2019-06-20 15:41:34 -04001042 if (int returnCount = SlotCount(f.fType)) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001043 this->write(ByteCodeInstruction::kReserve, returnCount);
Brian Osmand3494ed2019-06-20 15:41:34 -04001044 this->write8(returnCount);
1045 }
1046
1047 int argCount = f.fArguments.size();
1048 std::vector<std::unique_ptr<LValue>> lvalues;
1049 for (int i = 0; i < argCount; ++i) {
1050 const auto& param = f.fFunction.fParameters[i];
1051 const auto& arg = f.fArguments[i];
1052 if (param->fModifiers.fFlags & Modifiers::kOut_Flag) {
1053 lvalues.emplace_back(this->getLValue(*arg));
1054 lvalues.back()->load();
1055 } else {
1056 this->writeExpression(*arg);
1057 }
1058 }
1059
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001060 // The space used by the call is based on the callee, but it also unwinds all of that before
1061 // we continue execution. We adjust our max stack depths below.
Brian Osman226668a2019-05-14 16:47:30 -04001062 this->write(ByteCodeInstruction::kCall);
Brian Osman6f5358f2019-07-09 14:17:23 -04001063 this->write8(idx);
Brian Osmand3494ed2019-06-20 15:41:34 -04001064
Brian Osman4a47da72019-07-12 11:30:32 -04001065 const ByteCodeFunction* callee = fOutput->fFunctions[idx].get();
1066 fMaxLoopCount = std::max(fMaxLoopCount, fLoopCount + callee->fLoopCount);
1067 fMaxConditionCount = std::max(fMaxConditionCount, fConditionCount + callee->fConditionCount);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001068 fMaxStackCount = std::max(fMaxStackCount, fStackCount + callee->fLocalCount
1069 + callee->fStackCount);
Brian Osman4a47da72019-07-12 11:30:32 -04001070
Brian Osmand3494ed2019-06-20 15:41:34 -04001071 // After the called function returns, the stack will still contain our arguments. We have to
1072 // pop them (storing any out parameters back to their lvalues as we go). We glob together slot
1073 // counts for all parameters that aren't out-params, so we can pop them in one big chunk.
1074 int popCount = 0;
1075 auto pop = [&]() {
1076 if (popCount > 4) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001077 this->write(ByteCodeInstruction::kPopN, popCount);
Brian Osmand3494ed2019-06-20 15:41:34 -04001078 this->write8(popCount);
1079 } else if (popCount > 0) {
1080 this->write(vector_instruction(ByteCodeInstruction::kPop, popCount));
1081 }
1082 popCount = 0;
1083 };
1084
1085 for (int i = argCount - 1; i >= 0; --i) {
1086 const auto& param = f.fFunction.fParameters[i];
1087 const auto& arg = f.fArguments[i];
1088 if (param->fModifiers.fFlags & Modifiers::kOut_Flag) {
1089 pop();
1090 lvalues.back()->store(true);
1091 lvalues.pop_back();
1092 } else {
1093 popCount += SlotCount(arg->fType);
1094 }
1095 }
1096 pop();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001097}
1098
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001099void ByteCodeGenerator::writeIntLiteral(const IntLiteral& i) {
1100 this->write(ByteCodeInstruction::kPushImmediate);
1101 this->write32(i.fValue);
1102}
1103
1104void ByteCodeGenerator::writeNullLiteral(const NullLiteral& n) {
1105 // not yet implemented
1106 abort();
1107}
1108
Brian Osman3e29f1d2019-05-28 09:35:05 -04001109bool ByteCodeGenerator::writePrefixExpression(const PrefixExpression& p, bool discard) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001110 switch (p.fOperator) {
1111 case Token::Kind::PLUSPLUS: // fall through
1112 case Token::Kind::MINUSMINUS: {
Brian Osman07c117b2019-05-23 12:51:06 -07001113 SkASSERT(SlotCount(p.fOperand->fType) == 1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001114 std::unique_ptr<LValue> lvalue = this->getLValue(*p.fOperand);
1115 lvalue->load();
1116 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osmand30e0392019-06-14 14:05:14 -04001117 this->write32(type_category(p.fType) == TypeCategory::kFloat ? float_to_bits(1.0f) : 1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001118 if (p.fOperator == Token::Kind::PLUSPLUS) {
1119 this->writeTypedInstruction(p.fType,
1120 ByteCodeInstruction::kAddI,
1121 ByteCodeInstruction::kAddI,
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001122 ByteCodeInstruction::kAddF,
1123 1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001124 } else {
1125 this->writeTypedInstruction(p.fType,
1126 ByteCodeInstruction::kSubtractI,
1127 ByteCodeInstruction::kSubtractI,
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001128 ByteCodeInstruction::kSubtractF,
1129 1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001130 }
Brian Osman3e29f1d2019-05-28 09:35:05 -04001131 lvalue->store(discard);
1132 discard = false;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001133 break;
1134 }
Ethan Nicholas354ecf32019-05-07 16:13:02 -04001135 case Token::Kind::MINUS: {
1136 this->writeExpression(*p.fOperand);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001137 this->writeTypedInstruction(p.fType,
Mike Klein12710912019-05-21 11:04:59 -05001138 ByteCodeInstruction::kNegateI,
1139 ByteCodeInstruction::kNegateI,
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001140 ByteCodeInstruction::kNegateF,
Ethan Nicholasc70027b2019-09-05 16:50:52 -04001141 SlotCount(p.fOperand->fType),
1142 false);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001143 break;
Ethan Nicholas354ecf32019-05-07 16:13:02 -04001144 }
Brian Osmane5bbce22019-09-23 12:38:40 -04001145 case Token::Kind::LOGICALNOT:
1146 case Token::Kind::BITWISENOT: {
1147 SkASSERT(SlotCount(p.fOperand->fType) == 1);
1148 SkDEBUGCODE(TypeCategory tc = type_category(p.fOperand->fType));
1149 SkASSERT((p.fOperator == Token::Kind::LOGICALNOT && tc == TypeCategory::kBool) ||
1150 (p.fOperator == Token::Kind::BITWISENOT && (tc == TypeCategory::kSigned ||
1151 tc == TypeCategory::kUnsigned)));
1152 this->writeExpression(*p.fOperand);
1153 this->write(ByteCodeInstruction::kNotB);
1154 break;
1155 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001156 default:
1157 SkASSERT(false);
1158 }
Brian Osman3e29f1d2019-05-28 09:35:05 -04001159 return discard;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001160}
1161
Brian Osman3e29f1d2019-05-28 09:35:05 -04001162bool ByteCodeGenerator::writePostfixExpression(const PostfixExpression& p, bool discard) {
Brian Osmanf3fa6002019-05-17 14:26:53 -04001163 switch (p.fOperator) {
1164 case Token::Kind::PLUSPLUS: // fall through
1165 case Token::Kind::MINUSMINUS: {
Brian Osman07c117b2019-05-23 12:51:06 -07001166 SkASSERT(SlotCount(p.fOperand->fType) == 1);
Brian Osmanf3fa6002019-05-17 14:26:53 -04001167 std::unique_ptr<LValue> lvalue = this->getLValue(*p.fOperand);
1168 lvalue->load();
Brian Osman52c1bf12019-07-18 13:12:19 -04001169 // If we're not supposed to discard the result, then make a copy *before* the +/-
Brian Osman3e29f1d2019-05-28 09:35:05 -04001170 if (!discard) {
1171 this->write(ByteCodeInstruction::kDup);
Ethan Nicholasc70027b2019-09-05 16:50:52 -04001172 this->write8(1);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001173 }
Brian Osmanf3fa6002019-05-17 14:26:53 -04001174 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osmand30e0392019-06-14 14:05:14 -04001175 this->write32(type_category(p.fType) == TypeCategory::kFloat ? float_to_bits(1.0f) : 1);
Brian Osmanf3fa6002019-05-17 14:26:53 -04001176 if (p.fOperator == Token::Kind::PLUSPLUS) {
1177 this->writeTypedInstruction(p.fType,
1178 ByteCodeInstruction::kAddI,
1179 ByteCodeInstruction::kAddI,
1180 ByteCodeInstruction::kAddF,
1181 1);
1182 } else {
1183 this->writeTypedInstruction(p.fType,
1184 ByteCodeInstruction::kSubtractI,
1185 ByteCodeInstruction::kSubtractI,
1186 ByteCodeInstruction::kSubtractF,
1187 1);
1188 }
Brian Osman52c1bf12019-07-18 13:12:19 -04001189 // Always consume the result as part of the store
1190 lvalue->store(true);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001191 discard = false;
Brian Osmanf3fa6002019-05-17 14:26:53 -04001192 break;
1193 }
1194 default:
1195 SkASSERT(false);
1196 }
Brian Osman3e29f1d2019-05-28 09:35:05 -04001197 return discard;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001198}
1199
1200void ByteCodeGenerator::writeSwizzle(const Swizzle& s) {
Brian Osman0785db02019-05-24 14:19:11 -04001201 if (swizzle_is_simple(s)) {
1202 this->writeVariableExpression(s);
1203 return;
1204 }
1205
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001206 switch (s.fBase->fKind) {
1207 case Expression::kVariableReference_Kind: {
Brian Osman1c110a02019-10-01 14:53:32 -04001208 Location location = this->getLocation(*s.fBase);
1209 this->write(location.selectLoad(ByteCodeInstruction::kLoadSwizzle,
1210 ByteCodeInstruction::kLoadSwizzleGlobal,
1211 ByteCodeInstruction::kLoadSwizzleUniform),
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001212 s.fComponents.size());
Brian Osman1c110a02019-10-01 14:53:32 -04001213 this->write8(location.fSlot);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001214 this->write8(s.fComponents.size());
1215 for (int c : s.fComponents) {
1216 this->write8(c);
1217 }
1218 break;
1219 }
1220 default:
1221 this->writeExpression(*s.fBase);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001222 this->write(ByteCodeInstruction::kSwizzle,
1223 s.fComponents.size() - s.fBase->fType.columns());
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001224 this->write8(s.fBase->fType.columns());
1225 this->write8(s.fComponents.size());
1226 for (int c : s.fComponents) {
1227 this->write8(c);
1228 }
1229 }
1230}
1231
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001232void ByteCodeGenerator::writeTernaryExpression(const TernaryExpression& t) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001233 int count = SlotCount(t.fType);
1234 SkASSERT(count == SlotCount(t.fIfTrue->fType));
1235 SkASSERT(count == SlotCount(t.fIfFalse->fType));
1236
Brian Osman4e93feb2019-05-16 15:38:00 -04001237 this->writeExpression(*t.fTest);
Brian Osman569f12f2019-06-13 11:23:57 -04001238 this->write(ByteCodeInstruction::kMaskPush);
Brian Osman4e93feb2019-05-16 15:38:00 -04001239 this->writeExpression(*t.fIfTrue);
Brian Osman569f12f2019-06-13 11:23:57 -04001240 this->write(ByteCodeInstruction::kMaskNegate);
1241 this->writeExpression(*t.fIfFalse);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001242 this->write(ByteCodeInstruction::kMaskBlend, count);
1243 this->write8(count);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001244}
1245
Brian Osman3e29f1d2019-05-28 09:35:05 -04001246void ByteCodeGenerator::writeExpression(const Expression& e, bool discard) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001247 switch (e.fKind) {
1248 case Expression::kBinary_Kind:
Brian Osman3e29f1d2019-05-28 09:35:05 -04001249 discard = this->writeBinaryExpression((BinaryExpression&) e, discard);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001250 break;
1251 case Expression::kBoolLiteral_Kind:
1252 this->writeBoolLiteral((BoolLiteral&) e);
1253 break;
1254 case Expression::kConstructor_Kind:
1255 this->writeConstructor((Constructor&) e);
1256 break;
Ethan Nicholas9e6a3932019-05-17 16:31:21 -04001257 case Expression::kExternalFunctionCall_Kind:
1258 this->writeExternalFunctionCall((ExternalFunctionCall&) e);
1259 break;
Ethan Nicholas91164d12019-05-15 15:29:54 -04001260 case Expression::kExternalValue_Kind:
1261 this->writeExternalValue((ExternalValueReference&) e);
1262 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001263 case Expression::kFieldAccess_Kind:
Brian Osman07c117b2019-05-23 12:51:06 -07001264 case Expression::kIndex_Kind:
1265 case Expression::kVariableReference_Kind:
1266 this->writeVariableExpression(e);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001267 break;
1268 case Expression::kFloatLiteral_Kind:
1269 this->writeFloatLiteral((FloatLiteral&) e);
1270 break;
1271 case Expression::kFunctionCall_Kind:
1272 this->writeFunctionCall((FunctionCall&) e);
1273 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001274 case Expression::kIntLiteral_Kind:
1275 this->writeIntLiteral((IntLiteral&) e);
1276 break;
1277 case Expression::kNullLiteral_Kind:
1278 this->writeNullLiteral((NullLiteral&) e);
1279 break;
1280 case Expression::kPrefix_Kind:
Brian Osman3e29f1d2019-05-28 09:35:05 -04001281 discard = this->writePrefixExpression((PrefixExpression&) e, discard);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001282 break;
1283 case Expression::kPostfix_Kind:
Brian Osman3e29f1d2019-05-28 09:35:05 -04001284 discard = this->writePostfixExpression((PostfixExpression&) e, discard);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001285 break;
1286 case Expression::kSwizzle_Kind:
1287 this->writeSwizzle((Swizzle&) e);
1288 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001289 case Expression::kTernary_Kind:
1290 this->writeTernaryExpression((TernaryExpression&) e);
1291 break;
1292 default:
1293 printf("unsupported expression %s\n", e.description().c_str());
1294 SkASSERT(false);
1295 }
Brian Osman3e29f1d2019-05-28 09:35:05 -04001296 if (discard) {
1297 int count = SlotCount(e.fType);
1298 if (count > 4) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001299 this->write(ByteCodeInstruction::kPopN, count);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001300 this->write8(count);
Brian Osmanfba386b2019-06-20 14:54:15 -04001301 } else if (count != 0) {
Brian Osman3e29f1d2019-05-28 09:35:05 -04001302 this->write(vector_instruction(ByteCodeInstruction::kPop, count));
1303 }
1304 discard = false;
1305 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001306}
1307
Ethan Nicholas91164d12019-05-15 15:29:54 -04001308class ByteCodeExternalValueLValue : public ByteCodeGenerator::LValue {
1309public:
1310 ByteCodeExternalValueLValue(ByteCodeGenerator* generator, ExternalValue& value, int index)
1311 : INHERITED(*generator)
Brian Osman07c117b2019-05-23 12:51:06 -07001312 , fCount(ByteCodeGenerator::SlotCount(value.type()))
Ethan Nicholas91164d12019-05-15 15:29:54 -04001313 , fIndex(index) {}
1314
1315 void load() override {
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001316 fGenerator.write(vector_instruction(ByteCodeInstruction::kReadExternal, fCount));
Ethan Nicholasc70027b2019-09-05 16:50:52 -04001317 fGenerator.write8(fCount);
Ethan Nicholas91164d12019-05-15 15:29:54 -04001318 fGenerator.write8(fIndex);
1319 }
1320
Brian Osman3e29f1d2019-05-28 09:35:05 -04001321 void store(bool discard) override {
1322 if (!discard) {
1323 fGenerator.write(vector_instruction(ByteCodeInstruction::kDup, fCount));
Ethan Nicholasc70027b2019-09-05 16:50:52 -04001324 fGenerator.write8(fCount);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001325 }
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001326 fGenerator.write(vector_instruction(ByteCodeInstruction::kWriteExternal, fCount));
Ethan Nicholasc70027b2019-09-05 16:50:52 -04001327 fGenerator.write8(fCount);
Ethan Nicholas91164d12019-05-15 15:29:54 -04001328 fGenerator.write8(fIndex);
1329 }
1330
1331private:
1332 typedef LValue INHERITED;
1333
1334 int fCount;
1335
1336 int fIndex;
1337};
1338
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001339class ByteCodeSwizzleLValue : public ByteCodeGenerator::LValue {
1340public:
1341 ByteCodeSwizzleLValue(ByteCodeGenerator* generator, const Swizzle& swizzle)
1342 : INHERITED(*generator)
Brian Osman07c117b2019-05-23 12:51:06 -07001343 , fSwizzle(swizzle) {}
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001344
1345 void load() override {
Brian Osman1091f022019-05-16 09:42:16 -04001346 fGenerator.writeSwizzle(fSwizzle);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001347 }
1348
Brian Osman3e29f1d2019-05-28 09:35:05 -04001349 void store(bool discard) override {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001350 int count = fSwizzle.fComponents.size();
Brian Osman3e29f1d2019-05-28 09:35:05 -04001351 if (!discard) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001352 fGenerator.write(vector_instruction(ByteCodeInstruction::kDup, count));
Ethan Nicholasc70027b2019-09-05 16:50:52 -04001353 fGenerator.write8(count);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001354 }
Brian Osman1c110a02019-10-01 14:53:32 -04001355 ByteCodeGenerator::Location location = fGenerator.getLocation(*fSwizzle.fBase);
1356 if (location.isOnStack()) {
1357 fGenerator.write(location.selectStore(ByteCodeInstruction::kStoreSwizzleIndirect,
1358 ByteCodeInstruction::kStoreSwizzleIndirectGlobal),
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001359 count);
Brian Osman07c117b2019-05-23 12:51:06 -07001360 } else {
Brian Osman1c110a02019-10-01 14:53:32 -04001361 fGenerator.write(location.selectStore(ByteCodeInstruction::kStoreSwizzle,
1362 ByteCodeInstruction::kStoreSwizzleGlobal),
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001363 count);
Brian Osman1c110a02019-10-01 14:53:32 -04001364 fGenerator.write8(location.fSlot);
Brian Osman07c117b2019-05-23 12:51:06 -07001365 }
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001366 fGenerator.write8(count);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001367 for (int c : fSwizzle.fComponents) {
1368 fGenerator.write8(c);
1369 }
1370 }
1371
1372private:
1373 const Swizzle& fSwizzle;
1374
1375 typedef LValue INHERITED;
1376};
1377
Brian Osman07c117b2019-05-23 12:51:06 -07001378class ByteCodeExpressionLValue : public ByteCodeGenerator::LValue {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001379public:
Brian Osman07c117b2019-05-23 12:51:06 -07001380 ByteCodeExpressionLValue(ByteCodeGenerator* generator, const Expression& expr)
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001381 : INHERITED(*generator)
Brian Osman07c117b2019-05-23 12:51:06 -07001382 , fExpression(expr) {}
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001383
1384 void load() override {
Brian Osman07c117b2019-05-23 12:51:06 -07001385 fGenerator.writeVariableExpression(fExpression);
Brian Osman1091f022019-05-16 09:42:16 -04001386 }
1387
Brian Osman3e29f1d2019-05-28 09:35:05 -04001388 void store(bool discard) override {
Brian Osman07c117b2019-05-23 12:51:06 -07001389 int count = ByteCodeGenerator::SlotCount(fExpression.fType);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001390 if (!discard) {
1391 if (count > 4) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001392 fGenerator.write(ByteCodeInstruction::kDupN, count);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001393 fGenerator.write8(count);
1394 } else {
1395 fGenerator.write(vector_instruction(ByteCodeInstruction::kDup, count));
Ethan Nicholasc70027b2019-09-05 16:50:52 -04001396 fGenerator.write8(count);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001397 }
Brian Osman07c117b2019-05-23 12:51:06 -07001398 }
Brian Osman1c110a02019-10-01 14:53:32 -04001399 ByteCodeGenerator::Location location = fGenerator.getLocation(fExpression);
1400 if (location.isOnStack() || count > 4) {
1401 if (!location.isOnStack()) {
Brian Osman07c117b2019-05-23 12:51:06 -07001402 fGenerator.write(ByteCodeInstruction::kPushImmediate);
Brian Osman1c110a02019-10-01 14:53:32 -04001403 fGenerator.write32(location.fSlot);
Brian Osman07c117b2019-05-23 12:51:06 -07001404 }
Brian Osman1c110a02019-10-01 14:53:32 -04001405 fGenerator.write(location.selectStore(ByteCodeInstruction::kStoreExtended,
1406 ByteCodeInstruction::kStoreExtendedGlobal),
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001407 count);
Brian Osman07c117b2019-05-23 12:51:06 -07001408 fGenerator.write8(count);
1409 } else {
Brian Osman1c110a02019-10-01 14:53:32 -04001410 fGenerator.write(
1411 vector_instruction(location.selectStore(ByteCodeInstruction::kStore,
1412 ByteCodeInstruction::kStoreGlobal),
1413 count));
1414 fGenerator.write8(location.fSlot);
Brian Osman07c117b2019-05-23 12:51:06 -07001415 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001416 }
1417
1418private:
1419 typedef LValue INHERITED;
1420
Brian Osman07c117b2019-05-23 12:51:06 -07001421 const Expression& fExpression;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001422};
1423
1424std::unique_ptr<ByteCodeGenerator::LValue> ByteCodeGenerator::getLValue(const Expression& e) {
1425 switch (e.fKind) {
Ethan Nicholas91164d12019-05-15 15:29:54 -04001426 case Expression::kExternalValue_Kind: {
1427 ExternalValue* value = ((ExternalValueReference&) e).fValue;
1428 int index = fOutput->fExternalValues.size();
1429 fOutput->fExternalValues.push_back(value);
1430 SkASSERT(index <= 255);
1431 return std::unique_ptr<LValue>(new ByteCodeExternalValueLValue(this, *value, index));
1432 }
Brian Osman07c117b2019-05-23 12:51:06 -07001433 case Expression::kFieldAccess_Kind:
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001434 case Expression::kIndex_Kind:
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001435 case Expression::kVariableReference_Kind:
Brian Osman07c117b2019-05-23 12:51:06 -07001436 return std::unique_ptr<LValue>(new ByteCodeExpressionLValue(this, e));
Brian Osman0785db02019-05-24 14:19:11 -04001437 case Expression::kSwizzle_Kind: {
1438 const Swizzle& s = (const Swizzle&) e;
1439 return swizzle_is_simple(s)
1440 ? std::unique_ptr<LValue>(new ByteCodeExpressionLValue(this, e))
1441 : std::unique_ptr<LValue>(new ByteCodeSwizzleLValue(this, s));
1442 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001443 case Expression::kTernary_Kind:
1444 default:
1445 printf("unsupported lvalue %s\n", e.description().c_str());
1446 return nullptr;
1447 }
1448}
1449
1450void ByteCodeGenerator::writeBlock(const Block& b) {
1451 for (const auto& s : b.fStatements) {
1452 this->writeStatement(*s);
1453 }
1454}
1455
1456void ByteCodeGenerator::setBreakTargets() {
1457 std::vector<DeferredLocation>& breaks = fBreakTargets.top();
1458 for (DeferredLocation& b : breaks) {
1459 b.set();
1460 }
1461 fBreakTargets.pop();
1462}
1463
1464void ByteCodeGenerator::setContinueTargets() {
1465 std::vector<DeferredLocation>& continues = fContinueTargets.top();
1466 for (DeferredLocation& c : continues) {
1467 c.set();
1468 }
1469 fContinueTargets.pop();
1470}
1471
1472void ByteCodeGenerator::writeBreakStatement(const BreakStatement& b) {
Brian Osman569f12f2019-06-13 11:23:57 -04001473 // TODO: Include BranchIfAllFalse to top-most LoopNext
1474 this->write(ByteCodeInstruction::kLoopBreak);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001475}
1476
1477void ByteCodeGenerator::writeContinueStatement(const ContinueStatement& c) {
Brian Osman569f12f2019-06-13 11:23:57 -04001478 // TODO: Include BranchIfAllFalse to top-most LoopNext
1479 this->write(ByteCodeInstruction::kLoopContinue);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001480}
1481
1482void ByteCodeGenerator::writeDoStatement(const DoStatement& d) {
Brian Osman569f12f2019-06-13 11:23:57 -04001483 this->write(ByteCodeInstruction::kLoopBegin);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001484 size_t start = fCode->size();
1485 this->writeStatement(*d.fStatement);
Brian Osman569f12f2019-06-13 11:23:57 -04001486 this->write(ByteCodeInstruction::kLoopNext);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001487 this->writeExpression(*d.fTest);
Brian Osman569f12f2019-06-13 11:23:57 -04001488 this->write(ByteCodeInstruction::kLoopMask);
1489 // TODO: Could shorten this with kBranchIfAnyTrue
1490 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1491 DeferredLocation endLocation(this);
1492 this->write(ByteCodeInstruction::kBranch);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001493 this->write16(start);
Brian Osman569f12f2019-06-13 11:23:57 -04001494 endLocation.set();
1495 this->write(ByteCodeInstruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001496}
1497
1498void ByteCodeGenerator::writeForStatement(const ForStatement& f) {
1499 fContinueTargets.emplace();
1500 fBreakTargets.emplace();
1501 if (f.fInitializer) {
1502 this->writeStatement(*f.fInitializer);
1503 }
Brian Osman569f12f2019-06-13 11:23:57 -04001504 this->write(ByteCodeInstruction::kLoopBegin);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001505 size_t start = fCode->size();
1506 if (f.fTest) {
1507 this->writeExpression(*f.fTest);
Brian Osman569f12f2019-06-13 11:23:57 -04001508 this->write(ByteCodeInstruction::kLoopMask);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001509 }
Brian Osman569f12f2019-06-13 11:23:57 -04001510 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1511 DeferredLocation endLocation(this);
1512 this->writeStatement(*f.fStatement);
1513 this->write(ByteCodeInstruction::kLoopNext);
1514 if (f.fNext) {
1515 this->writeExpression(*f.fNext, true);
1516 }
1517 this->write(ByteCodeInstruction::kBranch);
1518 this->write16(start);
1519 endLocation.set();
1520 this->write(ByteCodeInstruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001521}
1522
1523void ByteCodeGenerator::writeIfStatement(const IfStatement& i) {
Brian Osman569f12f2019-06-13 11:23:57 -04001524 this->writeExpression(*i.fTest);
1525 this->write(ByteCodeInstruction::kMaskPush);
1526 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1527 DeferredLocation falseLocation(this);
1528 this->writeStatement(*i.fIfTrue);
1529 falseLocation.set();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001530 if (i.fIfFalse) {
Brian Osman569f12f2019-06-13 11:23:57 -04001531 this->write(ByteCodeInstruction::kMaskNegate);
1532 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1533 DeferredLocation endLocation(this);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001534 this->writeStatement(*i.fIfFalse);
Mike Kleinb45ee832019-05-17 11:11:11 -05001535 endLocation.set();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001536 }
Brian Osman569f12f2019-06-13 11:23:57 -04001537 this->write(ByteCodeInstruction::kMaskPop);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001538}
1539
1540void ByteCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
Brian Osman4a47da72019-07-12 11:30:32 -04001541 if (fLoopCount || fConditionCount) {
1542 fErrors.error(r.fOffset, "return not allowed inside conditional or loop");
1543 return;
1544 }
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001545 int count = SlotCount(r.fExpression->fType);
Ethan Nicholas746035a2019-04-23 13:31:09 -04001546 this->writeExpression(*r.fExpression);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001547
1548 // Technically, the kReturn also pops fOutput->fLocalCount values from the stack, too, but we
1549 // haven't counted pushing those (they're outside the scope of our stack tracking). Instead,
1550 // we account for those in writeFunction().
1551
1552 // This is all fine because we don't allow conditional returns, so we only return once anyway.
1553 this->write(ByteCodeInstruction::kReturn, -count);
1554 this->write8(count);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001555}
1556
1557void ByteCodeGenerator::writeSwitchStatement(const SwitchStatement& r) {
1558 // not yet implemented
1559 abort();
1560}
1561
1562void ByteCodeGenerator::writeVarDeclarations(const VarDeclarations& v) {
1563 for (const auto& declStatement : v.fVars) {
1564 const VarDeclaration& decl = (VarDeclaration&) *declStatement;
Brian Osman1c110a02019-10-01 14:53:32 -04001565 // we need to grab the location even if we don't use it, to ensure it has been allocated
1566 Location location = this->getLocation(*decl.fVar);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001567 if (decl.fValue) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001568 this->writeExpression(*decl.fValue);
Brian Osman07c117b2019-05-23 12:51:06 -07001569 int count = SlotCount(decl.fValue->fType);
1570 if (count > 4) {
1571 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osman1c110a02019-10-01 14:53:32 -04001572 this->write32(location.fSlot);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001573 this->write(ByteCodeInstruction::kStoreExtended, count);
Brian Osman07c117b2019-05-23 12:51:06 -07001574 this->write8(count);
1575 } else {
1576 this->write(vector_instruction(ByteCodeInstruction::kStore, count));
Brian Osman1c110a02019-10-01 14:53:32 -04001577 this->write8(location.fSlot);
Brian Osman07c117b2019-05-23 12:51:06 -07001578 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001579 }
1580 }
1581}
1582
1583void ByteCodeGenerator::writeWhileStatement(const WhileStatement& w) {
Brian Osman569f12f2019-06-13 11:23:57 -04001584 this->write(ByteCodeInstruction::kLoopBegin);
1585 size_t cond = fCode->size();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001586 this->writeExpression(*w.fTest);
Brian Osman569f12f2019-06-13 11:23:57 -04001587 this->write(ByteCodeInstruction::kLoopMask);
1588 this->write(ByteCodeInstruction::kBranchIfAllFalse);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001589 DeferredLocation endLocation(this);
1590 this->writeStatement(*w.fStatement);
Brian Osman569f12f2019-06-13 11:23:57 -04001591 this->write(ByteCodeInstruction::kLoopNext);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001592 this->write(ByteCodeInstruction::kBranch);
Brian Osman569f12f2019-06-13 11:23:57 -04001593 this->write16(cond);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001594 endLocation.set();
Brian Osman569f12f2019-06-13 11:23:57 -04001595 this->write(ByteCodeInstruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001596}
1597
1598void ByteCodeGenerator::writeStatement(const Statement& s) {
1599 switch (s.fKind) {
1600 case Statement::kBlock_Kind:
1601 this->writeBlock((Block&) s);
1602 break;
1603 case Statement::kBreak_Kind:
1604 this->writeBreakStatement((BreakStatement&) s);
1605 break;
1606 case Statement::kContinue_Kind:
1607 this->writeContinueStatement((ContinueStatement&) s);
1608 break;
1609 case Statement::kDiscard_Kind:
1610 // not yet implemented
1611 abort();
1612 case Statement::kDo_Kind:
1613 this->writeDoStatement((DoStatement&) s);
1614 break;
Brian Osman3e29f1d2019-05-28 09:35:05 -04001615 case Statement::kExpression_Kind:
1616 this->writeExpression(*((ExpressionStatement&) s).fExpression, true);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001617 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001618 case Statement::kFor_Kind:
1619 this->writeForStatement((ForStatement&) s);
1620 break;
1621 case Statement::kIf_Kind:
1622 this->writeIfStatement((IfStatement&) s);
1623 break;
1624 case Statement::kNop_Kind:
1625 break;
1626 case Statement::kReturn_Kind:
1627 this->writeReturnStatement((ReturnStatement&) s);
1628 break;
1629 case Statement::kSwitch_Kind:
1630 this->writeSwitchStatement((SwitchStatement&) s);
1631 break;
1632 case Statement::kVarDeclarations_Kind:
1633 this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration);
1634 break;
1635 case Statement::kWhile_Kind:
1636 this->writeWhileStatement((WhileStatement&) s);
1637 break;
1638 default:
1639 SkASSERT(false);
1640 }
1641}
1642
Brian Osman80164412019-06-07 13:00:23 -04001643ByteCodeFunction::ByteCodeFunction(const FunctionDeclaration* declaration)
1644 : fName(declaration->fName) {
1645 fParameterCount = 0;
1646 for (const auto& p : declaration->fParameters) {
1647 int slots = ByteCodeGenerator::SlotCount(p->fType);
1648 fParameters.push_back({ slots, (bool)(p->fModifiers.fFlags & Modifiers::kOut_Flag) });
1649 fParameterCount += slots;
1650 }
1651}
1652
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001653}