blob: 8893ddbf1c50514d1fbe57a3558dfb5f87d107b7 [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 {
Mike Reed634c9412019-07-18 13:20:04 -040020 { "cos", ByteCodeInstruction::kCos },
21 { "cross", ByteCodeInstruction::kCross },
22 { "dot", SpecialIntrinsic::kDot },
23 { "inverse", ByteCodeInstruction::kInverse2x2 },
24 { "sin", ByteCodeInstruction::kSin },
25 { "sqrt", ByteCodeInstruction::kSqrt },
26 { "tan", ByteCodeInstruction::kTan },
27 { "mix", ByteCodeInstruction::kMix },
Ethan Nicholasae9633b2019-05-24 12:46:34 -040028 } {}
29
Ethan Nicholas82162ee2019-05-21 16:05:08 -040030
Brian Osman07c117b2019-05-23 12:51:06 -070031int ByteCodeGenerator::SlotCount(const Type& type) {
Brian Osmanfba386b2019-06-20 14:54:15 -040032 if (type.kind() == Type::kOther_Kind) {
33 return 0;
34 } else if (type.kind() == Type::kStruct_Kind) {
Brian Osman07c117b2019-05-23 12:51:06 -070035 int slots = 0;
36 for (const auto& f : type.fields()) {
37 slots += SlotCount(*f.fType);
38 }
39 SkASSERT(slots <= 255);
40 return slots;
41 } else if (type.kind() == Type::kArray_Kind) {
42 int columns = type.columns();
43 SkASSERT(columns >= 0);
44 int slots = columns * SlotCount(type.componentType());
45 SkASSERT(slots <= 255);
46 return slots;
47 } else {
48 return type.columns() * type.rows();
49 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040050}
51
52bool ByteCodeGenerator::generateCode() {
53 for (const auto& e : fProgram) {
54 switch (e.fKind) {
55 case ProgramElement::kFunction_Kind: {
56 std::unique_ptr<ByteCodeFunction> f = this->writeFunction((FunctionDefinition&) e);
57 if (!f) {
58 return false;
59 }
60 fOutput->fFunctions.push_back(std::move(f));
Brian Osman80164412019-06-07 13:00:23 -040061 fFunctions.push_back(&(FunctionDefinition&)e);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040062 break;
63 }
64 case ProgramElement::kVar_Kind: {
65 VarDeclarations& decl = (VarDeclarations&) e;
66 for (const auto& v : decl.fVars) {
67 const Variable* declVar = ((VarDeclaration&) *v).fVar;
68 if (declVar->fModifiers.fLayout.fBuiltin >= 0) {
69 continue;
70 }
71 if (declVar->fModifiers.fFlags & Modifiers::kIn_Flag) {
Brian Osman07c117b2019-05-23 12:51:06 -070072 for (int i = SlotCount(declVar->fType); i > 0; --i) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040073 fOutput->fInputSlots.push_back(fOutput->fGlobalCount++);
74 }
75 } else {
Brian Osman07c117b2019-05-23 12:51:06 -070076 fOutput->fGlobalCount += SlotCount(declVar->fType);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040077 }
78 }
79 break;
80 }
81 default:
82 ; // ignore
83 }
84 }
Brian Osman6f5358f2019-07-09 14:17:23 -040085 return 0 == fErrors.errorCount();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040086}
87
88std::unique_ptr<ByteCodeFunction> ByteCodeGenerator::writeFunction(const FunctionDefinition& f) {
89 fFunction = &f;
Brian Osman226668a2019-05-14 16:47:30 -040090 std::unique_ptr<ByteCodeFunction> result(new ByteCodeFunction(&f.fDeclaration));
Brian Osman80164412019-06-07 13:00:23 -040091 fParameterCount = result->fParameterCount;
Brian Osman4a47da72019-07-12 11:30:32 -040092 fLoopCount = fMaxLoopCount = 0;
93 fConditionCount = fMaxConditionCount = 0;
Brian Osmanaa2ca3f2019-07-15 13:24:48 -040094 fStackCount = fMaxStackCount = 0;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040095 fCode = &result->fCode;
Brian Osman4a47da72019-07-12 11:30:32 -040096
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040097 this->writeStatement(*f.fBody);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -040098 if (0 == fErrors.errorCount()) {
99 SkASSERT(fLoopCount == 0);
100 SkASSERT(fConditionCount == 0);
101 SkASSERT(fStackCount == 0);
102 }
103 this->write(ByteCodeInstruction::kReturn, 0);
Ethan Nicholas7e603db2019-05-03 12:57:47 -0400104 this->write8(0);
Brian Osman4a47da72019-07-12 11:30:32 -0400105
106 result->fLocalCount = fLocals.size();
107 result->fConditionCount = fMaxConditionCount;
108 result->fLoopCount = fMaxLoopCount;
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400109 result->fStackCount = fMaxStackCount;
Brian Osman4a47da72019-07-12 11:30:32 -0400110
Ethan Nicholasdfcad062019-05-07 12:53:34 -0400111 const Type& returnType = f.fDeclaration.fReturnType;
112 if (returnType != *fContext.fVoid_Type) {
Brian Osman07c117b2019-05-23 12:51:06 -0700113 result->fReturnCount = SlotCount(returnType);
Ethan Nicholasdfcad062019-05-07 12:53:34 -0400114 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400115 fLocals.clear();
116 fFunction = nullptr;
117 return result;
118}
119
120enum class TypeCategory {
121 kBool,
122 kSigned,
123 kUnsigned,
124 kFloat,
125};
126
127static TypeCategory type_category(const Type& type) {
128 switch (type.kind()) {
129 case Type::Kind::kVector_Kind:
130 case Type::Kind::kMatrix_Kind:
131 return type_category(type.componentType());
132 default:
133 if (type.fName == "bool") {
134 return TypeCategory::kBool;
135 } else if (type.fName == "int" || type.fName == "short") {
136 return TypeCategory::kSigned;
137 } else if (type.fName == "uint" || type.fName == "ushort") {
138 return TypeCategory::kUnsigned;
139 } else {
140 SkASSERT(type.fName == "float" || type.fName == "half");
141 return TypeCategory::kFloat;
142 }
143 ABORT("unsupported type: %s\n", type.description().c_str());
144 }
145}
146
Brian Osman0785db02019-05-24 14:19:11 -0400147// A "simple" Swizzle is based on a variable (or a compound variable like a struct or array), and
148// that references consecutive values, such that it can be implemented using normal load/store ops
149// with an offset. Note that all single-component swizzles (of suitable base types) are simple.
150static bool swizzle_is_simple(const Swizzle& s) {
151 switch (s.fBase->fKind) {
152 case Expression::kFieldAccess_Kind:
153 case Expression::kIndex_Kind:
154 case Expression::kVariableReference_Kind:
155 break;
156 default:
157 return false;
158 }
159
160 for (size_t i = 1; i < s.fComponents.size(); ++i) {
161 if (s.fComponents[i] != s.fComponents[i - 1] + 1) {
162 return false;
163 }
164 }
165 return true;
166}
167
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400168int ByteCodeGenerator::StackUsage(ByteCodeInstruction inst, int count_) {
169 // Ensures that we use count iff we're passed a non-default value. Most instructions have an
170 // implicit count, so the caller shouldn't need to worry about it (or count makes no sense).
171 // The asserts avoids callers thinking they're supplying useful information in that scenario,
172 // or failing to supply necessary information for the ops that need a count.
173 struct CountValue {
174 operator int() {
175 SkASSERT(val != ByteCodeGenerator::kUnusedStackCount);
176 SkDEBUGCODE(used = true);
177 return val;
178 }
179 ~CountValue() {
180 SkASSERT(used || val == ByteCodeGenerator::kUnusedStackCount);
181 }
182 int val;
183 SkDEBUGCODE(bool used = false;)
184 } count = { count_ };
185
186 switch (inst) {
187 // Unary functions/operators that don't change stack depth at all:
188#define VECTOR_UNARY_OP(base) \
189 case ByteCodeInstruction::base: \
190 case ByteCodeInstruction::base ## 2: \
191 case ByteCodeInstruction::base ## 3: \
192 case ByteCodeInstruction::base ## 4: \
193 return 0;
194
195 VECTOR_UNARY_OP(kConvertFtoI)
196 VECTOR_UNARY_OP(kConvertStoF)
197 VECTOR_UNARY_OP(kConvertUtoF)
198
199 VECTOR_UNARY_OP(kCos)
200 VECTOR_UNARY_OP(kSin)
201 VECTOR_UNARY_OP(kSqrt)
202 VECTOR_UNARY_OP(kTan)
203
204 VECTOR_UNARY_OP(kNegateF)
205 VECTOR_UNARY_OP(kNegateI)
206
Mike Reed634c9412019-07-18 13:20:04 -0400207 case ByteCodeInstruction::kInverse2x2:
208 case ByteCodeInstruction::kInverse3x3:
209 case ByteCodeInstruction::kInverse4x4: return 0;
210
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400211 case ByteCodeInstruction::kNotB: return 0;
212 case ByteCodeInstruction::kNegateFN: return 0;
213
214#undef VECTOR_UNARY_OP
215
216 // Binary functions/operators that do a 2 -> 1 reduction (possibly N times)
217#define VECTOR_BINARY_OP(base) \
218 case ByteCodeInstruction::base: return -1; \
219 case ByteCodeInstruction::base ## 2: return -2; \
220 case ByteCodeInstruction::base ## 3: return -3; \
221 case ByteCodeInstruction::base ## 4: return -4;
222
223#define VECTOR_MATRIX_BINARY_OP(base) \
224 VECTOR_BINARY_OP(base) \
225 case ByteCodeInstruction::base ## N: return -count;
226
227 case ByteCodeInstruction::kAndB: return -1;
228 case ByteCodeInstruction::kOrB: return -1;
229 case ByteCodeInstruction::kXorB: return -1;
230
231 VECTOR_BINARY_OP(kAddI)
232 VECTOR_MATRIX_BINARY_OP(kAddF)
233
234 VECTOR_BINARY_OP(kCompareIEQ)
235 VECTOR_MATRIX_BINARY_OP(kCompareFEQ)
236 VECTOR_BINARY_OP(kCompareINEQ)
237 VECTOR_MATRIX_BINARY_OP(kCompareFNEQ)
238 VECTOR_BINARY_OP(kCompareSGT)
239 VECTOR_BINARY_OP(kCompareUGT)
240 VECTOR_BINARY_OP(kCompareFGT)
241 VECTOR_BINARY_OP(kCompareSGTEQ)
242 VECTOR_BINARY_OP(kCompareUGTEQ)
243 VECTOR_BINARY_OP(kCompareFGTEQ)
244 VECTOR_BINARY_OP(kCompareSLT)
245 VECTOR_BINARY_OP(kCompareULT)
246 VECTOR_BINARY_OP(kCompareFLT)
247 VECTOR_BINARY_OP(kCompareSLTEQ)
248 VECTOR_BINARY_OP(kCompareULTEQ)
249 VECTOR_BINARY_OP(kCompareFLTEQ)
250
251 VECTOR_BINARY_OP(kDivideS)
252 VECTOR_BINARY_OP(kDivideU)
253 VECTOR_MATRIX_BINARY_OP(kDivideF)
254 VECTOR_BINARY_OP(kMultiplyI)
255 VECTOR_MATRIX_BINARY_OP(kMultiplyF)
256 VECTOR_BINARY_OP(kRemainderF)
257 VECTOR_BINARY_OP(kRemainderS)
258 VECTOR_BINARY_OP(kRemainderU)
259 VECTOR_BINARY_OP(kSubtractI)
260 VECTOR_MATRIX_BINARY_OP(kSubtractF)
261
262#undef VECTOR_BINARY_OP
263#undef VECTOR_MATRIX_BINARY_OP
264
265 // Strange math operations with other behavior:
266 case ByteCodeInstruction::kCross: return -3;
267 // Binary, but also consumes T:
268 case ByteCodeInstruction::kMix: return -2;
269 case ByteCodeInstruction::kMix2: return -3;
270 case ByteCodeInstruction::kMix3: return -4;
271 case ByteCodeInstruction::kMix4: return -5;
272
273 // Ops that push or load data to grow the stack:
274 case ByteCodeInstruction::kDup:
275 case ByteCodeInstruction::kLoad:
276 case ByteCodeInstruction::kLoadGlobal:
277 case ByteCodeInstruction::kReadExternal:
278 case ByteCodeInstruction::kPushImmediate:
279 return 1;
280
281 case ByteCodeInstruction::kDup2:
282 case ByteCodeInstruction::kLoad2:
283 case ByteCodeInstruction::kLoadGlobal2:
284 case ByteCodeInstruction::kReadExternal2:
285 return 2;
286
287 case ByteCodeInstruction::kDup3:
288 case ByteCodeInstruction::kLoad3:
289 case ByteCodeInstruction::kLoadGlobal3:
290 case ByteCodeInstruction::kReadExternal3:
291 return 3;
292
293 case ByteCodeInstruction::kDup4:
294 case ByteCodeInstruction::kLoad4:
295 case ByteCodeInstruction::kLoadGlobal4:
296 case ByteCodeInstruction::kReadExternal4:
297 return 4;
298
299 case ByteCodeInstruction::kDupN:
300 case ByteCodeInstruction::kLoadSwizzle:
301 case ByteCodeInstruction::kLoadSwizzleGlobal:
302 return count;
303
304 // Pushes 'count' values, minus one for the 'address' that's consumed first
305 case ByteCodeInstruction::kLoadExtended:
306 case ByteCodeInstruction::kLoadExtendedGlobal:
307 return count - 1;
308
309 // Ops that pop or store data to shrink the stack:
310 case ByteCodeInstruction::kPop:
311 case ByteCodeInstruction::kStore:
312 case ByteCodeInstruction::kStoreGlobal:
313 case ByteCodeInstruction::kWriteExternal:
314 return -1;
315
316 case ByteCodeInstruction::kPop2:
317 case ByteCodeInstruction::kStore2:
318 case ByteCodeInstruction::kStoreGlobal2:
319 case ByteCodeInstruction::kWriteExternal2:
320 return -2;
321
322 case ByteCodeInstruction::kPop3:
323 case ByteCodeInstruction::kStore3:
324 case ByteCodeInstruction::kStoreGlobal3:
325 case ByteCodeInstruction::kWriteExternal3:
326 return -3;
327
328 case ByteCodeInstruction::kPop4:
329 case ByteCodeInstruction::kStore4:
330 case ByteCodeInstruction::kStoreGlobal4:
331 case ByteCodeInstruction::kWriteExternal4:
332 return -4;
333
334 case ByteCodeInstruction::kPopN:
335 case ByteCodeInstruction::kStoreSwizzle:
336 case ByteCodeInstruction::kStoreSwizzleGlobal:
337 return -count;
338
339 // Consumes 'count' values, plus one for the 'address'
340 case ByteCodeInstruction::kStoreExtended:
341 case ByteCodeInstruction::kStoreExtendedGlobal:
342 case ByteCodeInstruction::kStoreSwizzleIndirect:
343 case ByteCodeInstruction::kStoreSwizzleIndirectGlobal:
344 return -count - 1;
345
346 // Strange ops where the caller computes the delta for us:
347 case ByteCodeInstruction::kCallExternal:
348 case ByteCodeInstruction::kMatrixToMatrix:
349 case ByteCodeInstruction::kMatrixMultiply:
350 case ByteCodeInstruction::kReserve:
351 case ByteCodeInstruction::kReturn:
352 case ByteCodeInstruction::kScalarToMatrix:
353 case ByteCodeInstruction::kSwizzle:
354 return count;
355
356 // Miscellaneous
357
358 // kCall is net-zero. Max stack depth is adjusted in writeFunctionCall.
359 case ByteCodeInstruction::kCall: return 0;
360 case ByteCodeInstruction::kBranch: return 0;
361 case ByteCodeInstruction::kBranchIfAllFalse: return 0;
362
363 case ByteCodeInstruction::kMaskPush: return -1;
364 case ByteCodeInstruction::kMaskPop: return 0;
365 case ByteCodeInstruction::kMaskNegate: return 0;
366 case ByteCodeInstruction::kMaskBlend: return -count;
367
368 case ByteCodeInstruction::kLoopBegin: return 0;
369 case ByteCodeInstruction::kLoopNext: return 0;
370 case ByteCodeInstruction::kLoopMask: return -1;
371 case ByteCodeInstruction::kLoopEnd: return 0;
372 case ByteCodeInstruction::kLoopBreak: return 0;
373 case ByteCodeInstruction::kLoopContinue: return 0;
374
375 default:
Brian Osmanc7ec9e22019-07-16 08:49:11 -0400376 ABORT("unsupported instruction %d\n", (int)inst);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400377 return 0;
378 }
379}
380
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400381int ByteCodeGenerator::getLocation(const Variable& var) {
382 // given that we seldom have more than a couple of variables, linear search is probably the most
383 // efficient way to handle lookups
384 switch (var.fStorage) {
385 case Variable::kLocal_Storage: {
386 for (int i = fLocals.size() - 1; i >= 0; --i) {
387 if (fLocals[i] == &var) {
Brian Osman1091f022019-05-16 09:42:16 -0400388 SkASSERT(fParameterCount + i <= 255);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400389 return fParameterCount + i;
390 }
391 }
392 int result = fParameterCount + fLocals.size();
393 fLocals.push_back(&var);
Brian Osman07c117b2019-05-23 12:51:06 -0700394 for (int i = 0; i < SlotCount(var.fType) - 1; ++i) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400395 fLocals.push_back(nullptr);
396 }
Brian Osman1091f022019-05-16 09:42:16 -0400397 SkASSERT(result <= 255);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400398 return result;
399 }
400 case Variable::kParameter_Storage: {
401 int offset = 0;
402 for (const auto& p : fFunction->fDeclaration.fParameters) {
403 if (p == &var) {
Brian Osman1091f022019-05-16 09:42:16 -0400404 SkASSERT(offset <= 255);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400405 return offset;
406 }
Brian Osman07c117b2019-05-23 12:51:06 -0700407 offset += SlotCount(p->fType);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400408 }
409 SkASSERT(false);
Brian Osman1091f022019-05-16 09:42:16 -0400410 return 0;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400411 }
412 case Variable::kGlobal_Storage: {
413 int offset = 0;
414 for (const auto& e : fProgram) {
415 if (e.fKind == ProgramElement::kVar_Kind) {
416 VarDeclarations& decl = (VarDeclarations&) e;
417 for (const auto& v : decl.fVars) {
418 const Variable* declVar = ((VarDeclaration&) *v).fVar;
419 if (declVar->fModifiers.fLayout.fBuiltin >= 0) {
420 continue;
421 }
422 if (declVar == &var) {
Brian Osmanb7451292019-05-15 13:02:13 -0400423 SkASSERT(offset <= 255);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400424 return offset;
425 }
Brian Osman07c117b2019-05-23 12:51:06 -0700426 offset += SlotCount(declVar->fType);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400427 }
428 }
429 }
430 SkASSERT(false);
Brian Osman1091f022019-05-16 09:42:16 -0400431 return 0;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400432 }
433 default:
434 SkASSERT(false);
435 return 0;
436 }
437}
438
Brian Osman07c117b2019-05-23 12:51:06 -0700439int ByteCodeGenerator::getLocation(const Expression& expr, Variable::Storage* storage) {
440 switch (expr.fKind) {
441 case Expression::kFieldAccess_Kind: {
442 const FieldAccess& f = (const FieldAccess&)expr;
443 int baseAddr = this->getLocation(*f.fBase, storage);
444 int offset = 0;
445 for (int i = 0; i < f.fFieldIndex; ++i) {
446 offset += SlotCount(*f.fBase->fType.fields()[i].fType);
447 }
448 if (baseAddr < 0) {
Brian Osman86769292019-06-21 11:05:47 -0400449 if (offset != 0) {
450 this->write(ByteCodeInstruction::kPushImmediate);
451 this->write32(offset);
452 this->write(ByteCodeInstruction::kAddI);
453 }
Brian Osman07c117b2019-05-23 12:51:06 -0700454 return -1;
455 } else {
456 return baseAddr + offset;
457 }
458 }
459 case Expression::kIndex_Kind: {
460 const IndexExpression& i = (const IndexExpression&)expr;
461 int stride = SlotCount(i.fType);
462 int offset = -1;
463 if (i.fIndex->isConstant()) {
Brian Osman3e6aa9f2019-07-18 17:22:33 +0000464 offset = i.fIndex->getConstantInt() * stride;
Brian Osman07c117b2019-05-23 12:51:06 -0700465 } else {
Brian Osman86769292019-06-21 11:05:47 -0400466 if (i.fIndex->hasSideEffects()) {
467 // Having a side-effect in an indexer is technically safe for an rvalue,
468 // but with lvalues we have to evaluate the indexer twice, so make it an error.
469 fErrors.error(i.fIndex->fOffset,
470 "Index expressions with side-effects not supported in byte code.");
471 return 0;
472 }
Brian Osman07c117b2019-05-23 12:51:06 -0700473 this->writeExpression(*i.fIndex);
Brian Osman86769292019-06-21 11:05:47 -0400474 if (stride != 1) {
475 this->write(ByteCodeInstruction::kPushImmediate);
476 this->write32(stride);
477 this->write(ByteCodeInstruction::kMultiplyI);
478 }
Brian Osman07c117b2019-05-23 12:51:06 -0700479 }
480 int baseAddr = this->getLocation(*i.fBase, storage);
Brian Osman86769292019-06-21 11:05:47 -0400481
482 // Are both components known statically?
Brian Osman07c117b2019-05-23 12:51:06 -0700483 if (baseAddr >= 0 && offset >= 0) {
484 return baseAddr + offset;
485 }
Brian Osman86769292019-06-21 11:05:47 -0400486
487 // At least one component is dynamic (and on the stack).
488
489 // If the other component is zero, we're done
490 if (baseAddr == 0 || offset == 0) {
491 return -1;
492 }
493
494 // Push the non-dynamic component (if any) to the stack, then add the two
Brian Osman07c117b2019-05-23 12:51:06 -0700495 if (baseAddr >= 0) {
496 this->write(ByteCodeInstruction::kPushImmediate);
497 this->write32(baseAddr);
498 }
499 if (offset >= 0) {
500 this->write(ByteCodeInstruction::kPushImmediate);
501 this->write32(offset);
502 }
503 this->write(ByteCodeInstruction::kAddI);
504 return -1;
505 }
Brian Osman0785db02019-05-24 14:19:11 -0400506 case Expression::kSwizzle_Kind: {
507 const Swizzle& s = (const Swizzle&)expr;
508 SkASSERT(swizzle_is_simple(s));
509 int baseAddr = this->getLocation(*s.fBase, storage);
510 int offset = s.fComponents[0];
511 if (baseAddr < 0) {
Brian Osman86769292019-06-21 11:05:47 -0400512 if (offset != 0) {
513 this->write(ByteCodeInstruction::kPushImmediate);
514 this->write32(offset);
515 this->write(ByteCodeInstruction::kAddI);
516 }
Brian Osman0785db02019-05-24 14:19:11 -0400517 return -1;
518 } else {
519 return baseAddr + offset;
520 }
521 }
Brian Osman07c117b2019-05-23 12:51:06 -0700522 case Expression::kVariableReference_Kind: {
523 const Variable& var = ((const VariableReference&)expr).fVariable;
524 *storage = var.fStorage;
525 return this->getLocation(var);
526 }
527 default:
528 SkASSERT(false);
529 return 0;
530 }
531}
532
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400533void ByteCodeGenerator::write8(uint8_t b) {
534 fCode->push_back(b);
535}
536
537void ByteCodeGenerator::write16(uint16_t i) {
Mike Klein76346ac2019-05-17 11:57:10 -0500538 size_t n = fCode->size();
539 fCode->resize(n+2);
540 memcpy(fCode->data() + n, &i, 2);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400541}
542
543void ByteCodeGenerator::write32(uint32_t i) {
Mike Klein76346ac2019-05-17 11:57:10 -0500544 size_t n = fCode->size();
545 fCode->resize(n+4);
546 memcpy(fCode->data() + n, &i, 4);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400547}
548
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400549void ByteCodeGenerator::write(ByteCodeInstruction i, int count) {
Brian Osman4a47da72019-07-12 11:30:32 -0400550 switch (i) {
551 case ByteCodeInstruction::kLoopBegin: this->enterLoop(); break;
552 case ByteCodeInstruction::kLoopEnd: this->exitLoop(); break;
553
554 case ByteCodeInstruction::kMaskPush: this->enterCondition(); break;
555 case ByteCodeInstruction::kMaskPop:
556 case ByteCodeInstruction::kMaskBlend: this->exitCondition(); break;
557 default: /* Do nothing */ break;
558 }
Mike Klein108e9352019-05-21 11:05:17 -0500559 this->write16((uint16_t)i);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400560 fStackCount += StackUsage(i, count);
561 fMaxStackCount = std::max(fMaxStackCount, fStackCount);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400562}
563
Mike Klein76346ac2019-05-17 11:57:10 -0500564static ByteCodeInstruction vector_instruction(ByteCodeInstruction base, int count) {
Brian Osman07c117b2019-05-23 12:51:06 -0700565 SkASSERT(count >= 1 && count <= 4);
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400566 return ((ByteCodeInstruction) ((int) base + count - 1));
567}
568
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400569void ByteCodeGenerator::writeTypedInstruction(const Type& type, ByteCodeInstruction s,
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400570 ByteCodeInstruction u, ByteCodeInstruction f,
571 int count) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400572 switch (type_category(type)) {
573 case TypeCategory::kSigned:
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400574 this->write(vector_instruction(s, count));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400575 break;
576 case TypeCategory::kUnsigned:
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400577 this->write(vector_instruction(u, count));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400578 break;
Brian Osman1e855b22019-05-29 15:21:52 -0400579 case TypeCategory::kFloat: {
580 if (count > 4) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400581 this->write((ByteCodeInstruction)((int)f + 4), count);
Brian Osman1e855b22019-05-29 15:21:52 -0400582 this->write8(count);
583 } else {
584 this->write(vector_instruction(f, count));
585 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400586 break;
Brian Osman1e855b22019-05-29 15:21:52 -0400587 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400588 default:
589 SkASSERT(false);
590 }
591}
592
Brian Osman3e29f1d2019-05-28 09:35:05 -0400593bool ByteCodeGenerator::writeBinaryExpression(const BinaryExpression& b, bool discard) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400594 if (b.fOperator == Token::Kind::EQ) {
595 std::unique_ptr<LValue> lvalue = this->getLValue(*b.fLeft);
596 this->writeExpression(*b.fRight);
Brian Osman3e29f1d2019-05-28 09:35:05 -0400597 lvalue->store(discard);
598 discard = false;
599 return discard;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400600 }
Brian Osman16e6fd52019-05-29 11:19:00 -0400601 const Type& lType = b.fLeft->fType;
602 const Type& rType = b.fRight->fType;
Brian Osman909231c2019-05-29 15:34:36 -0400603 bool lVecOrMtx = (lType.kind() == Type::kVector_Kind || lType.kind() == Type::kMatrix_Kind);
604 bool rVecOrMtx = (rType.kind() == Type::kVector_Kind || rType.kind() == Type::kMatrix_Kind);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400605 Token::Kind op;
606 std::unique_ptr<LValue> lvalue;
607 if (is_assignment(b.fOperator)) {
608 lvalue = this->getLValue(*b.fLeft);
609 lvalue->load();
610 op = remove_assignment(b.fOperator);
611 } else {
612 this->writeExpression(*b.fLeft);
613 op = b.fOperator;
Brian Osman909231c2019-05-29 15:34:36 -0400614 if (!lVecOrMtx && rVecOrMtx) {
Brian Osman16e6fd52019-05-29 11:19:00 -0400615 for (int i = SlotCount(rType); i > 1; --i) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400616 this->write(ByteCodeInstruction::kDup);
617 }
618 }
619 }
620 this->writeExpression(*b.fRight);
Brian Osman909231c2019-05-29 15:34:36 -0400621 if (lVecOrMtx && !rVecOrMtx) {
Brian Osman16e6fd52019-05-29 11:19:00 -0400622 for (int i = SlotCount(lType); i > 1; --i) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400623 this->write(ByteCodeInstruction::kDup);
624 }
625 }
Brian Osman909231c2019-05-29 15:34:36 -0400626 // Special case for M*V, V*M, M*M (but not V*V!)
627 if (op == Token::Kind::STAR && lVecOrMtx && rVecOrMtx &&
628 !(lType.kind() == Type::kVector_Kind && rType.kind() == Type::kVector_Kind)) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400629 this->write(ByteCodeInstruction::kMatrixMultiply,
630 SlotCount(b.fType) - (SlotCount(lType) + SlotCount(rType)));
Brian Osman909231c2019-05-29 15:34:36 -0400631 int rCols = rType.columns(),
632 rRows = rType.rows(),
633 lCols = lType.columns(),
634 lRows = lType.rows();
635 // M*V treats the vector as a column
636 if (rType.kind() == Type::kVector_Kind) {
637 std::swap(rCols, rRows);
638 }
639 SkASSERT(lCols == rRows);
640 SkASSERT(SlotCount(b.fType) == lRows * rCols);
641 this->write8(lCols);
642 this->write8(lRows);
643 this->write8(rCols);
644 } else {
645 int count = std::max(SlotCount(lType), SlotCount(rType));
646 switch (op) {
647 case Token::Kind::EQEQ:
648 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareIEQ,
649 ByteCodeInstruction::kCompareIEQ,
650 ByteCodeInstruction::kCompareFEQ,
651 count);
652 // Collapse to a single bool
653 for (int i = count; i > 1; --i) {
654 this->write(ByteCodeInstruction::kAndB);
655 }
656 break;
657 case Token::Kind::GT:
658 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSGT,
659 ByteCodeInstruction::kCompareUGT,
660 ByteCodeInstruction::kCompareFGT,
661 count);
662 break;
663 case Token::Kind::GTEQ:
664 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSGTEQ,
665 ByteCodeInstruction::kCompareUGTEQ,
666 ByteCodeInstruction::kCompareFGTEQ,
667 count);
668 break;
669 case Token::Kind::LT:
670 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSLT,
671 ByteCodeInstruction::kCompareULT,
672 ByteCodeInstruction::kCompareFLT,
673 count);
674 break;
675 case Token::Kind::LTEQ:
676 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSLTEQ,
677 ByteCodeInstruction::kCompareULTEQ,
678 ByteCodeInstruction::kCompareFLTEQ,
679 count);
680 break;
681 case Token::Kind::MINUS:
682 this->writeTypedInstruction(lType, ByteCodeInstruction::kSubtractI,
683 ByteCodeInstruction::kSubtractI,
684 ByteCodeInstruction::kSubtractF,
685 count);
686 break;
687 case Token::Kind::NEQ:
688 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareINEQ,
689 ByteCodeInstruction::kCompareINEQ,
690 ByteCodeInstruction::kCompareFNEQ,
691 count);
692 // Collapse to a single bool
693 for (int i = count; i > 1; --i) {
694 this->write(ByteCodeInstruction::kOrB);
695 }
696 break;
697 case Token::Kind::PERCENT:
698 this->writeTypedInstruction(lType, ByteCodeInstruction::kRemainderS,
699 ByteCodeInstruction::kRemainderU,
700 ByteCodeInstruction::kRemainderF,
701 count);
702 break;
703 case Token::Kind::PLUS:
704 this->writeTypedInstruction(lType, ByteCodeInstruction::kAddI,
705 ByteCodeInstruction::kAddI,
706 ByteCodeInstruction::kAddF,
707 count);
708 break;
709 case Token::Kind::SLASH:
710 this->writeTypedInstruction(lType, ByteCodeInstruction::kDivideS,
711 ByteCodeInstruction::kDivideU,
712 ByteCodeInstruction::kDivideF,
713 count);
714 break;
715 case Token::Kind::STAR:
716 this->writeTypedInstruction(lType, ByteCodeInstruction::kMultiplyI,
717 ByteCodeInstruction::kMultiplyI,
718 ByteCodeInstruction::kMultiplyF,
719 count);
720 break;
Brian Osman569f12f2019-06-13 11:23:57 -0400721
722 case Token::Kind::LOGICALAND:
723 SkASSERT(type_category(lType) == SkSL::TypeCategory::kBool && count == 1);
724 this->write(ByteCodeInstruction::kAndB);
725 break;
726 case Token::Kind::LOGICALNOT:
727 SkASSERT(type_category(lType) == SkSL::TypeCategory::kBool && count == 1);
728 this->write(ByteCodeInstruction::kNotB);
729 break;
730 case Token::Kind::LOGICALOR:
731 SkASSERT(type_category(lType) == SkSL::TypeCategory::kBool && count == 1);
732 this->write(ByteCodeInstruction::kOrB);
733 break;
734 case Token::Kind::LOGICALXOR:
735 SkASSERT(type_category(lType) == SkSL::TypeCategory::kBool && count == 1);
736 this->write(ByteCodeInstruction::kXorB);
737 break;
738
Brian Osman909231c2019-05-29 15:34:36 -0400739 default:
740 SkASSERT(false);
741 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400742 }
743 if (lvalue) {
Brian Osman3e29f1d2019-05-28 09:35:05 -0400744 lvalue->store(discard);
745 discard = false;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400746 }
Brian Osman3e29f1d2019-05-28 09:35:05 -0400747 return discard;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400748}
749
750void ByteCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
751 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osman569f12f2019-06-13 11:23:57 -0400752 this->write32(b.fValue ? ~0 : 0);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400753}
754
755void ByteCodeGenerator::writeConstructor(const Constructor& c) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400756 for (const auto& arg : c.fArguments) {
757 this->writeExpression(*arg);
758 }
759 if (c.fArguments.size() == 1) {
Brian Osman29e013d2019-05-28 17:16:03 -0400760 const Type& inType = c.fArguments[0]->fType;
761 const Type& outType = c.fType;
762 TypeCategory inCategory = type_category(inType);
763 TypeCategory outCategory = type_category(outType);
764 int inCount = SlotCount(inType);
765 int outCount = SlotCount(outType);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400766 if (inCategory != outCategory) {
Brian Osmanc51d7912019-05-22 15:16:16 -0700767 SkASSERT(inCount == outCount);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400768 if (inCategory == TypeCategory::kFloat) {
769 SkASSERT(outCategory == TypeCategory::kSigned ||
770 outCategory == TypeCategory::kUnsigned);
Brian Osmanc51d7912019-05-22 15:16:16 -0700771 this->write(vector_instruction(ByteCodeInstruction::kConvertFtoI, outCount));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400772 } else if (outCategory == TypeCategory::kFloat) {
773 if (inCategory == TypeCategory::kSigned) {
Brian Osmanc51d7912019-05-22 15:16:16 -0700774 this->write(vector_instruction(ByteCodeInstruction::kConvertStoF, outCount));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400775 } else {
776 SkASSERT(inCategory == TypeCategory::kUnsigned);
Brian Osmanc51d7912019-05-22 15:16:16 -0700777 this->write(vector_instruction(ByteCodeInstruction::kConvertUtoF, outCount));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400778 }
779 } else {
780 SkASSERT(false);
781 }
782 }
Brian Osman29e013d2019-05-28 17:16:03 -0400783 if (inType.kind() == Type::kMatrix_Kind && outType.kind() == Type::kMatrix_Kind) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400784 this->write(ByteCodeInstruction::kMatrixToMatrix,
785 SlotCount(outType) - SlotCount(inType));
Brian Osman29e013d2019-05-28 17:16:03 -0400786 this->write8(inType.columns());
787 this->write8(inType.rows());
788 this->write8(outType.columns());
789 this->write8(outType.rows());
790 } else if (inCount != outCount) {
Brian Osmanc51d7912019-05-22 15:16:16 -0700791 SkASSERT(inCount == 1);
Brian Osman29e013d2019-05-28 17:16:03 -0400792 if (outType.kind() == Type::kMatrix_Kind) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400793 this->write(ByteCodeInstruction::kScalarToMatrix, SlotCount(outType) - 1);
Brian Osman29e013d2019-05-28 17:16:03 -0400794 this->write8(outType.columns());
795 this->write8(outType.rows());
796 } else {
797 SkASSERT(outType.kind() == Type::kVector_Kind);
798 for (; inCount != outCount; ++inCount) {
799 this->write(ByteCodeInstruction::kDup);
800 }
Brian Osmanc51d7912019-05-22 15:16:16 -0700801 }
802 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400803 }
804}
805
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400806void ByteCodeGenerator::writeExternalFunctionCall(const ExternalFunctionCall& f) {
807 int argumentCount = 0;
808 for (const auto& arg : f.fArguments) {
809 this->writeExpression(*arg);
Brian Osman07c117b2019-05-23 12:51:06 -0700810 argumentCount += SlotCount(arg->fType);
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400811 }
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400812 this->write(ByteCodeInstruction::kCallExternal, SlotCount(f.fType) - argumentCount);
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400813 SkASSERT(argumentCount <= 255);
814 this->write8(argumentCount);
Brian Osman07c117b2019-05-23 12:51:06 -0700815 this->write8(SlotCount(f.fType));
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400816 int index = fOutput->fExternalValues.size();
817 fOutput->fExternalValues.push_back(f.fFunction);
818 SkASSERT(index <= 255);
819 this->write8(index);
820}
821
Ethan Nicholas91164d12019-05-15 15:29:54 -0400822void ByteCodeGenerator::writeExternalValue(const ExternalValueReference& e) {
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400823 this->write(vector_instruction(ByteCodeInstruction::kReadExternal,
Brian Osman07c117b2019-05-23 12:51:06 -0700824 SlotCount(e.fValue->type())));
Ethan Nicholas91164d12019-05-15 15:29:54 -0400825 int index = fOutput->fExternalValues.size();
826 fOutput->fExternalValues.push_back(e.fValue);
827 SkASSERT(index <= 255);
828 this->write8(index);
829}
830
Brian Osman07c117b2019-05-23 12:51:06 -0700831void ByteCodeGenerator::writeVariableExpression(const Expression& expr) {
832 Variable::Storage storage;
833 int location = this->getLocation(expr, &storage);
834 bool isGlobal = storage == Variable::kGlobal_Storage;
835 int count = SlotCount(expr.fType);
836 if (location < 0 || count > 4) {
837 if (location >= 0) {
838 this->write(ByteCodeInstruction::kPushImmediate);
839 this->write32(location);
840 }
841 this->write(isGlobal ? ByteCodeInstruction::kLoadExtendedGlobal
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400842 : ByteCodeInstruction::kLoadExtended,
843 count);
Brian Osman07c117b2019-05-23 12:51:06 -0700844 this->write8(count);
845 } else {
846 this->write(vector_instruction(isGlobal ? ByteCodeInstruction::kLoadGlobal
847 : ByteCodeInstruction::kLoad,
848 count));
849 this->write8(location);
850 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400851}
852
Brian Osmand30e0392019-06-14 14:05:14 -0400853static inline uint32_t float_to_bits(float x) {
854 uint32_t u;
855 memcpy(&u, &x, sizeof(uint32_t));
856 return u;
857}
858
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400859void ByteCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
860 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osmand30e0392019-06-14 14:05:14 -0400861 this->write32(float_to_bits(f.fValue));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400862}
863
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400864void ByteCodeGenerator::writeIntrinsicCall(const FunctionCall& c) {
865 auto found = fIntrinsics.find(c.fFunction.fName);
866 if (found == fIntrinsics.end()) {
867 fErrors.error(c.fOffset, "unsupported intrinsic function");
868 return;
869 }
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400870 int count = SlotCount(c.fArguments[0]->fType);
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400871 if (found->second.fIsSpecial) {
872 SkASSERT(found->second.fValue.fSpecial == SpecialIntrinsic::kDot);
873 SkASSERT(c.fArguments.size() == 2);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400874 SkASSERT(count == SlotCount(c.fArguments[1]->fType));
875 this->write((ByteCodeInstruction)((int)ByteCodeInstruction::kMultiplyF + count - 1));
876 for (int i = count; i > 1; --i) {
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400877 this->write(ByteCodeInstruction::kAddF);
878 }
879 } else {
880 switch (found->second.fValue.fInstruction) {
881 case ByteCodeInstruction::kCos:
882 case ByteCodeInstruction::kMix:
883 case ByteCodeInstruction::kSin:
884 case ByteCodeInstruction::kSqrt:
885 case ByteCodeInstruction::kTan:
886 SkASSERT(c.fArguments.size() > 0);
887 this->write((ByteCodeInstruction) ((int) found->second.fValue.fInstruction +
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400888 count - 1));
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400889 break;
890 case ByteCodeInstruction::kCross:
891 this->write(found->second.fValue.fInstruction);
892 break;
Mike Reed634c9412019-07-18 13:20:04 -0400893 case ByteCodeInstruction::kInverse2x2: {
894 SkASSERT(c.fArguments.size() > 0);
895 auto op = ByteCodeInstruction::kInverse2x2;
896 switch (count) {
897 case 4: break; // float2x2
898 case 9: op = ByteCodeInstruction::kInverse3x3; break;
899 case 16: op = ByteCodeInstruction::kInverse4x4; break;
900 default: SkASSERT(false);
901 }
902 this->write(op);
903 } break;
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400904 default:
905 SkASSERT(false);
906 }
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400907 }
908}
909
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400910void ByteCodeGenerator::writeFunctionCall(const FunctionCall& f) {
Brian Osmand3494ed2019-06-20 15:41:34 -0400911 // Builtins have simple signatures...
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400912 if (f.fFunction.fBuiltin) {
Brian Osmand3494ed2019-06-20 15:41:34 -0400913 for (const auto& arg : f.fArguments) {
914 this->writeExpression(*arg);
915 }
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400916 this->writeIntrinsicCall(f);
917 return;
918 }
Brian Osmand3494ed2019-06-20 15:41:34 -0400919
Brian Osman6f5358f2019-07-09 14:17:23 -0400920 // Find the index of the function we're calling. We explicitly do not allow calls to functions
921 // before they're defined. This is an easy-to-understand rule that prevents recursion.
922 size_t idx;
923 for (idx = 0; idx < fFunctions.size(); ++idx) {
924 if (f.fFunction.matches(fFunctions[idx]->fDeclaration)) {
925 break;
926 }
927 }
928 if (idx > 255) {
929 fErrors.error(f.fOffset, "Function count limit exceeded");
930 return;
931 } else if (idx >= fFunctions.size()) {
932 fErrors.error(f.fOffset, "Call to undefined function");
933 return;
934 }
935
936 // We may need to deal with out parameters, so the sequence is tricky
Brian Osmand3494ed2019-06-20 15:41:34 -0400937 if (int returnCount = SlotCount(f.fType)) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400938 this->write(ByteCodeInstruction::kReserve, returnCount);
Brian Osmand3494ed2019-06-20 15:41:34 -0400939 this->write8(returnCount);
940 }
941
942 int argCount = f.fArguments.size();
943 std::vector<std::unique_ptr<LValue>> lvalues;
944 for (int i = 0; i < argCount; ++i) {
945 const auto& param = f.fFunction.fParameters[i];
946 const auto& arg = f.fArguments[i];
947 if (param->fModifiers.fFlags & Modifiers::kOut_Flag) {
948 lvalues.emplace_back(this->getLValue(*arg));
949 lvalues.back()->load();
950 } else {
951 this->writeExpression(*arg);
952 }
953 }
954
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400955 // The space used by the call is based on the callee, but it also unwinds all of that before
956 // we continue execution. We adjust our max stack depths below.
Brian Osman226668a2019-05-14 16:47:30 -0400957 this->write(ByteCodeInstruction::kCall);
Brian Osman6f5358f2019-07-09 14:17:23 -0400958 this->write8(idx);
Brian Osmand3494ed2019-06-20 15:41:34 -0400959
Brian Osman4a47da72019-07-12 11:30:32 -0400960 const ByteCodeFunction* callee = fOutput->fFunctions[idx].get();
961 fMaxLoopCount = std::max(fMaxLoopCount, fLoopCount + callee->fLoopCount);
962 fMaxConditionCount = std::max(fMaxConditionCount, fConditionCount + callee->fConditionCount);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400963 fMaxStackCount = std::max(fMaxStackCount, fStackCount + callee->fLocalCount
964 + callee->fStackCount);
Brian Osman4a47da72019-07-12 11:30:32 -0400965
Brian Osmand3494ed2019-06-20 15:41:34 -0400966 // After the called function returns, the stack will still contain our arguments. We have to
967 // pop them (storing any out parameters back to their lvalues as we go). We glob together slot
968 // counts for all parameters that aren't out-params, so we can pop them in one big chunk.
969 int popCount = 0;
970 auto pop = [&]() {
971 if (popCount > 4) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400972 this->write(ByteCodeInstruction::kPopN, popCount);
Brian Osmand3494ed2019-06-20 15:41:34 -0400973 this->write8(popCount);
974 } else if (popCount > 0) {
975 this->write(vector_instruction(ByteCodeInstruction::kPop, popCount));
976 }
977 popCount = 0;
978 };
979
980 for (int i = argCount - 1; i >= 0; --i) {
981 const auto& param = f.fFunction.fParameters[i];
982 const auto& arg = f.fArguments[i];
983 if (param->fModifiers.fFlags & Modifiers::kOut_Flag) {
984 pop();
985 lvalues.back()->store(true);
986 lvalues.pop_back();
987 } else {
988 popCount += SlotCount(arg->fType);
989 }
990 }
991 pop();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400992}
993
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400994void ByteCodeGenerator::writeIntLiteral(const IntLiteral& i) {
995 this->write(ByteCodeInstruction::kPushImmediate);
996 this->write32(i.fValue);
997}
998
999void ByteCodeGenerator::writeNullLiteral(const NullLiteral& n) {
1000 // not yet implemented
1001 abort();
1002}
1003
Brian Osman3e29f1d2019-05-28 09:35:05 -04001004bool ByteCodeGenerator::writePrefixExpression(const PrefixExpression& p, bool discard) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001005 switch (p.fOperator) {
1006 case Token::Kind::PLUSPLUS: // fall through
1007 case Token::Kind::MINUSMINUS: {
Brian Osman07c117b2019-05-23 12:51:06 -07001008 SkASSERT(SlotCount(p.fOperand->fType) == 1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001009 std::unique_ptr<LValue> lvalue = this->getLValue(*p.fOperand);
1010 lvalue->load();
1011 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osmand30e0392019-06-14 14:05:14 -04001012 this->write32(type_category(p.fType) == TypeCategory::kFloat ? float_to_bits(1.0f) : 1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001013 if (p.fOperator == Token::Kind::PLUSPLUS) {
1014 this->writeTypedInstruction(p.fType,
1015 ByteCodeInstruction::kAddI,
1016 ByteCodeInstruction::kAddI,
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001017 ByteCodeInstruction::kAddF,
1018 1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001019 } else {
1020 this->writeTypedInstruction(p.fType,
1021 ByteCodeInstruction::kSubtractI,
1022 ByteCodeInstruction::kSubtractI,
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001023 ByteCodeInstruction::kSubtractF,
1024 1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001025 }
Brian Osman3e29f1d2019-05-28 09:35:05 -04001026 lvalue->store(discard);
1027 discard = false;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001028 break;
1029 }
Ethan Nicholas354ecf32019-05-07 16:13:02 -04001030 case Token::Kind::MINUS: {
1031 this->writeExpression(*p.fOperand);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001032 this->writeTypedInstruction(p.fType,
Mike Klein12710912019-05-21 11:04:59 -05001033 ByteCodeInstruction::kNegateI,
1034 ByteCodeInstruction::kNegateI,
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001035 ByteCodeInstruction::kNegateF,
Brian Osman07c117b2019-05-23 12:51:06 -07001036 SlotCount(p.fOperand->fType));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001037 break;
Ethan Nicholas354ecf32019-05-07 16:13:02 -04001038 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001039 default:
1040 SkASSERT(false);
1041 }
Brian Osman3e29f1d2019-05-28 09:35:05 -04001042 return discard;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001043}
1044
Brian Osman3e29f1d2019-05-28 09:35:05 -04001045bool ByteCodeGenerator::writePostfixExpression(const PostfixExpression& p, bool discard) {
Brian Osmanf3fa6002019-05-17 14:26:53 -04001046 switch (p.fOperator) {
1047 case Token::Kind::PLUSPLUS: // fall through
1048 case Token::Kind::MINUSMINUS: {
Brian Osman07c117b2019-05-23 12:51:06 -07001049 SkASSERT(SlotCount(p.fOperand->fType) == 1);
Brian Osmanf3fa6002019-05-17 14:26:53 -04001050 std::unique_ptr<LValue> lvalue = this->getLValue(*p.fOperand);
1051 lvalue->load();
Brian Osman52c1bf12019-07-18 13:12:19 -04001052 // If we're not supposed to discard the result, then make a copy *before* the +/-
Brian Osman3e29f1d2019-05-28 09:35:05 -04001053 if (!discard) {
1054 this->write(ByteCodeInstruction::kDup);
1055 }
Brian Osmanf3fa6002019-05-17 14:26:53 -04001056 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osmand30e0392019-06-14 14:05:14 -04001057 this->write32(type_category(p.fType) == TypeCategory::kFloat ? float_to_bits(1.0f) : 1);
Brian Osmanf3fa6002019-05-17 14:26:53 -04001058 if (p.fOperator == Token::Kind::PLUSPLUS) {
1059 this->writeTypedInstruction(p.fType,
1060 ByteCodeInstruction::kAddI,
1061 ByteCodeInstruction::kAddI,
1062 ByteCodeInstruction::kAddF,
1063 1);
1064 } else {
1065 this->writeTypedInstruction(p.fType,
1066 ByteCodeInstruction::kSubtractI,
1067 ByteCodeInstruction::kSubtractI,
1068 ByteCodeInstruction::kSubtractF,
1069 1);
1070 }
Brian Osman52c1bf12019-07-18 13:12:19 -04001071 // Always consume the result as part of the store
1072 lvalue->store(true);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001073 discard = false;
Brian Osmanf3fa6002019-05-17 14:26:53 -04001074 break;
1075 }
1076 default:
1077 SkASSERT(false);
1078 }
Brian Osman3e29f1d2019-05-28 09:35:05 -04001079 return discard;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001080}
1081
1082void ByteCodeGenerator::writeSwizzle(const Swizzle& s) {
Brian Osman0785db02019-05-24 14:19:11 -04001083 if (swizzle_is_simple(s)) {
1084 this->writeVariableExpression(s);
1085 return;
1086 }
1087
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001088 switch (s.fBase->fKind) {
1089 case Expression::kVariableReference_Kind: {
1090 const Variable& var = ((VariableReference&) *s.fBase).fVariable;
Brian Osman1091f022019-05-16 09:42:16 -04001091 this->write(var.fStorage == Variable::kGlobal_Storage
1092 ? ByteCodeInstruction::kLoadSwizzleGlobal
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001093 : ByteCodeInstruction::kLoadSwizzle,
1094 s.fComponents.size());
Brian Osman1091f022019-05-16 09:42:16 -04001095 this->write8(this->getLocation(var));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001096 this->write8(s.fComponents.size());
1097 for (int c : s.fComponents) {
1098 this->write8(c);
1099 }
1100 break;
1101 }
1102 default:
1103 this->writeExpression(*s.fBase);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001104 this->write(ByteCodeInstruction::kSwizzle,
1105 s.fComponents.size() - s.fBase->fType.columns());
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001106 this->write8(s.fBase->fType.columns());
1107 this->write8(s.fComponents.size());
1108 for (int c : s.fComponents) {
1109 this->write8(c);
1110 }
1111 }
1112}
1113
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001114void ByteCodeGenerator::writeTernaryExpression(const TernaryExpression& t) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001115 int count = SlotCount(t.fType);
1116 SkASSERT(count == SlotCount(t.fIfTrue->fType));
1117 SkASSERT(count == SlotCount(t.fIfFalse->fType));
1118
Brian Osman4e93feb2019-05-16 15:38:00 -04001119 this->writeExpression(*t.fTest);
Brian Osman569f12f2019-06-13 11:23:57 -04001120 this->write(ByteCodeInstruction::kMaskPush);
Brian Osman4e93feb2019-05-16 15:38:00 -04001121 this->writeExpression(*t.fIfTrue);
Brian Osman569f12f2019-06-13 11:23:57 -04001122 this->write(ByteCodeInstruction::kMaskNegate);
1123 this->writeExpression(*t.fIfFalse);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001124 this->write(ByteCodeInstruction::kMaskBlend, count);
1125 this->write8(count);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001126}
1127
Brian Osman3e29f1d2019-05-28 09:35:05 -04001128void ByteCodeGenerator::writeExpression(const Expression& e, bool discard) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001129 switch (e.fKind) {
1130 case Expression::kBinary_Kind:
Brian Osman3e29f1d2019-05-28 09:35:05 -04001131 discard = this->writeBinaryExpression((BinaryExpression&) e, discard);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001132 break;
1133 case Expression::kBoolLiteral_Kind:
1134 this->writeBoolLiteral((BoolLiteral&) e);
1135 break;
1136 case Expression::kConstructor_Kind:
1137 this->writeConstructor((Constructor&) e);
1138 break;
Ethan Nicholas9e6a3932019-05-17 16:31:21 -04001139 case Expression::kExternalFunctionCall_Kind:
1140 this->writeExternalFunctionCall((ExternalFunctionCall&) e);
1141 break;
Ethan Nicholas91164d12019-05-15 15:29:54 -04001142 case Expression::kExternalValue_Kind:
1143 this->writeExternalValue((ExternalValueReference&) e);
1144 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001145 case Expression::kFieldAccess_Kind:
Brian Osman07c117b2019-05-23 12:51:06 -07001146 case Expression::kIndex_Kind:
1147 case Expression::kVariableReference_Kind:
1148 this->writeVariableExpression(e);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001149 break;
1150 case Expression::kFloatLiteral_Kind:
1151 this->writeFloatLiteral((FloatLiteral&) e);
1152 break;
1153 case Expression::kFunctionCall_Kind:
1154 this->writeFunctionCall((FunctionCall&) e);
1155 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001156 case Expression::kIntLiteral_Kind:
1157 this->writeIntLiteral((IntLiteral&) e);
1158 break;
1159 case Expression::kNullLiteral_Kind:
1160 this->writeNullLiteral((NullLiteral&) e);
1161 break;
1162 case Expression::kPrefix_Kind:
Brian Osman3e29f1d2019-05-28 09:35:05 -04001163 discard = this->writePrefixExpression((PrefixExpression&) e, discard);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001164 break;
1165 case Expression::kPostfix_Kind:
Brian Osman3e29f1d2019-05-28 09:35:05 -04001166 discard = this->writePostfixExpression((PostfixExpression&) e, discard);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001167 break;
1168 case Expression::kSwizzle_Kind:
1169 this->writeSwizzle((Swizzle&) e);
1170 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001171 case Expression::kTernary_Kind:
1172 this->writeTernaryExpression((TernaryExpression&) e);
1173 break;
1174 default:
1175 printf("unsupported expression %s\n", e.description().c_str());
1176 SkASSERT(false);
1177 }
Brian Osman3e29f1d2019-05-28 09:35:05 -04001178 if (discard) {
1179 int count = SlotCount(e.fType);
1180 if (count > 4) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001181 this->write(ByteCodeInstruction::kPopN, count);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001182 this->write8(count);
Brian Osmanfba386b2019-06-20 14:54:15 -04001183 } else if (count != 0) {
Brian Osman3e29f1d2019-05-28 09:35:05 -04001184 this->write(vector_instruction(ByteCodeInstruction::kPop, count));
1185 }
1186 discard = false;
1187 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001188}
1189
Ethan Nicholas91164d12019-05-15 15:29:54 -04001190class ByteCodeExternalValueLValue : public ByteCodeGenerator::LValue {
1191public:
1192 ByteCodeExternalValueLValue(ByteCodeGenerator* generator, ExternalValue& value, int index)
1193 : INHERITED(*generator)
Brian Osman07c117b2019-05-23 12:51:06 -07001194 , fCount(ByteCodeGenerator::SlotCount(value.type()))
Ethan Nicholas91164d12019-05-15 15:29:54 -04001195 , fIndex(index) {}
1196
1197 void load() override {
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001198 fGenerator.write(vector_instruction(ByteCodeInstruction::kReadExternal, fCount));
Ethan Nicholas91164d12019-05-15 15:29:54 -04001199 fGenerator.write8(fIndex);
1200 }
1201
Brian Osman3e29f1d2019-05-28 09:35:05 -04001202 void store(bool discard) override {
1203 if (!discard) {
1204 fGenerator.write(vector_instruction(ByteCodeInstruction::kDup, fCount));
1205 }
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001206 fGenerator.write(vector_instruction(ByteCodeInstruction::kWriteExternal, fCount));
Ethan Nicholas91164d12019-05-15 15:29:54 -04001207 fGenerator.write8(fIndex);
1208 }
1209
1210private:
1211 typedef LValue INHERITED;
1212
1213 int fCount;
1214
1215 int fIndex;
1216};
1217
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001218class ByteCodeSwizzleLValue : public ByteCodeGenerator::LValue {
1219public:
1220 ByteCodeSwizzleLValue(ByteCodeGenerator* generator, const Swizzle& swizzle)
1221 : INHERITED(*generator)
Brian Osman07c117b2019-05-23 12:51:06 -07001222 , fSwizzle(swizzle) {}
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001223
1224 void load() override {
Brian Osman1091f022019-05-16 09:42:16 -04001225 fGenerator.writeSwizzle(fSwizzle);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001226 }
1227
Brian Osman3e29f1d2019-05-28 09:35:05 -04001228 void store(bool discard) override {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001229 int count = fSwizzle.fComponents.size();
Brian Osman3e29f1d2019-05-28 09:35:05 -04001230 if (!discard) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001231 fGenerator.write(vector_instruction(ByteCodeInstruction::kDup, count));
Brian Osman3e29f1d2019-05-28 09:35:05 -04001232 }
Brian Osman07c117b2019-05-23 12:51:06 -07001233 Variable::Storage storage;
1234 int location = fGenerator.getLocation(*fSwizzle.fBase, &storage);
1235 bool isGlobal = storage == Variable::kGlobal_Storage;
1236 if (location < 0) {
1237 fGenerator.write(isGlobal ? ByteCodeInstruction::kStoreSwizzleIndirectGlobal
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001238 : ByteCodeInstruction::kStoreSwizzleIndirect,
1239 count);
Brian Osman07c117b2019-05-23 12:51:06 -07001240 } else {
1241 fGenerator.write(isGlobal ? ByteCodeInstruction::kStoreSwizzleGlobal
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001242 : ByteCodeInstruction::kStoreSwizzle,
1243 count);
Brian Osman07c117b2019-05-23 12:51:06 -07001244 fGenerator.write8(location);
1245 }
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001246 fGenerator.write8(count);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001247 for (int c : fSwizzle.fComponents) {
1248 fGenerator.write8(c);
1249 }
1250 }
1251
1252private:
1253 const Swizzle& fSwizzle;
1254
1255 typedef LValue INHERITED;
1256};
1257
Brian Osman07c117b2019-05-23 12:51:06 -07001258class ByteCodeExpressionLValue : public ByteCodeGenerator::LValue {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001259public:
Brian Osman07c117b2019-05-23 12:51:06 -07001260 ByteCodeExpressionLValue(ByteCodeGenerator* generator, const Expression& expr)
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001261 : INHERITED(*generator)
Brian Osman07c117b2019-05-23 12:51:06 -07001262 , fExpression(expr) {}
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001263
1264 void load() override {
Brian Osman07c117b2019-05-23 12:51:06 -07001265 fGenerator.writeVariableExpression(fExpression);
Brian Osman1091f022019-05-16 09:42:16 -04001266 }
1267
Brian Osman3e29f1d2019-05-28 09:35:05 -04001268 void store(bool discard) override {
Brian Osman07c117b2019-05-23 12:51:06 -07001269 int count = ByteCodeGenerator::SlotCount(fExpression.fType);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001270 if (!discard) {
1271 if (count > 4) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001272 fGenerator.write(ByteCodeInstruction::kDupN, count);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001273 fGenerator.write8(count);
1274 } else {
1275 fGenerator.write(vector_instruction(ByteCodeInstruction::kDup, count));
1276 }
Brian Osman07c117b2019-05-23 12:51:06 -07001277 }
1278 Variable::Storage storage;
1279 int location = fGenerator.getLocation(fExpression, &storage);
1280 bool isGlobal = storage == Variable::kGlobal_Storage;
1281 if (location < 0 || count > 4) {
1282 if (location >= 0) {
1283 fGenerator.write(ByteCodeInstruction::kPushImmediate);
1284 fGenerator.write32(location);
1285 }
1286 fGenerator.write(isGlobal ? ByteCodeInstruction::kStoreExtendedGlobal
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001287 : ByteCodeInstruction::kStoreExtended,
1288 count);
Brian Osman07c117b2019-05-23 12:51:06 -07001289 fGenerator.write8(count);
1290 } else {
1291 fGenerator.write(vector_instruction(isGlobal ? ByteCodeInstruction::kStoreGlobal
1292 : ByteCodeInstruction::kStore,
1293 count));
1294 fGenerator.write8(location);
1295 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001296 }
1297
1298private:
1299 typedef LValue INHERITED;
1300
Brian Osman07c117b2019-05-23 12:51:06 -07001301 const Expression& fExpression;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001302};
1303
1304std::unique_ptr<ByteCodeGenerator::LValue> ByteCodeGenerator::getLValue(const Expression& e) {
1305 switch (e.fKind) {
Ethan Nicholas91164d12019-05-15 15:29:54 -04001306 case Expression::kExternalValue_Kind: {
1307 ExternalValue* value = ((ExternalValueReference&) e).fValue;
1308 int index = fOutput->fExternalValues.size();
1309 fOutput->fExternalValues.push_back(value);
1310 SkASSERT(index <= 255);
1311 return std::unique_ptr<LValue>(new ByteCodeExternalValueLValue(this, *value, index));
1312 }
Brian Osman07c117b2019-05-23 12:51:06 -07001313 case Expression::kFieldAccess_Kind:
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001314 case Expression::kIndex_Kind:
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001315 case Expression::kVariableReference_Kind:
Brian Osman07c117b2019-05-23 12:51:06 -07001316 return std::unique_ptr<LValue>(new ByteCodeExpressionLValue(this, e));
Brian Osman0785db02019-05-24 14:19:11 -04001317 case Expression::kSwizzle_Kind: {
1318 const Swizzle& s = (const Swizzle&) e;
1319 return swizzle_is_simple(s)
1320 ? std::unique_ptr<LValue>(new ByteCodeExpressionLValue(this, e))
1321 : std::unique_ptr<LValue>(new ByteCodeSwizzleLValue(this, s));
1322 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001323 case Expression::kTernary_Kind:
1324 default:
1325 printf("unsupported lvalue %s\n", e.description().c_str());
1326 return nullptr;
1327 }
1328}
1329
1330void ByteCodeGenerator::writeBlock(const Block& b) {
1331 for (const auto& s : b.fStatements) {
1332 this->writeStatement(*s);
1333 }
1334}
1335
1336void ByteCodeGenerator::setBreakTargets() {
1337 std::vector<DeferredLocation>& breaks = fBreakTargets.top();
1338 for (DeferredLocation& b : breaks) {
1339 b.set();
1340 }
1341 fBreakTargets.pop();
1342}
1343
1344void ByteCodeGenerator::setContinueTargets() {
1345 std::vector<DeferredLocation>& continues = fContinueTargets.top();
1346 for (DeferredLocation& c : continues) {
1347 c.set();
1348 }
1349 fContinueTargets.pop();
1350}
1351
1352void ByteCodeGenerator::writeBreakStatement(const BreakStatement& b) {
Brian Osman569f12f2019-06-13 11:23:57 -04001353 // TODO: Include BranchIfAllFalse to top-most LoopNext
1354 this->write(ByteCodeInstruction::kLoopBreak);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001355}
1356
1357void ByteCodeGenerator::writeContinueStatement(const ContinueStatement& c) {
Brian Osman569f12f2019-06-13 11:23:57 -04001358 // TODO: Include BranchIfAllFalse to top-most LoopNext
1359 this->write(ByteCodeInstruction::kLoopContinue);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001360}
1361
1362void ByteCodeGenerator::writeDoStatement(const DoStatement& d) {
Brian Osman569f12f2019-06-13 11:23:57 -04001363 this->write(ByteCodeInstruction::kLoopBegin);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001364 size_t start = fCode->size();
1365 this->writeStatement(*d.fStatement);
Brian Osman569f12f2019-06-13 11:23:57 -04001366 this->write(ByteCodeInstruction::kLoopNext);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001367 this->writeExpression(*d.fTest);
Brian Osman569f12f2019-06-13 11:23:57 -04001368 this->write(ByteCodeInstruction::kLoopMask);
1369 // TODO: Could shorten this with kBranchIfAnyTrue
1370 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1371 DeferredLocation endLocation(this);
1372 this->write(ByteCodeInstruction::kBranch);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001373 this->write16(start);
Brian Osman569f12f2019-06-13 11:23:57 -04001374 endLocation.set();
1375 this->write(ByteCodeInstruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001376}
1377
1378void ByteCodeGenerator::writeForStatement(const ForStatement& f) {
1379 fContinueTargets.emplace();
1380 fBreakTargets.emplace();
1381 if (f.fInitializer) {
1382 this->writeStatement(*f.fInitializer);
1383 }
Brian Osman569f12f2019-06-13 11:23:57 -04001384 this->write(ByteCodeInstruction::kLoopBegin);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001385 size_t start = fCode->size();
1386 if (f.fTest) {
1387 this->writeExpression(*f.fTest);
Brian Osman569f12f2019-06-13 11:23:57 -04001388 this->write(ByteCodeInstruction::kLoopMask);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001389 }
Brian Osman569f12f2019-06-13 11:23:57 -04001390 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1391 DeferredLocation endLocation(this);
1392 this->writeStatement(*f.fStatement);
1393 this->write(ByteCodeInstruction::kLoopNext);
1394 if (f.fNext) {
1395 this->writeExpression(*f.fNext, true);
1396 }
1397 this->write(ByteCodeInstruction::kBranch);
1398 this->write16(start);
1399 endLocation.set();
1400 this->write(ByteCodeInstruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001401}
1402
1403void ByteCodeGenerator::writeIfStatement(const IfStatement& i) {
Brian Osman569f12f2019-06-13 11:23:57 -04001404 this->writeExpression(*i.fTest);
1405 this->write(ByteCodeInstruction::kMaskPush);
1406 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1407 DeferredLocation falseLocation(this);
1408 this->writeStatement(*i.fIfTrue);
1409 falseLocation.set();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001410 if (i.fIfFalse) {
Brian Osman569f12f2019-06-13 11:23:57 -04001411 this->write(ByteCodeInstruction::kMaskNegate);
1412 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1413 DeferredLocation endLocation(this);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001414 this->writeStatement(*i.fIfFalse);
Mike Kleinb45ee832019-05-17 11:11:11 -05001415 endLocation.set();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001416 }
Brian Osman569f12f2019-06-13 11:23:57 -04001417 this->write(ByteCodeInstruction::kMaskPop);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001418}
1419
1420void ByteCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
Brian Osman4a47da72019-07-12 11:30:32 -04001421 if (fLoopCount || fConditionCount) {
1422 fErrors.error(r.fOffset, "return not allowed inside conditional or loop");
1423 return;
1424 }
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001425 int count = SlotCount(r.fExpression->fType);
Ethan Nicholas746035a2019-04-23 13:31:09 -04001426 this->writeExpression(*r.fExpression);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001427
1428 // Technically, the kReturn also pops fOutput->fLocalCount values from the stack, too, but we
1429 // haven't counted pushing those (they're outside the scope of our stack tracking). Instead,
1430 // we account for those in writeFunction().
1431
1432 // This is all fine because we don't allow conditional returns, so we only return once anyway.
1433 this->write(ByteCodeInstruction::kReturn, -count);
1434 this->write8(count);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001435}
1436
1437void ByteCodeGenerator::writeSwitchStatement(const SwitchStatement& r) {
1438 // not yet implemented
1439 abort();
1440}
1441
1442void ByteCodeGenerator::writeVarDeclarations(const VarDeclarations& v) {
1443 for (const auto& declStatement : v.fVars) {
1444 const VarDeclaration& decl = (VarDeclaration&) *declStatement;
1445 // we need to grab the location even if we don't use it, to ensure it
1446 // has been allocated
1447 int location = getLocation(*decl.fVar);
1448 if (decl.fValue) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001449 this->writeExpression(*decl.fValue);
Brian Osman07c117b2019-05-23 12:51:06 -07001450 int count = SlotCount(decl.fValue->fType);
1451 if (count > 4) {
1452 this->write(ByteCodeInstruction::kPushImmediate);
1453 this->write32(location);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001454 this->write(ByteCodeInstruction::kStoreExtended, count);
Brian Osman07c117b2019-05-23 12:51:06 -07001455 this->write8(count);
1456 } else {
1457 this->write(vector_instruction(ByteCodeInstruction::kStore, count));
1458 this->write8(location);
1459 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001460 }
1461 }
1462}
1463
1464void ByteCodeGenerator::writeWhileStatement(const WhileStatement& w) {
Brian Osman569f12f2019-06-13 11:23:57 -04001465 this->write(ByteCodeInstruction::kLoopBegin);
1466 size_t cond = fCode->size();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001467 this->writeExpression(*w.fTest);
Brian Osman569f12f2019-06-13 11:23:57 -04001468 this->write(ByteCodeInstruction::kLoopMask);
1469 this->write(ByteCodeInstruction::kBranchIfAllFalse);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001470 DeferredLocation endLocation(this);
1471 this->writeStatement(*w.fStatement);
Brian Osman569f12f2019-06-13 11:23:57 -04001472 this->write(ByteCodeInstruction::kLoopNext);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001473 this->write(ByteCodeInstruction::kBranch);
Brian Osman569f12f2019-06-13 11:23:57 -04001474 this->write16(cond);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001475 endLocation.set();
Brian Osman569f12f2019-06-13 11:23:57 -04001476 this->write(ByteCodeInstruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001477}
1478
1479void ByteCodeGenerator::writeStatement(const Statement& s) {
1480 switch (s.fKind) {
1481 case Statement::kBlock_Kind:
1482 this->writeBlock((Block&) s);
1483 break;
1484 case Statement::kBreak_Kind:
1485 this->writeBreakStatement((BreakStatement&) s);
1486 break;
1487 case Statement::kContinue_Kind:
1488 this->writeContinueStatement((ContinueStatement&) s);
1489 break;
1490 case Statement::kDiscard_Kind:
1491 // not yet implemented
1492 abort();
1493 case Statement::kDo_Kind:
1494 this->writeDoStatement((DoStatement&) s);
1495 break;
Brian Osman3e29f1d2019-05-28 09:35:05 -04001496 case Statement::kExpression_Kind:
1497 this->writeExpression(*((ExpressionStatement&) s).fExpression, true);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001498 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001499 case Statement::kFor_Kind:
1500 this->writeForStatement((ForStatement&) s);
1501 break;
1502 case Statement::kIf_Kind:
1503 this->writeIfStatement((IfStatement&) s);
1504 break;
1505 case Statement::kNop_Kind:
1506 break;
1507 case Statement::kReturn_Kind:
1508 this->writeReturnStatement((ReturnStatement&) s);
1509 break;
1510 case Statement::kSwitch_Kind:
1511 this->writeSwitchStatement((SwitchStatement&) s);
1512 break;
1513 case Statement::kVarDeclarations_Kind:
1514 this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration);
1515 break;
1516 case Statement::kWhile_Kind:
1517 this->writeWhileStatement((WhileStatement&) s);
1518 break;
1519 default:
1520 SkASSERT(false);
1521 }
1522}
1523
Brian Osman80164412019-06-07 13:00:23 -04001524ByteCodeFunction::ByteCodeFunction(const FunctionDeclaration* declaration)
1525 : fName(declaration->fName) {
1526 fParameterCount = 0;
1527 for (const auto& p : declaration->fParameters) {
1528 int slots = ByteCodeGenerator::SlotCount(p->fType);
1529 fParameters.push_back({ slots, (bool)(p->fModifiers.fFlags & Modifiers::kOut_Flag) });
1530 fParameterCount += slots;
1531 }
1532}
1533
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001534}