blob: 4b57673d889f0dd71b65bfefd7df7bb86c4fca98 [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
206 case ByteCodeInstruction::kNotB: return 0;
207 case ByteCodeInstruction::kNegateFN: return 0;
208
209#undef VECTOR_UNARY_OP
210
211 // Binary functions/operators that do a 2 -> 1 reduction (possibly N times)
212#define VECTOR_BINARY_OP(base) \
213 case ByteCodeInstruction::base: return -1; \
214 case ByteCodeInstruction::base ## 2: return -2; \
215 case ByteCodeInstruction::base ## 3: return -3; \
216 case ByteCodeInstruction::base ## 4: return -4;
217
218#define VECTOR_MATRIX_BINARY_OP(base) \
219 VECTOR_BINARY_OP(base) \
220 case ByteCodeInstruction::base ## N: return -count;
221
222 case ByteCodeInstruction::kAndB: return -1;
223 case ByteCodeInstruction::kOrB: return -1;
224 case ByteCodeInstruction::kXorB: return -1;
225
226 VECTOR_BINARY_OP(kAddI)
227 VECTOR_MATRIX_BINARY_OP(kAddF)
228
229 VECTOR_BINARY_OP(kCompareIEQ)
230 VECTOR_MATRIX_BINARY_OP(kCompareFEQ)
231 VECTOR_BINARY_OP(kCompareINEQ)
232 VECTOR_MATRIX_BINARY_OP(kCompareFNEQ)
233 VECTOR_BINARY_OP(kCompareSGT)
234 VECTOR_BINARY_OP(kCompareUGT)
235 VECTOR_BINARY_OP(kCompareFGT)
236 VECTOR_BINARY_OP(kCompareSGTEQ)
237 VECTOR_BINARY_OP(kCompareUGTEQ)
238 VECTOR_BINARY_OP(kCompareFGTEQ)
239 VECTOR_BINARY_OP(kCompareSLT)
240 VECTOR_BINARY_OP(kCompareULT)
241 VECTOR_BINARY_OP(kCompareFLT)
242 VECTOR_BINARY_OP(kCompareSLTEQ)
243 VECTOR_BINARY_OP(kCompareULTEQ)
244 VECTOR_BINARY_OP(kCompareFLTEQ)
245
246 VECTOR_BINARY_OP(kDivideS)
247 VECTOR_BINARY_OP(kDivideU)
248 VECTOR_MATRIX_BINARY_OP(kDivideF)
249 VECTOR_BINARY_OP(kMultiplyI)
250 VECTOR_MATRIX_BINARY_OP(kMultiplyF)
251 VECTOR_BINARY_OP(kRemainderF)
252 VECTOR_BINARY_OP(kRemainderS)
253 VECTOR_BINARY_OP(kRemainderU)
254 VECTOR_BINARY_OP(kSubtractI)
255 VECTOR_MATRIX_BINARY_OP(kSubtractF)
256
257#undef VECTOR_BINARY_OP
258#undef VECTOR_MATRIX_BINARY_OP
259
260 // Strange math operations with other behavior:
261 case ByteCodeInstruction::kCross: return -3;
262 // Binary, but also consumes T:
263 case ByteCodeInstruction::kMix: return -2;
264 case ByteCodeInstruction::kMix2: return -3;
265 case ByteCodeInstruction::kMix3: return -4;
266 case ByteCodeInstruction::kMix4: return -5;
267
268 // Ops that push or load data to grow the stack:
269 case ByteCodeInstruction::kDup:
270 case ByteCodeInstruction::kLoad:
271 case ByteCodeInstruction::kLoadGlobal:
272 case ByteCodeInstruction::kReadExternal:
273 case ByteCodeInstruction::kPushImmediate:
274 return 1;
275
276 case ByteCodeInstruction::kDup2:
277 case ByteCodeInstruction::kLoad2:
278 case ByteCodeInstruction::kLoadGlobal2:
279 case ByteCodeInstruction::kReadExternal2:
280 return 2;
281
282 case ByteCodeInstruction::kDup3:
283 case ByteCodeInstruction::kLoad3:
284 case ByteCodeInstruction::kLoadGlobal3:
285 case ByteCodeInstruction::kReadExternal3:
286 return 3;
287
288 case ByteCodeInstruction::kDup4:
289 case ByteCodeInstruction::kLoad4:
290 case ByteCodeInstruction::kLoadGlobal4:
291 case ByteCodeInstruction::kReadExternal4:
292 return 4;
293
294 case ByteCodeInstruction::kDupN:
295 case ByteCodeInstruction::kLoadSwizzle:
296 case ByteCodeInstruction::kLoadSwizzleGlobal:
297 return count;
298
299 // Pushes 'count' values, minus one for the 'address' that's consumed first
300 case ByteCodeInstruction::kLoadExtended:
301 case ByteCodeInstruction::kLoadExtendedGlobal:
302 return count - 1;
303
304 // Ops that pop or store data to shrink the stack:
305 case ByteCodeInstruction::kPop:
306 case ByteCodeInstruction::kStore:
307 case ByteCodeInstruction::kStoreGlobal:
308 case ByteCodeInstruction::kWriteExternal:
309 return -1;
310
311 case ByteCodeInstruction::kPop2:
312 case ByteCodeInstruction::kStore2:
313 case ByteCodeInstruction::kStoreGlobal2:
314 case ByteCodeInstruction::kWriteExternal2:
315 return -2;
316
317 case ByteCodeInstruction::kPop3:
318 case ByteCodeInstruction::kStore3:
319 case ByteCodeInstruction::kStoreGlobal3:
320 case ByteCodeInstruction::kWriteExternal3:
321 return -3;
322
323 case ByteCodeInstruction::kPop4:
324 case ByteCodeInstruction::kStore4:
325 case ByteCodeInstruction::kStoreGlobal4:
326 case ByteCodeInstruction::kWriteExternal4:
327 return -4;
328
329 case ByteCodeInstruction::kPopN:
330 case ByteCodeInstruction::kStoreSwizzle:
331 case ByteCodeInstruction::kStoreSwizzleGlobal:
332 return -count;
333
334 // Consumes 'count' values, plus one for the 'address'
335 case ByteCodeInstruction::kStoreExtended:
336 case ByteCodeInstruction::kStoreExtendedGlobal:
337 case ByteCodeInstruction::kStoreSwizzleIndirect:
338 case ByteCodeInstruction::kStoreSwizzleIndirectGlobal:
339 return -count - 1;
340
341 // Strange ops where the caller computes the delta for us:
342 case ByteCodeInstruction::kCallExternal:
343 case ByteCodeInstruction::kMatrixToMatrix:
344 case ByteCodeInstruction::kMatrixMultiply:
345 case ByteCodeInstruction::kReserve:
346 case ByteCodeInstruction::kReturn:
347 case ByteCodeInstruction::kScalarToMatrix:
348 case ByteCodeInstruction::kSwizzle:
349 return count;
350
351 // Miscellaneous
352
353 // kCall is net-zero. Max stack depth is adjusted in writeFunctionCall.
354 case ByteCodeInstruction::kCall: return 0;
355 case ByteCodeInstruction::kBranch: return 0;
356 case ByteCodeInstruction::kBranchIfAllFalse: return 0;
357
358 case ByteCodeInstruction::kMaskPush: return -1;
359 case ByteCodeInstruction::kMaskPop: return 0;
360 case ByteCodeInstruction::kMaskNegate: return 0;
361 case ByteCodeInstruction::kMaskBlend: return -count;
362
363 case ByteCodeInstruction::kLoopBegin: return 0;
364 case ByteCodeInstruction::kLoopNext: return 0;
365 case ByteCodeInstruction::kLoopMask: return -1;
366 case ByteCodeInstruction::kLoopEnd: return 0;
367 case ByteCodeInstruction::kLoopBreak: return 0;
368 case ByteCodeInstruction::kLoopContinue: return 0;
369
370 default:
Brian Osmanc7ec9e22019-07-16 08:49:11 -0400371 ABORT("unsupported instruction %d\n", (int)inst);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400372 return 0;
373 }
374}
375
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400376int ByteCodeGenerator::getLocation(const Variable& var) {
377 // given that we seldom have more than a couple of variables, linear search is probably the most
378 // efficient way to handle lookups
379 switch (var.fStorage) {
380 case Variable::kLocal_Storage: {
381 for (int i = fLocals.size() - 1; i >= 0; --i) {
382 if (fLocals[i] == &var) {
Brian Osman1091f022019-05-16 09:42:16 -0400383 SkASSERT(fParameterCount + i <= 255);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400384 return fParameterCount + i;
385 }
386 }
387 int result = fParameterCount + fLocals.size();
388 fLocals.push_back(&var);
Brian Osman07c117b2019-05-23 12:51:06 -0700389 for (int i = 0; i < SlotCount(var.fType) - 1; ++i) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400390 fLocals.push_back(nullptr);
391 }
Brian Osman1091f022019-05-16 09:42:16 -0400392 SkASSERT(result <= 255);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400393 return result;
394 }
395 case Variable::kParameter_Storage: {
396 int offset = 0;
397 for (const auto& p : fFunction->fDeclaration.fParameters) {
398 if (p == &var) {
Brian Osman1091f022019-05-16 09:42:16 -0400399 SkASSERT(offset <= 255);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400400 return offset;
401 }
Brian Osman07c117b2019-05-23 12:51:06 -0700402 offset += SlotCount(p->fType);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400403 }
404 SkASSERT(false);
Brian Osman1091f022019-05-16 09:42:16 -0400405 return 0;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400406 }
407 case Variable::kGlobal_Storage: {
408 int offset = 0;
409 for (const auto& e : fProgram) {
410 if (e.fKind == ProgramElement::kVar_Kind) {
411 VarDeclarations& decl = (VarDeclarations&) e;
412 for (const auto& v : decl.fVars) {
413 const Variable* declVar = ((VarDeclaration&) *v).fVar;
414 if (declVar->fModifiers.fLayout.fBuiltin >= 0) {
415 continue;
416 }
417 if (declVar == &var) {
Brian Osmanb7451292019-05-15 13:02:13 -0400418 SkASSERT(offset <= 255);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400419 return offset;
420 }
Brian Osman07c117b2019-05-23 12:51:06 -0700421 offset += SlotCount(declVar->fType);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400422 }
423 }
424 }
425 SkASSERT(false);
Brian Osman1091f022019-05-16 09:42:16 -0400426 return 0;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400427 }
428 default:
429 SkASSERT(false);
430 return 0;
431 }
432}
433
Brian Osman07c117b2019-05-23 12:51:06 -0700434int ByteCodeGenerator::getLocation(const Expression& expr, Variable::Storage* storage) {
435 switch (expr.fKind) {
436 case Expression::kFieldAccess_Kind: {
437 const FieldAccess& f = (const FieldAccess&)expr;
438 int baseAddr = this->getLocation(*f.fBase, storage);
439 int offset = 0;
440 for (int i = 0; i < f.fFieldIndex; ++i) {
441 offset += SlotCount(*f.fBase->fType.fields()[i].fType);
442 }
443 if (baseAddr < 0) {
Brian Osman86769292019-06-21 11:05:47 -0400444 if (offset != 0) {
445 this->write(ByteCodeInstruction::kPushImmediate);
446 this->write32(offset);
447 this->write(ByteCodeInstruction::kAddI);
448 }
Brian Osman07c117b2019-05-23 12:51:06 -0700449 return -1;
450 } else {
451 return baseAddr + offset;
452 }
453 }
454 case Expression::kIndex_Kind: {
455 const IndexExpression& i = (const IndexExpression&)expr;
456 int stride = SlotCount(i.fType);
457 int offset = -1;
458 if (i.fIndex->isConstant()) {
Brian Osman3e6aa9f2019-07-18 17:22:33 +0000459 offset = i.fIndex->getConstantInt() * stride;
Brian Osman07c117b2019-05-23 12:51:06 -0700460 } else {
Brian Osman86769292019-06-21 11:05:47 -0400461 if (i.fIndex->hasSideEffects()) {
462 // Having a side-effect in an indexer is technically safe for an rvalue,
463 // but with lvalues we have to evaluate the indexer twice, so make it an error.
464 fErrors.error(i.fIndex->fOffset,
465 "Index expressions with side-effects not supported in byte code.");
466 return 0;
467 }
Brian Osman07c117b2019-05-23 12:51:06 -0700468 this->writeExpression(*i.fIndex);
Brian Osman86769292019-06-21 11:05:47 -0400469 if (stride != 1) {
470 this->write(ByteCodeInstruction::kPushImmediate);
471 this->write32(stride);
472 this->write(ByteCodeInstruction::kMultiplyI);
473 }
Brian Osman07c117b2019-05-23 12:51:06 -0700474 }
475 int baseAddr = this->getLocation(*i.fBase, storage);
Brian Osman86769292019-06-21 11:05:47 -0400476
477 // Are both components known statically?
Brian Osman07c117b2019-05-23 12:51:06 -0700478 if (baseAddr >= 0 && offset >= 0) {
479 return baseAddr + offset;
480 }
Brian Osman86769292019-06-21 11:05:47 -0400481
482 // At least one component is dynamic (and on the stack).
483
484 // If the other component is zero, we're done
485 if (baseAddr == 0 || offset == 0) {
486 return -1;
487 }
488
489 // Push the non-dynamic component (if any) to the stack, then add the two
Brian Osman07c117b2019-05-23 12:51:06 -0700490 if (baseAddr >= 0) {
491 this->write(ByteCodeInstruction::kPushImmediate);
492 this->write32(baseAddr);
493 }
494 if (offset >= 0) {
495 this->write(ByteCodeInstruction::kPushImmediate);
496 this->write32(offset);
497 }
498 this->write(ByteCodeInstruction::kAddI);
499 return -1;
500 }
Brian Osman0785db02019-05-24 14:19:11 -0400501 case Expression::kSwizzle_Kind: {
502 const Swizzle& s = (const Swizzle&)expr;
503 SkASSERT(swizzle_is_simple(s));
504 int baseAddr = this->getLocation(*s.fBase, storage);
505 int offset = s.fComponents[0];
506 if (baseAddr < 0) {
Brian Osman86769292019-06-21 11:05:47 -0400507 if (offset != 0) {
508 this->write(ByteCodeInstruction::kPushImmediate);
509 this->write32(offset);
510 this->write(ByteCodeInstruction::kAddI);
511 }
Brian Osman0785db02019-05-24 14:19:11 -0400512 return -1;
513 } else {
514 return baseAddr + offset;
515 }
516 }
Brian Osman07c117b2019-05-23 12:51:06 -0700517 case Expression::kVariableReference_Kind: {
518 const Variable& var = ((const VariableReference&)expr).fVariable;
519 *storage = var.fStorage;
520 return this->getLocation(var);
521 }
522 default:
523 SkASSERT(false);
524 return 0;
525 }
526}
527
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400528void ByteCodeGenerator::write8(uint8_t b) {
529 fCode->push_back(b);
530}
531
532void ByteCodeGenerator::write16(uint16_t i) {
Mike Klein76346ac2019-05-17 11:57:10 -0500533 size_t n = fCode->size();
534 fCode->resize(n+2);
535 memcpy(fCode->data() + n, &i, 2);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400536}
537
538void ByteCodeGenerator::write32(uint32_t i) {
Mike Klein76346ac2019-05-17 11:57:10 -0500539 size_t n = fCode->size();
540 fCode->resize(n+4);
541 memcpy(fCode->data() + n, &i, 4);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400542}
543
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400544void ByteCodeGenerator::write(ByteCodeInstruction i, int count) {
Brian Osman4a47da72019-07-12 11:30:32 -0400545 switch (i) {
546 case ByteCodeInstruction::kLoopBegin: this->enterLoop(); break;
547 case ByteCodeInstruction::kLoopEnd: this->exitLoop(); break;
548
549 case ByteCodeInstruction::kMaskPush: this->enterCondition(); break;
550 case ByteCodeInstruction::kMaskPop:
551 case ByteCodeInstruction::kMaskBlend: this->exitCondition(); break;
552 default: /* Do nothing */ break;
553 }
Mike Klein108e9352019-05-21 11:05:17 -0500554 this->write16((uint16_t)i);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400555 fStackCount += StackUsage(i, count);
556 fMaxStackCount = std::max(fMaxStackCount, fStackCount);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400557}
558
Mike Klein76346ac2019-05-17 11:57:10 -0500559static ByteCodeInstruction vector_instruction(ByteCodeInstruction base, int count) {
Brian Osman07c117b2019-05-23 12:51:06 -0700560 SkASSERT(count >= 1 && count <= 4);
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400561 return ((ByteCodeInstruction) ((int) base + count - 1));
562}
563
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400564void ByteCodeGenerator::writeTypedInstruction(const Type& type, ByteCodeInstruction s,
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400565 ByteCodeInstruction u, ByteCodeInstruction f,
566 int count) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400567 switch (type_category(type)) {
568 case TypeCategory::kSigned:
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400569 this->write(vector_instruction(s, count));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400570 break;
571 case TypeCategory::kUnsigned:
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400572 this->write(vector_instruction(u, count));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400573 break;
Brian Osman1e855b22019-05-29 15:21:52 -0400574 case TypeCategory::kFloat: {
575 if (count > 4) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400576 this->write((ByteCodeInstruction)((int)f + 4), count);
Brian Osman1e855b22019-05-29 15:21:52 -0400577 this->write8(count);
578 } else {
579 this->write(vector_instruction(f, count));
580 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400581 break;
Brian Osman1e855b22019-05-29 15:21:52 -0400582 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400583 default:
584 SkASSERT(false);
585 }
586}
587
Brian Osman3e29f1d2019-05-28 09:35:05 -0400588bool ByteCodeGenerator::writeBinaryExpression(const BinaryExpression& b, bool discard) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400589 if (b.fOperator == Token::Kind::EQ) {
590 std::unique_ptr<LValue> lvalue = this->getLValue(*b.fLeft);
591 this->writeExpression(*b.fRight);
Brian Osman3e29f1d2019-05-28 09:35:05 -0400592 lvalue->store(discard);
593 discard = false;
594 return discard;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400595 }
Brian Osman16e6fd52019-05-29 11:19:00 -0400596 const Type& lType = b.fLeft->fType;
597 const Type& rType = b.fRight->fType;
Brian Osman909231c2019-05-29 15:34:36 -0400598 bool lVecOrMtx = (lType.kind() == Type::kVector_Kind || lType.kind() == Type::kMatrix_Kind);
599 bool rVecOrMtx = (rType.kind() == Type::kVector_Kind || rType.kind() == Type::kMatrix_Kind);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400600 Token::Kind op;
601 std::unique_ptr<LValue> lvalue;
602 if (is_assignment(b.fOperator)) {
603 lvalue = this->getLValue(*b.fLeft);
604 lvalue->load();
605 op = remove_assignment(b.fOperator);
606 } else {
607 this->writeExpression(*b.fLeft);
608 op = b.fOperator;
Brian Osman909231c2019-05-29 15:34:36 -0400609 if (!lVecOrMtx && rVecOrMtx) {
Brian Osman16e6fd52019-05-29 11:19:00 -0400610 for (int i = SlotCount(rType); i > 1; --i) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400611 this->write(ByteCodeInstruction::kDup);
612 }
613 }
614 }
615 this->writeExpression(*b.fRight);
Brian Osman909231c2019-05-29 15:34:36 -0400616 if (lVecOrMtx && !rVecOrMtx) {
Brian Osman16e6fd52019-05-29 11:19:00 -0400617 for (int i = SlotCount(lType); i > 1; --i) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400618 this->write(ByteCodeInstruction::kDup);
619 }
620 }
Brian Osman909231c2019-05-29 15:34:36 -0400621 // Special case for M*V, V*M, M*M (but not V*V!)
622 if (op == Token::Kind::STAR && lVecOrMtx && rVecOrMtx &&
623 !(lType.kind() == Type::kVector_Kind && rType.kind() == Type::kVector_Kind)) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400624 this->write(ByteCodeInstruction::kMatrixMultiply,
625 SlotCount(b.fType) - (SlotCount(lType) + SlotCount(rType)));
Brian Osman909231c2019-05-29 15:34:36 -0400626 int rCols = rType.columns(),
627 rRows = rType.rows(),
628 lCols = lType.columns(),
629 lRows = lType.rows();
630 // M*V treats the vector as a column
631 if (rType.kind() == Type::kVector_Kind) {
632 std::swap(rCols, rRows);
633 }
634 SkASSERT(lCols == rRows);
635 SkASSERT(SlotCount(b.fType) == lRows * rCols);
636 this->write8(lCols);
637 this->write8(lRows);
638 this->write8(rCols);
639 } else {
640 int count = std::max(SlotCount(lType), SlotCount(rType));
641 switch (op) {
642 case Token::Kind::EQEQ:
643 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareIEQ,
644 ByteCodeInstruction::kCompareIEQ,
645 ByteCodeInstruction::kCompareFEQ,
646 count);
647 // Collapse to a single bool
648 for (int i = count; i > 1; --i) {
649 this->write(ByteCodeInstruction::kAndB);
650 }
651 break;
652 case Token::Kind::GT:
653 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSGT,
654 ByteCodeInstruction::kCompareUGT,
655 ByteCodeInstruction::kCompareFGT,
656 count);
657 break;
658 case Token::Kind::GTEQ:
659 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSGTEQ,
660 ByteCodeInstruction::kCompareUGTEQ,
661 ByteCodeInstruction::kCompareFGTEQ,
662 count);
663 break;
664 case Token::Kind::LT:
665 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSLT,
666 ByteCodeInstruction::kCompareULT,
667 ByteCodeInstruction::kCompareFLT,
668 count);
669 break;
670 case Token::Kind::LTEQ:
671 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSLTEQ,
672 ByteCodeInstruction::kCompareULTEQ,
673 ByteCodeInstruction::kCompareFLTEQ,
674 count);
675 break;
676 case Token::Kind::MINUS:
677 this->writeTypedInstruction(lType, ByteCodeInstruction::kSubtractI,
678 ByteCodeInstruction::kSubtractI,
679 ByteCodeInstruction::kSubtractF,
680 count);
681 break;
682 case Token::Kind::NEQ:
683 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareINEQ,
684 ByteCodeInstruction::kCompareINEQ,
685 ByteCodeInstruction::kCompareFNEQ,
686 count);
687 // Collapse to a single bool
688 for (int i = count; i > 1; --i) {
689 this->write(ByteCodeInstruction::kOrB);
690 }
691 break;
692 case Token::Kind::PERCENT:
693 this->writeTypedInstruction(lType, ByteCodeInstruction::kRemainderS,
694 ByteCodeInstruction::kRemainderU,
695 ByteCodeInstruction::kRemainderF,
696 count);
697 break;
698 case Token::Kind::PLUS:
699 this->writeTypedInstruction(lType, ByteCodeInstruction::kAddI,
700 ByteCodeInstruction::kAddI,
701 ByteCodeInstruction::kAddF,
702 count);
703 break;
704 case Token::Kind::SLASH:
705 this->writeTypedInstruction(lType, ByteCodeInstruction::kDivideS,
706 ByteCodeInstruction::kDivideU,
707 ByteCodeInstruction::kDivideF,
708 count);
709 break;
710 case Token::Kind::STAR:
711 this->writeTypedInstruction(lType, ByteCodeInstruction::kMultiplyI,
712 ByteCodeInstruction::kMultiplyI,
713 ByteCodeInstruction::kMultiplyF,
714 count);
715 break;
Brian Osman569f12f2019-06-13 11:23:57 -0400716
717 case Token::Kind::LOGICALAND:
718 SkASSERT(type_category(lType) == SkSL::TypeCategory::kBool && count == 1);
719 this->write(ByteCodeInstruction::kAndB);
720 break;
721 case Token::Kind::LOGICALNOT:
722 SkASSERT(type_category(lType) == SkSL::TypeCategory::kBool && count == 1);
723 this->write(ByteCodeInstruction::kNotB);
724 break;
725 case Token::Kind::LOGICALOR:
726 SkASSERT(type_category(lType) == SkSL::TypeCategory::kBool && count == 1);
727 this->write(ByteCodeInstruction::kOrB);
728 break;
729 case Token::Kind::LOGICALXOR:
730 SkASSERT(type_category(lType) == SkSL::TypeCategory::kBool && count == 1);
731 this->write(ByteCodeInstruction::kXorB);
732 break;
733
Brian Osman909231c2019-05-29 15:34:36 -0400734 default:
735 SkASSERT(false);
736 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400737 }
738 if (lvalue) {
Brian Osman3e29f1d2019-05-28 09:35:05 -0400739 lvalue->store(discard);
740 discard = false;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400741 }
Brian Osman3e29f1d2019-05-28 09:35:05 -0400742 return discard;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400743}
744
745void ByteCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
746 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osman569f12f2019-06-13 11:23:57 -0400747 this->write32(b.fValue ? ~0 : 0);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400748}
749
750void ByteCodeGenerator::writeConstructor(const Constructor& c) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400751 for (const auto& arg : c.fArguments) {
752 this->writeExpression(*arg);
753 }
754 if (c.fArguments.size() == 1) {
Brian Osman29e013d2019-05-28 17:16:03 -0400755 const Type& inType = c.fArguments[0]->fType;
756 const Type& outType = c.fType;
757 TypeCategory inCategory = type_category(inType);
758 TypeCategory outCategory = type_category(outType);
759 int inCount = SlotCount(inType);
760 int outCount = SlotCount(outType);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400761 if (inCategory != outCategory) {
Brian Osmanc51d7912019-05-22 15:16:16 -0700762 SkASSERT(inCount == outCount);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400763 if (inCategory == TypeCategory::kFloat) {
764 SkASSERT(outCategory == TypeCategory::kSigned ||
765 outCategory == TypeCategory::kUnsigned);
Brian Osmanc51d7912019-05-22 15:16:16 -0700766 this->write(vector_instruction(ByteCodeInstruction::kConvertFtoI, outCount));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400767 } else if (outCategory == TypeCategory::kFloat) {
768 if (inCategory == TypeCategory::kSigned) {
Brian Osmanc51d7912019-05-22 15:16:16 -0700769 this->write(vector_instruction(ByteCodeInstruction::kConvertStoF, outCount));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400770 } else {
771 SkASSERT(inCategory == TypeCategory::kUnsigned);
Brian Osmanc51d7912019-05-22 15:16:16 -0700772 this->write(vector_instruction(ByteCodeInstruction::kConvertUtoF, outCount));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400773 }
774 } else {
775 SkASSERT(false);
776 }
777 }
Brian Osman29e013d2019-05-28 17:16:03 -0400778 if (inType.kind() == Type::kMatrix_Kind && outType.kind() == Type::kMatrix_Kind) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400779 this->write(ByteCodeInstruction::kMatrixToMatrix,
780 SlotCount(outType) - SlotCount(inType));
Brian Osman29e013d2019-05-28 17:16:03 -0400781 this->write8(inType.columns());
782 this->write8(inType.rows());
783 this->write8(outType.columns());
784 this->write8(outType.rows());
785 } else if (inCount != outCount) {
Brian Osmanc51d7912019-05-22 15:16:16 -0700786 SkASSERT(inCount == 1);
Brian Osman29e013d2019-05-28 17:16:03 -0400787 if (outType.kind() == Type::kMatrix_Kind) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400788 this->write(ByteCodeInstruction::kScalarToMatrix, SlotCount(outType) - 1);
Brian Osman29e013d2019-05-28 17:16:03 -0400789 this->write8(outType.columns());
790 this->write8(outType.rows());
791 } else {
792 SkASSERT(outType.kind() == Type::kVector_Kind);
793 for (; inCount != outCount; ++inCount) {
794 this->write(ByteCodeInstruction::kDup);
795 }
Brian Osmanc51d7912019-05-22 15:16:16 -0700796 }
797 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400798 }
799}
800
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400801void ByteCodeGenerator::writeExternalFunctionCall(const ExternalFunctionCall& f) {
802 int argumentCount = 0;
803 for (const auto& arg : f.fArguments) {
804 this->writeExpression(*arg);
Brian Osman07c117b2019-05-23 12:51:06 -0700805 argumentCount += SlotCount(arg->fType);
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400806 }
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400807 this->write(ByteCodeInstruction::kCallExternal, SlotCount(f.fType) - argumentCount);
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400808 SkASSERT(argumentCount <= 255);
809 this->write8(argumentCount);
Brian Osman07c117b2019-05-23 12:51:06 -0700810 this->write8(SlotCount(f.fType));
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400811 int index = fOutput->fExternalValues.size();
812 fOutput->fExternalValues.push_back(f.fFunction);
813 SkASSERT(index <= 255);
814 this->write8(index);
815}
816
Ethan Nicholas91164d12019-05-15 15:29:54 -0400817void ByteCodeGenerator::writeExternalValue(const ExternalValueReference& e) {
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400818 this->write(vector_instruction(ByteCodeInstruction::kReadExternal,
Brian Osman07c117b2019-05-23 12:51:06 -0700819 SlotCount(e.fValue->type())));
Ethan Nicholas91164d12019-05-15 15:29:54 -0400820 int index = fOutput->fExternalValues.size();
821 fOutput->fExternalValues.push_back(e.fValue);
822 SkASSERT(index <= 255);
823 this->write8(index);
824}
825
Brian Osman07c117b2019-05-23 12:51:06 -0700826void ByteCodeGenerator::writeVariableExpression(const Expression& expr) {
827 Variable::Storage storage;
828 int location = this->getLocation(expr, &storage);
829 bool isGlobal = storage == Variable::kGlobal_Storage;
830 int count = SlotCount(expr.fType);
831 if (location < 0 || count > 4) {
832 if (location >= 0) {
833 this->write(ByteCodeInstruction::kPushImmediate);
834 this->write32(location);
835 }
836 this->write(isGlobal ? ByteCodeInstruction::kLoadExtendedGlobal
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400837 : ByteCodeInstruction::kLoadExtended,
838 count);
Brian Osman07c117b2019-05-23 12:51:06 -0700839 this->write8(count);
840 } else {
841 this->write(vector_instruction(isGlobal ? ByteCodeInstruction::kLoadGlobal
842 : ByteCodeInstruction::kLoad,
843 count));
844 this->write8(location);
845 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400846}
847
Brian Osmand30e0392019-06-14 14:05:14 -0400848static inline uint32_t float_to_bits(float x) {
849 uint32_t u;
850 memcpy(&u, &x, sizeof(uint32_t));
851 return u;
852}
853
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400854void ByteCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
855 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osmand30e0392019-06-14 14:05:14 -0400856 this->write32(float_to_bits(f.fValue));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400857}
858
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400859void ByteCodeGenerator::writeIntrinsicCall(const FunctionCall& c) {
860 auto found = fIntrinsics.find(c.fFunction.fName);
861 if (found == fIntrinsics.end()) {
862 fErrors.error(c.fOffset, "unsupported intrinsic function");
863 return;
864 }
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400865 int count = SlotCount(c.fArguments[0]->fType);
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400866 if (found->second.fIsSpecial) {
867 SkASSERT(found->second.fValue.fSpecial == SpecialIntrinsic::kDot);
868 SkASSERT(c.fArguments.size() == 2);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400869 SkASSERT(count == SlotCount(c.fArguments[1]->fType));
870 this->write((ByteCodeInstruction)((int)ByteCodeInstruction::kMultiplyF + count - 1));
871 for (int i = count; i > 1; --i) {
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400872 this->write(ByteCodeInstruction::kAddF);
873 }
874 } else {
875 switch (found->second.fValue.fInstruction) {
876 case ByteCodeInstruction::kCos:
877 case ByteCodeInstruction::kMix:
878 case ByteCodeInstruction::kSin:
879 case ByteCodeInstruction::kSqrt:
880 case ByteCodeInstruction::kTan:
881 SkASSERT(c.fArguments.size() > 0);
882 this->write((ByteCodeInstruction) ((int) found->second.fValue.fInstruction +
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400883 count - 1));
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400884 break;
885 case ByteCodeInstruction::kCross:
886 this->write(found->second.fValue.fInstruction);
887 break;
888 default:
889 SkASSERT(false);
890 }
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400891 }
892}
893
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400894void ByteCodeGenerator::writeFunctionCall(const FunctionCall& f) {
Brian Osmand3494ed2019-06-20 15:41:34 -0400895 // Builtins have simple signatures...
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400896 if (f.fFunction.fBuiltin) {
Brian Osmand3494ed2019-06-20 15:41:34 -0400897 for (const auto& arg : f.fArguments) {
898 this->writeExpression(*arg);
899 }
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400900 this->writeIntrinsicCall(f);
901 return;
902 }
Brian Osmand3494ed2019-06-20 15:41:34 -0400903
Brian Osman6f5358f2019-07-09 14:17:23 -0400904 // Find the index of the function we're calling. We explicitly do not allow calls to functions
905 // before they're defined. This is an easy-to-understand rule that prevents recursion.
906 size_t idx;
907 for (idx = 0; idx < fFunctions.size(); ++idx) {
908 if (f.fFunction.matches(fFunctions[idx]->fDeclaration)) {
909 break;
910 }
911 }
912 if (idx > 255) {
913 fErrors.error(f.fOffset, "Function count limit exceeded");
914 return;
915 } else if (idx >= fFunctions.size()) {
916 fErrors.error(f.fOffset, "Call to undefined function");
917 return;
918 }
919
920 // We may need to deal with out parameters, so the sequence is tricky
Brian Osmand3494ed2019-06-20 15:41:34 -0400921 if (int returnCount = SlotCount(f.fType)) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400922 this->write(ByteCodeInstruction::kReserve, returnCount);
Brian Osmand3494ed2019-06-20 15:41:34 -0400923 this->write8(returnCount);
924 }
925
926 int argCount = f.fArguments.size();
927 std::vector<std::unique_ptr<LValue>> lvalues;
928 for (int i = 0; i < argCount; ++i) {
929 const auto& param = f.fFunction.fParameters[i];
930 const auto& arg = f.fArguments[i];
931 if (param->fModifiers.fFlags & Modifiers::kOut_Flag) {
932 lvalues.emplace_back(this->getLValue(*arg));
933 lvalues.back()->load();
934 } else {
935 this->writeExpression(*arg);
936 }
937 }
938
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400939 // The space used by the call is based on the callee, but it also unwinds all of that before
940 // we continue execution. We adjust our max stack depths below.
Brian Osman226668a2019-05-14 16:47:30 -0400941 this->write(ByteCodeInstruction::kCall);
Brian Osman6f5358f2019-07-09 14:17:23 -0400942 this->write8(idx);
Brian Osmand3494ed2019-06-20 15:41:34 -0400943
Brian Osman4a47da72019-07-12 11:30:32 -0400944 const ByteCodeFunction* callee = fOutput->fFunctions[idx].get();
945 fMaxLoopCount = std::max(fMaxLoopCount, fLoopCount + callee->fLoopCount);
946 fMaxConditionCount = std::max(fMaxConditionCount, fConditionCount + callee->fConditionCount);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400947 fMaxStackCount = std::max(fMaxStackCount, fStackCount + callee->fLocalCount
948 + callee->fStackCount);
Brian Osman4a47da72019-07-12 11:30:32 -0400949
Brian Osmand3494ed2019-06-20 15:41:34 -0400950 // After the called function returns, the stack will still contain our arguments. We have to
951 // pop them (storing any out parameters back to their lvalues as we go). We glob together slot
952 // counts for all parameters that aren't out-params, so we can pop them in one big chunk.
953 int popCount = 0;
954 auto pop = [&]() {
955 if (popCount > 4) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400956 this->write(ByteCodeInstruction::kPopN, popCount);
Brian Osmand3494ed2019-06-20 15:41:34 -0400957 this->write8(popCount);
958 } else if (popCount > 0) {
959 this->write(vector_instruction(ByteCodeInstruction::kPop, popCount));
960 }
961 popCount = 0;
962 };
963
964 for (int i = argCount - 1; i >= 0; --i) {
965 const auto& param = f.fFunction.fParameters[i];
966 const auto& arg = f.fArguments[i];
967 if (param->fModifiers.fFlags & Modifiers::kOut_Flag) {
968 pop();
969 lvalues.back()->store(true);
970 lvalues.pop_back();
971 } else {
972 popCount += SlotCount(arg->fType);
973 }
974 }
975 pop();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400976}
977
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400978void ByteCodeGenerator::writeIntLiteral(const IntLiteral& i) {
979 this->write(ByteCodeInstruction::kPushImmediate);
980 this->write32(i.fValue);
981}
982
983void ByteCodeGenerator::writeNullLiteral(const NullLiteral& n) {
984 // not yet implemented
985 abort();
986}
987
Brian Osman3e29f1d2019-05-28 09:35:05 -0400988bool ByteCodeGenerator::writePrefixExpression(const PrefixExpression& p, bool discard) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400989 switch (p.fOperator) {
990 case Token::Kind::PLUSPLUS: // fall through
991 case Token::Kind::MINUSMINUS: {
Brian Osman07c117b2019-05-23 12:51:06 -0700992 SkASSERT(SlotCount(p.fOperand->fType) == 1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400993 std::unique_ptr<LValue> lvalue = this->getLValue(*p.fOperand);
994 lvalue->load();
995 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osmand30e0392019-06-14 14:05:14 -0400996 this->write32(type_category(p.fType) == TypeCategory::kFloat ? float_to_bits(1.0f) : 1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400997 if (p.fOperator == Token::Kind::PLUSPLUS) {
998 this->writeTypedInstruction(p.fType,
999 ByteCodeInstruction::kAddI,
1000 ByteCodeInstruction::kAddI,
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001001 ByteCodeInstruction::kAddF,
1002 1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001003 } else {
1004 this->writeTypedInstruction(p.fType,
1005 ByteCodeInstruction::kSubtractI,
1006 ByteCodeInstruction::kSubtractI,
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001007 ByteCodeInstruction::kSubtractF,
1008 1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001009 }
Brian Osman3e29f1d2019-05-28 09:35:05 -04001010 lvalue->store(discard);
1011 discard = false;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001012 break;
1013 }
Ethan Nicholas354ecf32019-05-07 16:13:02 -04001014 case Token::Kind::MINUS: {
1015 this->writeExpression(*p.fOperand);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001016 this->writeTypedInstruction(p.fType,
Mike Klein12710912019-05-21 11:04:59 -05001017 ByteCodeInstruction::kNegateI,
1018 ByteCodeInstruction::kNegateI,
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001019 ByteCodeInstruction::kNegateF,
Brian Osman07c117b2019-05-23 12:51:06 -07001020 SlotCount(p.fOperand->fType));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001021 break;
Ethan Nicholas354ecf32019-05-07 16:13:02 -04001022 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001023 default:
1024 SkASSERT(false);
1025 }
Brian Osman3e29f1d2019-05-28 09:35:05 -04001026 return discard;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001027}
1028
Brian Osman3e29f1d2019-05-28 09:35:05 -04001029bool ByteCodeGenerator::writePostfixExpression(const PostfixExpression& p, bool discard) {
Brian Osmanf3fa6002019-05-17 14:26:53 -04001030 switch (p.fOperator) {
1031 case Token::Kind::PLUSPLUS: // fall through
1032 case Token::Kind::MINUSMINUS: {
Brian Osman07c117b2019-05-23 12:51:06 -07001033 SkASSERT(SlotCount(p.fOperand->fType) == 1);
Brian Osmanf3fa6002019-05-17 14:26:53 -04001034 std::unique_ptr<LValue> lvalue = this->getLValue(*p.fOperand);
1035 lvalue->load();
Brian Osman52c1bf12019-07-18 13:12:19 -04001036 // If we're not supposed to discard the result, then make a copy *before* the +/-
Brian Osman3e29f1d2019-05-28 09:35:05 -04001037 if (!discard) {
1038 this->write(ByteCodeInstruction::kDup);
1039 }
Brian Osmanf3fa6002019-05-17 14:26:53 -04001040 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osmand30e0392019-06-14 14:05:14 -04001041 this->write32(type_category(p.fType) == TypeCategory::kFloat ? float_to_bits(1.0f) : 1);
Brian Osmanf3fa6002019-05-17 14:26:53 -04001042 if (p.fOperator == Token::Kind::PLUSPLUS) {
1043 this->writeTypedInstruction(p.fType,
1044 ByteCodeInstruction::kAddI,
1045 ByteCodeInstruction::kAddI,
1046 ByteCodeInstruction::kAddF,
1047 1);
1048 } else {
1049 this->writeTypedInstruction(p.fType,
1050 ByteCodeInstruction::kSubtractI,
1051 ByteCodeInstruction::kSubtractI,
1052 ByteCodeInstruction::kSubtractF,
1053 1);
1054 }
Brian Osman52c1bf12019-07-18 13:12:19 -04001055 // Always consume the result as part of the store
1056 lvalue->store(true);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001057 discard = false;
Brian Osmanf3fa6002019-05-17 14:26:53 -04001058 break;
1059 }
1060 default:
1061 SkASSERT(false);
1062 }
Brian Osman3e29f1d2019-05-28 09:35:05 -04001063 return discard;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001064}
1065
1066void ByteCodeGenerator::writeSwizzle(const Swizzle& s) {
Brian Osman0785db02019-05-24 14:19:11 -04001067 if (swizzle_is_simple(s)) {
1068 this->writeVariableExpression(s);
1069 return;
1070 }
1071
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001072 switch (s.fBase->fKind) {
1073 case Expression::kVariableReference_Kind: {
1074 const Variable& var = ((VariableReference&) *s.fBase).fVariable;
Brian Osman1091f022019-05-16 09:42:16 -04001075 this->write(var.fStorage == Variable::kGlobal_Storage
1076 ? ByteCodeInstruction::kLoadSwizzleGlobal
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001077 : ByteCodeInstruction::kLoadSwizzle,
1078 s.fComponents.size());
Brian Osman1091f022019-05-16 09:42:16 -04001079 this->write8(this->getLocation(var));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001080 this->write8(s.fComponents.size());
1081 for (int c : s.fComponents) {
1082 this->write8(c);
1083 }
1084 break;
1085 }
1086 default:
1087 this->writeExpression(*s.fBase);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001088 this->write(ByteCodeInstruction::kSwizzle,
1089 s.fComponents.size() - s.fBase->fType.columns());
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001090 this->write8(s.fBase->fType.columns());
1091 this->write8(s.fComponents.size());
1092 for (int c : s.fComponents) {
1093 this->write8(c);
1094 }
1095 }
1096}
1097
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001098void ByteCodeGenerator::writeTernaryExpression(const TernaryExpression& t) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001099 int count = SlotCount(t.fType);
1100 SkASSERT(count == SlotCount(t.fIfTrue->fType));
1101 SkASSERT(count == SlotCount(t.fIfFalse->fType));
1102
Brian Osman4e93feb2019-05-16 15:38:00 -04001103 this->writeExpression(*t.fTest);
Brian Osman569f12f2019-06-13 11:23:57 -04001104 this->write(ByteCodeInstruction::kMaskPush);
Brian Osman4e93feb2019-05-16 15:38:00 -04001105 this->writeExpression(*t.fIfTrue);
Brian Osman569f12f2019-06-13 11:23:57 -04001106 this->write(ByteCodeInstruction::kMaskNegate);
1107 this->writeExpression(*t.fIfFalse);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001108 this->write(ByteCodeInstruction::kMaskBlend, count);
1109 this->write8(count);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001110}
1111
Brian Osman3e29f1d2019-05-28 09:35:05 -04001112void ByteCodeGenerator::writeExpression(const Expression& e, bool discard) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001113 switch (e.fKind) {
1114 case Expression::kBinary_Kind:
Brian Osman3e29f1d2019-05-28 09:35:05 -04001115 discard = this->writeBinaryExpression((BinaryExpression&) e, discard);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001116 break;
1117 case Expression::kBoolLiteral_Kind:
1118 this->writeBoolLiteral((BoolLiteral&) e);
1119 break;
1120 case Expression::kConstructor_Kind:
1121 this->writeConstructor((Constructor&) e);
1122 break;
Ethan Nicholas9e6a3932019-05-17 16:31:21 -04001123 case Expression::kExternalFunctionCall_Kind:
1124 this->writeExternalFunctionCall((ExternalFunctionCall&) e);
1125 break;
Ethan Nicholas91164d12019-05-15 15:29:54 -04001126 case Expression::kExternalValue_Kind:
1127 this->writeExternalValue((ExternalValueReference&) e);
1128 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001129 case Expression::kFieldAccess_Kind:
Brian Osman07c117b2019-05-23 12:51:06 -07001130 case Expression::kIndex_Kind:
1131 case Expression::kVariableReference_Kind:
1132 this->writeVariableExpression(e);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001133 break;
1134 case Expression::kFloatLiteral_Kind:
1135 this->writeFloatLiteral((FloatLiteral&) e);
1136 break;
1137 case Expression::kFunctionCall_Kind:
1138 this->writeFunctionCall((FunctionCall&) e);
1139 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001140 case Expression::kIntLiteral_Kind:
1141 this->writeIntLiteral((IntLiteral&) e);
1142 break;
1143 case Expression::kNullLiteral_Kind:
1144 this->writeNullLiteral((NullLiteral&) e);
1145 break;
1146 case Expression::kPrefix_Kind:
Brian Osman3e29f1d2019-05-28 09:35:05 -04001147 discard = this->writePrefixExpression((PrefixExpression&) e, discard);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001148 break;
1149 case Expression::kPostfix_Kind:
Brian Osman3e29f1d2019-05-28 09:35:05 -04001150 discard = this->writePostfixExpression((PostfixExpression&) e, discard);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001151 break;
1152 case Expression::kSwizzle_Kind:
1153 this->writeSwizzle((Swizzle&) e);
1154 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001155 case Expression::kTernary_Kind:
1156 this->writeTernaryExpression((TernaryExpression&) e);
1157 break;
1158 default:
1159 printf("unsupported expression %s\n", e.description().c_str());
1160 SkASSERT(false);
1161 }
Brian Osman3e29f1d2019-05-28 09:35:05 -04001162 if (discard) {
1163 int count = SlotCount(e.fType);
1164 if (count > 4) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001165 this->write(ByteCodeInstruction::kPopN, count);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001166 this->write8(count);
Brian Osmanfba386b2019-06-20 14:54:15 -04001167 } else if (count != 0) {
Brian Osman3e29f1d2019-05-28 09:35:05 -04001168 this->write(vector_instruction(ByteCodeInstruction::kPop, count));
1169 }
1170 discard = false;
1171 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001172}
1173
Ethan Nicholas91164d12019-05-15 15:29:54 -04001174class ByteCodeExternalValueLValue : public ByteCodeGenerator::LValue {
1175public:
1176 ByteCodeExternalValueLValue(ByteCodeGenerator* generator, ExternalValue& value, int index)
1177 : INHERITED(*generator)
Brian Osman07c117b2019-05-23 12:51:06 -07001178 , fCount(ByteCodeGenerator::SlotCount(value.type()))
Ethan Nicholas91164d12019-05-15 15:29:54 -04001179 , fIndex(index) {}
1180
1181 void load() override {
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001182 fGenerator.write(vector_instruction(ByteCodeInstruction::kReadExternal, fCount));
Ethan Nicholas91164d12019-05-15 15:29:54 -04001183 fGenerator.write8(fIndex);
1184 }
1185
Brian Osman3e29f1d2019-05-28 09:35:05 -04001186 void store(bool discard) override {
1187 if (!discard) {
1188 fGenerator.write(vector_instruction(ByteCodeInstruction::kDup, fCount));
1189 }
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001190 fGenerator.write(vector_instruction(ByteCodeInstruction::kWriteExternal, fCount));
Ethan Nicholas91164d12019-05-15 15:29:54 -04001191 fGenerator.write8(fIndex);
1192 }
1193
1194private:
1195 typedef LValue INHERITED;
1196
1197 int fCount;
1198
1199 int fIndex;
1200};
1201
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001202class ByteCodeSwizzleLValue : public ByteCodeGenerator::LValue {
1203public:
1204 ByteCodeSwizzleLValue(ByteCodeGenerator* generator, const Swizzle& swizzle)
1205 : INHERITED(*generator)
Brian Osman07c117b2019-05-23 12:51:06 -07001206 , fSwizzle(swizzle) {}
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001207
1208 void load() override {
Brian Osman1091f022019-05-16 09:42:16 -04001209 fGenerator.writeSwizzle(fSwizzle);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001210 }
1211
Brian Osman3e29f1d2019-05-28 09:35:05 -04001212 void store(bool discard) override {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001213 int count = fSwizzle.fComponents.size();
Brian Osman3e29f1d2019-05-28 09:35:05 -04001214 if (!discard) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001215 fGenerator.write(vector_instruction(ByteCodeInstruction::kDup, count));
Brian Osman3e29f1d2019-05-28 09:35:05 -04001216 }
Brian Osman07c117b2019-05-23 12:51:06 -07001217 Variable::Storage storage;
1218 int location = fGenerator.getLocation(*fSwizzle.fBase, &storage);
1219 bool isGlobal = storage == Variable::kGlobal_Storage;
1220 if (location < 0) {
1221 fGenerator.write(isGlobal ? ByteCodeInstruction::kStoreSwizzleIndirectGlobal
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001222 : ByteCodeInstruction::kStoreSwizzleIndirect,
1223 count);
Brian Osman07c117b2019-05-23 12:51:06 -07001224 } else {
1225 fGenerator.write(isGlobal ? ByteCodeInstruction::kStoreSwizzleGlobal
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001226 : ByteCodeInstruction::kStoreSwizzle,
1227 count);
Brian Osman07c117b2019-05-23 12:51:06 -07001228 fGenerator.write8(location);
1229 }
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001230 fGenerator.write8(count);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001231 for (int c : fSwizzle.fComponents) {
1232 fGenerator.write8(c);
1233 }
1234 }
1235
1236private:
1237 const Swizzle& fSwizzle;
1238
1239 typedef LValue INHERITED;
1240};
1241
Brian Osman07c117b2019-05-23 12:51:06 -07001242class ByteCodeExpressionLValue : public ByteCodeGenerator::LValue {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001243public:
Brian Osman07c117b2019-05-23 12:51:06 -07001244 ByteCodeExpressionLValue(ByteCodeGenerator* generator, const Expression& expr)
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001245 : INHERITED(*generator)
Brian Osman07c117b2019-05-23 12:51:06 -07001246 , fExpression(expr) {}
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001247
1248 void load() override {
Brian Osman07c117b2019-05-23 12:51:06 -07001249 fGenerator.writeVariableExpression(fExpression);
Brian Osman1091f022019-05-16 09:42:16 -04001250 }
1251
Brian Osman3e29f1d2019-05-28 09:35:05 -04001252 void store(bool discard) override {
Brian Osman07c117b2019-05-23 12:51:06 -07001253 int count = ByteCodeGenerator::SlotCount(fExpression.fType);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001254 if (!discard) {
1255 if (count > 4) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001256 fGenerator.write(ByteCodeInstruction::kDupN, count);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001257 fGenerator.write8(count);
1258 } else {
1259 fGenerator.write(vector_instruction(ByteCodeInstruction::kDup, count));
1260 }
Brian Osman07c117b2019-05-23 12:51:06 -07001261 }
1262 Variable::Storage storage;
1263 int location = fGenerator.getLocation(fExpression, &storage);
1264 bool isGlobal = storage == Variable::kGlobal_Storage;
1265 if (location < 0 || count > 4) {
1266 if (location >= 0) {
1267 fGenerator.write(ByteCodeInstruction::kPushImmediate);
1268 fGenerator.write32(location);
1269 }
1270 fGenerator.write(isGlobal ? ByteCodeInstruction::kStoreExtendedGlobal
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001271 : ByteCodeInstruction::kStoreExtended,
1272 count);
Brian Osman07c117b2019-05-23 12:51:06 -07001273 fGenerator.write8(count);
1274 } else {
1275 fGenerator.write(vector_instruction(isGlobal ? ByteCodeInstruction::kStoreGlobal
1276 : ByteCodeInstruction::kStore,
1277 count));
1278 fGenerator.write8(location);
1279 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001280 }
1281
1282private:
1283 typedef LValue INHERITED;
1284
Brian Osman07c117b2019-05-23 12:51:06 -07001285 const Expression& fExpression;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001286};
1287
1288std::unique_ptr<ByteCodeGenerator::LValue> ByteCodeGenerator::getLValue(const Expression& e) {
1289 switch (e.fKind) {
Ethan Nicholas91164d12019-05-15 15:29:54 -04001290 case Expression::kExternalValue_Kind: {
1291 ExternalValue* value = ((ExternalValueReference&) e).fValue;
1292 int index = fOutput->fExternalValues.size();
1293 fOutput->fExternalValues.push_back(value);
1294 SkASSERT(index <= 255);
1295 return std::unique_ptr<LValue>(new ByteCodeExternalValueLValue(this, *value, index));
1296 }
Brian Osman07c117b2019-05-23 12:51:06 -07001297 case Expression::kFieldAccess_Kind:
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001298 case Expression::kIndex_Kind:
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001299 case Expression::kVariableReference_Kind:
Brian Osman07c117b2019-05-23 12:51:06 -07001300 return std::unique_ptr<LValue>(new ByteCodeExpressionLValue(this, e));
Brian Osman0785db02019-05-24 14:19:11 -04001301 case Expression::kSwizzle_Kind: {
1302 const Swizzle& s = (const Swizzle&) e;
1303 return swizzle_is_simple(s)
1304 ? std::unique_ptr<LValue>(new ByteCodeExpressionLValue(this, e))
1305 : std::unique_ptr<LValue>(new ByteCodeSwizzleLValue(this, s));
1306 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001307 case Expression::kTernary_Kind:
1308 default:
1309 printf("unsupported lvalue %s\n", e.description().c_str());
1310 return nullptr;
1311 }
1312}
1313
1314void ByteCodeGenerator::writeBlock(const Block& b) {
1315 for (const auto& s : b.fStatements) {
1316 this->writeStatement(*s);
1317 }
1318}
1319
1320void ByteCodeGenerator::setBreakTargets() {
1321 std::vector<DeferredLocation>& breaks = fBreakTargets.top();
1322 for (DeferredLocation& b : breaks) {
1323 b.set();
1324 }
1325 fBreakTargets.pop();
1326}
1327
1328void ByteCodeGenerator::setContinueTargets() {
1329 std::vector<DeferredLocation>& continues = fContinueTargets.top();
1330 for (DeferredLocation& c : continues) {
1331 c.set();
1332 }
1333 fContinueTargets.pop();
1334}
1335
1336void ByteCodeGenerator::writeBreakStatement(const BreakStatement& b) {
Brian Osman569f12f2019-06-13 11:23:57 -04001337 // TODO: Include BranchIfAllFalse to top-most LoopNext
1338 this->write(ByteCodeInstruction::kLoopBreak);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001339}
1340
1341void ByteCodeGenerator::writeContinueStatement(const ContinueStatement& c) {
Brian Osman569f12f2019-06-13 11:23:57 -04001342 // TODO: Include BranchIfAllFalse to top-most LoopNext
1343 this->write(ByteCodeInstruction::kLoopContinue);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001344}
1345
1346void ByteCodeGenerator::writeDoStatement(const DoStatement& d) {
Brian Osman569f12f2019-06-13 11:23:57 -04001347 this->write(ByteCodeInstruction::kLoopBegin);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001348 size_t start = fCode->size();
1349 this->writeStatement(*d.fStatement);
Brian Osman569f12f2019-06-13 11:23:57 -04001350 this->write(ByteCodeInstruction::kLoopNext);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001351 this->writeExpression(*d.fTest);
Brian Osman569f12f2019-06-13 11:23:57 -04001352 this->write(ByteCodeInstruction::kLoopMask);
1353 // TODO: Could shorten this with kBranchIfAnyTrue
1354 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1355 DeferredLocation endLocation(this);
1356 this->write(ByteCodeInstruction::kBranch);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001357 this->write16(start);
Brian Osman569f12f2019-06-13 11:23:57 -04001358 endLocation.set();
1359 this->write(ByteCodeInstruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001360}
1361
1362void ByteCodeGenerator::writeForStatement(const ForStatement& f) {
1363 fContinueTargets.emplace();
1364 fBreakTargets.emplace();
1365 if (f.fInitializer) {
1366 this->writeStatement(*f.fInitializer);
1367 }
Brian Osman569f12f2019-06-13 11:23:57 -04001368 this->write(ByteCodeInstruction::kLoopBegin);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001369 size_t start = fCode->size();
1370 if (f.fTest) {
1371 this->writeExpression(*f.fTest);
Brian Osman569f12f2019-06-13 11:23:57 -04001372 this->write(ByteCodeInstruction::kLoopMask);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001373 }
Brian Osman569f12f2019-06-13 11:23:57 -04001374 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1375 DeferredLocation endLocation(this);
1376 this->writeStatement(*f.fStatement);
1377 this->write(ByteCodeInstruction::kLoopNext);
1378 if (f.fNext) {
1379 this->writeExpression(*f.fNext, true);
1380 }
1381 this->write(ByteCodeInstruction::kBranch);
1382 this->write16(start);
1383 endLocation.set();
1384 this->write(ByteCodeInstruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001385}
1386
1387void ByteCodeGenerator::writeIfStatement(const IfStatement& i) {
Brian Osman569f12f2019-06-13 11:23:57 -04001388 this->writeExpression(*i.fTest);
1389 this->write(ByteCodeInstruction::kMaskPush);
1390 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1391 DeferredLocation falseLocation(this);
1392 this->writeStatement(*i.fIfTrue);
1393 falseLocation.set();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001394 if (i.fIfFalse) {
Brian Osman569f12f2019-06-13 11:23:57 -04001395 this->write(ByteCodeInstruction::kMaskNegate);
1396 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1397 DeferredLocation endLocation(this);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001398 this->writeStatement(*i.fIfFalse);
Mike Kleinb45ee832019-05-17 11:11:11 -05001399 endLocation.set();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001400 }
Brian Osman569f12f2019-06-13 11:23:57 -04001401 this->write(ByteCodeInstruction::kMaskPop);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001402}
1403
1404void ByteCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
Brian Osman4a47da72019-07-12 11:30:32 -04001405 if (fLoopCount || fConditionCount) {
1406 fErrors.error(r.fOffset, "return not allowed inside conditional or loop");
1407 return;
1408 }
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001409 int count = SlotCount(r.fExpression->fType);
Ethan Nicholas746035a2019-04-23 13:31:09 -04001410 this->writeExpression(*r.fExpression);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001411
1412 // Technically, the kReturn also pops fOutput->fLocalCount values from the stack, too, but we
1413 // haven't counted pushing those (they're outside the scope of our stack tracking). Instead,
1414 // we account for those in writeFunction().
1415
1416 // This is all fine because we don't allow conditional returns, so we only return once anyway.
1417 this->write(ByteCodeInstruction::kReturn, -count);
1418 this->write8(count);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001419}
1420
1421void ByteCodeGenerator::writeSwitchStatement(const SwitchStatement& r) {
1422 // not yet implemented
1423 abort();
1424}
1425
1426void ByteCodeGenerator::writeVarDeclarations(const VarDeclarations& v) {
1427 for (const auto& declStatement : v.fVars) {
1428 const VarDeclaration& decl = (VarDeclaration&) *declStatement;
1429 // we need to grab the location even if we don't use it, to ensure it
1430 // has been allocated
1431 int location = getLocation(*decl.fVar);
1432 if (decl.fValue) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001433 this->writeExpression(*decl.fValue);
Brian Osman07c117b2019-05-23 12:51:06 -07001434 int count = SlotCount(decl.fValue->fType);
1435 if (count > 4) {
1436 this->write(ByteCodeInstruction::kPushImmediate);
1437 this->write32(location);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001438 this->write(ByteCodeInstruction::kStoreExtended, count);
Brian Osman07c117b2019-05-23 12:51:06 -07001439 this->write8(count);
1440 } else {
1441 this->write(vector_instruction(ByteCodeInstruction::kStore, count));
1442 this->write8(location);
1443 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001444 }
1445 }
1446}
1447
1448void ByteCodeGenerator::writeWhileStatement(const WhileStatement& w) {
Brian Osman569f12f2019-06-13 11:23:57 -04001449 this->write(ByteCodeInstruction::kLoopBegin);
1450 size_t cond = fCode->size();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001451 this->writeExpression(*w.fTest);
Brian Osman569f12f2019-06-13 11:23:57 -04001452 this->write(ByteCodeInstruction::kLoopMask);
1453 this->write(ByteCodeInstruction::kBranchIfAllFalse);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001454 DeferredLocation endLocation(this);
1455 this->writeStatement(*w.fStatement);
Brian Osman569f12f2019-06-13 11:23:57 -04001456 this->write(ByteCodeInstruction::kLoopNext);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001457 this->write(ByteCodeInstruction::kBranch);
Brian Osman569f12f2019-06-13 11:23:57 -04001458 this->write16(cond);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001459 endLocation.set();
Brian Osman569f12f2019-06-13 11:23:57 -04001460 this->write(ByteCodeInstruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001461}
1462
1463void ByteCodeGenerator::writeStatement(const Statement& s) {
1464 switch (s.fKind) {
1465 case Statement::kBlock_Kind:
1466 this->writeBlock((Block&) s);
1467 break;
1468 case Statement::kBreak_Kind:
1469 this->writeBreakStatement((BreakStatement&) s);
1470 break;
1471 case Statement::kContinue_Kind:
1472 this->writeContinueStatement((ContinueStatement&) s);
1473 break;
1474 case Statement::kDiscard_Kind:
1475 // not yet implemented
1476 abort();
1477 case Statement::kDo_Kind:
1478 this->writeDoStatement((DoStatement&) s);
1479 break;
Brian Osman3e29f1d2019-05-28 09:35:05 -04001480 case Statement::kExpression_Kind:
1481 this->writeExpression(*((ExpressionStatement&) s).fExpression, true);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001482 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001483 case Statement::kFor_Kind:
1484 this->writeForStatement((ForStatement&) s);
1485 break;
1486 case Statement::kIf_Kind:
1487 this->writeIfStatement((IfStatement&) s);
1488 break;
1489 case Statement::kNop_Kind:
1490 break;
1491 case Statement::kReturn_Kind:
1492 this->writeReturnStatement((ReturnStatement&) s);
1493 break;
1494 case Statement::kSwitch_Kind:
1495 this->writeSwitchStatement((SwitchStatement&) s);
1496 break;
1497 case Statement::kVarDeclarations_Kind:
1498 this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration);
1499 break;
1500 case Statement::kWhile_Kind:
1501 this->writeWhileStatement((WhileStatement&) s);
1502 break;
1503 default:
1504 SkASSERT(false);
1505 }
1506}
1507
Brian Osman80164412019-06-07 13:00:23 -04001508ByteCodeFunction::ByteCodeFunction(const FunctionDeclaration* declaration)
1509 : fName(declaration->fName) {
1510 fParameterCount = 0;
1511 for (const auto& p : declaration->fParameters) {
1512 int slots = ByteCodeGenerator::SlotCount(p->fType);
1513 fParameters.push_back({ slots, (bool)(p->fModifiers.fFlags & Modifiers::kOut_Flag) });
1514 fParameterCount += slots;
1515 }
1516}
1517
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001518}