blob: 8d52fad371d87bd19f48d57936508fb2ae648d2c [file] [log] [blame]
Brian Osmanb380e712019-07-24 17:02:39 -04001/*
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04002 * Copyright 2019 Google LLC
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "src/sksl/SkSLByteCodeGenerator.h"
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04009
Brian Osman95253bd2019-06-05 10:28:45 -040010#include <algorithm>
11
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040012namespace SkSL {
13
Ethan Nicholas82162ee2019-05-21 16:05:08 -040014ByteCodeGenerator::ByteCodeGenerator(const Context* context, const Program* program, ErrorReporter* errors,
15 ByteCode* output)
16 : INHERITED(program, errors, nullptr)
17 , fContext(*context)
Ethan Nicholasae9633b2019-05-24 12:46:34 -040018 , fOutput(output)
19 , fIntrinsics {
Brian Osmanb380e712019-07-24 17:02:39 -040020 { "cos", ByteCodeInstruction::kCos },
21 { "cross", ByteCodeInstruction::kCross },
22 { "dot", SpecialIntrinsic::kDot },
23 { "inverse", ByteCodeInstruction::kInverse2x2 },
24 { "normalize", ByteCodeInstruction::kNormalize },
25 { "radians", SpecialIntrinsic::kRadians },
26 { "sin", ByteCodeInstruction::kSin },
27 { "sqrt", ByteCodeInstruction::kSqrt },
28 { "tan", ByteCodeInstruction::kTan },
29 { "mix", ByteCodeInstruction::kMix },
Ethan Nicholasae9633b2019-05-24 12:46:34 -040030 } {}
31
Ethan Nicholas82162ee2019-05-21 16:05:08 -040032
Brian Osman07c117b2019-05-23 12:51:06 -070033int ByteCodeGenerator::SlotCount(const Type& type) {
Brian Osmanfba386b2019-06-20 14:54:15 -040034 if (type.kind() == Type::kOther_Kind) {
35 return 0;
36 } else if (type.kind() == Type::kStruct_Kind) {
Brian Osman07c117b2019-05-23 12:51:06 -070037 int slots = 0;
38 for (const auto& f : type.fields()) {
39 slots += SlotCount(*f.fType);
40 }
41 SkASSERT(slots <= 255);
42 return slots;
43 } else if (type.kind() == Type::kArray_Kind) {
44 int columns = type.columns();
45 SkASSERT(columns >= 0);
46 int slots = columns * SlotCount(type.componentType());
47 SkASSERT(slots <= 255);
48 return slots;
49 } else {
50 return type.columns() * type.rows();
51 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040052}
53
54bool ByteCodeGenerator::generateCode() {
55 for (const auto& e : fProgram) {
56 switch (e.fKind) {
57 case ProgramElement::kFunction_Kind: {
58 std::unique_ptr<ByteCodeFunction> f = this->writeFunction((FunctionDefinition&) e);
59 if (!f) {
60 return false;
61 }
62 fOutput->fFunctions.push_back(std::move(f));
Brian Osman80164412019-06-07 13:00:23 -040063 fFunctions.push_back(&(FunctionDefinition&)e);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040064 break;
65 }
66 case ProgramElement::kVar_Kind: {
67 VarDeclarations& decl = (VarDeclarations&) e;
68 for (const auto& v : decl.fVars) {
69 const Variable* declVar = ((VarDeclaration&) *v).fVar;
70 if (declVar->fModifiers.fLayout.fBuiltin >= 0) {
71 continue;
72 }
73 if (declVar->fModifiers.fFlags & Modifiers::kIn_Flag) {
Brian Osman07c117b2019-05-23 12:51:06 -070074 for (int i = SlotCount(declVar->fType); i > 0; --i) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040075 fOutput->fInputSlots.push_back(fOutput->fGlobalCount++);
76 }
77 } else {
Brian Osman07c117b2019-05-23 12:51:06 -070078 fOutput->fGlobalCount += SlotCount(declVar->fType);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040079 }
80 }
81 break;
82 }
83 default:
84 ; // ignore
85 }
86 }
Brian Osman6f5358f2019-07-09 14:17:23 -040087 return 0 == fErrors.errorCount();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040088}
89
90std::unique_ptr<ByteCodeFunction> ByteCodeGenerator::writeFunction(const FunctionDefinition& f) {
91 fFunction = &f;
Brian Osman226668a2019-05-14 16:47:30 -040092 std::unique_ptr<ByteCodeFunction> result(new ByteCodeFunction(&f.fDeclaration));
Brian Osman80164412019-06-07 13:00:23 -040093 fParameterCount = result->fParameterCount;
Brian Osman4a47da72019-07-12 11:30:32 -040094 fLoopCount = fMaxLoopCount = 0;
95 fConditionCount = fMaxConditionCount = 0;
Brian Osmanaa2ca3f2019-07-15 13:24:48 -040096 fStackCount = fMaxStackCount = 0;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040097 fCode = &result->fCode;
Brian Osman4a47da72019-07-12 11:30:32 -040098
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040099 this->writeStatement(*f.fBody);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400100 if (0 == fErrors.errorCount()) {
101 SkASSERT(fLoopCount == 0);
102 SkASSERT(fConditionCount == 0);
103 SkASSERT(fStackCount == 0);
104 }
105 this->write(ByteCodeInstruction::kReturn, 0);
Ethan Nicholas7e603db2019-05-03 12:57:47 -0400106 this->write8(0);
Brian Osman4a47da72019-07-12 11:30:32 -0400107
108 result->fLocalCount = fLocals.size();
109 result->fConditionCount = fMaxConditionCount;
110 result->fLoopCount = fMaxLoopCount;
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400111 result->fStackCount = fMaxStackCount;
Brian Osman4a47da72019-07-12 11:30:32 -0400112
Ethan Nicholasdfcad062019-05-07 12:53:34 -0400113 const Type& returnType = f.fDeclaration.fReturnType;
114 if (returnType != *fContext.fVoid_Type) {
Brian Osman07c117b2019-05-23 12:51:06 -0700115 result->fReturnCount = SlotCount(returnType);
Ethan Nicholasdfcad062019-05-07 12:53:34 -0400116 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400117 fLocals.clear();
118 fFunction = nullptr;
119 return result;
120}
121
122enum class TypeCategory {
123 kBool,
124 kSigned,
125 kUnsigned,
126 kFloat,
127};
128
129static TypeCategory type_category(const Type& type) {
130 switch (type.kind()) {
131 case Type::Kind::kVector_Kind:
132 case Type::Kind::kMatrix_Kind:
133 return type_category(type.componentType());
134 default:
135 if (type.fName == "bool") {
136 return TypeCategory::kBool;
137 } else if (type.fName == "int" || type.fName == "short") {
138 return TypeCategory::kSigned;
139 } else if (type.fName == "uint" || type.fName == "ushort") {
140 return TypeCategory::kUnsigned;
141 } else {
142 SkASSERT(type.fName == "float" || type.fName == "half");
143 return TypeCategory::kFloat;
144 }
145 ABORT("unsupported type: %s\n", type.description().c_str());
146 }
147}
148
Brian Osman0785db02019-05-24 14:19:11 -0400149// A "simple" Swizzle is based on a variable (or a compound variable like a struct or array), and
150// that references consecutive values, such that it can be implemented using normal load/store ops
151// with an offset. Note that all single-component swizzles (of suitable base types) are simple.
152static bool swizzle_is_simple(const Swizzle& s) {
153 switch (s.fBase->fKind) {
154 case Expression::kFieldAccess_Kind:
155 case Expression::kIndex_Kind:
156 case Expression::kVariableReference_Kind:
157 break;
158 default:
159 return false;
160 }
161
162 for (size_t i = 1; i < s.fComponents.size(); ++i) {
163 if (s.fComponents[i] != s.fComponents[i - 1] + 1) {
164 return false;
165 }
166 }
167 return true;
168}
169
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400170int ByteCodeGenerator::StackUsage(ByteCodeInstruction inst, int count_) {
171 // Ensures that we use count iff we're passed a non-default value. Most instructions have an
172 // implicit count, so the caller shouldn't need to worry about it (or count makes no sense).
173 // The asserts avoids callers thinking they're supplying useful information in that scenario,
174 // or failing to supply necessary information for the ops that need a count.
175 struct CountValue {
176 operator int() {
177 SkASSERT(val != ByteCodeGenerator::kUnusedStackCount);
178 SkDEBUGCODE(used = true);
179 return val;
180 }
181 ~CountValue() {
182 SkASSERT(used || val == ByteCodeGenerator::kUnusedStackCount);
183 }
184 int val;
185 SkDEBUGCODE(bool used = false;)
186 } count = { count_ };
187
188 switch (inst) {
189 // Unary functions/operators that don't change stack depth at all:
190#define VECTOR_UNARY_OP(base) \
191 case ByteCodeInstruction::base: \
192 case ByteCodeInstruction::base ## 2: \
193 case ByteCodeInstruction::base ## 3: \
194 case ByteCodeInstruction::base ## 4: \
195 return 0;
196
197 VECTOR_UNARY_OP(kConvertFtoI)
198 VECTOR_UNARY_OP(kConvertStoF)
199 VECTOR_UNARY_OP(kConvertUtoF)
200
201 VECTOR_UNARY_OP(kCos)
Brian Osmanb380e712019-07-24 17:02:39 -0400202 VECTOR_UNARY_OP(kNormalize)
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400203 VECTOR_UNARY_OP(kSin)
204 VECTOR_UNARY_OP(kSqrt)
205 VECTOR_UNARY_OP(kTan)
206
207 VECTOR_UNARY_OP(kNegateF)
208 VECTOR_UNARY_OP(kNegateI)
209
Mike Reed634c9412019-07-18 13:20:04 -0400210 case ByteCodeInstruction::kInverse2x2:
211 case ByteCodeInstruction::kInverse3x3:
212 case ByteCodeInstruction::kInverse4x4: return 0;
213
Brian Osman869a3e82019-07-18 17:00:34 -0400214 case ByteCodeInstruction::kClampIndex: return 0;
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400215 case ByteCodeInstruction::kNotB: return 0;
216 case ByteCodeInstruction::kNegateFN: return 0;
217
218#undef VECTOR_UNARY_OP
219
220 // Binary functions/operators that do a 2 -> 1 reduction (possibly N times)
221#define VECTOR_BINARY_OP(base) \
222 case ByteCodeInstruction::base: return -1; \
223 case ByteCodeInstruction::base ## 2: return -2; \
224 case ByteCodeInstruction::base ## 3: return -3; \
225 case ByteCodeInstruction::base ## 4: return -4;
226
227#define VECTOR_MATRIX_BINARY_OP(base) \
228 VECTOR_BINARY_OP(base) \
229 case ByteCodeInstruction::base ## N: return -count;
230
231 case ByteCodeInstruction::kAndB: return -1;
232 case ByteCodeInstruction::kOrB: return -1;
233 case ByteCodeInstruction::kXorB: return -1;
234
235 VECTOR_BINARY_OP(kAddI)
236 VECTOR_MATRIX_BINARY_OP(kAddF)
237
238 VECTOR_BINARY_OP(kCompareIEQ)
239 VECTOR_MATRIX_BINARY_OP(kCompareFEQ)
240 VECTOR_BINARY_OP(kCompareINEQ)
241 VECTOR_MATRIX_BINARY_OP(kCompareFNEQ)
242 VECTOR_BINARY_OP(kCompareSGT)
243 VECTOR_BINARY_OP(kCompareUGT)
244 VECTOR_BINARY_OP(kCompareFGT)
245 VECTOR_BINARY_OP(kCompareSGTEQ)
246 VECTOR_BINARY_OP(kCompareUGTEQ)
247 VECTOR_BINARY_OP(kCompareFGTEQ)
248 VECTOR_BINARY_OP(kCompareSLT)
249 VECTOR_BINARY_OP(kCompareULT)
250 VECTOR_BINARY_OP(kCompareFLT)
251 VECTOR_BINARY_OP(kCompareSLTEQ)
252 VECTOR_BINARY_OP(kCompareULTEQ)
253 VECTOR_BINARY_OP(kCompareFLTEQ)
254
255 VECTOR_BINARY_OP(kDivideS)
256 VECTOR_BINARY_OP(kDivideU)
257 VECTOR_MATRIX_BINARY_OP(kDivideF)
258 VECTOR_BINARY_OP(kMultiplyI)
259 VECTOR_MATRIX_BINARY_OP(kMultiplyF)
260 VECTOR_BINARY_OP(kRemainderF)
261 VECTOR_BINARY_OP(kRemainderS)
262 VECTOR_BINARY_OP(kRemainderU)
263 VECTOR_BINARY_OP(kSubtractI)
264 VECTOR_MATRIX_BINARY_OP(kSubtractF)
265
266#undef VECTOR_BINARY_OP
267#undef VECTOR_MATRIX_BINARY_OP
268
269 // Strange math operations with other behavior:
270 case ByteCodeInstruction::kCross: return -3;
271 // Binary, but also consumes T:
272 case ByteCodeInstruction::kMix: return -2;
273 case ByteCodeInstruction::kMix2: return -3;
274 case ByteCodeInstruction::kMix3: return -4;
275 case ByteCodeInstruction::kMix4: return -5;
276
277 // Ops that push or load data to grow the stack:
278 case ByteCodeInstruction::kDup:
279 case ByteCodeInstruction::kLoad:
280 case ByteCodeInstruction::kLoadGlobal:
281 case ByteCodeInstruction::kReadExternal:
282 case ByteCodeInstruction::kPushImmediate:
283 return 1;
284
285 case ByteCodeInstruction::kDup2:
286 case ByteCodeInstruction::kLoad2:
287 case ByteCodeInstruction::kLoadGlobal2:
288 case ByteCodeInstruction::kReadExternal2:
289 return 2;
290
291 case ByteCodeInstruction::kDup3:
292 case ByteCodeInstruction::kLoad3:
293 case ByteCodeInstruction::kLoadGlobal3:
294 case ByteCodeInstruction::kReadExternal3:
295 return 3;
296
297 case ByteCodeInstruction::kDup4:
298 case ByteCodeInstruction::kLoad4:
299 case ByteCodeInstruction::kLoadGlobal4:
300 case ByteCodeInstruction::kReadExternal4:
301 return 4;
302
303 case ByteCodeInstruction::kDupN:
304 case ByteCodeInstruction::kLoadSwizzle:
305 case ByteCodeInstruction::kLoadSwizzleGlobal:
306 return count;
307
308 // Pushes 'count' values, minus one for the 'address' that's consumed first
309 case ByteCodeInstruction::kLoadExtended:
310 case ByteCodeInstruction::kLoadExtendedGlobal:
311 return count - 1;
312
313 // Ops that pop or store data to shrink the stack:
314 case ByteCodeInstruction::kPop:
315 case ByteCodeInstruction::kStore:
316 case ByteCodeInstruction::kStoreGlobal:
317 case ByteCodeInstruction::kWriteExternal:
318 return -1;
319
320 case ByteCodeInstruction::kPop2:
321 case ByteCodeInstruction::kStore2:
322 case ByteCodeInstruction::kStoreGlobal2:
323 case ByteCodeInstruction::kWriteExternal2:
324 return -2;
325
326 case ByteCodeInstruction::kPop3:
327 case ByteCodeInstruction::kStore3:
328 case ByteCodeInstruction::kStoreGlobal3:
329 case ByteCodeInstruction::kWriteExternal3:
330 return -3;
331
332 case ByteCodeInstruction::kPop4:
333 case ByteCodeInstruction::kStore4:
334 case ByteCodeInstruction::kStoreGlobal4:
335 case ByteCodeInstruction::kWriteExternal4:
336 return -4;
337
338 case ByteCodeInstruction::kPopN:
339 case ByteCodeInstruction::kStoreSwizzle:
340 case ByteCodeInstruction::kStoreSwizzleGlobal:
341 return -count;
342
343 // Consumes 'count' values, plus one for the 'address'
344 case ByteCodeInstruction::kStoreExtended:
345 case ByteCodeInstruction::kStoreExtendedGlobal:
346 case ByteCodeInstruction::kStoreSwizzleIndirect:
347 case ByteCodeInstruction::kStoreSwizzleIndirectGlobal:
348 return -count - 1;
349
350 // Strange ops where the caller computes the delta for us:
351 case ByteCodeInstruction::kCallExternal:
352 case ByteCodeInstruction::kMatrixToMatrix:
353 case ByteCodeInstruction::kMatrixMultiply:
354 case ByteCodeInstruction::kReserve:
355 case ByteCodeInstruction::kReturn:
356 case ByteCodeInstruction::kScalarToMatrix:
357 case ByteCodeInstruction::kSwizzle:
358 return count;
359
360 // Miscellaneous
361
362 // kCall is net-zero. Max stack depth is adjusted in writeFunctionCall.
363 case ByteCodeInstruction::kCall: return 0;
364 case ByteCodeInstruction::kBranch: return 0;
365 case ByteCodeInstruction::kBranchIfAllFalse: return 0;
366
367 case ByteCodeInstruction::kMaskPush: return -1;
368 case ByteCodeInstruction::kMaskPop: return 0;
369 case ByteCodeInstruction::kMaskNegate: return 0;
370 case ByteCodeInstruction::kMaskBlend: return -count;
371
372 case ByteCodeInstruction::kLoopBegin: return 0;
373 case ByteCodeInstruction::kLoopNext: return 0;
374 case ByteCodeInstruction::kLoopMask: return -1;
375 case ByteCodeInstruction::kLoopEnd: return 0;
376 case ByteCodeInstruction::kLoopBreak: return 0;
377 case ByteCodeInstruction::kLoopContinue: return 0;
378
379 default:
Brian Osmanc7ec9e22019-07-16 08:49:11 -0400380 ABORT("unsupported instruction %d\n", (int)inst);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400381 return 0;
382 }
383}
384
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400385int ByteCodeGenerator::getLocation(const Variable& var) {
386 // given that we seldom have more than a couple of variables, linear search is probably the most
387 // efficient way to handle lookups
388 switch (var.fStorage) {
389 case Variable::kLocal_Storage: {
390 for (int i = fLocals.size() - 1; i >= 0; --i) {
391 if (fLocals[i] == &var) {
Brian Osman1091f022019-05-16 09:42:16 -0400392 SkASSERT(fParameterCount + i <= 255);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400393 return fParameterCount + i;
394 }
395 }
396 int result = fParameterCount + fLocals.size();
397 fLocals.push_back(&var);
Brian Osman07c117b2019-05-23 12:51:06 -0700398 for (int i = 0; i < SlotCount(var.fType) - 1; ++i) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400399 fLocals.push_back(nullptr);
400 }
Brian Osman1091f022019-05-16 09:42:16 -0400401 SkASSERT(result <= 255);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400402 return result;
403 }
404 case Variable::kParameter_Storage: {
405 int offset = 0;
406 for (const auto& p : fFunction->fDeclaration.fParameters) {
407 if (p == &var) {
Brian Osman1091f022019-05-16 09:42:16 -0400408 SkASSERT(offset <= 255);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400409 return offset;
410 }
Brian Osman07c117b2019-05-23 12:51:06 -0700411 offset += SlotCount(p->fType);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400412 }
413 SkASSERT(false);
Brian Osman1091f022019-05-16 09:42:16 -0400414 return 0;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400415 }
416 case Variable::kGlobal_Storage: {
417 int offset = 0;
418 for (const auto& e : fProgram) {
419 if (e.fKind == ProgramElement::kVar_Kind) {
420 VarDeclarations& decl = (VarDeclarations&) e;
421 for (const auto& v : decl.fVars) {
422 const Variable* declVar = ((VarDeclaration&) *v).fVar;
423 if (declVar->fModifiers.fLayout.fBuiltin >= 0) {
424 continue;
425 }
426 if (declVar == &var) {
Brian Osmanb7451292019-05-15 13:02:13 -0400427 SkASSERT(offset <= 255);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400428 return offset;
429 }
Brian Osman07c117b2019-05-23 12:51:06 -0700430 offset += SlotCount(declVar->fType);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400431 }
432 }
433 }
434 SkASSERT(false);
Brian Osman1091f022019-05-16 09:42:16 -0400435 return 0;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400436 }
437 default:
438 SkASSERT(false);
439 return 0;
440 }
441}
442
Brian Osman07c117b2019-05-23 12:51:06 -0700443int ByteCodeGenerator::getLocation(const Expression& expr, Variable::Storage* storage) {
444 switch (expr.fKind) {
445 case Expression::kFieldAccess_Kind: {
446 const FieldAccess& f = (const FieldAccess&)expr;
447 int baseAddr = this->getLocation(*f.fBase, storage);
448 int offset = 0;
449 for (int i = 0; i < f.fFieldIndex; ++i) {
450 offset += SlotCount(*f.fBase->fType.fields()[i].fType);
451 }
452 if (baseAddr < 0) {
Brian Osman86769292019-06-21 11:05:47 -0400453 if (offset != 0) {
454 this->write(ByteCodeInstruction::kPushImmediate);
455 this->write32(offset);
456 this->write(ByteCodeInstruction::kAddI);
457 }
Brian Osman07c117b2019-05-23 12:51:06 -0700458 return -1;
459 } else {
460 return baseAddr + offset;
461 }
462 }
463 case Expression::kIndex_Kind: {
464 const IndexExpression& i = (const IndexExpression&)expr;
465 int stride = SlotCount(i.fType);
Brian Osman869a3e82019-07-18 17:00:34 -0400466 int length = i.fBase->fType.columns();
467 SkASSERT(length <= 255);
Brian Osman07c117b2019-05-23 12:51:06 -0700468 int offset = -1;
469 if (i.fIndex->isConstant()) {
Brian Osman869a3e82019-07-18 17:00:34 -0400470 int64_t index = i.fIndex->getConstantInt();
471 if (index < 0 || index >= length) {
472 fErrors.error(i.fIndex->fOffset, "Array index out of bounds.");
473 return 0;
474 }
475 offset = index * stride;
Brian Osman07c117b2019-05-23 12:51:06 -0700476 } else {
Brian Osman86769292019-06-21 11:05:47 -0400477 if (i.fIndex->hasSideEffects()) {
478 // Having a side-effect in an indexer is technically safe for an rvalue,
479 // but with lvalues we have to evaluate the indexer twice, so make it an error.
480 fErrors.error(i.fIndex->fOffset,
481 "Index expressions with side-effects not supported in byte code.");
482 return 0;
483 }
Brian Osman07c117b2019-05-23 12:51:06 -0700484 this->writeExpression(*i.fIndex);
Brian Osman869a3e82019-07-18 17:00:34 -0400485 this->write(ByteCodeInstruction::kClampIndex);
486 this->write8(length);
Brian Osman86769292019-06-21 11:05:47 -0400487 if (stride != 1) {
488 this->write(ByteCodeInstruction::kPushImmediate);
489 this->write32(stride);
490 this->write(ByteCodeInstruction::kMultiplyI);
491 }
Brian Osman07c117b2019-05-23 12:51:06 -0700492 }
493 int baseAddr = this->getLocation(*i.fBase, storage);
Brian Osman86769292019-06-21 11:05:47 -0400494
495 // Are both components known statically?
Brian Osman07c117b2019-05-23 12:51:06 -0700496 if (baseAddr >= 0 && offset >= 0) {
497 return baseAddr + offset;
498 }
Brian Osman86769292019-06-21 11:05:47 -0400499
500 // At least one component is dynamic (and on the stack).
501
502 // If the other component is zero, we're done
503 if (baseAddr == 0 || offset == 0) {
504 return -1;
505 }
506
507 // Push the non-dynamic component (if any) to the stack, then add the two
Brian Osman07c117b2019-05-23 12:51:06 -0700508 if (baseAddr >= 0) {
509 this->write(ByteCodeInstruction::kPushImmediate);
510 this->write32(baseAddr);
511 }
512 if (offset >= 0) {
513 this->write(ByteCodeInstruction::kPushImmediate);
514 this->write32(offset);
515 }
516 this->write(ByteCodeInstruction::kAddI);
517 return -1;
518 }
Brian Osman0785db02019-05-24 14:19:11 -0400519 case Expression::kSwizzle_Kind: {
520 const Swizzle& s = (const Swizzle&)expr;
521 SkASSERT(swizzle_is_simple(s));
522 int baseAddr = this->getLocation(*s.fBase, storage);
523 int offset = s.fComponents[0];
524 if (baseAddr < 0) {
Brian Osman86769292019-06-21 11:05:47 -0400525 if (offset != 0) {
526 this->write(ByteCodeInstruction::kPushImmediate);
527 this->write32(offset);
528 this->write(ByteCodeInstruction::kAddI);
529 }
Brian Osman0785db02019-05-24 14:19:11 -0400530 return -1;
531 } else {
532 return baseAddr + offset;
533 }
534 }
Brian Osman07c117b2019-05-23 12:51:06 -0700535 case Expression::kVariableReference_Kind: {
536 const Variable& var = ((const VariableReference&)expr).fVariable;
537 *storage = var.fStorage;
538 return this->getLocation(var);
539 }
540 default:
541 SkASSERT(false);
542 return 0;
543 }
544}
545
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400546void ByteCodeGenerator::write8(uint8_t b) {
547 fCode->push_back(b);
548}
549
550void ByteCodeGenerator::write16(uint16_t i) {
Mike Klein76346ac2019-05-17 11:57:10 -0500551 size_t n = fCode->size();
552 fCode->resize(n+2);
553 memcpy(fCode->data() + n, &i, 2);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400554}
555
556void ByteCodeGenerator::write32(uint32_t i) {
Mike Klein76346ac2019-05-17 11:57:10 -0500557 size_t n = fCode->size();
558 fCode->resize(n+4);
559 memcpy(fCode->data() + n, &i, 4);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400560}
561
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400562void ByteCodeGenerator::write(ByteCodeInstruction i, int count) {
Brian Osman4a47da72019-07-12 11:30:32 -0400563 switch (i) {
564 case ByteCodeInstruction::kLoopBegin: this->enterLoop(); break;
565 case ByteCodeInstruction::kLoopEnd: this->exitLoop(); break;
566
567 case ByteCodeInstruction::kMaskPush: this->enterCondition(); break;
568 case ByteCodeInstruction::kMaskPop:
569 case ByteCodeInstruction::kMaskBlend: this->exitCondition(); break;
570 default: /* Do nothing */ break;
571 }
Mike Klein108e9352019-05-21 11:05:17 -0500572 this->write16((uint16_t)i);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400573 fStackCount += StackUsage(i, count);
574 fMaxStackCount = std::max(fMaxStackCount, fStackCount);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400575}
576
Mike Klein76346ac2019-05-17 11:57:10 -0500577static ByteCodeInstruction vector_instruction(ByteCodeInstruction base, int count) {
Brian Osman07c117b2019-05-23 12:51:06 -0700578 SkASSERT(count >= 1 && count <= 4);
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400579 return ((ByteCodeInstruction) ((int) base + count - 1));
580}
581
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400582void ByteCodeGenerator::writeTypedInstruction(const Type& type, ByteCodeInstruction s,
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400583 ByteCodeInstruction u, ByteCodeInstruction f,
584 int count) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400585 switch (type_category(type)) {
586 case TypeCategory::kSigned:
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400587 this->write(vector_instruction(s, count));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400588 break;
589 case TypeCategory::kUnsigned:
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400590 this->write(vector_instruction(u, count));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400591 break;
Brian Osman1e855b22019-05-29 15:21:52 -0400592 case TypeCategory::kFloat: {
593 if (count > 4) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400594 this->write((ByteCodeInstruction)((int)f + 4), count);
Brian Osman1e855b22019-05-29 15:21:52 -0400595 this->write8(count);
596 } else {
597 this->write(vector_instruction(f, count));
598 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400599 break;
Brian Osman1e855b22019-05-29 15:21:52 -0400600 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400601 default:
602 SkASSERT(false);
603 }
604}
605
Brian Osman3e29f1d2019-05-28 09:35:05 -0400606bool ByteCodeGenerator::writeBinaryExpression(const BinaryExpression& b, bool discard) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400607 if (b.fOperator == Token::Kind::EQ) {
608 std::unique_ptr<LValue> lvalue = this->getLValue(*b.fLeft);
609 this->writeExpression(*b.fRight);
Brian Osman3e29f1d2019-05-28 09:35:05 -0400610 lvalue->store(discard);
611 discard = false;
612 return discard;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400613 }
Brian Osman16e6fd52019-05-29 11:19:00 -0400614 const Type& lType = b.fLeft->fType;
615 const Type& rType = b.fRight->fType;
Brian Osman909231c2019-05-29 15:34:36 -0400616 bool lVecOrMtx = (lType.kind() == Type::kVector_Kind || lType.kind() == Type::kMatrix_Kind);
617 bool rVecOrMtx = (rType.kind() == Type::kVector_Kind || rType.kind() == Type::kMatrix_Kind);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400618 Token::Kind op;
619 std::unique_ptr<LValue> lvalue;
620 if (is_assignment(b.fOperator)) {
621 lvalue = this->getLValue(*b.fLeft);
622 lvalue->load();
623 op = remove_assignment(b.fOperator);
624 } else {
625 this->writeExpression(*b.fLeft);
626 op = b.fOperator;
Brian Osman909231c2019-05-29 15:34:36 -0400627 if (!lVecOrMtx && rVecOrMtx) {
Brian Osman16e6fd52019-05-29 11:19:00 -0400628 for (int i = SlotCount(rType); i > 1; --i) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400629 this->write(ByteCodeInstruction::kDup);
630 }
631 }
632 }
633 this->writeExpression(*b.fRight);
Brian Osman909231c2019-05-29 15:34:36 -0400634 if (lVecOrMtx && !rVecOrMtx) {
Brian Osman16e6fd52019-05-29 11:19:00 -0400635 for (int i = SlotCount(lType); i > 1; --i) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400636 this->write(ByteCodeInstruction::kDup);
637 }
638 }
Brian Osman909231c2019-05-29 15:34:36 -0400639 // Special case for M*V, V*M, M*M (but not V*V!)
640 if (op == Token::Kind::STAR && lVecOrMtx && rVecOrMtx &&
641 !(lType.kind() == Type::kVector_Kind && rType.kind() == Type::kVector_Kind)) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400642 this->write(ByteCodeInstruction::kMatrixMultiply,
643 SlotCount(b.fType) - (SlotCount(lType) + SlotCount(rType)));
Brian Osman909231c2019-05-29 15:34:36 -0400644 int rCols = rType.columns(),
645 rRows = rType.rows(),
646 lCols = lType.columns(),
647 lRows = lType.rows();
648 // M*V treats the vector as a column
649 if (rType.kind() == Type::kVector_Kind) {
650 std::swap(rCols, rRows);
651 }
652 SkASSERT(lCols == rRows);
653 SkASSERT(SlotCount(b.fType) == lRows * rCols);
654 this->write8(lCols);
655 this->write8(lRows);
656 this->write8(rCols);
657 } else {
658 int count = std::max(SlotCount(lType), SlotCount(rType));
659 switch (op) {
660 case Token::Kind::EQEQ:
661 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareIEQ,
662 ByteCodeInstruction::kCompareIEQ,
663 ByteCodeInstruction::kCompareFEQ,
664 count);
665 // Collapse to a single bool
666 for (int i = count; i > 1; --i) {
667 this->write(ByteCodeInstruction::kAndB);
668 }
669 break;
670 case Token::Kind::GT:
671 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSGT,
672 ByteCodeInstruction::kCompareUGT,
673 ByteCodeInstruction::kCompareFGT,
674 count);
675 break;
676 case Token::Kind::GTEQ:
677 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSGTEQ,
678 ByteCodeInstruction::kCompareUGTEQ,
679 ByteCodeInstruction::kCompareFGTEQ,
680 count);
681 break;
682 case Token::Kind::LT:
683 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSLT,
684 ByteCodeInstruction::kCompareULT,
685 ByteCodeInstruction::kCompareFLT,
686 count);
687 break;
688 case Token::Kind::LTEQ:
689 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSLTEQ,
690 ByteCodeInstruction::kCompareULTEQ,
691 ByteCodeInstruction::kCompareFLTEQ,
692 count);
693 break;
694 case Token::Kind::MINUS:
695 this->writeTypedInstruction(lType, ByteCodeInstruction::kSubtractI,
696 ByteCodeInstruction::kSubtractI,
697 ByteCodeInstruction::kSubtractF,
698 count);
699 break;
700 case Token::Kind::NEQ:
701 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareINEQ,
702 ByteCodeInstruction::kCompareINEQ,
703 ByteCodeInstruction::kCompareFNEQ,
704 count);
705 // Collapse to a single bool
706 for (int i = count; i > 1; --i) {
707 this->write(ByteCodeInstruction::kOrB);
708 }
709 break;
710 case Token::Kind::PERCENT:
711 this->writeTypedInstruction(lType, ByteCodeInstruction::kRemainderS,
712 ByteCodeInstruction::kRemainderU,
713 ByteCodeInstruction::kRemainderF,
714 count);
715 break;
716 case Token::Kind::PLUS:
717 this->writeTypedInstruction(lType, ByteCodeInstruction::kAddI,
718 ByteCodeInstruction::kAddI,
719 ByteCodeInstruction::kAddF,
720 count);
721 break;
722 case Token::Kind::SLASH:
723 this->writeTypedInstruction(lType, ByteCodeInstruction::kDivideS,
724 ByteCodeInstruction::kDivideU,
725 ByteCodeInstruction::kDivideF,
726 count);
727 break;
728 case Token::Kind::STAR:
729 this->writeTypedInstruction(lType, ByteCodeInstruction::kMultiplyI,
730 ByteCodeInstruction::kMultiplyI,
731 ByteCodeInstruction::kMultiplyF,
732 count);
733 break;
Brian Osman569f12f2019-06-13 11:23:57 -0400734
735 case Token::Kind::LOGICALAND:
736 SkASSERT(type_category(lType) == SkSL::TypeCategory::kBool && count == 1);
737 this->write(ByteCodeInstruction::kAndB);
738 break;
739 case Token::Kind::LOGICALNOT:
740 SkASSERT(type_category(lType) == SkSL::TypeCategory::kBool && count == 1);
741 this->write(ByteCodeInstruction::kNotB);
742 break;
743 case Token::Kind::LOGICALOR:
744 SkASSERT(type_category(lType) == SkSL::TypeCategory::kBool && count == 1);
745 this->write(ByteCodeInstruction::kOrB);
746 break;
747 case Token::Kind::LOGICALXOR:
748 SkASSERT(type_category(lType) == SkSL::TypeCategory::kBool && count == 1);
749 this->write(ByteCodeInstruction::kXorB);
750 break;
751
Brian Osman909231c2019-05-29 15:34:36 -0400752 default:
Brian Osmandb3dad22019-07-26 15:44:29 -0400753 fErrors.error(b.fOffset, SkSL::String::printf("Unsupported binary operator '%s'",
754 Compiler::OperatorName(op)));
755 break;
Brian Osman909231c2019-05-29 15:34:36 -0400756 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400757 }
758 if (lvalue) {
Brian Osman3e29f1d2019-05-28 09:35:05 -0400759 lvalue->store(discard);
760 discard = false;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400761 }
Brian Osman3e29f1d2019-05-28 09:35:05 -0400762 return discard;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400763}
764
765void ByteCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
766 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osman569f12f2019-06-13 11:23:57 -0400767 this->write32(b.fValue ? ~0 : 0);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400768}
769
770void ByteCodeGenerator::writeConstructor(const Constructor& c) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400771 for (const auto& arg : c.fArguments) {
772 this->writeExpression(*arg);
773 }
774 if (c.fArguments.size() == 1) {
Brian Osman29e013d2019-05-28 17:16:03 -0400775 const Type& inType = c.fArguments[0]->fType;
776 const Type& outType = c.fType;
777 TypeCategory inCategory = type_category(inType);
778 TypeCategory outCategory = type_category(outType);
779 int inCount = SlotCount(inType);
780 int outCount = SlotCount(outType);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400781 if (inCategory != outCategory) {
Brian Osmanc51d7912019-05-22 15:16:16 -0700782 SkASSERT(inCount == outCount);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400783 if (inCategory == TypeCategory::kFloat) {
784 SkASSERT(outCategory == TypeCategory::kSigned ||
785 outCategory == TypeCategory::kUnsigned);
Brian Osmanc51d7912019-05-22 15:16:16 -0700786 this->write(vector_instruction(ByteCodeInstruction::kConvertFtoI, outCount));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400787 } else if (outCategory == TypeCategory::kFloat) {
788 if (inCategory == TypeCategory::kSigned) {
Brian Osmanc51d7912019-05-22 15:16:16 -0700789 this->write(vector_instruction(ByteCodeInstruction::kConvertStoF, outCount));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400790 } else {
791 SkASSERT(inCategory == TypeCategory::kUnsigned);
Brian Osmanc51d7912019-05-22 15:16:16 -0700792 this->write(vector_instruction(ByteCodeInstruction::kConvertUtoF, outCount));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400793 }
794 } else {
795 SkASSERT(false);
796 }
797 }
Brian Osman29e013d2019-05-28 17:16:03 -0400798 if (inType.kind() == Type::kMatrix_Kind && outType.kind() == Type::kMatrix_Kind) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400799 this->write(ByteCodeInstruction::kMatrixToMatrix,
800 SlotCount(outType) - SlotCount(inType));
Brian Osman29e013d2019-05-28 17:16:03 -0400801 this->write8(inType.columns());
802 this->write8(inType.rows());
803 this->write8(outType.columns());
804 this->write8(outType.rows());
805 } else if (inCount != outCount) {
Brian Osmanc51d7912019-05-22 15:16:16 -0700806 SkASSERT(inCount == 1);
Brian Osman29e013d2019-05-28 17:16:03 -0400807 if (outType.kind() == Type::kMatrix_Kind) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400808 this->write(ByteCodeInstruction::kScalarToMatrix, SlotCount(outType) - 1);
Brian Osman29e013d2019-05-28 17:16:03 -0400809 this->write8(outType.columns());
810 this->write8(outType.rows());
811 } else {
812 SkASSERT(outType.kind() == Type::kVector_Kind);
813 for (; inCount != outCount; ++inCount) {
814 this->write(ByteCodeInstruction::kDup);
815 }
Brian Osmanc51d7912019-05-22 15:16:16 -0700816 }
817 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400818 }
819}
820
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400821void ByteCodeGenerator::writeExternalFunctionCall(const ExternalFunctionCall& f) {
822 int argumentCount = 0;
823 for (const auto& arg : f.fArguments) {
824 this->writeExpression(*arg);
Brian Osman07c117b2019-05-23 12:51:06 -0700825 argumentCount += SlotCount(arg->fType);
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400826 }
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400827 this->write(ByteCodeInstruction::kCallExternal, SlotCount(f.fType) - argumentCount);
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400828 SkASSERT(argumentCount <= 255);
829 this->write8(argumentCount);
Brian Osman07c117b2019-05-23 12:51:06 -0700830 this->write8(SlotCount(f.fType));
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400831 int index = fOutput->fExternalValues.size();
832 fOutput->fExternalValues.push_back(f.fFunction);
833 SkASSERT(index <= 255);
834 this->write8(index);
835}
836
Ethan Nicholas91164d12019-05-15 15:29:54 -0400837void ByteCodeGenerator::writeExternalValue(const ExternalValueReference& e) {
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400838 this->write(vector_instruction(ByteCodeInstruction::kReadExternal,
Brian Osman07c117b2019-05-23 12:51:06 -0700839 SlotCount(e.fValue->type())));
Ethan Nicholas91164d12019-05-15 15:29:54 -0400840 int index = fOutput->fExternalValues.size();
841 fOutput->fExternalValues.push_back(e.fValue);
842 SkASSERT(index <= 255);
843 this->write8(index);
844}
845
Brian Osman07c117b2019-05-23 12:51:06 -0700846void ByteCodeGenerator::writeVariableExpression(const Expression& expr) {
Brian Osman869a3e82019-07-18 17:00:34 -0400847 Variable::Storage storage = Variable::kLocal_Storage;
Brian Osman07c117b2019-05-23 12:51:06 -0700848 int location = this->getLocation(expr, &storage);
849 bool isGlobal = storage == Variable::kGlobal_Storage;
850 int count = SlotCount(expr.fType);
851 if (location < 0 || count > 4) {
852 if (location >= 0) {
853 this->write(ByteCodeInstruction::kPushImmediate);
854 this->write32(location);
855 }
856 this->write(isGlobal ? ByteCodeInstruction::kLoadExtendedGlobal
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400857 : ByteCodeInstruction::kLoadExtended,
858 count);
Brian Osman07c117b2019-05-23 12:51:06 -0700859 this->write8(count);
860 } else {
861 this->write(vector_instruction(isGlobal ? ByteCodeInstruction::kLoadGlobal
862 : ByteCodeInstruction::kLoad,
863 count));
864 this->write8(location);
865 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400866}
867
Brian Osmand30e0392019-06-14 14:05:14 -0400868static inline uint32_t float_to_bits(float x) {
869 uint32_t u;
870 memcpy(&u, &x, sizeof(uint32_t));
871 return u;
872}
873
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400874void ByteCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
875 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osmand30e0392019-06-14 14:05:14 -0400876 this->write32(float_to_bits(f.fValue));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400877}
878
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400879void ByteCodeGenerator::writeIntrinsicCall(const FunctionCall& c) {
880 auto found = fIntrinsics.find(c.fFunction.fName);
881 if (found == fIntrinsics.end()) {
882 fErrors.error(c.fOffset, "unsupported intrinsic function");
883 return;
884 }
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400885 int count = SlotCount(c.fArguments[0]->fType);
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400886 if (found->second.fIsSpecial) {
Brian Osmanb380e712019-07-24 17:02:39 -0400887 SpecialIntrinsic special = found->second.fValue.fSpecial;
888 switch (special) {
889 case SpecialIntrinsic::kDot: {
890 SkASSERT(c.fArguments.size() == 2);
891 SkASSERT(count == SlotCount(c.fArguments[1]->fType));
892 this->write((ByteCodeInstruction)((int)ByteCodeInstruction::kMultiplyF + count-1));
893 for (int i = count; i > 1; --i) {
894 this->write(ByteCodeInstruction::kAddF);
895 }
896 break;
897 }
898 case SpecialIntrinsic::kRadians: {
899 this->write(ByteCodeInstruction::kPushImmediate);
900 this->write32(float_to_bits(0.0174532925f)); // π/180
901 for (int i = count; i > 1; --i) {
902 this->write(ByteCodeInstruction::kDup);
903 }
904 this->write((ByteCodeInstruction)((int)ByteCodeInstruction::kMultiplyF + count-1));
905 break;
906 }
907 default:
908 SkASSERT(false);
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400909 }
910 } else {
911 switch (found->second.fValue.fInstruction) {
912 case ByteCodeInstruction::kCos:
913 case ByteCodeInstruction::kMix:
Brian Osmanb380e712019-07-24 17:02:39 -0400914 case ByteCodeInstruction::kNormalize:
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400915 case ByteCodeInstruction::kSin:
916 case ByteCodeInstruction::kSqrt:
917 case ByteCodeInstruction::kTan:
918 SkASSERT(c.fArguments.size() > 0);
919 this->write((ByteCodeInstruction) ((int) found->second.fValue.fInstruction +
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400920 count - 1));
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400921 break;
922 case ByteCodeInstruction::kCross:
923 this->write(found->second.fValue.fInstruction);
924 break;
Mike Reed634c9412019-07-18 13:20:04 -0400925 case ByteCodeInstruction::kInverse2x2: {
926 SkASSERT(c.fArguments.size() > 0);
927 auto op = ByteCodeInstruction::kInverse2x2;
928 switch (count) {
929 case 4: break; // float2x2
930 case 9: op = ByteCodeInstruction::kInverse3x3; break;
931 case 16: op = ByteCodeInstruction::kInverse4x4; break;
932 default: SkASSERT(false);
933 }
934 this->write(op);
Brian Osmanb380e712019-07-24 17:02:39 -0400935 break;
936 }
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400937 default:
938 SkASSERT(false);
939 }
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400940 }
941}
942
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400943void ByteCodeGenerator::writeFunctionCall(const FunctionCall& f) {
Brian Osmand3494ed2019-06-20 15:41:34 -0400944 // Builtins have simple signatures...
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400945 if (f.fFunction.fBuiltin) {
Brian Osmand3494ed2019-06-20 15:41:34 -0400946 for (const auto& arg : f.fArguments) {
947 this->writeExpression(*arg);
948 }
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400949 this->writeIntrinsicCall(f);
950 return;
951 }
Brian Osmand3494ed2019-06-20 15:41:34 -0400952
Brian Osman6f5358f2019-07-09 14:17:23 -0400953 // Find the index of the function we're calling. We explicitly do not allow calls to functions
954 // before they're defined. This is an easy-to-understand rule that prevents recursion.
955 size_t idx;
956 for (idx = 0; idx < fFunctions.size(); ++idx) {
957 if (f.fFunction.matches(fFunctions[idx]->fDeclaration)) {
958 break;
959 }
960 }
961 if (idx > 255) {
962 fErrors.error(f.fOffset, "Function count limit exceeded");
963 return;
964 } else if (idx >= fFunctions.size()) {
965 fErrors.error(f.fOffset, "Call to undefined function");
966 return;
967 }
968
969 // We may need to deal with out parameters, so the sequence is tricky
Brian Osmand3494ed2019-06-20 15:41:34 -0400970 if (int returnCount = SlotCount(f.fType)) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400971 this->write(ByteCodeInstruction::kReserve, returnCount);
Brian Osmand3494ed2019-06-20 15:41:34 -0400972 this->write8(returnCount);
973 }
974
975 int argCount = f.fArguments.size();
976 std::vector<std::unique_ptr<LValue>> lvalues;
977 for (int i = 0; i < argCount; ++i) {
978 const auto& param = f.fFunction.fParameters[i];
979 const auto& arg = f.fArguments[i];
980 if (param->fModifiers.fFlags & Modifiers::kOut_Flag) {
981 lvalues.emplace_back(this->getLValue(*arg));
982 lvalues.back()->load();
983 } else {
984 this->writeExpression(*arg);
985 }
986 }
987
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400988 // The space used by the call is based on the callee, but it also unwinds all of that before
989 // we continue execution. We adjust our max stack depths below.
Brian Osman226668a2019-05-14 16:47:30 -0400990 this->write(ByteCodeInstruction::kCall);
Brian Osman6f5358f2019-07-09 14:17:23 -0400991 this->write8(idx);
Brian Osmand3494ed2019-06-20 15:41:34 -0400992
Brian Osman4a47da72019-07-12 11:30:32 -0400993 const ByteCodeFunction* callee = fOutput->fFunctions[idx].get();
994 fMaxLoopCount = std::max(fMaxLoopCount, fLoopCount + callee->fLoopCount);
995 fMaxConditionCount = std::max(fMaxConditionCount, fConditionCount + callee->fConditionCount);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400996 fMaxStackCount = std::max(fMaxStackCount, fStackCount + callee->fLocalCount
997 + callee->fStackCount);
Brian Osman4a47da72019-07-12 11:30:32 -0400998
Brian Osmand3494ed2019-06-20 15:41:34 -0400999 // After the called function returns, the stack will still contain our arguments. We have to
1000 // pop them (storing any out parameters back to their lvalues as we go). We glob together slot
1001 // counts for all parameters that aren't out-params, so we can pop them in one big chunk.
1002 int popCount = 0;
1003 auto pop = [&]() {
1004 if (popCount > 4) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001005 this->write(ByteCodeInstruction::kPopN, popCount);
Brian Osmand3494ed2019-06-20 15:41:34 -04001006 this->write8(popCount);
1007 } else if (popCount > 0) {
1008 this->write(vector_instruction(ByteCodeInstruction::kPop, popCount));
1009 }
1010 popCount = 0;
1011 };
1012
1013 for (int i = argCount - 1; i >= 0; --i) {
1014 const auto& param = f.fFunction.fParameters[i];
1015 const auto& arg = f.fArguments[i];
1016 if (param->fModifiers.fFlags & Modifiers::kOut_Flag) {
1017 pop();
1018 lvalues.back()->store(true);
1019 lvalues.pop_back();
1020 } else {
1021 popCount += SlotCount(arg->fType);
1022 }
1023 }
1024 pop();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001025}
1026
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001027void ByteCodeGenerator::writeIntLiteral(const IntLiteral& i) {
1028 this->write(ByteCodeInstruction::kPushImmediate);
1029 this->write32(i.fValue);
1030}
1031
1032void ByteCodeGenerator::writeNullLiteral(const NullLiteral& n) {
1033 // not yet implemented
1034 abort();
1035}
1036
Brian Osman3e29f1d2019-05-28 09:35:05 -04001037bool ByteCodeGenerator::writePrefixExpression(const PrefixExpression& p, bool discard) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001038 switch (p.fOperator) {
1039 case Token::Kind::PLUSPLUS: // fall through
1040 case Token::Kind::MINUSMINUS: {
Brian Osman07c117b2019-05-23 12:51:06 -07001041 SkASSERT(SlotCount(p.fOperand->fType) == 1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001042 std::unique_ptr<LValue> lvalue = this->getLValue(*p.fOperand);
1043 lvalue->load();
1044 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osmand30e0392019-06-14 14:05:14 -04001045 this->write32(type_category(p.fType) == TypeCategory::kFloat ? float_to_bits(1.0f) : 1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001046 if (p.fOperator == Token::Kind::PLUSPLUS) {
1047 this->writeTypedInstruction(p.fType,
1048 ByteCodeInstruction::kAddI,
1049 ByteCodeInstruction::kAddI,
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001050 ByteCodeInstruction::kAddF,
1051 1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001052 } else {
1053 this->writeTypedInstruction(p.fType,
1054 ByteCodeInstruction::kSubtractI,
1055 ByteCodeInstruction::kSubtractI,
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001056 ByteCodeInstruction::kSubtractF,
1057 1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001058 }
Brian Osman3e29f1d2019-05-28 09:35:05 -04001059 lvalue->store(discard);
1060 discard = false;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001061 break;
1062 }
Ethan Nicholas354ecf32019-05-07 16:13:02 -04001063 case Token::Kind::MINUS: {
1064 this->writeExpression(*p.fOperand);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001065 this->writeTypedInstruction(p.fType,
Mike Klein12710912019-05-21 11:04:59 -05001066 ByteCodeInstruction::kNegateI,
1067 ByteCodeInstruction::kNegateI,
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001068 ByteCodeInstruction::kNegateF,
Brian Osman07c117b2019-05-23 12:51:06 -07001069 SlotCount(p.fOperand->fType));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001070 break;
Ethan Nicholas354ecf32019-05-07 16:13:02 -04001071 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001072 default:
1073 SkASSERT(false);
1074 }
Brian Osman3e29f1d2019-05-28 09:35:05 -04001075 return discard;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001076}
1077
Brian Osman3e29f1d2019-05-28 09:35:05 -04001078bool ByteCodeGenerator::writePostfixExpression(const PostfixExpression& p, bool discard) {
Brian Osmanf3fa6002019-05-17 14:26:53 -04001079 switch (p.fOperator) {
1080 case Token::Kind::PLUSPLUS: // fall through
1081 case Token::Kind::MINUSMINUS: {
Brian Osman07c117b2019-05-23 12:51:06 -07001082 SkASSERT(SlotCount(p.fOperand->fType) == 1);
Brian Osmanf3fa6002019-05-17 14:26:53 -04001083 std::unique_ptr<LValue> lvalue = this->getLValue(*p.fOperand);
1084 lvalue->load();
Brian Osman52c1bf12019-07-18 13:12:19 -04001085 // If we're not supposed to discard the result, then make a copy *before* the +/-
Brian Osman3e29f1d2019-05-28 09:35:05 -04001086 if (!discard) {
1087 this->write(ByteCodeInstruction::kDup);
1088 }
Brian Osmanf3fa6002019-05-17 14:26:53 -04001089 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osmand30e0392019-06-14 14:05:14 -04001090 this->write32(type_category(p.fType) == TypeCategory::kFloat ? float_to_bits(1.0f) : 1);
Brian Osmanf3fa6002019-05-17 14:26:53 -04001091 if (p.fOperator == Token::Kind::PLUSPLUS) {
1092 this->writeTypedInstruction(p.fType,
1093 ByteCodeInstruction::kAddI,
1094 ByteCodeInstruction::kAddI,
1095 ByteCodeInstruction::kAddF,
1096 1);
1097 } else {
1098 this->writeTypedInstruction(p.fType,
1099 ByteCodeInstruction::kSubtractI,
1100 ByteCodeInstruction::kSubtractI,
1101 ByteCodeInstruction::kSubtractF,
1102 1);
1103 }
Brian Osman52c1bf12019-07-18 13:12:19 -04001104 // Always consume the result as part of the store
1105 lvalue->store(true);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001106 discard = false;
Brian Osmanf3fa6002019-05-17 14:26:53 -04001107 break;
1108 }
1109 default:
1110 SkASSERT(false);
1111 }
Brian Osman3e29f1d2019-05-28 09:35:05 -04001112 return discard;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001113}
1114
1115void ByteCodeGenerator::writeSwizzle(const Swizzle& s) {
Brian Osman0785db02019-05-24 14:19:11 -04001116 if (swizzle_is_simple(s)) {
1117 this->writeVariableExpression(s);
1118 return;
1119 }
1120
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001121 switch (s.fBase->fKind) {
1122 case Expression::kVariableReference_Kind: {
1123 const Variable& var = ((VariableReference&) *s.fBase).fVariable;
Brian Osman1091f022019-05-16 09:42:16 -04001124 this->write(var.fStorage == Variable::kGlobal_Storage
1125 ? ByteCodeInstruction::kLoadSwizzleGlobal
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001126 : ByteCodeInstruction::kLoadSwizzle,
1127 s.fComponents.size());
Brian Osman1091f022019-05-16 09:42:16 -04001128 this->write8(this->getLocation(var));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001129 this->write8(s.fComponents.size());
1130 for (int c : s.fComponents) {
1131 this->write8(c);
1132 }
1133 break;
1134 }
1135 default:
1136 this->writeExpression(*s.fBase);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001137 this->write(ByteCodeInstruction::kSwizzle,
1138 s.fComponents.size() - s.fBase->fType.columns());
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001139 this->write8(s.fBase->fType.columns());
1140 this->write8(s.fComponents.size());
1141 for (int c : s.fComponents) {
1142 this->write8(c);
1143 }
1144 }
1145}
1146
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001147void ByteCodeGenerator::writeTernaryExpression(const TernaryExpression& t) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001148 int count = SlotCount(t.fType);
1149 SkASSERT(count == SlotCount(t.fIfTrue->fType));
1150 SkASSERT(count == SlotCount(t.fIfFalse->fType));
1151
Brian Osman4e93feb2019-05-16 15:38:00 -04001152 this->writeExpression(*t.fTest);
Brian Osman569f12f2019-06-13 11:23:57 -04001153 this->write(ByteCodeInstruction::kMaskPush);
Brian Osman4e93feb2019-05-16 15:38:00 -04001154 this->writeExpression(*t.fIfTrue);
Brian Osman569f12f2019-06-13 11:23:57 -04001155 this->write(ByteCodeInstruction::kMaskNegate);
1156 this->writeExpression(*t.fIfFalse);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001157 this->write(ByteCodeInstruction::kMaskBlend, count);
1158 this->write8(count);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001159}
1160
Brian Osman3e29f1d2019-05-28 09:35:05 -04001161void ByteCodeGenerator::writeExpression(const Expression& e, bool discard) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001162 switch (e.fKind) {
1163 case Expression::kBinary_Kind:
Brian Osman3e29f1d2019-05-28 09:35:05 -04001164 discard = this->writeBinaryExpression((BinaryExpression&) e, discard);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001165 break;
1166 case Expression::kBoolLiteral_Kind:
1167 this->writeBoolLiteral((BoolLiteral&) e);
1168 break;
1169 case Expression::kConstructor_Kind:
1170 this->writeConstructor((Constructor&) e);
1171 break;
Ethan Nicholas9e6a3932019-05-17 16:31:21 -04001172 case Expression::kExternalFunctionCall_Kind:
1173 this->writeExternalFunctionCall((ExternalFunctionCall&) e);
1174 break;
Ethan Nicholas91164d12019-05-15 15:29:54 -04001175 case Expression::kExternalValue_Kind:
1176 this->writeExternalValue((ExternalValueReference&) e);
1177 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001178 case Expression::kFieldAccess_Kind:
Brian Osman07c117b2019-05-23 12:51:06 -07001179 case Expression::kIndex_Kind:
1180 case Expression::kVariableReference_Kind:
1181 this->writeVariableExpression(e);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001182 break;
1183 case Expression::kFloatLiteral_Kind:
1184 this->writeFloatLiteral((FloatLiteral&) e);
1185 break;
1186 case Expression::kFunctionCall_Kind:
1187 this->writeFunctionCall((FunctionCall&) e);
1188 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001189 case Expression::kIntLiteral_Kind:
1190 this->writeIntLiteral((IntLiteral&) e);
1191 break;
1192 case Expression::kNullLiteral_Kind:
1193 this->writeNullLiteral((NullLiteral&) e);
1194 break;
1195 case Expression::kPrefix_Kind:
Brian Osman3e29f1d2019-05-28 09:35:05 -04001196 discard = this->writePrefixExpression((PrefixExpression&) e, discard);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001197 break;
1198 case Expression::kPostfix_Kind:
Brian Osman3e29f1d2019-05-28 09:35:05 -04001199 discard = this->writePostfixExpression((PostfixExpression&) e, discard);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001200 break;
1201 case Expression::kSwizzle_Kind:
1202 this->writeSwizzle((Swizzle&) e);
1203 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001204 case Expression::kTernary_Kind:
1205 this->writeTernaryExpression((TernaryExpression&) e);
1206 break;
1207 default:
1208 printf("unsupported expression %s\n", e.description().c_str());
1209 SkASSERT(false);
1210 }
Brian Osman3e29f1d2019-05-28 09:35:05 -04001211 if (discard) {
1212 int count = SlotCount(e.fType);
1213 if (count > 4) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001214 this->write(ByteCodeInstruction::kPopN, count);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001215 this->write8(count);
Brian Osmanfba386b2019-06-20 14:54:15 -04001216 } else if (count != 0) {
Brian Osman3e29f1d2019-05-28 09:35:05 -04001217 this->write(vector_instruction(ByteCodeInstruction::kPop, count));
1218 }
1219 discard = false;
1220 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001221}
1222
Ethan Nicholas91164d12019-05-15 15:29:54 -04001223class ByteCodeExternalValueLValue : public ByteCodeGenerator::LValue {
1224public:
1225 ByteCodeExternalValueLValue(ByteCodeGenerator* generator, ExternalValue& value, int index)
1226 : INHERITED(*generator)
Brian Osman07c117b2019-05-23 12:51:06 -07001227 , fCount(ByteCodeGenerator::SlotCount(value.type()))
Ethan Nicholas91164d12019-05-15 15:29:54 -04001228 , fIndex(index) {}
1229
1230 void load() override {
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001231 fGenerator.write(vector_instruction(ByteCodeInstruction::kReadExternal, fCount));
Ethan Nicholas91164d12019-05-15 15:29:54 -04001232 fGenerator.write8(fIndex);
1233 }
1234
Brian Osman3e29f1d2019-05-28 09:35:05 -04001235 void store(bool discard) override {
1236 if (!discard) {
1237 fGenerator.write(vector_instruction(ByteCodeInstruction::kDup, fCount));
1238 }
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001239 fGenerator.write(vector_instruction(ByteCodeInstruction::kWriteExternal, fCount));
Ethan Nicholas91164d12019-05-15 15:29:54 -04001240 fGenerator.write8(fIndex);
1241 }
1242
1243private:
1244 typedef LValue INHERITED;
1245
1246 int fCount;
1247
1248 int fIndex;
1249};
1250
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001251class ByteCodeSwizzleLValue : public ByteCodeGenerator::LValue {
1252public:
1253 ByteCodeSwizzleLValue(ByteCodeGenerator* generator, const Swizzle& swizzle)
1254 : INHERITED(*generator)
Brian Osman07c117b2019-05-23 12:51:06 -07001255 , fSwizzle(swizzle) {}
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001256
1257 void load() override {
Brian Osman1091f022019-05-16 09:42:16 -04001258 fGenerator.writeSwizzle(fSwizzle);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001259 }
1260
Brian Osman3e29f1d2019-05-28 09:35:05 -04001261 void store(bool discard) override {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001262 int count = fSwizzle.fComponents.size();
Brian Osman3e29f1d2019-05-28 09:35:05 -04001263 if (!discard) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001264 fGenerator.write(vector_instruction(ByteCodeInstruction::kDup, count));
Brian Osman3e29f1d2019-05-28 09:35:05 -04001265 }
Brian Osman869a3e82019-07-18 17:00:34 -04001266 Variable::Storage storage = Variable::kLocal_Storage;
Brian Osman07c117b2019-05-23 12:51:06 -07001267 int location = fGenerator.getLocation(*fSwizzle.fBase, &storage);
1268 bool isGlobal = storage == Variable::kGlobal_Storage;
1269 if (location < 0) {
1270 fGenerator.write(isGlobal ? ByteCodeInstruction::kStoreSwizzleIndirectGlobal
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001271 : ByteCodeInstruction::kStoreSwizzleIndirect,
1272 count);
Brian Osman07c117b2019-05-23 12:51:06 -07001273 } else {
1274 fGenerator.write(isGlobal ? ByteCodeInstruction::kStoreSwizzleGlobal
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001275 : ByteCodeInstruction::kStoreSwizzle,
1276 count);
Brian Osman07c117b2019-05-23 12:51:06 -07001277 fGenerator.write8(location);
1278 }
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001279 fGenerator.write8(count);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001280 for (int c : fSwizzle.fComponents) {
1281 fGenerator.write8(c);
1282 }
1283 }
1284
1285private:
1286 const Swizzle& fSwizzle;
1287
1288 typedef LValue INHERITED;
1289};
1290
Brian Osman07c117b2019-05-23 12:51:06 -07001291class ByteCodeExpressionLValue : public ByteCodeGenerator::LValue {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001292public:
Brian Osman07c117b2019-05-23 12:51:06 -07001293 ByteCodeExpressionLValue(ByteCodeGenerator* generator, const Expression& expr)
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001294 : INHERITED(*generator)
Brian Osman07c117b2019-05-23 12:51:06 -07001295 , fExpression(expr) {}
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001296
1297 void load() override {
Brian Osman07c117b2019-05-23 12:51:06 -07001298 fGenerator.writeVariableExpression(fExpression);
Brian Osman1091f022019-05-16 09:42:16 -04001299 }
1300
Brian Osman3e29f1d2019-05-28 09:35:05 -04001301 void store(bool discard) override {
Brian Osman07c117b2019-05-23 12:51:06 -07001302 int count = ByteCodeGenerator::SlotCount(fExpression.fType);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001303 if (!discard) {
1304 if (count > 4) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001305 fGenerator.write(ByteCodeInstruction::kDupN, count);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001306 fGenerator.write8(count);
1307 } else {
1308 fGenerator.write(vector_instruction(ByteCodeInstruction::kDup, count));
1309 }
Brian Osman07c117b2019-05-23 12:51:06 -07001310 }
Brian Osman869a3e82019-07-18 17:00:34 -04001311 Variable::Storage storage = Variable::kLocal_Storage;
Brian Osman07c117b2019-05-23 12:51:06 -07001312 int location = fGenerator.getLocation(fExpression, &storage);
1313 bool isGlobal = storage == Variable::kGlobal_Storage;
1314 if (location < 0 || count > 4) {
1315 if (location >= 0) {
1316 fGenerator.write(ByteCodeInstruction::kPushImmediate);
1317 fGenerator.write32(location);
1318 }
1319 fGenerator.write(isGlobal ? ByteCodeInstruction::kStoreExtendedGlobal
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001320 : ByteCodeInstruction::kStoreExtended,
1321 count);
Brian Osman07c117b2019-05-23 12:51:06 -07001322 fGenerator.write8(count);
1323 } else {
1324 fGenerator.write(vector_instruction(isGlobal ? ByteCodeInstruction::kStoreGlobal
1325 : ByteCodeInstruction::kStore,
1326 count));
1327 fGenerator.write8(location);
1328 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001329 }
1330
1331private:
1332 typedef LValue INHERITED;
1333
Brian Osman07c117b2019-05-23 12:51:06 -07001334 const Expression& fExpression;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001335};
1336
1337std::unique_ptr<ByteCodeGenerator::LValue> ByteCodeGenerator::getLValue(const Expression& e) {
1338 switch (e.fKind) {
Ethan Nicholas91164d12019-05-15 15:29:54 -04001339 case Expression::kExternalValue_Kind: {
1340 ExternalValue* value = ((ExternalValueReference&) e).fValue;
1341 int index = fOutput->fExternalValues.size();
1342 fOutput->fExternalValues.push_back(value);
1343 SkASSERT(index <= 255);
1344 return std::unique_ptr<LValue>(new ByteCodeExternalValueLValue(this, *value, index));
1345 }
Brian Osman07c117b2019-05-23 12:51:06 -07001346 case Expression::kFieldAccess_Kind:
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001347 case Expression::kIndex_Kind:
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001348 case Expression::kVariableReference_Kind:
Brian Osman07c117b2019-05-23 12:51:06 -07001349 return std::unique_ptr<LValue>(new ByteCodeExpressionLValue(this, e));
Brian Osman0785db02019-05-24 14:19:11 -04001350 case Expression::kSwizzle_Kind: {
1351 const Swizzle& s = (const Swizzle&) e;
1352 return swizzle_is_simple(s)
1353 ? std::unique_ptr<LValue>(new ByteCodeExpressionLValue(this, e))
1354 : std::unique_ptr<LValue>(new ByteCodeSwizzleLValue(this, s));
1355 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001356 case Expression::kTernary_Kind:
1357 default:
1358 printf("unsupported lvalue %s\n", e.description().c_str());
1359 return nullptr;
1360 }
1361}
1362
1363void ByteCodeGenerator::writeBlock(const Block& b) {
1364 for (const auto& s : b.fStatements) {
1365 this->writeStatement(*s);
1366 }
1367}
1368
1369void ByteCodeGenerator::setBreakTargets() {
1370 std::vector<DeferredLocation>& breaks = fBreakTargets.top();
1371 for (DeferredLocation& b : breaks) {
1372 b.set();
1373 }
1374 fBreakTargets.pop();
1375}
1376
1377void ByteCodeGenerator::setContinueTargets() {
1378 std::vector<DeferredLocation>& continues = fContinueTargets.top();
1379 for (DeferredLocation& c : continues) {
1380 c.set();
1381 }
1382 fContinueTargets.pop();
1383}
1384
1385void ByteCodeGenerator::writeBreakStatement(const BreakStatement& b) {
Brian Osman569f12f2019-06-13 11:23:57 -04001386 // TODO: Include BranchIfAllFalse to top-most LoopNext
1387 this->write(ByteCodeInstruction::kLoopBreak);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001388}
1389
1390void ByteCodeGenerator::writeContinueStatement(const ContinueStatement& c) {
Brian Osman569f12f2019-06-13 11:23:57 -04001391 // TODO: Include BranchIfAllFalse to top-most LoopNext
1392 this->write(ByteCodeInstruction::kLoopContinue);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001393}
1394
1395void ByteCodeGenerator::writeDoStatement(const DoStatement& d) {
Brian Osman569f12f2019-06-13 11:23:57 -04001396 this->write(ByteCodeInstruction::kLoopBegin);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001397 size_t start = fCode->size();
1398 this->writeStatement(*d.fStatement);
Brian Osman569f12f2019-06-13 11:23:57 -04001399 this->write(ByteCodeInstruction::kLoopNext);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001400 this->writeExpression(*d.fTest);
Brian Osman569f12f2019-06-13 11:23:57 -04001401 this->write(ByteCodeInstruction::kLoopMask);
1402 // TODO: Could shorten this with kBranchIfAnyTrue
1403 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1404 DeferredLocation endLocation(this);
1405 this->write(ByteCodeInstruction::kBranch);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001406 this->write16(start);
Brian Osman569f12f2019-06-13 11:23:57 -04001407 endLocation.set();
1408 this->write(ByteCodeInstruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001409}
1410
1411void ByteCodeGenerator::writeForStatement(const ForStatement& f) {
1412 fContinueTargets.emplace();
1413 fBreakTargets.emplace();
1414 if (f.fInitializer) {
1415 this->writeStatement(*f.fInitializer);
1416 }
Brian Osman569f12f2019-06-13 11:23:57 -04001417 this->write(ByteCodeInstruction::kLoopBegin);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001418 size_t start = fCode->size();
1419 if (f.fTest) {
1420 this->writeExpression(*f.fTest);
Brian Osman569f12f2019-06-13 11:23:57 -04001421 this->write(ByteCodeInstruction::kLoopMask);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001422 }
Brian Osman569f12f2019-06-13 11:23:57 -04001423 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1424 DeferredLocation endLocation(this);
1425 this->writeStatement(*f.fStatement);
1426 this->write(ByteCodeInstruction::kLoopNext);
1427 if (f.fNext) {
1428 this->writeExpression(*f.fNext, true);
1429 }
1430 this->write(ByteCodeInstruction::kBranch);
1431 this->write16(start);
1432 endLocation.set();
1433 this->write(ByteCodeInstruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001434}
1435
1436void ByteCodeGenerator::writeIfStatement(const IfStatement& i) {
Brian Osman569f12f2019-06-13 11:23:57 -04001437 this->writeExpression(*i.fTest);
1438 this->write(ByteCodeInstruction::kMaskPush);
1439 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1440 DeferredLocation falseLocation(this);
1441 this->writeStatement(*i.fIfTrue);
1442 falseLocation.set();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001443 if (i.fIfFalse) {
Brian Osman569f12f2019-06-13 11:23:57 -04001444 this->write(ByteCodeInstruction::kMaskNegate);
1445 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1446 DeferredLocation endLocation(this);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001447 this->writeStatement(*i.fIfFalse);
Mike Kleinb45ee832019-05-17 11:11:11 -05001448 endLocation.set();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001449 }
Brian Osman569f12f2019-06-13 11:23:57 -04001450 this->write(ByteCodeInstruction::kMaskPop);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001451}
1452
1453void ByteCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
Brian Osman4a47da72019-07-12 11:30:32 -04001454 if (fLoopCount || fConditionCount) {
1455 fErrors.error(r.fOffset, "return not allowed inside conditional or loop");
1456 return;
1457 }
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001458 int count = SlotCount(r.fExpression->fType);
Ethan Nicholas746035a2019-04-23 13:31:09 -04001459 this->writeExpression(*r.fExpression);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001460
1461 // Technically, the kReturn also pops fOutput->fLocalCount values from the stack, too, but we
1462 // haven't counted pushing those (they're outside the scope of our stack tracking). Instead,
1463 // we account for those in writeFunction().
1464
1465 // This is all fine because we don't allow conditional returns, so we only return once anyway.
1466 this->write(ByteCodeInstruction::kReturn, -count);
1467 this->write8(count);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001468}
1469
1470void ByteCodeGenerator::writeSwitchStatement(const SwitchStatement& r) {
1471 // not yet implemented
1472 abort();
1473}
1474
1475void ByteCodeGenerator::writeVarDeclarations(const VarDeclarations& v) {
1476 for (const auto& declStatement : v.fVars) {
1477 const VarDeclaration& decl = (VarDeclaration&) *declStatement;
1478 // we need to grab the location even if we don't use it, to ensure it
1479 // has been allocated
1480 int location = getLocation(*decl.fVar);
1481 if (decl.fValue) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001482 this->writeExpression(*decl.fValue);
Brian Osman07c117b2019-05-23 12:51:06 -07001483 int count = SlotCount(decl.fValue->fType);
1484 if (count > 4) {
1485 this->write(ByteCodeInstruction::kPushImmediate);
1486 this->write32(location);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001487 this->write(ByteCodeInstruction::kStoreExtended, count);
Brian Osman07c117b2019-05-23 12:51:06 -07001488 this->write8(count);
1489 } else {
1490 this->write(vector_instruction(ByteCodeInstruction::kStore, count));
1491 this->write8(location);
1492 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001493 }
1494 }
1495}
1496
1497void ByteCodeGenerator::writeWhileStatement(const WhileStatement& w) {
Brian Osman569f12f2019-06-13 11:23:57 -04001498 this->write(ByteCodeInstruction::kLoopBegin);
1499 size_t cond = fCode->size();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001500 this->writeExpression(*w.fTest);
Brian Osman569f12f2019-06-13 11:23:57 -04001501 this->write(ByteCodeInstruction::kLoopMask);
1502 this->write(ByteCodeInstruction::kBranchIfAllFalse);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001503 DeferredLocation endLocation(this);
1504 this->writeStatement(*w.fStatement);
Brian Osman569f12f2019-06-13 11:23:57 -04001505 this->write(ByteCodeInstruction::kLoopNext);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001506 this->write(ByteCodeInstruction::kBranch);
Brian Osman569f12f2019-06-13 11:23:57 -04001507 this->write16(cond);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001508 endLocation.set();
Brian Osman569f12f2019-06-13 11:23:57 -04001509 this->write(ByteCodeInstruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001510}
1511
1512void ByteCodeGenerator::writeStatement(const Statement& s) {
1513 switch (s.fKind) {
1514 case Statement::kBlock_Kind:
1515 this->writeBlock((Block&) s);
1516 break;
1517 case Statement::kBreak_Kind:
1518 this->writeBreakStatement((BreakStatement&) s);
1519 break;
1520 case Statement::kContinue_Kind:
1521 this->writeContinueStatement((ContinueStatement&) s);
1522 break;
1523 case Statement::kDiscard_Kind:
1524 // not yet implemented
1525 abort();
1526 case Statement::kDo_Kind:
1527 this->writeDoStatement((DoStatement&) s);
1528 break;
Brian Osman3e29f1d2019-05-28 09:35:05 -04001529 case Statement::kExpression_Kind:
1530 this->writeExpression(*((ExpressionStatement&) s).fExpression, true);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001531 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001532 case Statement::kFor_Kind:
1533 this->writeForStatement((ForStatement&) s);
1534 break;
1535 case Statement::kIf_Kind:
1536 this->writeIfStatement((IfStatement&) s);
1537 break;
1538 case Statement::kNop_Kind:
1539 break;
1540 case Statement::kReturn_Kind:
1541 this->writeReturnStatement((ReturnStatement&) s);
1542 break;
1543 case Statement::kSwitch_Kind:
1544 this->writeSwitchStatement((SwitchStatement&) s);
1545 break;
1546 case Statement::kVarDeclarations_Kind:
1547 this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration);
1548 break;
1549 case Statement::kWhile_Kind:
1550 this->writeWhileStatement((WhileStatement&) s);
1551 break;
1552 default:
1553 SkASSERT(false);
1554 }
1555}
1556
Brian Osman80164412019-06-07 13:00:23 -04001557ByteCodeFunction::ByteCodeFunction(const FunctionDeclaration* declaration)
1558 : fName(declaration->fName) {
1559 fParameterCount = 0;
1560 for (const auto& p : declaration->fParameters) {
1561 int slots = ByteCodeGenerator::SlotCount(p->fType);
1562 fParameters.push_back({ slots, (bool)(p->fModifiers.fFlags & Modifiers::kOut_Flag) });
1563 fParameterCount += slots;
1564 }
1565}
1566
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001567}