blob: f1fdbdd922f188b851a737abbc00c6bae4114e83 [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 Osman869a3e82019-07-18 17:00:34 -0400211 case ByteCodeInstruction::kClampIndex: return 0;
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400212 case ByteCodeInstruction::kNotB: return 0;
213 case ByteCodeInstruction::kNegateFN: return 0;
214
215#undef VECTOR_UNARY_OP
216
217 // Binary functions/operators that do a 2 -> 1 reduction (possibly N times)
218#define VECTOR_BINARY_OP(base) \
219 case ByteCodeInstruction::base: return -1; \
220 case ByteCodeInstruction::base ## 2: return -2; \
221 case ByteCodeInstruction::base ## 3: return -3; \
222 case ByteCodeInstruction::base ## 4: return -4;
223
224#define VECTOR_MATRIX_BINARY_OP(base) \
225 VECTOR_BINARY_OP(base) \
226 case ByteCodeInstruction::base ## N: return -count;
227
228 case ByteCodeInstruction::kAndB: return -1;
229 case ByteCodeInstruction::kOrB: return -1;
230 case ByteCodeInstruction::kXorB: return -1;
231
232 VECTOR_BINARY_OP(kAddI)
233 VECTOR_MATRIX_BINARY_OP(kAddF)
234
235 VECTOR_BINARY_OP(kCompareIEQ)
236 VECTOR_MATRIX_BINARY_OP(kCompareFEQ)
237 VECTOR_BINARY_OP(kCompareINEQ)
238 VECTOR_MATRIX_BINARY_OP(kCompareFNEQ)
239 VECTOR_BINARY_OP(kCompareSGT)
240 VECTOR_BINARY_OP(kCompareUGT)
241 VECTOR_BINARY_OP(kCompareFGT)
242 VECTOR_BINARY_OP(kCompareSGTEQ)
243 VECTOR_BINARY_OP(kCompareUGTEQ)
244 VECTOR_BINARY_OP(kCompareFGTEQ)
245 VECTOR_BINARY_OP(kCompareSLT)
246 VECTOR_BINARY_OP(kCompareULT)
247 VECTOR_BINARY_OP(kCompareFLT)
248 VECTOR_BINARY_OP(kCompareSLTEQ)
249 VECTOR_BINARY_OP(kCompareULTEQ)
250 VECTOR_BINARY_OP(kCompareFLTEQ)
251
252 VECTOR_BINARY_OP(kDivideS)
253 VECTOR_BINARY_OP(kDivideU)
254 VECTOR_MATRIX_BINARY_OP(kDivideF)
255 VECTOR_BINARY_OP(kMultiplyI)
256 VECTOR_MATRIX_BINARY_OP(kMultiplyF)
257 VECTOR_BINARY_OP(kRemainderF)
258 VECTOR_BINARY_OP(kRemainderS)
259 VECTOR_BINARY_OP(kRemainderU)
260 VECTOR_BINARY_OP(kSubtractI)
261 VECTOR_MATRIX_BINARY_OP(kSubtractF)
262
263#undef VECTOR_BINARY_OP
264#undef VECTOR_MATRIX_BINARY_OP
265
266 // Strange math operations with other behavior:
267 case ByteCodeInstruction::kCross: return -3;
268 // Binary, but also consumes T:
269 case ByteCodeInstruction::kMix: return -2;
270 case ByteCodeInstruction::kMix2: return -3;
271 case ByteCodeInstruction::kMix3: return -4;
272 case ByteCodeInstruction::kMix4: return -5;
273
274 // Ops that push or load data to grow the stack:
275 case ByteCodeInstruction::kDup:
276 case ByteCodeInstruction::kLoad:
277 case ByteCodeInstruction::kLoadGlobal:
278 case ByteCodeInstruction::kReadExternal:
279 case ByteCodeInstruction::kPushImmediate:
280 return 1;
281
282 case ByteCodeInstruction::kDup2:
283 case ByteCodeInstruction::kLoad2:
284 case ByteCodeInstruction::kLoadGlobal2:
285 case ByteCodeInstruction::kReadExternal2:
286 return 2;
287
288 case ByteCodeInstruction::kDup3:
289 case ByteCodeInstruction::kLoad3:
290 case ByteCodeInstruction::kLoadGlobal3:
291 case ByteCodeInstruction::kReadExternal3:
292 return 3;
293
294 case ByteCodeInstruction::kDup4:
295 case ByteCodeInstruction::kLoad4:
296 case ByteCodeInstruction::kLoadGlobal4:
297 case ByteCodeInstruction::kReadExternal4:
298 return 4;
299
300 case ByteCodeInstruction::kDupN:
301 case ByteCodeInstruction::kLoadSwizzle:
302 case ByteCodeInstruction::kLoadSwizzleGlobal:
303 return count;
304
305 // Pushes 'count' values, minus one for the 'address' that's consumed first
306 case ByteCodeInstruction::kLoadExtended:
307 case ByteCodeInstruction::kLoadExtendedGlobal:
308 return count - 1;
309
310 // Ops that pop or store data to shrink the stack:
311 case ByteCodeInstruction::kPop:
312 case ByteCodeInstruction::kStore:
313 case ByteCodeInstruction::kStoreGlobal:
314 case ByteCodeInstruction::kWriteExternal:
315 return -1;
316
317 case ByteCodeInstruction::kPop2:
318 case ByteCodeInstruction::kStore2:
319 case ByteCodeInstruction::kStoreGlobal2:
320 case ByteCodeInstruction::kWriteExternal2:
321 return -2;
322
323 case ByteCodeInstruction::kPop3:
324 case ByteCodeInstruction::kStore3:
325 case ByteCodeInstruction::kStoreGlobal3:
326 case ByteCodeInstruction::kWriteExternal3:
327 return -3;
328
329 case ByteCodeInstruction::kPop4:
330 case ByteCodeInstruction::kStore4:
331 case ByteCodeInstruction::kStoreGlobal4:
332 case ByteCodeInstruction::kWriteExternal4:
333 return -4;
334
335 case ByteCodeInstruction::kPopN:
336 case ByteCodeInstruction::kStoreSwizzle:
337 case ByteCodeInstruction::kStoreSwizzleGlobal:
338 return -count;
339
340 // Consumes 'count' values, plus one for the 'address'
341 case ByteCodeInstruction::kStoreExtended:
342 case ByteCodeInstruction::kStoreExtendedGlobal:
343 case ByteCodeInstruction::kStoreSwizzleIndirect:
344 case ByteCodeInstruction::kStoreSwizzleIndirectGlobal:
345 return -count - 1;
346
347 // Strange ops where the caller computes the delta for us:
348 case ByteCodeInstruction::kCallExternal:
349 case ByteCodeInstruction::kMatrixToMatrix:
350 case ByteCodeInstruction::kMatrixMultiply:
351 case ByteCodeInstruction::kReserve:
352 case ByteCodeInstruction::kReturn:
353 case ByteCodeInstruction::kScalarToMatrix:
354 case ByteCodeInstruction::kSwizzle:
355 return count;
356
357 // Miscellaneous
358
359 // kCall is net-zero. Max stack depth is adjusted in writeFunctionCall.
360 case ByteCodeInstruction::kCall: return 0;
361 case ByteCodeInstruction::kBranch: return 0;
362 case ByteCodeInstruction::kBranchIfAllFalse: return 0;
363
364 case ByteCodeInstruction::kMaskPush: return -1;
365 case ByteCodeInstruction::kMaskPop: return 0;
366 case ByteCodeInstruction::kMaskNegate: return 0;
367 case ByteCodeInstruction::kMaskBlend: return -count;
368
369 case ByteCodeInstruction::kLoopBegin: return 0;
370 case ByteCodeInstruction::kLoopNext: return 0;
371 case ByteCodeInstruction::kLoopMask: return -1;
372 case ByteCodeInstruction::kLoopEnd: return 0;
373 case ByteCodeInstruction::kLoopBreak: return 0;
374 case ByteCodeInstruction::kLoopContinue: return 0;
375
376 default:
Brian Osmanc7ec9e22019-07-16 08:49:11 -0400377 ABORT("unsupported instruction %d\n", (int)inst);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400378 return 0;
379 }
380}
381
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400382int ByteCodeGenerator::getLocation(const Variable& var) {
383 // given that we seldom have more than a couple of variables, linear search is probably the most
384 // efficient way to handle lookups
385 switch (var.fStorage) {
386 case Variable::kLocal_Storage: {
387 for (int i = fLocals.size() - 1; i >= 0; --i) {
388 if (fLocals[i] == &var) {
Brian Osman1091f022019-05-16 09:42:16 -0400389 SkASSERT(fParameterCount + i <= 255);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400390 return fParameterCount + i;
391 }
392 }
393 int result = fParameterCount + fLocals.size();
394 fLocals.push_back(&var);
Brian Osman07c117b2019-05-23 12:51:06 -0700395 for (int i = 0; i < SlotCount(var.fType) - 1; ++i) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400396 fLocals.push_back(nullptr);
397 }
Brian Osman1091f022019-05-16 09:42:16 -0400398 SkASSERT(result <= 255);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400399 return result;
400 }
401 case Variable::kParameter_Storage: {
402 int offset = 0;
403 for (const auto& p : fFunction->fDeclaration.fParameters) {
404 if (p == &var) {
Brian Osman1091f022019-05-16 09:42:16 -0400405 SkASSERT(offset <= 255);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400406 return offset;
407 }
Brian Osman07c117b2019-05-23 12:51:06 -0700408 offset += SlotCount(p->fType);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400409 }
410 SkASSERT(false);
Brian Osman1091f022019-05-16 09:42:16 -0400411 return 0;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400412 }
413 case Variable::kGlobal_Storage: {
414 int offset = 0;
415 for (const auto& e : fProgram) {
416 if (e.fKind == ProgramElement::kVar_Kind) {
417 VarDeclarations& decl = (VarDeclarations&) e;
418 for (const auto& v : decl.fVars) {
419 const Variable* declVar = ((VarDeclaration&) *v).fVar;
420 if (declVar->fModifiers.fLayout.fBuiltin >= 0) {
421 continue;
422 }
423 if (declVar == &var) {
Brian Osmanb7451292019-05-15 13:02:13 -0400424 SkASSERT(offset <= 255);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400425 return offset;
426 }
Brian Osman07c117b2019-05-23 12:51:06 -0700427 offset += SlotCount(declVar->fType);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400428 }
429 }
430 }
431 SkASSERT(false);
Brian Osman1091f022019-05-16 09:42:16 -0400432 return 0;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400433 }
434 default:
435 SkASSERT(false);
436 return 0;
437 }
438}
439
Brian Osman07c117b2019-05-23 12:51:06 -0700440int ByteCodeGenerator::getLocation(const Expression& expr, Variable::Storage* storage) {
441 switch (expr.fKind) {
442 case Expression::kFieldAccess_Kind: {
443 const FieldAccess& f = (const FieldAccess&)expr;
444 int baseAddr = this->getLocation(*f.fBase, storage);
445 int offset = 0;
446 for (int i = 0; i < f.fFieldIndex; ++i) {
447 offset += SlotCount(*f.fBase->fType.fields()[i].fType);
448 }
449 if (baseAddr < 0) {
Brian Osman86769292019-06-21 11:05:47 -0400450 if (offset != 0) {
451 this->write(ByteCodeInstruction::kPushImmediate);
452 this->write32(offset);
453 this->write(ByteCodeInstruction::kAddI);
454 }
Brian Osman07c117b2019-05-23 12:51:06 -0700455 return -1;
456 } else {
457 return baseAddr + offset;
458 }
459 }
460 case Expression::kIndex_Kind: {
461 const IndexExpression& i = (const IndexExpression&)expr;
462 int stride = SlotCount(i.fType);
Brian Osman869a3e82019-07-18 17:00:34 -0400463 int length = i.fBase->fType.columns();
464 SkASSERT(length <= 255);
Brian Osman07c117b2019-05-23 12:51:06 -0700465 int offset = -1;
466 if (i.fIndex->isConstant()) {
Brian Osman869a3e82019-07-18 17:00:34 -0400467 int64_t index = i.fIndex->getConstantInt();
468 if (index < 0 || index >= length) {
469 fErrors.error(i.fIndex->fOffset, "Array index out of bounds.");
470 return 0;
471 }
472 offset = index * stride;
Brian Osman07c117b2019-05-23 12:51:06 -0700473 } else {
Brian Osman86769292019-06-21 11:05:47 -0400474 if (i.fIndex->hasSideEffects()) {
475 // Having a side-effect in an indexer is technically safe for an rvalue,
476 // but with lvalues we have to evaluate the indexer twice, so make it an error.
477 fErrors.error(i.fIndex->fOffset,
478 "Index expressions with side-effects not supported in byte code.");
479 return 0;
480 }
Brian Osman07c117b2019-05-23 12:51:06 -0700481 this->writeExpression(*i.fIndex);
Brian Osman869a3e82019-07-18 17:00:34 -0400482 this->write(ByteCodeInstruction::kClampIndex);
483 this->write8(length);
Brian Osman86769292019-06-21 11:05:47 -0400484 if (stride != 1) {
485 this->write(ByteCodeInstruction::kPushImmediate);
486 this->write32(stride);
487 this->write(ByteCodeInstruction::kMultiplyI);
488 }
Brian Osman07c117b2019-05-23 12:51:06 -0700489 }
490 int baseAddr = this->getLocation(*i.fBase, storage);
Brian Osman86769292019-06-21 11:05:47 -0400491
492 // Are both components known statically?
Brian Osman07c117b2019-05-23 12:51:06 -0700493 if (baseAddr >= 0 && offset >= 0) {
494 return baseAddr + offset;
495 }
Brian Osman86769292019-06-21 11:05:47 -0400496
497 // At least one component is dynamic (and on the stack).
498
499 // If the other component is zero, we're done
500 if (baseAddr == 0 || offset == 0) {
501 return -1;
502 }
503
504 // Push the non-dynamic component (if any) to the stack, then add the two
Brian Osman07c117b2019-05-23 12:51:06 -0700505 if (baseAddr >= 0) {
506 this->write(ByteCodeInstruction::kPushImmediate);
507 this->write32(baseAddr);
508 }
509 if (offset >= 0) {
510 this->write(ByteCodeInstruction::kPushImmediate);
511 this->write32(offset);
512 }
513 this->write(ByteCodeInstruction::kAddI);
514 return -1;
515 }
Brian Osman0785db02019-05-24 14:19:11 -0400516 case Expression::kSwizzle_Kind: {
517 const Swizzle& s = (const Swizzle&)expr;
518 SkASSERT(swizzle_is_simple(s));
519 int baseAddr = this->getLocation(*s.fBase, storage);
520 int offset = s.fComponents[0];
521 if (baseAddr < 0) {
Brian Osman86769292019-06-21 11:05:47 -0400522 if (offset != 0) {
523 this->write(ByteCodeInstruction::kPushImmediate);
524 this->write32(offset);
525 this->write(ByteCodeInstruction::kAddI);
526 }
Brian Osman0785db02019-05-24 14:19:11 -0400527 return -1;
528 } else {
529 return baseAddr + offset;
530 }
531 }
Brian Osman07c117b2019-05-23 12:51:06 -0700532 case Expression::kVariableReference_Kind: {
533 const Variable& var = ((const VariableReference&)expr).fVariable;
534 *storage = var.fStorage;
535 return this->getLocation(var);
536 }
537 default:
538 SkASSERT(false);
539 return 0;
540 }
541}
542
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400543void ByteCodeGenerator::write8(uint8_t b) {
544 fCode->push_back(b);
545}
546
547void ByteCodeGenerator::write16(uint16_t i) {
Mike Klein76346ac2019-05-17 11:57:10 -0500548 size_t n = fCode->size();
549 fCode->resize(n+2);
550 memcpy(fCode->data() + n, &i, 2);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400551}
552
553void ByteCodeGenerator::write32(uint32_t i) {
Mike Klein76346ac2019-05-17 11:57:10 -0500554 size_t n = fCode->size();
555 fCode->resize(n+4);
556 memcpy(fCode->data() + n, &i, 4);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400557}
558
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400559void ByteCodeGenerator::write(ByteCodeInstruction i, int count) {
Brian Osman4a47da72019-07-12 11:30:32 -0400560 switch (i) {
561 case ByteCodeInstruction::kLoopBegin: this->enterLoop(); break;
562 case ByteCodeInstruction::kLoopEnd: this->exitLoop(); break;
563
564 case ByteCodeInstruction::kMaskPush: this->enterCondition(); break;
565 case ByteCodeInstruction::kMaskPop:
566 case ByteCodeInstruction::kMaskBlend: this->exitCondition(); break;
567 default: /* Do nothing */ break;
568 }
Mike Klein108e9352019-05-21 11:05:17 -0500569 this->write16((uint16_t)i);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400570 fStackCount += StackUsage(i, count);
571 fMaxStackCount = std::max(fMaxStackCount, fStackCount);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400572}
573
Mike Klein76346ac2019-05-17 11:57:10 -0500574static ByteCodeInstruction vector_instruction(ByteCodeInstruction base, int count) {
Brian Osman07c117b2019-05-23 12:51:06 -0700575 SkASSERT(count >= 1 && count <= 4);
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400576 return ((ByteCodeInstruction) ((int) base + count - 1));
577}
578
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400579void ByteCodeGenerator::writeTypedInstruction(const Type& type, ByteCodeInstruction s,
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400580 ByteCodeInstruction u, ByteCodeInstruction f,
581 int count) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400582 switch (type_category(type)) {
583 case TypeCategory::kSigned:
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400584 this->write(vector_instruction(s, count));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400585 break;
586 case TypeCategory::kUnsigned:
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400587 this->write(vector_instruction(u, count));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400588 break;
Brian Osman1e855b22019-05-29 15:21:52 -0400589 case TypeCategory::kFloat: {
590 if (count > 4) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400591 this->write((ByteCodeInstruction)((int)f + 4), count);
Brian Osman1e855b22019-05-29 15:21:52 -0400592 this->write8(count);
593 } else {
594 this->write(vector_instruction(f, count));
595 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400596 break;
Brian Osman1e855b22019-05-29 15:21:52 -0400597 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400598 default:
599 SkASSERT(false);
600 }
601}
602
Brian Osman3e29f1d2019-05-28 09:35:05 -0400603bool ByteCodeGenerator::writeBinaryExpression(const BinaryExpression& b, bool discard) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400604 if (b.fOperator == Token::Kind::EQ) {
605 std::unique_ptr<LValue> lvalue = this->getLValue(*b.fLeft);
606 this->writeExpression(*b.fRight);
Brian Osman3e29f1d2019-05-28 09:35:05 -0400607 lvalue->store(discard);
608 discard = false;
609 return discard;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400610 }
Brian Osman16e6fd52019-05-29 11:19:00 -0400611 const Type& lType = b.fLeft->fType;
612 const Type& rType = b.fRight->fType;
Brian Osman909231c2019-05-29 15:34:36 -0400613 bool lVecOrMtx = (lType.kind() == Type::kVector_Kind || lType.kind() == Type::kMatrix_Kind);
614 bool rVecOrMtx = (rType.kind() == Type::kVector_Kind || rType.kind() == Type::kMatrix_Kind);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400615 Token::Kind op;
616 std::unique_ptr<LValue> lvalue;
617 if (is_assignment(b.fOperator)) {
618 lvalue = this->getLValue(*b.fLeft);
619 lvalue->load();
620 op = remove_assignment(b.fOperator);
621 } else {
622 this->writeExpression(*b.fLeft);
623 op = b.fOperator;
Brian Osman909231c2019-05-29 15:34:36 -0400624 if (!lVecOrMtx && rVecOrMtx) {
Brian Osman16e6fd52019-05-29 11:19:00 -0400625 for (int i = SlotCount(rType); i > 1; --i) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400626 this->write(ByteCodeInstruction::kDup);
627 }
628 }
629 }
630 this->writeExpression(*b.fRight);
Brian Osman909231c2019-05-29 15:34:36 -0400631 if (lVecOrMtx && !rVecOrMtx) {
Brian Osman16e6fd52019-05-29 11:19:00 -0400632 for (int i = SlotCount(lType); i > 1; --i) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400633 this->write(ByteCodeInstruction::kDup);
634 }
635 }
Brian Osman909231c2019-05-29 15:34:36 -0400636 // Special case for M*V, V*M, M*M (but not V*V!)
637 if (op == Token::Kind::STAR && lVecOrMtx && rVecOrMtx &&
638 !(lType.kind() == Type::kVector_Kind && rType.kind() == Type::kVector_Kind)) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400639 this->write(ByteCodeInstruction::kMatrixMultiply,
640 SlotCount(b.fType) - (SlotCount(lType) + SlotCount(rType)));
Brian Osman909231c2019-05-29 15:34:36 -0400641 int rCols = rType.columns(),
642 rRows = rType.rows(),
643 lCols = lType.columns(),
644 lRows = lType.rows();
645 // M*V treats the vector as a column
646 if (rType.kind() == Type::kVector_Kind) {
647 std::swap(rCols, rRows);
648 }
649 SkASSERT(lCols == rRows);
650 SkASSERT(SlotCount(b.fType) == lRows * rCols);
651 this->write8(lCols);
652 this->write8(lRows);
653 this->write8(rCols);
654 } else {
655 int count = std::max(SlotCount(lType), SlotCount(rType));
656 switch (op) {
657 case Token::Kind::EQEQ:
658 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareIEQ,
659 ByteCodeInstruction::kCompareIEQ,
660 ByteCodeInstruction::kCompareFEQ,
661 count);
662 // Collapse to a single bool
663 for (int i = count; i > 1; --i) {
664 this->write(ByteCodeInstruction::kAndB);
665 }
666 break;
667 case Token::Kind::GT:
668 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSGT,
669 ByteCodeInstruction::kCompareUGT,
670 ByteCodeInstruction::kCompareFGT,
671 count);
672 break;
673 case Token::Kind::GTEQ:
674 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSGTEQ,
675 ByteCodeInstruction::kCompareUGTEQ,
676 ByteCodeInstruction::kCompareFGTEQ,
677 count);
678 break;
679 case Token::Kind::LT:
680 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSLT,
681 ByteCodeInstruction::kCompareULT,
682 ByteCodeInstruction::kCompareFLT,
683 count);
684 break;
685 case Token::Kind::LTEQ:
686 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSLTEQ,
687 ByteCodeInstruction::kCompareULTEQ,
688 ByteCodeInstruction::kCompareFLTEQ,
689 count);
690 break;
691 case Token::Kind::MINUS:
692 this->writeTypedInstruction(lType, ByteCodeInstruction::kSubtractI,
693 ByteCodeInstruction::kSubtractI,
694 ByteCodeInstruction::kSubtractF,
695 count);
696 break;
697 case Token::Kind::NEQ:
698 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareINEQ,
699 ByteCodeInstruction::kCompareINEQ,
700 ByteCodeInstruction::kCompareFNEQ,
701 count);
702 // Collapse to a single bool
703 for (int i = count; i > 1; --i) {
704 this->write(ByteCodeInstruction::kOrB);
705 }
706 break;
707 case Token::Kind::PERCENT:
708 this->writeTypedInstruction(lType, ByteCodeInstruction::kRemainderS,
709 ByteCodeInstruction::kRemainderU,
710 ByteCodeInstruction::kRemainderF,
711 count);
712 break;
713 case Token::Kind::PLUS:
714 this->writeTypedInstruction(lType, ByteCodeInstruction::kAddI,
715 ByteCodeInstruction::kAddI,
716 ByteCodeInstruction::kAddF,
717 count);
718 break;
719 case Token::Kind::SLASH:
720 this->writeTypedInstruction(lType, ByteCodeInstruction::kDivideS,
721 ByteCodeInstruction::kDivideU,
722 ByteCodeInstruction::kDivideF,
723 count);
724 break;
725 case Token::Kind::STAR:
726 this->writeTypedInstruction(lType, ByteCodeInstruction::kMultiplyI,
727 ByteCodeInstruction::kMultiplyI,
728 ByteCodeInstruction::kMultiplyF,
729 count);
730 break;
Brian Osman569f12f2019-06-13 11:23:57 -0400731
732 case Token::Kind::LOGICALAND:
733 SkASSERT(type_category(lType) == SkSL::TypeCategory::kBool && count == 1);
734 this->write(ByteCodeInstruction::kAndB);
735 break;
736 case Token::Kind::LOGICALNOT:
737 SkASSERT(type_category(lType) == SkSL::TypeCategory::kBool && count == 1);
738 this->write(ByteCodeInstruction::kNotB);
739 break;
740 case Token::Kind::LOGICALOR:
741 SkASSERT(type_category(lType) == SkSL::TypeCategory::kBool && count == 1);
742 this->write(ByteCodeInstruction::kOrB);
743 break;
744 case Token::Kind::LOGICALXOR:
745 SkASSERT(type_category(lType) == SkSL::TypeCategory::kBool && count == 1);
746 this->write(ByteCodeInstruction::kXorB);
747 break;
748
Brian Osman909231c2019-05-29 15:34:36 -0400749 default:
750 SkASSERT(false);
751 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400752 }
753 if (lvalue) {
Brian Osman3e29f1d2019-05-28 09:35:05 -0400754 lvalue->store(discard);
755 discard = false;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400756 }
Brian Osman3e29f1d2019-05-28 09:35:05 -0400757 return discard;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400758}
759
760void ByteCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
761 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osman569f12f2019-06-13 11:23:57 -0400762 this->write32(b.fValue ? ~0 : 0);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400763}
764
765void ByteCodeGenerator::writeConstructor(const Constructor& c) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400766 for (const auto& arg : c.fArguments) {
767 this->writeExpression(*arg);
768 }
769 if (c.fArguments.size() == 1) {
Brian Osman29e013d2019-05-28 17:16:03 -0400770 const Type& inType = c.fArguments[0]->fType;
771 const Type& outType = c.fType;
772 TypeCategory inCategory = type_category(inType);
773 TypeCategory outCategory = type_category(outType);
774 int inCount = SlotCount(inType);
775 int outCount = SlotCount(outType);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400776 if (inCategory != outCategory) {
Brian Osmanc51d7912019-05-22 15:16:16 -0700777 SkASSERT(inCount == outCount);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400778 if (inCategory == TypeCategory::kFloat) {
779 SkASSERT(outCategory == TypeCategory::kSigned ||
780 outCategory == TypeCategory::kUnsigned);
Brian Osmanc51d7912019-05-22 15:16:16 -0700781 this->write(vector_instruction(ByteCodeInstruction::kConvertFtoI, outCount));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400782 } else if (outCategory == TypeCategory::kFloat) {
783 if (inCategory == TypeCategory::kSigned) {
Brian Osmanc51d7912019-05-22 15:16:16 -0700784 this->write(vector_instruction(ByteCodeInstruction::kConvertStoF, outCount));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400785 } else {
786 SkASSERT(inCategory == TypeCategory::kUnsigned);
Brian Osmanc51d7912019-05-22 15:16:16 -0700787 this->write(vector_instruction(ByteCodeInstruction::kConvertUtoF, outCount));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400788 }
789 } else {
790 SkASSERT(false);
791 }
792 }
Brian Osman29e013d2019-05-28 17:16:03 -0400793 if (inType.kind() == Type::kMatrix_Kind && outType.kind() == Type::kMatrix_Kind) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400794 this->write(ByteCodeInstruction::kMatrixToMatrix,
795 SlotCount(outType) - SlotCount(inType));
Brian Osman29e013d2019-05-28 17:16:03 -0400796 this->write8(inType.columns());
797 this->write8(inType.rows());
798 this->write8(outType.columns());
799 this->write8(outType.rows());
800 } else if (inCount != outCount) {
Brian Osmanc51d7912019-05-22 15:16:16 -0700801 SkASSERT(inCount == 1);
Brian Osman29e013d2019-05-28 17:16:03 -0400802 if (outType.kind() == Type::kMatrix_Kind) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400803 this->write(ByteCodeInstruction::kScalarToMatrix, SlotCount(outType) - 1);
Brian Osman29e013d2019-05-28 17:16:03 -0400804 this->write8(outType.columns());
805 this->write8(outType.rows());
806 } else {
807 SkASSERT(outType.kind() == Type::kVector_Kind);
808 for (; inCount != outCount; ++inCount) {
809 this->write(ByteCodeInstruction::kDup);
810 }
Brian Osmanc51d7912019-05-22 15:16:16 -0700811 }
812 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400813 }
814}
815
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400816void ByteCodeGenerator::writeExternalFunctionCall(const ExternalFunctionCall& f) {
817 int argumentCount = 0;
818 for (const auto& arg : f.fArguments) {
819 this->writeExpression(*arg);
Brian Osman07c117b2019-05-23 12:51:06 -0700820 argumentCount += SlotCount(arg->fType);
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400821 }
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400822 this->write(ByteCodeInstruction::kCallExternal, SlotCount(f.fType) - argumentCount);
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400823 SkASSERT(argumentCount <= 255);
824 this->write8(argumentCount);
Brian Osman07c117b2019-05-23 12:51:06 -0700825 this->write8(SlotCount(f.fType));
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400826 int index = fOutput->fExternalValues.size();
827 fOutput->fExternalValues.push_back(f.fFunction);
828 SkASSERT(index <= 255);
829 this->write8(index);
830}
831
Ethan Nicholas91164d12019-05-15 15:29:54 -0400832void ByteCodeGenerator::writeExternalValue(const ExternalValueReference& e) {
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400833 this->write(vector_instruction(ByteCodeInstruction::kReadExternal,
Brian Osman07c117b2019-05-23 12:51:06 -0700834 SlotCount(e.fValue->type())));
Ethan Nicholas91164d12019-05-15 15:29:54 -0400835 int index = fOutput->fExternalValues.size();
836 fOutput->fExternalValues.push_back(e.fValue);
837 SkASSERT(index <= 255);
838 this->write8(index);
839}
840
Brian Osman07c117b2019-05-23 12:51:06 -0700841void ByteCodeGenerator::writeVariableExpression(const Expression& expr) {
Brian Osman869a3e82019-07-18 17:00:34 -0400842 Variable::Storage storage = Variable::kLocal_Storage;
Brian Osman07c117b2019-05-23 12:51:06 -0700843 int location = this->getLocation(expr, &storage);
844 bool isGlobal = storage == Variable::kGlobal_Storage;
845 int count = SlotCount(expr.fType);
846 if (location < 0 || count > 4) {
847 if (location >= 0) {
848 this->write(ByteCodeInstruction::kPushImmediate);
849 this->write32(location);
850 }
851 this->write(isGlobal ? ByteCodeInstruction::kLoadExtendedGlobal
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400852 : ByteCodeInstruction::kLoadExtended,
853 count);
Brian Osman07c117b2019-05-23 12:51:06 -0700854 this->write8(count);
855 } else {
856 this->write(vector_instruction(isGlobal ? ByteCodeInstruction::kLoadGlobal
857 : ByteCodeInstruction::kLoad,
858 count));
859 this->write8(location);
860 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400861}
862
Brian Osmand30e0392019-06-14 14:05:14 -0400863static inline uint32_t float_to_bits(float x) {
864 uint32_t u;
865 memcpy(&u, &x, sizeof(uint32_t));
866 return u;
867}
868
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400869void ByteCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
870 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osmand30e0392019-06-14 14:05:14 -0400871 this->write32(float_to_bits(f.fValue));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400872}
873
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400874void ByteCodeGenerator::writeIntrinsicCall(const FunctionCall& c) {
875 auto found = fIntrinsics.find(c.fFunction.fName);
876 if (found == fIntrinsics.end()) {
877 fErrors.error(c.fOffset, "unsupported intrinsic function");
878 return;
879 }
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400880 int count = SlotCount(c.fArguments[0]->fType);
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400881 if (found->second.fIsSpecial) {
882 SkASSERT(found->second.fValue.fSpecial == SpecialIntrinsic::kDot);
883 SkASSERT(c.fArguments.size() == 2);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400884 SkASSERT(count == SlotCount(c.fArguments[1]->fType));
885 this->write((ByteCodeInstruction)((int)ByteCodeInstruction::kMultiplyF + count - 1));
886 for (int i = count; i > 1; --i) {
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400887 this->write(ByteCodeInstruction::kAddF);
888 }
889 } else {
890 switch (found->second.fValue.fInstruction) {
891 case ByteCodeInstruction::kCos:
892 case ByteCodeInstruction::kMix:
893 case ByteCodeInstruction::kSin:
894 case ByteCodeInstruction::kSqrt:
895 case ByteCodeInstruction::kTan:
896 SkASSERT(c.fArguments.size() > 0);
897 this->write((ByteCodeInstruction) ((int) found->second.fValue.fInstruction +
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400898 count - 1));
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400899 break;
900 case ByteCodeInstruction::kCross:
901 this->write(found->second.fValue.fInstruction);
902 break;
Mike Reed634c9412019-07-18 13:20:04 -0400903 case ByteCodeInstruction::kInverse2x2: {
904 SkASSERT(c.fArguments.size() > 0);
905 auto op = ByteCodeInstruction::kInverse2x2;
906 switch (count) {
907 case 4: break; // float2x2
908 case 9: op = ByteCodeInstruction::kInverse3x3; break;
909 case 16: op = ByteCodeInstruction::kInverse4x4; break;
910 default: SkASSERT(false);
911 }
912 this->write(op);
913 } break;
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400914 default:
915 SkASSERT(false);
916 }
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400917 }
918}
919
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400920void ByteCodeGenerator::writeFunctionCall(const FunctionCall& f) {
Brian Osmand3494ed2019-06-20 15:41:34 -0400921 // Builtins have simple signatures...
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400922 if (f.fFunction.fBuiltin) {
Brian Osmand3494ed2019-06-20 15:41:34 -0400923 for (const auto& arg : f.fArguments) {
924 this->writeExpression(*arg);
925 }
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400926 this->writeIntrinsicCall(f);
927 return;
928 }
Brian Osmand3494ed2019-06-20 15:41:34 -0400929
Brian Osman6f5358f2019-07-09 14:17:23 -0400930 // Find the index of the function we're calling. We explicitly do not allow calls to functions
931 // before they're defined. This is an easy-to-understand rule that prevents recursion.
932 size_t idx;
933 for (idx = 0; idx < fFunctions.size(); ++idx) {
934 if (f.fFunction.matches(fFunctions[idx]->fDeclaration)) {
935 break;
936 }
937 }
938 if (idx > 255) {
939 fErrors.error(f.fOffset, "Function count limit exceeded");
940 return;
941 } else if (idx >= fFunctions.size()) {
942 fErrors.error(f.fOffset, "Call to undefined function");
943 return;
944 }
945
946 // We may need to deal with out parameters, so the sequence is tricky
Brian Osmand3494ed2019-06-20 15:41:34 -0400947 if (int returnCount = SlotCount(f.fType)) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400948 this->write(ByteCodeInstruction::kReserve, returnCount);
Brian Osmand3494ed2019-06-20 15:41:34 -0400949 this->write8(returnCount);
950 }
951
952 int argCount = f.fArguments.size();
953 std::vector<std::unique_ptr<LValue>> lvalues;
954 for (int i = 0; i < argCount; ++i) {
955 const auto& param = f.fFunction.fParameters[i];
956 const auto& arg = f.fArguments[i];
957 if (param->fModifiers.fFlags & Modifiers::kOut_Flag) {
958 lvalues.emplace_back(this->getLValue(*arg));
959 lvalues.back()->load();
960 } else {
961 this->writeExpression(*arg);
962 }
963 }
964
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400965 // The space used by the call is based on the callee, but it also unwinds all of that before
966 // we continue execution. We adjust our max stack depths below.
Brian Osman226668a2019-05-14 16:47:30 -0400967 this->write(ByteCodeInstruction::kCall);
Brian Osman6f5358f2019-07-09 14:17:23 -0400968 this->write8(idx);
Brian Osmand3494ed2019-06-20 15:41:34 -0400969
Brian Osman4a47da72019-07-12 11:30:32 -0400970 const ByteCodeFunction* callee = fOutput->fFunctions[idx].get();
971 fMaxLoopCount = std::max(fMaxLoopCount, fLoopCount + callee->fLoopCount);
972 fMaxConditionCount = std::max(fMaxConditionCount, fConditionCount + callee->fConditionCount);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400973 fMaxStackCount = std::max(fMaxStackCount, fStackCount + callee->fLocalCount
974 + callee->fStackCount);
Brian Osman4a47da72019-07-12 11:30:32 -0400975
Brian Osmand3494ed2019-06-20 15:41:34 -0400976 // After the called function returns, the stack will still contain our arguments. We have to
977 // pop them (storing any out parameters back to their lvalues as we go). We glob together slot
978 // counts for all parameters that aren't out-params, so we can pop them in one big chunk.
979 int popCount = 0;
980 auto pop = [&]() {
981 if (popCount > 4) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400982 this->write(ByteCodeInstruction::kPopN, popCount);
Brian Osmand3494ed2019-06-20 15:41:34 -0400983 this->write8(popCount);
984 } else if (popCount > 0) {
985 this->write(vector_instruction(ByteCodeInstruction::kPop, popCount));
986 }
987 popCount = 0;
988 };
989
990 for (int i = argCount - 1; i >= 0; --i) {
991 const auto& param = f.fFunction.fParameters[i];
992 const auto& arg = f.fArguments[i];
993 if (param->fModifiers.fFlags & Modifiers::kOut_Flag) {
994 pop();
995 lvalues.back()->store(true);
996 lvalues.pop_back();
997 } else {
998 popCount += SlotCount(arg->fType);
999 }
1000 }
1001 pop();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001002}
1003
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001004void ByteCodeGenerator::writeIntLiteral(const IntLiteral& i) {
1005 this->write(ByteCodeInstruction::kPushImmediate);
1006 this->write32(i.fValue);
1007}
1008
1009void ByteCodeGenerator::writeNullLiteral(const NullLiteral& n) {
1010 // not yet implemented
1011 abort();
1012}
1013
Brian Osman3e29f1d2019-05-28 09:35:05 -04001014bool ByteCodeGenerator::writePrefixExpression(const PrefixExpression& p, bool discard) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001015 switch (p.fOperator) {
1016 case Token::Kind::PLUSPLUS: // fall through
1017 case Token::Kind::MINUSMINUS: {
Brian Osman07c117b2019-05-23 12:51:06 -07001018 SkASSERT(SlotCount(p.fOperand->fType) == 1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001019 std::unique_ptr<LValue> lvalue = this->getLValue(*p.fOperand);
1020 lvalue->load();
1021 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osmand30e0392019-06-14 14:05:14 -04001022 this->write32(type_category(p.fType) == TypeCategory::kFloat ? float_to_bits(1.0f) : 1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001023 if (p.fOperator == Token::Kind::PLUSPLUS) {
1024 this->writeTypedInstruction(p.fType,
1025 ByteCodeInstruction::kAddI,
1026 ByteCodeInstruction::kAddI,
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001027 ByteCodeInstruction::kAddF,
1028 1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001029 } else {
1030 this->writeTypedInstruction(p.fType,
1031 ByteCodeInstruction::kSubtractI,
1032 ByteCodeInstruction::kSubtractI,
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001033 ByteCodeInstruction::kSubtractF,
1034 1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001035 }
Brian Osman3e29f1d2019-05-28 09:35:05 -04001036 lvalue->store(discard);
1037 discard = false;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001038 break;
1039 }
Ethan Nicholas354ecf32019-05-07 16:13:02 -04001040 case Token::Kind::MINUS: {
1041 this->writeExpression(*p.fOperand);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001042 this->writeTypedInstruction(p.fType,
Mike Klein12710912019-05-21 11:04:59 -05001043 ByteCodeInstruction::kNegateI,
1044 ByteCodeInstruction::kNegateI,
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001045 ByteCodeInstruction::kNegateF,
Brian Osman07c117b2019-05-23 12:51:06 -07001046 SlotCount(p.fOperand->fType));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001047 break;
Ethan Nicholas354ecf32019-05-07 16:13:02 -04001048 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001049 default:
1050 SkASSERT(false);
1051 }
Brian Osman3e29f1d2019-05-28 09:35:05 -04001052 return discard;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001053}
1054
Brian Osman3e29f1d2019-05-28 09:35:05 -04001055bool ByteCodeGenerator::writePostfixExpression(const PostfixExpression& p, bool discard) {
Brian Osmanf3fa6002019-05-17 14:26:53 -04001056 switch (p.fOperator) {
1057 case Token::Kind::PLUSPLUS: // fall through
1058 case Token::Kind::MINUSMINUS: {
Brian Osman07c117b2019-05-23 12:51:06 -07001059 SkASSERT(SlotCount(p.fOperand->fType) == 1);
Brian Osmanf3fa6002019-05-17 14:26:53 -04001060 std::unique_ptr<LValue> lvalue = this->getLValue(*p.fOperand);
1061 lvalue->load();
Brian Osman52c1bf12019-07-18 13:12:19 -04001062 // If we're not supposed to discard the result, then make a copy *before* the +/-
Brian Osman3e29f1d2019-05-28 09:35:05 -04001063 if (!discard) {
1064 this->write(ByteCodeInstruction::kDup);
1065 }
Brian Osmanf3fa6002019-05-17 14:26:53 -04001066 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osmand30e0392019-06-14 14:05:14 -04001067 this->write32(type_category(p.fType) == TypeCategory::kFloat ? float_to_bits(1.0f) : 1);
Brian Osmanf3fa6002019-05-17 14:26:53 -04001068 if (p.fOperator == Token::Kind::PLUSPLUS) {
1069 this->writeTypedInstruction(p.fType,
1070 ByteCodeInstruction::kAddI,
1071 ByteCodeInstruction::kAddI,
1072 ByteCodeInstruction::kAddF,
1073 1);
1074 } else {
1075 this->writeTypedInstruction(p.fType,
1076 ByteCodeInstruction::kSubtractI,
1077 ByteCodeInstruction::kSubtractI,
1078 ByteCodeInstruction::kSubtractF,
1079 1);
1080 }
Brian Osman52c1bf12019-07-18 13:12:19 -04001081 // Always consume the result as part of the store
1082 lvalue->store(true);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001083 discard = false;
Brian Osmanf3fa6002019-05-17 14:26:53 -04001084 break;
1085 }
1086 default:
1087 SkASSERT(false);
1088 }
Brian Osman3e29f1d2019-05-28 09:35:05 -04001089 return discard;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001090}
1091
1092void ByteCodeGenerator::writeSwizzle(const Swizzle& s) {
Brian Osman0785db02019-05-24 14:19:11 -04001093 if (swizzle_is_simple(s)) {
1094 this->writeVariableExpression(s);
1095 return;
1096 }
1097
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001098 switch (s.fBase->fKind) {
1099 case Expression::kVariableReference_Kind: {
1100 const Variable& var = ((VariableReference&) *s.fBase).fVariable;
Brian Osman1091f022019-05-16 09:42:16 -04001101 this->write(var.fStorage == Variable::kGlobal_Storage
1102 ? ByteCodeInstruction::kLoadSwizzleGlobal
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001103 : ByteCodeInstruction::kLoadSwizzle,
1104 s.fComponents.size());
Brian Osman1091f022019-05-16 09:42:16 -04001105 this->write8(this->getLocation(var));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001106 this->write8(s.fComponents.size());
1107 for (int c : s.fComponents) {
1108 this->write8(c);
1109 }
1110 break;
1111 }
1112 default:
1113 this->writeExpression(*s.fBase);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001114 this->write(ByteCodeInstruction::kSwizzle,
1115 s.fComponents.size() - s.fBase->fType.columns());
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001116 this->write8(s.fBase->fType.columns());
1117 this->write8(s.fComponents.size());
1118 for (int c : s.fComponents) {
1119 this->write8(c);
1120 }
1121 }
1122}
1123
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001124void ByteCodeGenerator::writeTernaryExpression(const TernaryExpression& t) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001125 int count = SlotCount(t.fType);
1126 SkASSERT(count == SlotCount(t.fIfTrue->fType));
1127 SkASSERT(count == SlotCount(t.fIfFalse->fType));
1128
Brian Osman4e93feb2019-05-16 15:38:00 -04001129 this->writeExpression(*t.fTest);
Brian Osman569f12f2019-06-13 11:23:57 -04001130 this->write(ByteCodeInstruction::kMaskPush);
Brian Osman4e93feb2019-05-16 15:38:00 -04001131 this->writeExpression(*t.fIfTrue);
Brian Osman569f12f2019-06-13 11:23:57 -04001132 this->write(ByteCodeInstruction::kMaskNegate);
1133 this->writeExpression(*t.fIfFalse);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001134 this->write(ByteCodeInstruction::kMaskBlend, count);
1135 this->write8(count);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001136}
1137
Brian Osman3e29f1d2019-05-28 09:35:05 -04001138void ByteCodeGenerator::writeExpression(const Expression& e, bool discard) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001139 switch (e.fKind) {
1140 case Expression::kBinary_Kind:
Brian Osman3e29f1d2019-05-28 09:35:05 -04001141 discard = this->writeBinaryExpression((BinaryExpression&) e, discard);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001142 break;
1143 case Expression::kBoolLiteral_Kind:
1144 this->writeBoolLiteral((BoolLiteral&) e);
1145 break;
1146 case Expression::kConstructor_Kind:
1147 this->writeConstructor((Constructor&) e);
1148 break;
Ethan Nicholas9e6a3932019-05-17 16:31:21 -04001149 case Expression::kExternalFunctionCall_Kind:
1150 this->writeExternalFunctionCall((ExternalFunctionCall&) e);
1151 break;
Ethan Nicholas91164d12019-05-15 15:29:54 -04001152 case Expression::kExternalValue_Kind:
1153 this->writeExternalValue((ExternalValueReference&) e);
1154 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001155 case Expression::kFieldAccess_Kind:
Brian Osman07c117b2019-05-23 12:51:06 -07001156 case Expression::kIndex_Kind:
1157 case Expression::kVariableReference_Kind:
1158 this->writeVariableExpression(e);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001159 break;
1160 case Expression::kFloatLiteral_Kind:
1161 this->writeFloatLiteral((FloatLiteral&) e);
1162 break;
1163 case Expression::kFunctionCall_Kind:
1164 this->writeFunctionCall((FunctionCall&) e);
1165 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001166 case Expression::kIntLiteral_Kind:
1167 this->writeIntLiteral((IntLiteral&) e);
1168 break;
1169 case Expression::kNullLiteral_Kind:
1170 this->writeNullLiteral((NullLiteral&) e);
1171 break;
1172 case Expression::kPrefix_Kind:
Brian Osman3e29f1d2019-05-28 09:35:05 -04001173 discard = this->writePrefixExpression((PrefixExpression&) e, discard);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001174 break;
1175 case Expression::kPostfix_Kind:
Brian Osman3e29f1d2019-05-28 09:35:05 -04001176 discard = this->writePostfixExpression((PostfixExpression&) e, discard);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001177 break;
1178 case Expression::kSwizzle_Kind:
1179 this->writeSwizzle((Swizzle&) e);
1180 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001181 case Expression::kTernary_Kind:
1182 this->writeTernaryExpression((TernaryExpression&) e);
1183 break;
1184 default:
1185 printf("unsupported expression %s\n", e.description().c_str());
1186 SkASSERT(false);
1187 }
Brian Osman3e29f1d2019-05-28 09:35:05 -04001188 if (discard) {
1189 int count = SlotCount(e.fType);
1190 if (count > 4) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001191 this->write(ByteCodeInstruction::kPopN, count);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001192 this->write8(count);
Brian Osmanfba386b2019-06-20 14:54:15 -04001193 } else if (count != 0) {
Brian Osman3e29f1d2019-05-28 09:35:05 -04001194 this->write(vector_instruction(ByteCodeInstruction::kPop, count));
1195 }
1196 discard = false;
1197 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001198}
1199
Ethan Nicholas91164d12019-05-15 15:29:54 -04001200class ByteCodeExternalValueLValue : public ByteCodeGenerator::LValue {
1201public:
1202 ByteCodeExternalValueLValue(ByteCodeGenerator* generator, ExternalValue& value, int index)
1203 : INHERITED(*generator)
Brian Osman07c117b2019-05-23 12:51:06 -07001204 , fCount(ByteCodeGenerator::SlotCount(value.type()))
Ethan Nicholas91164d12019-05-15 15:29:54 -04001205 , fIndex(index) {}
1206
1207 void load() override {
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001208 fGenerator.write(vector_instruction(ByteCodeInstruction::kReadExternal, fCount));
Ethan Nicholas91164d12019-05-15 15:29:54 -04001209 fGenerator.write8(fIndex);
1210 }
1211
Brian Osman3e29f1d2019-05-28 09:35:05 -04001212 void store(bool discard) override {
1213 if (!discard) {
1214 fGenerator.write(vector_instruction(ByteCodeInstruction::kDup, fCount));
1215 }
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001216 fGenerator.write(vector_instruction(ByteCodeInstruction::kWriteExternal, fCount));
Ethan Nicholas91164d12019-05-15 15:29:54 -04001217 fGenerator.write8(fIndex);
1218 }
1219
1220private:
1221 typedef LValue INHERITED;
1222
1223 int fCount;
1224
1225 int fIndex;
1226};
1227
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001228class ByteCodeSwizzleLValue : public ByteCodeGenerator::LValue {
1229public:
1230 ByteCodeSwizzleLValue(ByteCodeGenerator* generator, const Swizzle& swizzle)
1231 : INHERITED(*generator)
Brian Osman07c117b2019-05-23 12:51:06 -07001232 , fSwizzle(swizzle) {}
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001233
1234 void load() override {
Brian Osman1091f022019-05-16 09:42:16 -04001235 fGenerator.writeSwizzle(fSwizzle);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001236 }
1237
Brian Osman3e29f1d2019-05-28 09:35:05 -04001238 void store(bool discard) override {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001239 int count = fSwizzle.fComponents.size();
Brian Osman3e29f1d2019-05-28 09:35:05 -04001240 if (!discard) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001241 fGenerator.write(vector_instruction(ByteCodeInstruction::kDup, count));
Brian Osman3e29f1d2019-05-28 09:35:05 -04001242 }
Brian Osman869a3e82019-07-18 17:00:34 -04001243 Variable::Storage storage = Variable::kLocal_Storage;
Brian Osman07c117b2019-05-23 12:51:06 -07001244 int location = fGenerator.getLocation(*fSwizzle.fBase, &storage);
1245 bool isGlobal = storage == Variable::kGlobal_Storage;
1246 if (location < 0) {
1247 fGenerator.write(isGlobal ? ByteCodeInstruction::kStoreSwizzleIndirectGlobal
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001248 : ByteCodeInstruction::kStoreSwizzleIndirect,
1249 count);
Brian Osman07c117b2019-05-23 12:51:06 -07001250 } else {
1251 fGenerator.write(isGlobal ? ByteCodeInstruction::kStoreSwizzleGlobal
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001252 : ByteCodeInstruction::kStoreSwizzle,
1253 count);
Brian Osman07c117b2019-05-23 12:51:06 -07001254 fGenerator.write8(location);
1255 }
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001256 fGenerator.write8(count);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001257 for (int c : fSwizzle.fComponents) {
1258 fGenerator.write8(c);
1259 }
1260 }
1261
1262private:
1263 const Swizzle& fSwizzle;
1264
1265 typedef LValue INHERITED;
1266};
1267
Brian Osman07c117b2019-05-23 12:51:06 -07001268class ByteCodeExpressionLValue : public ByteCodeGenerator::LValue {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001269public:
Brian Osman07c117b2019-05-23 12:51:06 -07001270 ByteCodeExpressionLValue(ByteCodeGenerator* generator, const Expression& expr)
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001271 : INHERITED(*generator)
Brian Osman07c117b2019-05-23 12:51:06 -07001272 , fExpression(expr) {}
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001273
1274 void load() override {
Brian Osman07c117b2019-05-23 12:51:06 -07001275 fGenerator.writeVariableExpression(fExpression);
Brian Osman1091f022019-05-16 09:42:16 -04001276 }
1277
Brian Osman3e29f1d2019-05-28 09:35:05 -04001278 void store(bool discard) override {
Brian Osman07c117b2019-05-23 12:51:06 -07001279 int count = ByteCodeGenerator::SlotCount(fExpression.fType);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001280 if (!discard) {
1281 if (count > 4) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001282 fGenerator.write(ByteCodeInstruction::kDupN, count);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001283 fGenerator.write8(count);
1284 } else {
1285 fGenerator.write(vector_instruction(ByteCodeInstruction::kDup, count));
1286 }
Brian Osman07c117b2019-05-23 12:51:06 -07001287 }
Brian Osman869a3e82019-07-18 17:00:34 -04001288 Variable::Storage storage = Variable::kLocal_Storage;
Brian Osman07c117b2019-05-23 12:51:06 -07001289 int location = fGenerator.getLocation(fExpression, &storage);
1290 bool isGlobal = storage == Variable::kGlobal_Storage;
1291 if (location < 0 || count > 4) {
1292 if (location >= 0) {
1293 fGenerator.write(ByteCodeInstruction::kPushImmediate);
1294 fGenerator.write32(location);
1295 }
1296 fGenerator.write(isGlobal ? ByteCodeInstruction::kStoreExtendedGlobal
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001297 : ByteCodeInstruction::kStoreExtended,
1298 count);
Brian Osman07c117b2019-05-23 12:51:06 -07001299 fGenerator.write8(count);
1300 } else {
1301 fGenerator.write(vector_instruction(isGlobal ? ByteCodeInstruction::kStoreGlobal
1302 : ByteCodeInstruction::kStore,
1303 count));
1304 fGenerator.write8(location);
1305 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001306 }
1307
1308private:
1309 typedef LValue INHERITED;
1310
Brian Osman07c117b2019-05-23 12:51:06 -07001311 const Expression& fExpression;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001312};
1313
1314std::unique_ptr<ByteCodeGenerator::LValue> ByteCodeGenerator::getLValue(const Expression& e) {
1315 switch (e.fKind) {
Ethan Nicholas91164d12019-05-15 15:29:54 -04001316 case Expression::kExternalValue_Kind: {
1317 ExternalValue* value = ((ExternalValueReference&) e).fValue;
1318 int index = fOutput->fExternalValues.size();
1319 fOutput->fExternalValues.push_back(value);
1320 SkASSERT(index <= 255);
1321 return std::unique_ptr<LValue>(new ByteCodeExternalValueLValue(this, *value, index));
1322 }
Brian Osman07c117b2019-05-23 12:51:06 -07001323 case Expression::kFieldAccess_Kind:
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001324 case Expression::kIndex_Kind:
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001325 case Expression::kVariableReference_Kind:
Brian Osman07c117b2019-05-23 12:51:06 -07001326 return std::unique_ptr<LValue>(new ByteCodeExpressionLValue(this, e));
Brian Osman0785db02019-05-24 14:19:11 -04001327 case Expression::kSwizzle_Kind: {
1328 const Swizzle& s = (const Swizzle&) e;
1329 return swizzle_is_simple(s)
1330 ? std::unique_ptr<LValue>(new ByteCodeExpressionLValue(this, e))
1331 : std::unique_ptr<LValue>(new ByteCodeSwizzleLValue(this, s));
1332 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001333 case Expression::kTernary_Kind:
1334 default:
1335 printf("unsupported lvalue %s\n", e.description().c_str());
1336 return nullptr;
1337 }
1338}
1339
1340void ByteCodeGenerator::writeBlock(const Block& b) {
1341 for (const auto& s : b.fStatements) {
1342 this->writeStatement(*s);
1343 }
1344}
1345
1346void ByteCodeGenerator::setBreakTargets() {
1347 std::vector<DeferredLocation>& breaks = fBreakTargets.top();
1348 for (DeferredLocation& b : breaks) {
1349 b.set();
1350 }
1351 fBreakTargets.pop();
1352}
1353
1354void ByteCodeGenerator::setContinueTargets() {
1355 std::vector<DeferredLocation>& continues = fContinueTargets.top();
1356 for (DeferredLocation& c : continues) {
1357 c.set();
1358 }
1359 fContinueTargets.pop();
1360}
1361
1362void ByteCodeGenerator::writeBreakStatement(const BreakStatement& b) {
Brian Osman569f12f2019-06-13 11:23:57 -04001363 // TODO: Include BranchIfAllFalse to top-most LoopNext
1364 this->write(ByteCodeInstruction::kLoopBreak);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001365}
1366
1367void ByteCodeGenerator::writeContinueStatement(const ContinueStatement& c) {
Brian Osman569f12f2019-06-13 11:23:57 -04001368 // TODO: Include BranchIfAllFalse to top-most LoopNext
1369 this->write(ByteCodeInstruction::kLoopContinue);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001370}
1371
1372void ByteCodeGenerator::writeDoStatement(const DoStatement& d) {
Brian Osman569f12f2019-06-13 11:23:57 -04001373 this->write(ByteCodeInstruction::kLoopBegin);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001374 size_t start = fCode->size();
1375 this->writeStatement(*d.fStatement);
Brian Osman569f12f2019-06-13 11:23:57 -04001376 this->write(ByteCodeInstruction::kLoopNext);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001377 this->writeExpression(*d.fTest);
Brian Osman569f12f2019-06-13 11:23:57 -04001378 this->write(ByteCodeInstruction::kLoopMask);
1379 // TODO: Could shorten this with kBranchIfAnyTrue
1380 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1381 DeferredLocation endLocation(this);
1382 this->write(ByteCodeInstruction::kBranch);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001383 this->write16(start);
Brian Osman569f12f2019-06-13 11:23:57 -04001384 endLocation.set();
1385 this->write(ByteCodeInstruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001386}
1387
1388void ByteCodeGenerator::writeForStatement(const ForStatement& f) {
1389 fContinueTargets.emplace();
1390 fBreakTargets.emplace();
1391 if (f.fInitializer) {
1392 this->writeStatement(*f.fInitializer);
1393 }
Brian Osman569f12f2019-06-13 11:23:57 -04001394 this->write(ByteCodeInstruction::kLoopBegin);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001395 size_t start = fCode->size();
1396 if (f.fTest) {
1397 this->writeExpression(*f.fTest);
Brian Osman569f12f2019-06-13 11:23:57 -04001398 this->write(ByteCodeInstruction::kLoopMask);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001399 }
Brian Osman569f12f2019-06-13 11:23:57 -04001400 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1401 DeferredLocation endLocation(this);
1402 this->writeStatement(*f.fStatement);
1403 this->write(ByteCodeInstruction::kLoopNext);
1404 if (f.fNext) {
1405 this->writeExpression(*f.fNext, true);
1406 }
1407 this->write(ByteCodeInstruction::kBranch);
1408 this->write16(start);
1409 endLocation.set();
1410 this->write(ByteCodeInstruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001411}
1412
1413void ByteCodeGenerator::writeIfStatement(const IfStatement& i) {
Brian Osman569f12f2019-06-13 11:23:57 -04001414 this->writeExpression(*i.fTest);
1415 this->write(ByteCodeInstruction::kMaskPush);
1416 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1417 DeferredLocation falseLocation(this);
1418 this->writeStatement(*i.fIfTrue);
1419 falseLocation.set();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001420 if (i.fIfFalse) {
Brian Osman569f12f2019-06-13 11:23:57 -04001421 this->write(ByteCodeInstruction::kMaskNegate);
1422 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1423 DeferredLocation endLocation(this);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001424 this->writeStatement(*i.fIfFalse);
Mike Kleinb45ee832019-05-17 11:11:11 -05001425 endLocation.set();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001426 }
Brian Osman569f12f2019-06-13 11:23:57 -04001427 this->write(ByteCodeInstruction::kMaskPop);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001428}
1429
1430void ByteCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
Brian Osman4a47da72019-07-12 11:30:32 -04001431 if (fLoopCount || fConditionCount) {
1432 fErrors.error(r.fOffset, "return not allowed inside conditional or loop");
1433 return;
1434 }
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001435 int count = SlotCount(r.fExpression->fType);
Ethan Nicholas746035a2019-04-23 13:31:09 -04001436 this->writeExpression(*r.fExpression);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001437
1438 // Technically, the kReturn also pops fOutput->fLocalCount values from the stack, too, but we
1439 // haven't counted pushing those (they're outside the scope of our stack tracking). Instead,
1440 // we account for those in writeFunction().
1441
1442 // This is all fine because we don't allow conditional returns, so we only return once anyway.
1443 this->write(ByteCodeInstruction::kReturn, -count);
1444 this->write8(count);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001445}
1446
1447void ByteCodeGenerator::writeSwitchStatement(const SwitchStatement& r) {
1448 // not yet implemented
1449 abort();
1450}
1451
1452void ByteCodeGenerator::writeVarDeclarations(const VarDeclarations& v) {
1453 for (const auto& declStatement : v.fVars) {
1454 const VarDeclaration& decl = (VarDeclaration&) *declStatement;
1455 // we need to grab the location even if we don't use it, to ensure it
1456 // has been allocated
1457 int location = getLocation(*decl.fVar);
1458 if (decl.fValue) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001459 this->writeExpression(*decl.fValue);
Brian Osman07c117b2019-05-23 12:51:06 -07001460 int count = SlotCount(decl.fValue->fType);
1461 if (count > 4) {
1462 this->write(ByteCodeInstruction::kPushImmediate);
1463 this->write32(location);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001464 this->write(ByteCodeInstruction::kStoreExtended, count);
Brian Osman07c117b2019-05-23 12:51:06 -07001465 this->write8(count);
1466 } else {
1467 this->write(vector_instruction(ByteCodeInstruction::kStore, count));
1468 this->write8(location);
1469 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001470 }
1471 }
1472}
1473
1474void ByteCodeGenerator::writeWhileStatement(const WhileStatement& w) {
Brian Osman569f12f2019-06-13 11:23:57 -04001475 this->write(ByteCodeInstruction::kLoopBegin);
1476 size_t cond = fCode->size();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001477 this->writeExpression(*w.fTest);
Brian Osman569f12f2019-06-13 11:23:57 -04001478 this->write(ByteCodeInstruction::kLoopMask);
1479 this->write(ByteCodeInstruction::kBranchIfAllFalse);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001480 DeferredLocation endLocation(this);
1481 this->writeStatement(*w.fStatement);
Brian Osman569f12f2019-06-13 11:23:57 -04001482 this->write(ByteCodeInstruction::kLoopNext);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001483 this->write(ByteCodeInstruction::kBranch);
Brian Osman569f12f2019-06-13 11:23:57 -04001484 this->write16(cond);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001485 endLocation.set();
Brian Osman569f12f2019-06-13 11:23:57 -04001486 this->write(ByteCodeInstruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001487}
1488
1489void ByteCodeGenerator::writeStatement(const Statement& s) {
1490 switch (s.fKind) {
1491 case Statement::kBlock_Kind:
1492 this->writeBlock((Block&) s);
1493 break;
1494 case Statement::kBreak_Kind:
1495 this->writeBreakStatement((BreakStatement&) s);
1496 break;
1497 case Statement::kContinue_Kind:
1498 this->writeContinueStatement((ContinueStatement&) s);
1499 break;
1500 case Statement::kDiscard_Kind:
1501 // not yet implemented
1502 abort();
1503 case Statement::kDo_Kind:
1504 this->writeDoStatement((DoStatement&) s);
1505 break;
Brian Osman3e29f1d2019-05-28 09:35:05 -04001506 case Statement::kExpression_Kind:
1507 this->writeExpression(*((ExpressionStatement&) s).fExpression, true);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001508 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001509 case Statement::kFor_Kind:
1510 this->writeForStatement((ForStatement&) s);
1511 break;
1512 case Statement::kIf_Kind:
1513 this->writeIfStatement((IfStatement&) s);
1514 break;
1515 case Statement::kNop_Kind:
1516 break;
1517 case Statement::kReturn_Kind:
1518 this->writeReturnStatement((ReturnStatement&) s);
1519 break;
1520 case Statement::kSwitch_Kind:
1521 this->writeSwitchStatement((SwitchStatement&) s);
1522 break;
1523 case Statement::kVarDeclarations_Kind:
1524 this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration);
1525 break;
1526 case Statement::kWhile_Kind:
1527 this->writeWhileStatement((WhileStatement&) s);
1528 break;
1529 default:
1530 SkASSERT(false);
1531 }
1532}
1533
Brian Osman80164412019-06-07 13:00:23 -04001534ByteCodeFunction::ByteCodeFunction(const FunctionDeclaration* declaration)
1535 : fName(declaration->fName) {
1536 fParameterCount = 0;
1537 for (const auto& p : declaration->fParameters) {
1538 int slots = ByteCodeGenerator::SlotCount(p->fType);
1539 fParameters.push_back({ slots, (bool)(p->fModifiers.fFlags & Modifiers::kOut_Flag) });
1540 fParameterCount += slots;
1541 }
1542}
1543
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001544}