blob: 6092593d2e627d275fbadae41a69d52ad78fbd16 [file] [log] [blame]
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001/*
2 * Copyright 2019 Google LLC
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
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 {
20 { "cos", ByteCodeInstruction::kCos },
21 { "cross", ByteCodeInstruction::kCross },
22 { "dot", SpecialIntrinsic::kDot },
23 { "sin", ByteCodeInstruction::kSin },
24 { "sqrt", ByteCodeInstruction::kSqrt },
25 { "tan", ByteCodeInstruction::kTan },
26 { "mix", ByteCodeInstruction::kMix },
27 } {}
28
Ethan Nicholas82162ee2019-05-21 16:05:08 -040029
Brian Osman07c117b2019-05-23 12:51:06 -070030int ByteCodeGenerator::SlotCount(const Type& type) {
Brian Osmanfba386b2019-06-20 14:54:15 -040031 if (type.kind() == Type::kOther_Kind) {
32 return 0;
33 } else if (type.kind() == Type::kStruct_Kind) {
Brian Osman07c117b2019-05-23 12:51:06 -070034 int slots = 0;
35 for (const auto& f : type.fields()) {
36 slots += SlotCount(*f.fType);
37 }
38 SkASSERT(slots <= 255);
39 return slots;
40 } else if (type.kind() == Type::kArray_Kind) {
41 int columns = type.columns();
42 SkASSERT(columns >= 0);
43 int slots = columns * SlotCount(type.componentType());
44 SkASSERT(slots <= 255);
45 return slots;
46 } else {
47 return type.columns() * type.rows();
48 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040049}
50
51bool ByteCodeGenerator::generateCode() {
52 for (const auto& e : fProgram) {
53 switch (e.fKind) {
54 case ProgramElement::kFunction_Kind: {
55 std::unique_ptr<ByteCodeFunction> f = this->writeFunction((FunctionDefinition&) e);
56 if (!f) {
57 return false;
58 }
59 fOutput->fFunctions.push_back(std::move(f));
Brian Osman80164412019-06-07 13:00:23 -040060 fFunctions.push_back(&(FunctionDefinition&)e);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040061 break;
62 }
63 case ProgramElement::kVar_Kind: {
64 VarDeclarations& decl = (VarDeclarations&) e;
65 for (const auto& v : decl.fVars) {
66 const Variable* declVar = ((VarDeclaration&) *v).fVar;
67 if (declVar->fModifiers.fLayout.fBuiltin >= 0) {
68 continue;
69 }
70 if (declVar->fModifiers.fFlags & Modifiers::kIn_Flag) {
Brian Osman07c117b2019-05-23 12:51:06 -070071 for (int i = SlotCount(declVar->fType); i > 0; --i) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040072 fOutput->fInputSlots.push_back(fOutput->fGlobalCount++);
73 }
74 } else {
Brian Osman07c117b2019-05-23 12:51:06 -070075 fOutput->fGlobalCount += SlotCount(declVar->fType);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040076 }
77 }
78 break;
79 }
80 default:
81 ; // ignore
82 }
83 }
Brian Osman6f5358f2019-07-09 14:17:23 -040084 return 0 == fErrors.errorCount();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040085}
86
87std::unique_ptr<ByteCodeFunction> ByteCodeGenerator::writeFunction(const FunctionDefinition& f) {
88 fFunction = &f;
Brian Osman226668a2019-05-14 16:47:30 -040089 std::unique_ptr<ByteCodeFunction> result(new ByteCodeFunction(&f.fDeclaration));
Brian Osman80164412019-06-07 13:00:23 -040090 fParameterCount = result->fParameterCount;
Brian Osman4a47da72019-07-12 11:30:32 -040091 fLoopCount = fMaxLoopCount = 0;
92 fConditionCount = fMaxConditionCount = 0;
Brian Osmanaa2ca3f2019-07-15 13:24:48 -040093 fStackCount = fMaxStackCount = 0;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040094 fCode = &result->fCode;
Brian Osman4a47da72019-07-12 11:30:32 -040095
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040096 this->writeStatement(*f.fBody);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -040097 if (0 == fErrors.errorCount()) {
98 SkASSERT(fLoopCount == 0);
99 SkASSERT(fConditionCount == 0);
100 SkASSERT(fStackCount == 0);
101 }
102 this->write(ByteCodeInstruction::kReturn, 0);
Ethan Nicholas7e603db2019-05-03 12:57:47 -0400103 this->write8(0);
Brian Osman4a47da72019-07-12 11:30:32 -0400104
105 result->fLocalCount = fLocals.size();
106 result->fConditionCount = fMaxConditionCount;
107 result->fLoopCount = fMaxLoopCount;
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400108 result->fStackCount = fMaxStackCount;
Brian Osman4a47da72019-07-12 11:30:32 -0400109
Ethan Nicholasdfcad062019-05-07 12:53:34 -0400110 const Type& returnType = f.fDeclaration.fReturnType;
111 if (returnType != *fContext.fVoid_Type) {
Brian Osman07c117b2019-05-23 12:51:06 -0700112 result->fReturnCount = SlotCount(returnType);
Ethan Nicholasdfcad062019-05-07 12:53:34 -0400113 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400114 fLocals.clear();
115 fFunction = nullptr;
116 return result;
117}
118
119enum class TypeCategory {
120 kBool,
121 kSigned,
122 kUnsigned,
123 kFloat,
124};
125
126static TypeCategory type_category(const Type& type) {
127 switch (type.kind()) {
128 case Type::Kind::kVector_Kind:
129 case Type::Kind::kMatrix_Kind:
130 return type_category(type.componentType());
131 default:
132 if (type.fName == "bool") {
133 return TypeCategory::kBool;
134 } else if (type.fName == "int" || type.fName == "short") {
135 return TypeCategory::kSigned;
136 } else if (type.fName == "uint" || type.fName == "ushort") {
137 return TypeCategory::kUnsigned;
138 } else {
139 SkASSERT(type.fName == "float" || type.fName == "half");
140 return TypeCategory::kFloat;
141 }
142 ABORT("unsupported type: %s\n", type.description().c_str());
143 }
144}
145
Brian Osman0785db02019-05-24 14:19:11 -0400146// A "simple" Swizzle is based on a variable (or a compound variable like a struct or array), and
147// that references consecutive values, such that it can be implemented using normal load/store ops
148// with an offset. Note that all single-component swizzles (of suitable base types) are simple.
149static bool swizzle_is_simple(const Swizzle& s) {
150 switch (s.fBase->fKind) {
151 case Expression::kFieldAccess_Kind:
152 case Expression::kIndex_Kind:
153 case Expression::kVariableReference_Kind:
154 break;
155 default:
156 return false;
157 }
158
159 for (size_t i = 1; i < s.fComponents.size(); ++i) {
160 if (s.fComponents[i] != s.fComponents[i - 1] + 1) {
161 return false;
162 }
163 }
164 return true;
165}
166
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400167int ByteCodeGenerator::StackUsage(ByteCodeInstruction inst, int count_) {
168 // Ensures that we use count iff we're passed a non-default value. Most instructions have an
169 // implicit count, so the caller shouldn't need to worry about it (or count makes no sense).
170 // The asserts avoids callers thinking they're supplying useful information in that scenario,
171 // or failing to supply necessary information for the ops that need a count.
172 struct CountValue {
173 operator int() {
174 SkASSERT(val != ByteCodeGenerator::kUnusedStackCount);
175 SkDEBUGCODE(used = true);
176 return val;
177 }
178 ~CountValue() {
179 SkASSERT(used || val == ByteCodeGenerator::kUnusedStackCount);
180 }
181 int val;
182 SkDEBUGCODE(bool used = false;)
183 } count = { count_ };
184
185 switch (inst) {
186 // Unary functions/operators that don't change stack depth at all:
187#define VECTOR_UNARY_OP(base) \
188 case ByteCodeInstruction::base: \
189 case ByteCodeInstruction::base ## 2: \
190 case ByteCodeInstruction::base ## 3: \
191 case ByteCodeInstruction::base ## 4: \
192 return 0;
193
194 VECTOR_UNARY_OP(kConvertFtoI)
195 VECTOR_UNARY_OP(kConvertStoF)
196 VECTOR_UNARY_OP(kConvertUtoF)
197
198 VECTOR_UNARY_OP(kCos)
199 VECTOR_UNARY_OP(kSin)
200 VECTOR_UNARY_OP(kSqrt)
201 VECTOR_UNARY_OP(kTan)
202
203 VECTOR_UNARY_OP(kNegateF)
204 VECTOR_UNARY_OP(kNegateI)
205
Brian Osmanf42de9e2019-07-18 10:25:39 -0400206 case ByteCodeInstruction::kClampIndex: return 0;
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400207 case ByteCodeInstruction::kNotB: return 0;
208 case ByteCodeInstruction::kNegateFN: return 0;
209
210#undef VECTOR_UNARY_OP
211
212 // Binary functions/operators that do a 2 -> 1 reduction (possibly N times)
213#define VECTOR_BINARY_OP(base) \
214 case ByteCodeInstruction::base: return -1; \
215 case ByteCodeInstruction::base ## 2: return -2; \
216 case ByteCodeInstruction::base ## 3: return -3; \
217 case ByteCodeInstruction::base ## 4: return -4;
218
219#define VECTOR_MATRIX_BINARY_OP(base) \
220 VECTOR_BINARY_OP(base) \
221 case ByteCodeInstruction::base ## N: return -count;
222
223 case ByteCodeInstruction::kAndB: return -1;
224 case ByteCodeInstruction::kOrB: return -1;
225 case ByteCodeInstruction::kXorB: return -1;
226
227 VECTOR_BINARY_OP(kAddI)
228 VECTOR_MATRIX_BINARY_OP(kAddF)
229
230 VECTOR_BINARY_OP(kCompareIEQ)
231 VECTOR_MATRIX_BINARY_OP(kCompareFEQ)
232 VECTOR_BINARY_OP(kCompareINEQ)
233 VECTOR_MATRIX_BINARY_OP(kCompareFNEQ)
234 VECTOR_BINARY_OP(kCompareSGT)
235 VECTOR_BINARY_OP(kCompareUGT)
236 VECTOR_BINARY_OP(kCompareFGT)
237 VECTOR_BINARY_OP(kCompareSGTEQ)
238 VECTOR_BINARY_OP(kCompareUGTEQ)
239 VECTOR_BINARY_OP(kCompareFGTEQ)
240 VECTOR_BINARY_OP(kCompareSLT)
241 VECTOR_BINARY_OP(kCompareULT)
242 VECTOR_BINARY_OP(kCompareFLT)
243 VECTOR_BINARY_OP(kCompareSLTEQ)
244 VECTOR_BINARY_OP(kCompareULTEQ)
245 VECTOR_BINARY_OP(kCompareFLTEQ)
246
247 VECTOR_BINARY_OP(kDivideS)
248 VECTOR_BINARY_OP(kDivideU)
249 VECTOR_MATRIX_BINARY_OP(kDivideF)
250 VECTOR_BINARY_OP(kMultiplyI)
251 VECTOR_MATRIX_BINARY_OP(kMultiplyF)
252 VECTOR_BINARY_OP(kRemainderF)
253 VECTOR_BINARY_OP(kRemainderS)
254 VECTOR_BINARY_OP(kRemainderU)
255 VECTOR_BINARY_OP(kSubtractI)
256 VECTOR_MATRIX_BINARY_OP(kSubtractF)
257
258#undef VECTOR_BINARY_OP
259#undef VECTOR_MATRIX_BINARY_OP
260
261 // Strange math operations with other behavior:
262 case ByteCodeInstruction::kCross: return -3;
263 // Binary, but also consumes T:
264 case ByteCodeInstruction::kMix: return -2;
265 case ByteCodeInstruction::kMix2: return -3;
266 case ByteCodeInstruction::kMix3: return -4;
267 case ByteCodeInstruction::kMix4: return -5;
268
269 // Ops that push or load data to grow the stack:
270 case ByteCodeInstruction::kDup:
271 case ByteCodeInstruction::kLoad:
272 case ByteCodeInstruction::kLoadGlobal:
273 case ByteCodeInstruction::kReadExternal:
274 case ByteCodeInstruction::kPushImmediate:
275 return 1;
276
277 case ByteCodeInstruction::kDup2:
278 case ByteCodeInstruction::kLoad2:
279 case ByteCodeInstruction::kLoadGlobal2:
280 case ByteCodeInstruction::kReadExternal2:
281 return 2;
282
283 case ByteCodeInstruction::kDup3:
284 case ByteCodeInstruction::kLoad3:
285 case ByteCodeInstruction::kLoadGlobal3:
286 case ByteCodeInstruction::kReadExternal3:
287 return 3;
288
289 case ByteCodeInstruction::kDup4:
290 case ByteCodeInstruction::kLoad4:
291 case ByteCodeInstruction::kLoadGlobal4:
292 case ByteCodeInstruction::kReadExternal4:
293 return 4;
294
295 case ByteCodeInstruction::kDupN:
296 case ByteCodeInstruction::kLoadSwizzle:
297 case ByteCodeInstruction::kLoadSwizzleGlobal:
298 return count;
299
300 // Pushes 'count' values, minus one for the 'address' that's consumed first
301 case ByteCodeInstruction::kLoadExtended:
302 case ByteCodeInstruction::kLoadExtendedGlobal:
303 return count - 1;
304
305 // Ops that pop or store data to shrink the stack:
306 case ByteCodeInstruction::kPop:
307 case ByteCodeInstruction::kStore:
308 case ByteCodeInstruction::kStoreGlobal:
309 case ByteCodeInstruction::kWriteExternal:
310 return -1;
311
312 case ByteCodeInstruction::kPop2:
313 case ByteCodeInstruction::kStore2:
314 case ByteCodeInstruction::kStoreGlobal2:
315 case ByteCodeInstruction::kWriteExternal2:
316 return -2;
317
318 case ByteCodeInstruction::kPop3:
319 case ByteCodeInstruction::kStore3:
320 case ByteCodeInstruction::kStoreGlobal3:
321 case ByteCodeInstruction::kWriteExternal3:
322 return -3;
323
324 case ByteCodeInstruction::kPop4:
325 case ByteCodeInstruction::kStore4:
326 case ByteCodeInstruction::kStoreGlobal4:
327 case ByteCodeInstruction::kWriteExternal4:
328 return -4;
329
330 case ByteCodeInstruction::kPopN:
331 case ByteCodeInstruction::kStoreSwizzle:
332 case ByteCodeInstruction::kStoreSwizzleGlobal:
333 return -count;
334
335 // Consumes 'count' values, plus one for the 'address'
336 case ByteCodeInstruction::kStoreExtended:
337 case ByteCodeInstruction::kStoreExtendedGlobal:
338 case ByteCodeInstruction::kStoreSwizzleIndirect:
339 case ByteCodeInstruction::kStoreSwizzleIndirectGlobal:
340 return -count - 1;
341
342 // Strange ops where the caller computes the delta for us:
343 case ByteCodeInstruction::kCallExternal:
344 case ByteCodeInstruction::kMatrixToMatrix:
345 case ByteCodeInstruction::kMatrixMultiply:
346 case ByteCodeInstruction::kReserve:
347 case ByteCodeInstruction::kReturn:
348 case ByteCodeInstruction::kScalarToMatrix:
349 case ByteCodeInstruction::kSwizzle:
350 return count;
351
352 // Miscellaneous
353
354 // kCall is net-zero. Max stack depth is adjusted in writeFunctionCall.
355 case ByteCodeInstruction::kCall: return 0;
356 case ByteCodeInstruction::kBranch: return 0;
357 case ByteCodeInstruction::kBranchIfAllFalse: return 0;
358
359 case ByteCodeInstruction::kMaskPush: return -1;
360 case ByteCodeInstruction::kMaskPop: return 0;
361 case ByteCodeInstruction::kMaskNegate: return 0;
362 case ByteCodeInstruction::kMaskBlend: return -count;
363
364 case ByteCodeInstruction::kLoopBegin: return 0;
365 case ByteCodeInstruction::kLoopNext: return 0;
366 case ByteCodeInstruction::kLoopMask: return -1;
367 case ByteCodeInstruction::kLoopEnd: return 0;
368 case ByteCodeInstruction::kLoopBreak: return 0;
369 case ByteCodeInstruction::kLoopContinue: return 0;
370
371 default:
Brian Osmanc7ec9e22019-07-16 08:49:11 -0400372 ABORT("unsupported instruction %d\n", (int)inst);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400373 return 0;
374 }
375}
376
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400377int ByteCodeGenerator::getLocation(const Variable& var) {
378 // given that we seldom have more than a couple of variables, linear search is probably the most
379 // efficient way to handle lookups
380 switch (var.fStorage) {
381 case Variable::kLocal_Storage: {
382 for (int i = fLocals.size() - 1; i >= 0; --i) {
383 if (fLocals[i] == &var) {
Brian Osman1091f022019-05-16 09:42:16 -0400384 SkASSERT(fParameterCount + i <= 255);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400385 return fParameterCount + i;
386 }
387 }
388 int result = fParameterCount + fLocals.size();
389 fLocals.push_back(&var);
Brian Osman07c117b2019-05-23 12:51:06 -0700390 for (int i = 0; i < SlotCount(var.fType) - 1; ++i) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400391 fLocals.push_back(nullptr);
392 }
Brian Osman1091f022019-05-16 09:42:16 -0400393 SkASSERT(result <= 255);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400394 return result;
395 }
396 case Variable::kParameter_Storage: {
397 int offset = 0;
398 for (const auto& p : fFunction->fDeclaration.fParameters) {
399 if (p == &var) {
Brian Osman1091f022019-05-16 09:42:16 -0400400 SkASSERT(offset <= 255);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400401 return offset;
402 }
Brian Osman07c117b2019-05-23 12:51:06 -0700403 offset += SlotCount(p->fType);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400404 }
405 SkASSERT(false);
Brian Osman1091f022019-05-16 09:42:16 -0400406 return 0;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400407 }
408 case Variable::kGlobal_Storage: {
409 int offset = 0;
410 for (const auto& e : fProgram) {
411 if (e.fKind == ProgramElement::kVar_Kind) {
412 VarDeclarations& decl = (VarDeclarations&) e;
413 for (const auto& v : decl.fVars) {
414 const Variable* declVar = ((VarDeclaration&) *v).fVar;
415 if (declVar->fModifiers.fLayout.fBuiltin >= 0) {
416 continue;
417 }
418 if (declVar == &var) {
Brian Osmanb7451292019-05-15 13:02:13 -0400419 SkASSERT(offset <= 255);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400420 return offset;
421 }
Brian Osman07c117b2019-05-23 12:51:06 -0700422 offset += SlotCount(declVar->fType);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400423 }
424 }
425 }
426 SkASSERT(false);
Brian Osman1091f022019-05-16 09:42:16 -0400427 return 0;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400428 }
429 default:
430 SkASSERT(false);
431 return 0;
432 }
433}
434
Brian Osman07c117b2019-05-23 12:51:06 -0700435int ByteCodeGenerator::getLocation(const Expression& expr, Variable::Storage* storage) {
436 switch (expr.fKind) {
437 case Expression::kFieldAccess_Kind: {
438 const FieldAccess& f = (const FieldAccess&)expr;
439 int baseAddr = this->getLocation(*f.fBase, storage);
440 int offset = 0;
441 for (int i = 0; i < f.fFieldIndex; ++i) {
442 offset += SlotCount(*f.fBase->fType.fields()[i].fType);
443 }
444 if (baseAddr < 0) {
Brian Osman86769292019-06-21 11:05:47 -0400445 if (offset != 0) {
446 this->write(ByteCodeInstruction::kPushImmediate);
447 this->write32(offset);
448 this->write(ByteCodeInstruction::kAddI);
449 }
Brian Osman07c117b2019-05-23 12:51:06 -0700450 return -1;
451 } else {
452 return baseAddr + offset;
453 }
454 }
455 case Expression::kIndex_Kind: {
456 const IndexExpression& i = (const IndexExpression&)expr;
457 int stride = SlotCount(i.fType);
Brian Osmanf42de9e2019-07-18 10:25:39 -0400458 int length = i.fBase->fType.columns();
459 SkASSERT(length <= 255);
Brian Osman07c117b2019-05-23 12:51:06 -0700460 int offset = -1;
461 if (i.fIndex->isConstant()) {
Brian Osmanf42de9e2019-07-18 10:25:39 -0400462 int64_t index = i.fIndex->getConstantInt();
463 if (index < 0 || index >= length) {
464 fErrors.error(i.fIndex->fOffset, "Array index out of bounds.");
465 return 0;
466 }
467 offset = index * stride;
Brian Osman07c117b2019-05-23 12:51:06 -0700468 } else {
Brian Osman86769292019-06-21 11:05:47 -0400469 if (i.fIndex->hasSideEffects()) {
470 // Having a side-effect in an indexer is technically safe for an rvalue,
471 // but with lvalues we have to evaluate the indexer twice, so make it an error.
472 fErrors.error(i.fIndex->fOffset,
473 "Index expressions with side-effects not supported in byte code.");
474 return 0;
475 }
Brian Osman07c117b2019-05-23 12:51:06 -0700476 this->writeExpression(*i.fIndex);
Brian Osmanf42de9e2019-07-18 10:25:39 -0400477 this->write(ByteCodeInstruction::kClampIndex);
478 this->write8(length);
Brian Osman86769292019-06-21 11:05:47 -0400479 if (stride != 1) {
480 this->write(ByteCodeInstruction::kPushImmediate);
481 this->write32(stride);
482 this->write(ByteCodeInstruction::kMultiplyI);
483 }
Brian Osman07c117b2019-05-23 12:51:06 -0700484 }
485 int baseAddr = this->getLocation(*i.fBase, storage);
Brian Osman86769292019-06-21 11:05:47 -0400486
487 // Are both components known statically?
Brian Osman07c117b2019-05-23 12:51:06 -0700488 if (baseAddr >= 0 && offset >= 0) {
489 return baseAddr + offset;
490 }
Brian Osman86769292019-06-21 11:05:47 -0400491
492 // At least one component is dynamic (and on the stack).
493
494 // If the other component is zero, we're done
495 if (baseAddr == 0 || offset == 0) {
496 return -1;
497 }
498
499 // Push the non-dynamic component (if any) to the stack, then add the two
Brian Osman07c117b2019-05-23 12:51:06 -0700500 if (baseAddr >= 0) {
501 this->write(ByteCodeInstruction::kPushImmediate);
502 this->write32(baseAddr);
503 }
504 if (offset >= 0) {
505 this->write(ByteCodeInstruction::kPushImmediate);
506 this->write32(offset);
507 }
508 this->write(ByteCodeInstruction::kAddI);
509 return -1;
510 }
Brian Osman0785db02019-05-24 14:19:11 -0400511 case Expression::kSwizzle_Kind: {
512 const Swizzle& s = (const Swizzle&)expr;
513 SkASSERT(swizzle_is_simple(s));
514 int baseAddr = this->getLocation(*s.fBase, storage);
515 int offset = s.fComponents[0];
516 if (baseAddr < 0) {
Brian Osman86769292019-06-21 11:05:47 -0400517 if (offset != 0) {
518 this->write(ByteCodeInstruction::kPushImmediate);
519 this->write32(offset);
520 this->write(ByteCodeInstruction::kAddI);
521 }
Brian Osman0785db02019-05-24 14:19:11 -0400522 return -1;
523 } else {
524 return baseAddr + offset;
525 }
526 }
Brian Osman07c117b2019-05-23 12:51:06 -0700527 case Expression::kVariableReference_Kind: {
528 const Variable& var = ((const VariableReference&)expr).fVariable;
529 *storage = var.fStorage;
530 return this->getLocation(var);
531 }
532 default:
533 SkASSERT(false);
534 return 0;
535 }
536}
537
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400538void ByteCodeGenerator::write8(uint8_t b) {
539 fCode->push_back(b);
540}
541
542void ByteCodeGenerator::write16(uint16_t i) {
Mike Klein76346ac2019-05-17 11:57:10 -0500543 size_t n = fCode->size();
544 fCode->resize(n+2);
545 memcpy(fCode->data() + n, &i, 2);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400546}
547
548void ByteCodeGenerator::write32(uint32_t i) {
Mike Klein76346ac2019-05-17 11:57:10 -0500549 size_t n = fCode->size();
550 fCode->resize(n+4);
551 memcpy(fCode->data() + n, &i, 4);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400552}
553
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400554void ByteCodeGenerator::write(ByteCodeInstruction i, int count) {
Brian Osman4a47da72019-07-12 11:30:32 -0400555 switch (i) {
556 case ByteCodeInstruction::kLoopBegin: this->enterLoop(); break;
557 case ByteCodeInstruction::kLoopEnd: this->exitLoop(); break;
558
559 case ByteCodeInstruction::kMaskPush: this->enterCondition(); break;
560 case ByteCodeInstruction::kMaskPop:
561 case ByteCodeInstruction::kMaskBlend: this->exitCondition(); break;
562 default: /* Do nothing */ break;
563 }
Mike Klein108e9352019-05-21 11:05:17 -0500564 this->write16((uint16_t)i);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400565 fStackCount += StackUsage(i, count);
566 fMaxStackCount = std::max(fMaxStackCount, fStackCount);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400567}
568
Mike Klein76346ac2019-05-17 11:57:10 -0500569static ByteCodeInstruction vector_instruction(ByteCodeInstruction base, int count) {
Brian Osman07c117b2019-05-23 12:51:06 -0700570 SkASSERT(count >= 1 && count <= 4);
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400571 return ((ByteCodeInstruction) ((int) base + count - 1));
572}
573
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400574void ByteCodeGenerator::writeTypedInstruction(const Type& type, ByteCodeInstruction s,
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400575 ByteCodeInstruction u, ByteCodeInstruction f,
576 int count) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400577 switch (type_category(type)) {
578 case TypeCategory::kSigned:
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400579 this->write(vector_instruction(s, count));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400580 break;
581 case TypeCategory::kUnsigned:
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400582 this->write(vector_instruction(u, count));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400583 break;
Brian Osman1e855b22019-05-29 15:21:52 -0400584 case TypeCategory::kFloat: {
585 if (count > 4) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400586 this->write((ByteCodeInstruction)((int)f + 4), count);
Brian Osman1e855b22019-05-29 15:21:52 -0400587 this->write8(count);
588 } else {
589 this->write(vector_instruction(f, count));
590 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400591 break;
Brian Osman1e855b22019-05-29 15:21:52 -0400592 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400593 default:
594 SkASSERT(false);
595 }
596}
597
Brian Osman3e29f1d2019-05-28 09:35:05 -0400598bool ByteCodeGenerator::writeBinaryExpression(const BinaryExpression& b, bool discard) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400599 if (b.fOperator == Token::Kind::EQ) {
600 std::unique_ptr<LValue> lvalue = this->getLValue(*b.fLeft);
601 this->writeExpression(*b.fRight);
Brian Osman3e29f1d2019-05-28 09:35:05 -0400602 lvalue->store(discard);
603 discard = false;
604 return discard;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400605 }
Brian Osman16e6fd52019-05-29 11:19:00 -0400606 const Type& lType = b.fLeft->fType;
607 const Type& rType = b.fRight->fType;
Brian Osman909231c2019-05-29 15:34:36 -0400608 bool lVecOrMtx = (lType.kind() == Type::kVector_Kind || lType.kind() == Type::kMatrix_Kind);
609 bool rVecOrMtx = (rType.kind() == Type::kVector_Kind || rType.kind() == Type::kMatrix_Kind);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400610 Token::Kind op;
611 std::unique_ptr<LValue> lvalue;
612 if (is_assignment(b.fOperator)) {
613 lvalue = this->getLValue(*b.fLeft);
614 lvalue->load();
615 op = remove_assignment(b.fOperator);
616 } else {
617 this->writeExpression(*b.fLeft);
618 op = b.fOperator;
Brian Osman909231c2019-05-29 15:34:36 -0400619 if (!lVecOrMtx && rVecOrMtx) {
Brian Osman16e6fd52019-05-29 11:19:00 -0400620 for (int i = SlotCount(rType); i > 1; --i) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400621 this->write(ByteCodeInstruction::kDup);
622 }
623 }
624 }
625 this->writeExpression(*b.fRight);
Brian Osman909231c2019-05-29 15:34:36 -0400626 if (lVecOrMtx && !rVecOrMtx) {
Brian Osman16e6fd52019-05-29 11:19:00 -0400627 for (int i = SlotCount(lType); i > 1; --i) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400628 this->write(ByteCodeInstruction::kDup);
629 }
630 }
Brian Osman909231c2019-05-29 15:34:36 -0400631 // Special case for M*V, V*M, M*M (but not V*V!)
632 if (op == Token::Kind::STAR && lVecOrMtx && rVecOrMtx &&
633 !(lType.kind() == Type::kVector_Kind && rType.kind() == Type::kVector_Kind)) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400634 this->write(ByteCodeInstruction::kMatrixMultiply,
635 SlotCount(b.fType) - (SlotCount(lType) + SlotCount(rType)));
Brian Osman909231c2019-05-29 15:34:36 -0400636 int rCols = rType.columns(),
637 rRows = rType.rows(),
638 lCols = lType.columns(),
639 lRows = lType.rows();
640 // M*V treats the vector as a column
641 if (rType.kind() == Type::kVector_Kind) {
642 std::swap(rCols, rRows);
643 }
644 SkASSERT(lCols == rRows);
645 SkASSERT(SlotCount(b.fType) == lRows * rCols);
646 this->write8(lCols);
647 this->write8(lRows);
648 this->write8(rCols);
649 } else {
650 int count = std::max(SlotCount(lType), SlotCount(rType));
651 switch (op) {
652 case Token::Kind::EQEQ:
653 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareIEQ,
654 ByteCodeInstruction::kCompareIEQ,
655 ByteCodeInstruction::kCompareFEQ,
656 count);
657 // Collapse to a single bool
658 for (int i = count; i > 1; --i) {
659 this->write(ByteCodeInstruction::kAndB);
660 }
661 break;
662 case Token::Kind::GT:
663 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSGT,
664 ByteCodeInstruction::kCompareUGT,
665 ByteCodeInstruction::kCompareFGT,
666 count);
667 break;
668 case Token::Kind::GTEQ:
669 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSGTEQ,
670 ByteCodeInstruction::kCompareUGTEQ,
671 ByteCodeInstruction::kCompareFGTEQ,
672 count);
673 break;
674 case Token::Kind::LT:
675 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSLT,
676 ByteCodeInstruction::kCompareULT,
677 ByteCodeInstruction::kCompareFLT,
678 count);
679 break;
680 case Token::Kind::LTEQ:
681 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSLTEQ,
682 ByteCodeInstruction::kCompareULTEQ,
683 ByteCodeInstruction::kCompareFLTEQ,
684 count);
685 break;
686 case Token::Kind::MINUS:
687 this->writeTypedInstruction(lType, ByteCodeInstruction::kSubtractI,
688 ByteCodeInstruction::kSubtractI,
689 ByteCodeInstruction::kSubtractF,
690 count);
691 break;
692 case Token::Kind::NEQ:
693 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareINEQ,
694 ByteCodeInstruction::kCompareINEQ,
695 ByteCodeInstruction::kCompareFNEQ,
696 count);
697 // Collapse to a single bool
698 for (int i = count; i > 1; --i) {
699 this->write(ByteCodeInstruction::kOrB);
700 }
701 break;
702 case Token::Kind::PERCENT:
703 this->writeTypedInstruction(lType, ByteCodeInstruction::kRemainderS,
704 ByteCodeInstruction::kRemainderU,
705 ByteCodeInstruction::kRemainderF,
706 count);
707 break;
708 case Token::Kind::PLUS:
709 this->writeTypedInstruction(lType, ByteCodeInstruction::kAddI,
710 ByteCodeInstruction::kAddI,
711 ByteCodeInstruction::kAddF,
712 count);
713 break;
714 case Token::Kind::SLASH:
715 this->writeTypedInstruction(lType, ByteCodeInstruction::kDivideS,
716 ByteCodeInstruction::kDivideU,
717 ByteCodeInstruction::kDivideF,
718 count);
719 break;
720 case Token::Kind::STAR:
721 this->writeTypedInstruction(lType, ByteCodeInstruction::kMultiplyI,
722 ByteCodeInstruction::kMultiplyI,
723 ByteCodeInstruction::kMultiplyF,
724 count);
725 break;
Brian Osman569f12f2019-06-13 11:23:57 -0400726
727 case Token::Kind::LOGICALAND:
728 SkASSERT(type_category(lType) == SkSL::TypeCategory::kBool && count == 1);
729 this->write(ByteCodeInstruction::kAndB);
730 break;
731 case Token::Kind::LOGICALNOT:
732 SkASSERT(type_category(lType) == SkSL::TypeCategory::kBool && count == 1);
733 this->write(ByteCodeInstruction::kNotB);
734 break;
735 case Token::Kind::LOGICALOR:
736 SkASSERT(type_category(lType) == SkSL::TypeCategory::kBool && count == 1);
737 this->write(ByteCodeInstruction::kOrB);
738 break;
739 case Token::Kind::LOGICALXOR:
740 SkASSERT(type_category(lType) == SkSL::TypeCategory::kBool && count == 1);
741 this->write(ByteCodeInstruction::kXorB);
742 break;
743
Brian Osman909231c2019-05-29 15:34:36 -0400744 default:
745 SkASSERT(false);
746 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400747 }
748 if (lvalue) {
Brian Osman3e29f1d2019-05-28 09:35:05 -0400749 lvalue->store(discard);
750 discard = false;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400751 }
Brian Osman3e29f1d2019-05-28 09:35:05 -0400752 return discard;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400753}
754
755void ByteCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
756 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osman569f12f2019-06-13 11:23:57 -0400757 this->write32(b.fValue ? ~0 : 0);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400758}
759
760void ByteCodeGenerator::writeConstructor(const Constructor& c) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400761 for (const auto& arg : c.fArguments) {
762 this->writeExpression(*arg);
763 }
764 if (c.fArguments.size() == 1) {
Brian Osman29e013d2019-05-28 17:16:03 -0400765 const Type& inType = c.fArguments[0]->fType;
766 const Type& outType = c.fType;
767 TypeCategory inCategory = type_category(inType);
768 TypeCategory outCategory = type_category(outType);
769 int inCount = SlotCount(inType);
770 int outCount = SlotCount(outType);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400771 if (inCategory != outCategory) {
Brian Osmanc51d7912019-05-22 15:16:16 -0700772 SkASSERT(inCount == outCount);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400773 if (inCategory == TypeCategory::kFloat) {
774 SkASSERT(outCategory == TypeCategory::kSigned ||
775 outCategory == TypeCategory::kUnsigned);
Brian Osmanc51d7912019-05-22 15:16:16 -0700776 this->write(vector_instruction(ByteCodeInstruction::kConvertFtoI, outCount));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400777 } else if (outCategory == TypeCategory::kFloat) {
778 if (inCategory == TypeCategory::kSigned) {
Brian Osmanc51d7912019-05-22 15:16:16 -0700779 this->write(vector_instruction(ByteCodeInstruction::kConvertStoF, outCount));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400780 } else {
781 SkASSERT(inCategory == TypeCategory::kUnsigned);
Brian Osmanc51d7912019-05-22 15:16:16 -0700782 this->write(vector_instruction(ByteCodeInstruction::kConvertUtoF, outCount));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400783 }
784 } else {
785 SkASSERT(false);
786 }
787 }
Brian Osman29e013d2019-05-28 17:16:03 -0400788 if (inType.kind() == Type::kMatrix_Kind && outType.kind() == Type::kMatrix_Kind) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400789 this->write(ByteCodeInstruction::kMatrixToMatrix,
790 SlotCount(outType) - SlotCount(inType));
Brian Osman29e013d2019-05-28 17:16:03 -0400791 this->write8(inType.columns());
792 this->write8(inType.rows());
793 this->write8(outType.columns());
794 this->write8(outType.rows());
795 } else if (inCount != outCount) {
Brian Osmanc51d7912019-05-22 15:16:16 -0700796 SkASSERT(inCount == 1);
Brian Osman29e013d2019-05-28 17:16:03 -0400797 if (outType.kind() == Type::kMatrix_Kind) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400798 this->write(ByteCodeInstruction::kScalarToMatrix, SlotCount(outType) - 1);
Brian Osman29e013d2019-05-28 17:16:03 -0400799 this->write8(outType.columns());
800 this->write8(outType.rows());
801 } else {
802 SkASSERT(outType.kind() == Type::kVector_Kind);
803 for (; inCount != outCount; ++inCount) {
804 this->write(ByteCodeInstruction::kDup);
805 }
Brian Osmanc51d7912019-05-22 15:16:16 -0700806 }
807 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400808 }
809}
810
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400811void ByteCodeGenerator::writeExternalFunctionCall(const ExternalFunctionCall& f) {
812 int argumentCount = 0;
813 for (const auto& arg : f.fArguments) {
814 this->writeExpression(*arg);
Brian Osman07c117b2019-05-23 12:51:06 -0700815 argumentCount += SlotCount(arg->fType);
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400816 }
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400817 this->write(ByteCodeInstruction::kCallExternal, SlotCount(f.fType) - argumentCount);
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400818 SkASSERT(argumentCount <= 255);
819 this->write8(argumentCount);
Brian Osman07c117b2019-05-23 12:51:06 -0700820 this->write8(SlotCount(f.fType));
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400821 int index = fOutput->fExternalValues.size();
822 fOutput->fExternalValues.push_back(f.fFunction);
823 SkASSERT(index <= 255);
824 this->write8(index);
825}
826
Ethan Nicholas91164d12019-05-15 15:29:54 -0400827void ByteCodeGenerator::writeExternalValue(const ExternalValueReference& e) {
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400828 this->write(vector_instruction(ByteCodeInstruction::kReadExternal,
Brian Osman07c117b2019-05-23 12:51:06 -0700829 SlotCount(e.fValue->type())));
Ethan Nicholas91164d12019-05-15 15:29:54 -0400830 int index = fOutput->fExternalValues.size();
831 fOutput->fExternalValues.push_back(e.fValue);
832 SkASSERT(index <= 255);
833 this->write8(index);
834}
835
Brian Osman07c117b2019-05-23 12:51:06 -0700836void ByteCodeGenerator::writeVariableExpression(const Expression& expr) {
837 Variable::Storage storage;
838 int location = this->getLocation(expr, &storage);
839 bool isGlobal = storage == Variable::kGlobal_Storage;
840 int count = SlotCount(expr.fType);
841 if (location < 0 || count > 4) {
842 if (location >= 0) {
843 this->write(ByteCodeInstruction::kPushImmediate);
844 this->write32(location);
845 }
846 this->write(isGlobal ? ByteCodeInstruction::kLoadExtendedGlobal
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400847 : ByteCodeInstruction::kLoadExtended,
848 count);
Brian Osman07c117b2019-05-23 12:51:06 -0700849 this->write8(count);
850 } else {
851 this->write(vector_instruction(isGlobal ? ByteCodeInstruction::kLoadGlobal
852 : ByteCodeInstruction::kLoad,
853 count));
854 this->write8(location);
855 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400856}
857
Brian Osmand30e0392019-06-14 14:05:14 -0400858static inline uint32_t float_to_bits(float x) {
859 uint32_t u;
860 memcpy(&u, &x, sizeof(uint32_t));
861 return u;
862}
863
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400864void ByteCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
865 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osmand30e0392019-06-14 14:05:14 -0400866 this->write32(float_to_bits(f.fValue));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400867}
868
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400869void ByteCodeGenerator::writeIntrinsicCall(const FunctionCall& c) {
870 auto found = fIntrinsics.find(c.fFunction.fName);
871 if (found == fIntrinsics.end()) {
872 fErrors.error(c.fOffset, "unsupported intrinsic function");
873 return;
874 }
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400875 int count = SlotCount(c.fArguments[0]->fType);
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400876 if (found->second.fIsSpecial) {
877 SkASSERT(found->second.fValue.fSpecial == SpecialIntrinsic::kDot);
878 SkASSERT(c.fArguments.size() == 2);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400879 SkASSERT(count == SlotCount(c.fArguments[1]->fType));
880 this->write((ByteCodeInstruction)((int)ByteCodeInstruction::kMultiplyF + count - 1));
881 for (int i = count; i > 1; --i) {
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400882 this->write(ByteCodeInstruction::kAddF);
883 }
884 } else {
885 switch (found->second.fValue.fInstruction) {
886 case ByteCodeInstruction::kCos:
887 case ByteCodeInstruction::kMix:
888 case ByteCodeInstruction::kSin:
889 case ByteCodeInstruction::kSqrt:
890 case ByteCodeInstruction::kTan:
891 SkASSERT(c.fArguments.size() > 0);
892 this->write((ByteCodeInstruction) ((int) found->second.fValue.fInstruction +
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400893 count - 1));
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400894 break;
895 case ByteCodeInstruction::kCross:
896 this->write(found->second.fValue.fInstruction);
897 break;
898 default:
899 SkASSERT(false);
900 }
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400901 }
902}
903
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400904void ByteCodeGenerator::writeFunctionCall(const FunctionCall& f) {
Brian Osmand3494ed2019-06-20 15:41:34 -0400905 // Builtins have simple signatures...
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400906 if (f.fFunction.fBuiltin) {
Brian Osmand3494ed2019-06-20 15:41:34 -0400907 for (const auto& arg : f.fArguments) {
908 this->writeExpression(*arg);
909 }
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400910 this->writeIntrinsicCall(f);
911 return;
912 }
Brian Osmand3494ed2019-06-20 15:41:34 -0400913
Brian Osman6f5358f2019-07-09 14:17:23 -0400914 // Find the index of the function we're calling. We explicitly do not allow calls to functions
915 // before they're defined. This is an easy-to-understand rule that prevents recursion.
916 size_t idx;
917 for (idx = 0; idx < fFunctions.size(); ++idx) {
918 if (f.fFunction.matches(fFunctions[idx]->fDeclaration)) {
919 break;
920 }
921 }
922 if (idx > 255) {
923 fErrors.error(f.fOffset, "Function count limit exceeded");
924 return;
925 } else if (idx >= fFunctions.size()) {
926 fErrors.error(f.fOffset, "Call to undefined function");
927 return;
928 }
929
930 // We may need to deal with out parameters, so the sequence is tricky
Brian Osmand3494ed2019-06-20 15:41:34 -0400931 if (int returnCount = SlotCount(f.fType)) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400932 this->write(ByteCodeInstruction::kReserve, returnCount);
Brian Osmand3494ed2019-06-20 15:41:34 -0400933 this->write8(returnCount);
934 }
935
936 int argCount = f.fArguments.size();
937 std::vector<std::unique_ptr<LValue>> lvalues;
938 for (int i = 0; i < argCount; ++i) {
939 const auto& param = f.fFunction.fParameters[i];
940 const auto& arg = f.fArguments[i];
941 if (param->fModifiers.fFlags & Modifiers::kOut_Flag) {
942 lvalues.emplace_back(this->getLValue(*arg));
943 lvalues.back()->load();
944 } else {
945 this->writeExpression(*arg);
946 }
947 }
948
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400949 // The space used by the call is based on the callee, but it also unwinds all of that before
950 // we continue execution. We adjust our max stack depths below.
Brian Osman226668a2019-05-14 16:47:30 -0400951 this->write(ByteCodeInstruction::kCall);
Brian Osman6f5358f2019-07-09 14:17:23 -0400952 this->write8(idx);
Brian Osmand3494ed2019-06-20 15:41:34 -0400953
Brian Osman4a47da72019-07-12 11:30:32 -0400954 const ByteCodeFunction* callee = fOutput->fFunctions[idx].get();
955 fMaxLoopCount = std::max(fMaxLoopCount, fLoopCount + callee->fLoopCount);
956 fMaxConditionCount = std::max(fMaxConditionCount, fConditionCount + callee->fConditionCount);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400957 fMaxStackCount = std::max(fMaxStackCount, fStackCount + callee->fLocalCount
958 + callee->fStackCount);
Brian Osman4a47da72019-07-12 11:30:32 -0400959
Brian Osmand3494ed2019-06-20 15:41:34 -0400960 // After the called function returns, the stack will still contain our arguments. We have to
961 // pop them (storing any out parameters back to their lvalues as we go). We glob together slot
962 // counts for all parameters that aren't out-params, so we can pop them in one big chunk.
963 int popCount = 0;
964 auto pop = [&]() {
965 if (popCount > 4) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400966 this->write(ByteCodeInstruction::kPopN, popCount);
Brian Osmand3494ed2019-06-20 15:41:34 -0400967 this->write8(popCount);
968 } else if (popCount > 0) {
969 this->write(vector_instruction(ByteCodeInstruction::kPop, popCount));
970 }
971 popCount = 0;
972 };
973
974 for (int i = argCount - 1; i >= 0; --i) {
975 const auto& param = f.fFunction.fParameters[i];
976 const auto& arg = f.fArguments[i];
977 if (param->fModifiers.fFlags & Modifiers::kOut_Flag) {
978 pop();
979 lvalues.back()->store(true);
980 lvalues.pop_back();
981 } else {
982 popCount += SlotCount(arg->fType);
983 }
984 }
985 pop();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400986}
987
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400988void ByteCodeGenerator::writeIntLiteral(const IntLiteral& i) {
989 this->write(ByteCodeInstruction::kPushImmediate);
990 this->write32(i.fValue);
991}
992
993void ByteCodeGenerator::writeNullLiteral(const NullLiteral& n) {
994 // not yet implemented
995 abort();
996}
997
Brian Osman3e29f1d2019-05-28 09:35:05 -0400998bool ByteCodeGenerator::writePrefixExpression(const PrefixExpression& p, bool discard) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400999 switch (p.fOperator) {
1000 case Token::Kind::PLUSPLUS: // fall through
1001 case Token::Kind::MINUSMINUS: {
Brian Osman07c117b2019-05-23 12:51:06 -07001002 SkASSERT(SlotCount(p.fOperand->fType) == 1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001003 std::unique_ptr<LValue> lvalue = this->getLValue(*p.fOperand);
1004 lvalue->load();
1005 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osmand30e0392019-06-14 14:05:14 -04001006 this->write32(type_category(p.fType) == TypeCategory::kFloat ? float_to_bits(1.0f) : 1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001007 if (p.fOperator == Token::Kind::PLUSPLUS) {
1008 this->writeTypedInstruction(p.fType,
1009 ByteCodeInstruction::kAddI,
1010 ByteCodeInstruction::kAddI,
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001011 ByteCodeInstruction::kAddF,
1012 1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001013 } else {
1014 this->writeTypedInstruction(p.fType,
1015 ByteCodeInstruction::kSubtractI,
1016 ByteCodeInstruction::kSubtractI,
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001017 ByteCodeInstruction::kSubtractF,
1018 1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001019 }
Brian Osman3e29f1d2019-05-28 09:35:05 -04001020 lvalue->store(discard);
1021 discard = false;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001022 break;
1023 }
Ethan Nicholas354ecf32019-05-07 16:13:02 -04001024 case Token::Kind::MINUS: {
1025 this->writeExpression(*p.fOperand);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001026 this->writeTypedInstruction(p.fType,
Mike Klein12710912019-05-21 11:04:59 -05001027 ByteCodeInstruction::kNegateI,
1028 ByteCodeInstruction::kNegateI,
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001029 ByteCodeInstruction::kNegateF,
Brian Osman07c117b2019-05-23 12:51:06 -07001030 SlotCount(p.fOperand->fType));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001031 break;
Ethan Nicholas354ecf32019-05-07 16:13:02 -04001032 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001033 default:
1034 SkASSERT(false);
1035 }
Brian Osman3e29f1d2019-05-28 09:35:05 -04001036 return discard;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001037}
1038
Brian Osman3e29f1d2019-05-28 09:35:05 -04001039bool ByteCodeGenerator::writePostfixExpression(const PostfixExpression& p, bool discard) {
Brian Osmanf3fa6002019-05-17 14:26:53 -04001040 switch (p.fOperator) {
1041 case Token::Kind::PLUSPLUS: // fall through
1042 case Token::Kind::MINUSMINUS: {
Brian Osman07c117b2019-05-23 12:51:06 -07001043 SkASSERT(SlotCount(p.fOperand->fType) == 1);
Brian Osmanf3fa6002019-05-17 14:26:53 -04001044 std::unique_ptr<LValue> lvalue = this->getLValue(*p.fOperand);
1045 lvalue->load();
Brian Osman3e29f1d2019-05-28 09:35:05 -04001046 if (!discard) {
1047 this->write(ByteCodeInstruction::kDup);
1048 }
Brian Osmanf3fa6002019-05-17 14:26:53 -04001049 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osmand30e0392019-06-14 14:05:14 -04001050 this->write32(type_category(p.fType) == TypeCategory::kFloat ? float_to_bits(1.0f) : 1);
Brian Osmanf3fa6002019-05-17 14:26:53 -04001051 if (p.fOperator == Token::Kind::PLUSPLUS) {
1052 this->writeTypedInstruction(p.fType,
1053 ByteCodeInstruction::kAddI,
1054 ByteCodeInstruction::kAddI,
1055 ByteCodeInstruction::kAddF,
1056 1);
1057 } else {
1058 this->writeTypedInstruction(p.fType,
1059 ByteCodeInstruction::kSubtractI,
1060 ByteCodeInstruction::kSubtractI,
1061 ByteCodeInstruction::kSubtractF,
1062 1);
1063 }
Brian Osman3e29f1d2019-05-28 09:35:05 -04001064 lvalue->store(discard);
Brian Osmanf3fa6002019-05-17 14:26:53 -04001065 this->write(ByteCodeInstruction::kPop);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001066 discard = false;
Brian Osmanf3fa6002019-05-17 14:26:53 -04001067 break;
1068 }
1069 default:
1070 SkASSERT(false);
1071 }
Brian Osman3e29f1d2019-05-28 09:35:05 -04001072 return discard;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001073}
1074
1075void ByteCodeGenerator::writeSwizzle(const Swizzle& s) {
Brian Osman0785db02019-05-24 14:19:11 -04001076 if (swizzle_is_simple(s)) {
1077 this->writeVariableExpression(s);
1078 return;
1079 }
1080
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001081 switch (s.fBase->fKind) {
1082 case Expression::kVariableReference_Kind: {
1083 const Variable& var = ((VariableReference&) *s.fBase).fVariable;
Brian Osman1091f022019-05-16 09:42:16 -04001084 this->write(var.fStorage == Variable::kGlobal_Storage
1085 ? ByteCodeInstruction::kLoadSwizzleGlobal
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001086 : ByteCodeInstruction::kLoadSwizzle,
1087 s.fComponents.size());
Brian Osman1091f022019-05-16 09:42:16 -04001088 this->write8(this->getLocation(var));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001089 this->write8(s.fComponents.size());
1090 for (int c : s.fComponents) {
1091 this->write8(c);
1092 }
1093 break;
1094 }
1095 default:
1096 this->writeExpression(*s.fBase);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001097 this->write(ByteCodeInstruction::kSwizzle,
1098 s.fComponents.size() - s.fBase->fType.columns());
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001099 this->write8(s.fBase->fType.columns());
1100 this->write8(s.fComponents.size());
1101 for (int c : s.fComponents) {
1102 this->write8(c);
1103 }
1104 }
1105}
1106
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001107void ByteCodeGenerator::writeTernaryExpression(const TernaryExpression& t) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001108 int count = SlotCount(t.fType);
1109 SkASSERT(count == SlotCount(t.fIfTrue->fType));
1110 SkASSERT(count == SlotCount(t.fIfFalse->fType));
1111
Brian Osman4e93feb2019-05-16 15:38:00 -04001112 this->writeExpression(*t.fTest);
Brian Osman569f12f2019-06-13 11:23:57 -04001113 this->write(ByteCodeInstruction::kMaskPush);
Brian Osman4e93feb2019-05-16 15:38:00 -04001114 this->writeExpression(*t.fIfTrue);
Brian Osman569f12f2019-06-13 11:23:57 -04001115 this->write(ByteCodeInstruction::kMaskNegate);
1116 this->writeExpression(*t.fIfFalse);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001117 this->write(ByteCodeInstruction::kMaskBlend, count);
1118 this->write8(count);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001119}
1120
Brian Osman3e29f1d2019-05-28 09:35:05 -04001121void ByteCodeGenerator::writeExpression(const Expression& e, bool discard) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001122 switch (e.fKind) {
1123 case Expression::kBinary_Kind:
Brian Osman3e29f1d2019-05-28 09:35:05 -04001124 discard = this->writeBinaryExpression((BinaryExpression&) e, discard);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001125 break;
1126 case Expression::kBoolLiteral_Kind:
1127 this->writeBoolLiteral((BoolLiteral&) e);
1128 break;
1129 case Expression::kConstructor_Kind:
1130 this->writeConstructor((Constructor&) e);
1131 break;
Ethan Nicholas9e6a3932019-05-17 16:31:21 -04001132 case Expression::kExternalFunctionCall_Kind:
1133 this->writeExternalFunctionCall((ExternalFunctionCall&) e);
1134 break;
Ethan Nicholas91164d12019-05-15 15:29:54 -04001135 case Expression::kExternalValue_Kind:
1136 this->writeExternalValue((ExternalValueReference&) e);
1137 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001138 case Expression::kFieldAccess_Kind:
Brian Osman07c117b2019-05-23 12:51:06 -07001139 case Expression::kIndex_Kind:
1140 case Expression::kVariableReference_Kind:
1141 this->writeVariableExpression(e);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001142 break;
1143 case Expression::kFloatLiteral_Kind:
1144 this->writeFloatLiteral((FloatLiteral&) e);
1145 break;
1146 case Expression::kFunctionCall_Kind:
1147 this->writeFunctionCall((FunctionCall&) e);
1148 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001149 case Expression::kIntLiteral_Kind:
1150 this->writeIntLiteral((IntLiteral&) e);
1151 break;
1152 case Expression::kNullLiteral_Kind:
1153 this->writeNullLiteral((NullLiteral&) e);
1154 break;
1155 case Expression::kPrefix_Kind:
Brian Osman3e29f1d2019-05-28 09:35:05 -04001156 discard = this->writePrefixExpression((PrefixExpression&) e, discard);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001157 break;
1158 case Expression::kPostfix_Kind:
Brian Osman3e29f1d2019-05-28 09:35:05 -04001159 discard = this->writePostfixExpression((PostfixExpression&) e, discard);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001160 break;
1161 case Expression::kSwizzle_Kind:
1162 this->writeSwizzle((Swizzle&) e);
1163 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001164 case Expression::kTernary_Kind:
1165 this->writeTernaryExpression((TernaryExpression&) e);
1166 break;
1167 default:
1168 printf("unsupported expression %s\n", e.description().c_str());
1169 SkASSERT(false);
1170 }
Brian Osman3e29f1d2019-05-28 09:35:05 -04001171 if (discard) {
1172 int count = SlotCount(e.fType);
1173 if (count > 4) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001174 this->write(ByteCodeInstruction::kPopN, count);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001175 this->write8(count);
Brian Osmanfba386b2019-06-20 14:54:15 -04001176 } else if (count != 0) {
Brian Osman3e29f1d2019-05-28 09:35:05 -04001177 this->write(vector_instruction(ByteCodeInstruction::kPop, count));
1178 }
1179 discard = false;
1180 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001181}
1182
Ethan Nicholas91164d12019-05-15 15:29:54 -04001183class ByteCodeExternalValueLValue : public ByteCodeGenerator::LValue {
1184public:
1185 ByteCodeExternalValueLValue(ByteCodeGenerator* generator, ExternalValue& value, int index)
1186 : INHERITED(*generator)
Brian Osman07c117b2019-05-23 12:51:06 -07001187 , fCount(ByteCodeGenerator::SlotCount(value.type()))
Ethan Nicholas91164d12019-05-15 15:29:54 -04001188 , fIndex(index) {}
1189
1190 void load() override {
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001191 fGenerator.write(vector_instruction(ByteCodeInstruction::kReadExternal, fCount));
Ethan Nicholas91164d12019-05-15 15:29:54 -04001192 fGenerator.write8(fIndex);
1193 }
1194
Brian Osman3e29f1d2019-05-28 09:35:05 -04001195 void store(bool discard) override {
1196 if (!discard) {
1197 fGenerator.write(vector_instruction(ByteCodeInstruction::kDup, fCount));
1198 }
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001199 fGenerator.write(vector_instruction(ByteCodeInstruction::kWriteExternal, fCount));
Ethan Nicholas91164d12019-05-15 15:29:54 -04001200 fGenerator.write8(fIndex);
1201 }
1202
1203private:
1204 typedef LValue INHERITED;
1205
1206 int fCount;
1207
1208 int fIndex;
1209};
1210
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001211class ByteCodeSwizzleLValue : public ByteCodeGenerator::LValue {
1212public:
1213 ByteCodeSwizzleLValue(ByteCodeGenerator* generator, const Swizzle& swizzle)
1214 : INHERITED(*generator)
Brian Osman07c117b2019-05-23 12:51:06 -07001215 , fSwizzle(swizzle) {}
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001216
1217 void load() override {
Brian Osman1091f022019-05-16 09:42:16 -04001218 fGenerator.writeSwizzle(fSwizzle);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001219 }
1220
Brian Osman3e29f1d2019-05-28 09:35:05 -04001221 void store(bool discard) override {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001222 int count = fSwizzle.fComponents.size();
Brian Osman3e29f1d2019-05-28 09:35:05 -04001223 if (!discard) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001224 fGenerator.write(vector_instruction(ByteCodeInstruction::kDup, count));
Brian Osman3e29f1d2019-05-28 09:35:05 -04001225 }
Brian Osman07c117b2019-05-23 12:51:06 -07001226 Variable::Storage storage;
1227 int location = fGenerator.getLocation(*fSwizzle.fBase, &storage);
1228 bool isGlobal = storage == Variable::kGlobal_Storage;
1229 if (location < 0) {
1230 fGenerator.write(isGlobal ? ByteCodeInstruction::kStoreSwizzleIndirectGlobal
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001231 : ByteCodeInstruction::kStoreSwizzleIndirect,
1232 count);
Brian Osman07c117b2019-05-23 12:51:06 -07001233 } else {
1234 fGenerator.write(isGlobal ? ByteCodeInstruction::kStoreSwizzleGlobal
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001235 : ByteCodeInstruction::kStoreSwizzle,
1236 count);
Brian Osman07c117b2019-05-23 12:51:06 -07001237 fGenerator.write8(location);
1238 }
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001239 fGenerator.write8(count);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001240 for (int c : fSwizzle.fComponents) {
1241 fGenerator.write8(c);
1242 }
1243 }
1244
1245private:
1246 const Swizzle& fSwizzle;
1247
1248 typedef LValue INHERITED;
1249};
1250
Brian Osman07c117b2019-05-23 12:51:06 -07001251class ByteCodeExpressionLValue : public ByteCodeGenerator::LValue {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001252public:
Brian Osman07c117b2019-05-23 12:51:06 -07001253 ByteCodeExpressionLValue(ByteCodeGenerator* generator, const Expression& expr)
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001254 : INHERITED(*generator)
Brian Osman07c117b2019-05-23 12:51:06 -07001255 , fExpression(expr) {}
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001256
1257 void load() override {
Brian Osman07c117b2019-05-23 12:51:06 -07001258 fGenerator.writeVariableExpression(fExpression);
Brian Osman1091f022019-05-16 09:42:16 -04001259 }
1260
Brian Osman3e29f1d2019-05-28 09:35:05 -04001261 void store(bool discard) override {
Brian Osman07c117b2019-05-23 12:51:06 -07001262 int count = ByteCodeGenerator::SlotCount(fExpression.fType);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001263 if (!discard) {
1264 if (count > 4) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001265 fGenerator.write(ByteCodeInstruction::kDupN, count);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001266 fGenerator.write8(count);
1267 } else {
1268 fGenerator.write(vector_instruction(ByteCodeInstruction::kDup, count));
1269 }
Brian Osman07c117b2019-05-23 12:51:06 -07001270 }
1271 Variable::Storage storage;
1272 int location = fGenerator.getLocation(fExpression, &storage);
1273 bool isGlobal = storage == Variable::kGlobal_Storage;
1274 if (location < 0 || count > 4) {
1275 if (location >= 0) {
1276 fGenerator.write(ByteCodeInstruction::kPushImmediate);
1277 fGenerator.write32(location);
1278 }
1279 fGenerator.write(isGlobal ? ByteCodeInstruction::kStoreExtendedGlobal
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001280 : ByteCodeInstruction::kStoreExtended,
1281 count);
Brian Osman07c117b2019-05-23 12:51:06 -07001282 fGenerator.write8(count);
1283 } else {
1284 fGenerator.write(vector_instruction(isGlobal ? ByteCodeInstruction::kStoreGlobal
1285 : ByteCodeInstruction::kStore,
1286 count));
1287 fGenerator.write8(location);
1288 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001289 }
1290
1291private:
1292 typedef LValue INHERITED;
1293
Brian Osman07c117b2019-05-23 12:51:06 -07001294 const Expression& fExpression;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001295};
1296
1297std::unique_ptr<ByteCodeGenerator::LValue> ByteCodeGenerator::getLValue(const Expression& e) {
1298 switch (e.fKind) {
Ethan Nicholas91164d12019-05-15 15:29:54 -04001299 case Expression::kExternalValue_Kind: {
1300 ExternalValue* value = ((ExternalValueReference&) e).fValue;
1301 int index = fOutput->fExternalValues.size();
1302 fOutput->fExternalValues.push_back(value);
1303 SkASSERT(index <= 255);
1304 return std::unique_ptr<LValue>(new ByteCodeExternalValueLValue(this, *value, index));
1305 }
Brian Osman07c117b2019-05-23 12:51:06 -07001306 case Expression::kFieldAccess_Kind:
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001307 case Expression::kIndex_Kind:
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001308 case Expression::kVariableReference_Kind:
Brian Osman07c117b2019-05-23 12:51:06 -07001309 return std::unique_ptr<LValue>(new ByteCodeExpressionLValue(this, e));
Brian Osman0785db02019-05-24 14:19:11 -04001310 case Expression::kSwizzle_Kind: {
1311 const Swizzle& s = (const Swizzle&) e;
1312 return swizzle_is_simple(s)
1313 ? std::unique_ptr<LValue>(new ByteCodeExpressionLValue(this, e))
1314 : std::unique_ptr<LValue>(new ByteCodeSwizzleLValue(this, s));
1315 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001316 case Expression::kTernary_Kind:
1317 default:
1318 printf("unsupported lvalue %s\n", e.description().c_str());
1319 return nullptr;
1320 }
1321}
1322
1323void ByteCodeGenerator::writeBlock(const Block& b) {
1324 for (const auto& s : b.fStatements) {
1325 this->writeStatement(*s);
1326 }
1327}
1328
1329void ByteCodeGenerator::setBreakTargets() {
1330 std::vector<DeferredLocation>& breaks = fBreakTargets.top();
1331 for (DeferredLocation& b : breaks) {
1332 b.set();
1333 }
1334 fBreakTargets.pop();
1335}
1336
1337void ByteCodeGenerator::setContinueTargets() {
1338 std::vector<DeferredLocation>& continues = fContinueTargets.top();
1339 for (DeferredLocation& c : continues) {
1340 c.set();
1341 }
1342 fContinueTargets.pop();
1343}
1344
1345void ByteCodeGenerator::writeBreakStatement(const BreakStatement& b) {
Brian Osman569f12f2019-06-13 11:23:57 -04001346 // TODO: Include BranchIfAllFalse to top-most LoopNext
1347 this->write(ByteCodeInstruction::kLoopBreak);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001348}
1349
1350void ByteCodeGenerator::writeContinueStatement(const ContinueStatement& c) {
Brian Osman569f12f2019-06-13 11:23:57 -04001351 // TODO: Include BranchIfAllFalse to top-most LoopNext
1352 this->write(ByteCodeInstruction::kLoopContinue);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001353}
1354
1355void ByteCodeGenerator::writeDoStatement(const DoStatement& d) {
Brian Osman569f12f2019-06-13 11:23:57 -04001356 this->write(ByteCodeInstruction::kLoopBegin);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001357 size_t start = fCode->size();
1358 this->writeStatement(*d.fStatement);
Brian Osman569f12f2019-06-13 11:23:57 -04001359 this->write(ByteCodeInstruction::kLoopNext);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001360 this->writeExpression(*d.fTest);
Brian Osman569f12f2019-06-13 11:23:57 -04001361 this->write(ByteCodeInstruction::kLoopMask);
1362 // TODO: Could shorten this with kBranchIfAnyTrue
1363 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1364 DeferredLocation endLocation(this);
1365 this->write(ByteCodeInstruction::kBranch);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001366 this->write16(start);
Brian Osman569f12f2019-06-13 11:23:57 -04001367 endLocation.set();
1368 this->write(ByteCodeInstruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001369}
1370
1371void ByteCodeGenerator::writeForStatement(const ForStatement& f) {
1372 fContinueTargets.emplace();
1373 fBreakTargets.emplace();
1374 if (f.fInitializer) {
1375 this->writeStatement(*f.fInitializer);
1376 }
Brian Osman569f12f2019-06-13 11:23:57 -04001377 this->write(ByteCodeInstruction::kLoopBegin);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001378 size_t start = fCode->size();
1379 if (f.fTest) {
1380 this->writeExpression(*f.fTest);
Brian Osman569f12f2019-06-13 11:23:57 -04001381 this->write(ByteCodeInstruction::kLoopMask);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001382 }
Brian Osman569f12f2019-06-13 11:23:57 -04001383 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1384 DeferredLocation endLocation(this);
1385 this->writeStatement(*f.fStatement);
1386 this->write(ByteCodeInstruction::kLoopNext);
1387 if (f.fNext) {
1388 this->writeExpression(*f.fNext, true);
1389 }
1390 this->write(ByteCodeInstruction::kBranch);
1391 this->write16(start);
1392 endLocation.set();
1393 this->write(ByteCodeInstruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001394}
1395
1396void ByteCodeGenerator::writeIfStatement(const IfStatement& i) {
Brian Osman569f12f2019-06-13 11:23:57 -04001397 this->writeExpression(*i.fTest);
1398 this->write(ByteCodeInstruction::kMaskPush);
1399 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1400 DeferredLocation falseLocation(this);
1401 this->writeStatement(*i.fIfTrue);
1402 falseLocation.set();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001403 if (i.fIfFalse) {
Brian Osman569f12f2019-06-13 11:23:57 -04001404 this->write(ByteCodeInstruction::kMaskNegate);
1405 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1406 DeferredLocation endLocation(this);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001407 this->writeStatement(*i.fIfFalse);
Mike Kleinb45ee832019-05-17 11:11:11 -05001408 endLocation.set();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001409 }
Brian Osman569f12f2019-06-13 11:23:57 -04001410 this->write(ByteCodeInstruction::kMaskPop);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001411}
1412
1413void ByteCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
Brian Osman4a47da72019-07-12 11:30:32 -04001414 if (fLoopCount || fConditionCount) {
1415 fErrors.error(r.fOffset, "return not allowed inside conditional or loop");
1416 return;
1417 }
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001418 int count = SlotCount(r.fExpression->fType);
Ethan Nicholas746035a2019-04-23 13:31:09 -04001419 this->writeExpression(*r.fExpression);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001420
1421 // Technically, the kReturn also pops fOutput->fLocalCount values from the stack, too, but we
1422 // haven't counted pushing those (they're outside the scope of our stack tracking). Instead,
1423 // we account for those in writeFunction().
1424
1425 // This is all fine because we don't allow conditional returns, so we only return once anyway.
1426 this->write(ByteCodeInstruction::kReturn, -count);
1427 this->write8(count);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001428}
1429
1430void ByteCodeGenerator::writeSwitchStatement(const SwitchStatement& r) {
1431 // not yet implemented
1432 abort();
1433}
1434
1435void ByteCodeGenerator::writeVarDeclarations(const VarDeclarations& v) {
1436 for (const auto& declStatement : v.fVars) {
1437 const VarDeclaration& decl = (VarDeclaration&) *declStatement;
1438 // we need to grab the location even if we don't use it, to ensure it
1439 // has been allocated
1440 int location = getLocation(*decl.fVar);
1441 if (decl.fValue) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001442 this->writeExpression(*decl.fValue);
Brian Osman07c117b2019-05-23 12:51:06 -07001443 int count = SlotCount(decl.fValue->fType);
1444 if (count > 4) {
1445 this->write(ByteCodeInstruction::kPushImmediate);
1446 this->write32(location);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001447 this->write(ByteCodeInstruction::kStoreExtended, count);
Brian Osman07c117b2019-05-23 12:51:06 -07001448 this->write8(count);
1449 } else {
1450 this->write(vector_instruction(ByteCodeInstruction::kStore, count));
1451 this->write8(location);
1452 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001453 }
1454 }
1455}
1456
1457void ByteCodeGenerator::writeWhileStatement(const WhileStatement& w) {
Brian Osman569f12f2019-06-13 11:23:57 -04001458 this->write(ByteCodeInstruction::kLoopBegin);
1459 size_t cond = fCode->size();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001460 this->writeExpression(*w.fTest);
Brian Osman569f12f2019-06-13 11:23:57 -04001461 this->write(ByteCodeInstruction::kLoopMask);
1462 this->write(ByteCodeInstruction::kBranchIfAllFalse);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001463 DeferredLocation endLocation(this);
1464 this->writeStatement(*w.fStatement);
Brian Osman569f12f2019-06-13 11:23:57 -04001465 this->write(ByteCodeInstruction::kLoopNext);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001466 this->write(ByteCodeInstruction::kBranch);
Brian Osman569f12f2019-06-13 11:23:57 -04001467 this->write16(cond);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001468 endLocation.set();
Brian Osman569f12f2019-06-13 11:23:57 -04001469 this->write(ByteCodeInstruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001470}
1471
1472void ByteCodeGenerator::writeStatement(const Statement& s) {
1473 switch (s.fKind) {
1474 case Statement::kBlock_Kind:
1475 this->writeBlock((Block&) s);
1476 break;
1477 case Statement::kBreak_Kind:
1478 this->writeBreakStatement((BreakStatement&) s);
1479 break;
1480 case Statement::kContinue_Kind:
1481 this->writeContinueStatement((ContinueStatement&) s);
1482 break;
1483 case Statement::kDiscard_Kind:
1484 // not yet implemented
1485 abort();
1486 case Statement::kDo_Kind:
1487 this->writeDoStatement((DoStatement&) s);
1488 break;
Brian Osman3e29f1d2019-05-28 09:35:05 -04001489 case Statement::kExpression_Kind:
1490 this->writeExpression(*((ExpressionStatement&) s).fExpression, true);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001491 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001492 case Statement::kFor_Kind:
1493 this->writeForStatement((ForStatement&) s);
1494 break;
1495 case Statement::kIf_Kind:
1496 this->writeIfStatement((IfStatement&) s);
1497 break;
1498 case Statement::kNop_Kind:
1499 break;
1500 case Statement::kReturn_Kind:
1501 this->writeReturnStatement((ReturnStatement&) s);
1502 break;
1503 case Statement::kSwitch_Kind:
1504 this->writeSwitchStatement((SwitchStatement&) s);
1505 break;
1506 case Statement::kVarDeclarations_Kind:
1507 this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration);
1508 break;
1509 case Statement::kWhile_Kind:
1510 this->writeWhileStatement((WhileStatement&) s);
1511 break;
1512 default:
1513 SkASSERT(false);
1514 }
1515}
1516
Brian Osman80164412019-06-07 13:00:23 -04001517ByteCodeFunction::ByteCodeFunction(const FunctionDeclaration* declaration)
1518 : fName(declaration->fName) {
1519 fParameterCount = 0;
1520 for (const auto& p : declaration->fParameters) {
1521 int slots = ByteCodeGenerator::SlotCount(p->fType);
1522 fParameters.push_back({ slots, (bool)(p->fModifiers.fFlags & Modifiers::kOut_Flag) });
1523 fParameterCount += slots;
1524 }
1525}
1526
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001527}