blob: b035596deafbb043bb39f220f8c4670293f404d9 [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 Osman886af0d2019-07-26 15:12:56 -040020 { "cos", ByteCodeInstruction::kCos },
21 { "dot", SpecialIntrinsic::kDot },
22 { "inverse", ByteCodeInstruction::kInverse2x2 },
23 { "sin", ByteCodeInstruction::kSin },
24 { "sqrt", ByteCodeInstruction::kSqrt },
25 { "tan", ByteCodeInstruction::kTan },
Ethan Nicholasae9633b2019-05-24 12:46:34 -040026 } {}
27
Ethan Nicholas82162ee2019-05-21 16:05:08 -040028
Brian Osman07c117b2019-05-23 12:51:06 -070029int ByteCodeGenerator::SlotCount(const Type& type) {
Brian Osmanfba386b2019-06-20 14:54:15 -040030 if (type.kind() == Type::kOther_Kind) {
31 return 0;
32 } else if (type.kind() == Type::kStruct_Kind) {
Brian Osman07c117b2019-05-23 12:51:06 -070033 int slots = 0;
34 for (const auto& f : type.fields()) {
35 slots += SlotCount(*f.fType);
36 }
37 SkASSERT(slots <= 255);
38 return slots;
39 } else if (type.kind() == Type::kArray_Kind) {
40 int columns = type.columns();
41 SkASSERT(columns >= 0);
42 int slots = columns * SlotCount(type.componentType());
43 SkASSERT(slots <= 255);
44 return slots;
45 } else {
46 return type.columns() * type.rows();
47 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040048}
49
50bool ByteCodeGenerator::generateCode() {
51 for (const auto& e : fProgram) {
52 switch (e.fKind) {
53 case ProgramElement::kFunction_Kind: {
54 std::unique_ptr<ByteCodeFunction> f = this->writeFunction((FunctionDefinition&) e);
55 if (!f) {
56 return false;
57 }
58 fOutput->fFunctions.push_back(std::move(f));
Brian Osman80164412019-06-07 13:00:23 -040059 fFunctions.push_back(&(FunctionDefinition&)e);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040060 break;
61 }
62 case ProgramElement::kVar_Kind: {
63 VarDeclarations& decl = (VarDeclarations&) e;
64 for (const auto& v : decl.fVars) {
65 const Variable* declVar = ((VarDeclaration&) *v).fVar;
66 if (declVar->fModifiers.fLayout.fBuiltin >= 0) {
67 continue;
68 }
69 if (declVar->fModifiers.fFlags & Modifiers::kIn_Flag) {
Brian Osman07c117b2019-05-23 12:51:06 -070070 for (int i = SlotCount(declVar->fType); i > 0; --i) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040071 fOutput->fInputSlots.push_back(fOutput->fGlobalCount++);
72 }
73 } else {
Brian Osman07c117b2019-05-23 12:51:06 -070074 fOutput->fGlobalCount += SlotCount(declVar->fType);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040075 }
76 }
77 break;
78 }
79 default:
80 ; // ignore
81 }
82 }
Brian Osman6f5358f2019-07-09 14:17:23 -040083 return 0 == fErrors.errorCount();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040084}
85
86std::unique_ptr<ByteCodeFunction> ByteCodeGenerator::writeFunction(const FunctionDefinition& f) {
87 fFunction = &f;
Brian Osman226668a2019-05-14 16:47:30 -040088 std::unique_ptr<ByteCodeFunction> result(new ByteCodeFunction(&f.fDeclaration));
Brian Osman80164412019-06-07 13:00:23 -040089 fParameterCount = result->fParameterCount;
Brian Osman4a47da72019-07-12 11:30:32 -040090 fLoopCount = fMaxLoopCount = 0;
91 fConditionCount = fMaxConditionCount = 0;
Brian Osmanaa2ca3f2019-07-15 13:24:48 -040092 fStackCount = fMaxStackCount = 0;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040093 fCode = &result->fCode;
Brian Osman4a47da72019-07-12 11:30:32 -040094
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040095 this->writeStatement(*f.fBody);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -040096 if (0 == fErrors.errorCount()) {
97 SkASSERT(fLoopCount == 0);
98 SkASSERT(fConditionCount == 0);
99 SkASSERT(fStackCount == 0);
100 }
101 this->write(ByteCodeInstruction::kReturn, 0);
Ethan Nicholas7e603db2019-05-03 12:57:47 -0400102 this->write8(0);
Brian Osman4a47da72019-07-12 11:30:32 -0400103
104 result->fLocalCount = fLocals.size();
105 result->fConditionCount = fMaxConditionCount;
106 result->fLoopCount = fMaxLoopCount;
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400107 result->fStackCount = fMaxStackCount;
Brian Osman4a47da72019-07-12 11:30:32 -0400108
Ethan Nicholasdfcad062019-05-07 12:53:34 -0400109 const Type& returnType = f.fDeclaration.fReturnType;
110 if (returnType != *fContext.fVoid_Type) {
Brian Osman07c117b2019-05-23 12:51:06 -0700111 result->fReturnCount = SlotCount(returnType);
Ethan Nicholasdfcad062019-05-07 12:53:34 -0400112 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400113 fLocals.clear();
114 fFunction = nullptr;
115 return result;
116}
117
118enum class TypeCategory {
119 kBool,
120 kSigned,
121 kUnsigned,
122 kFloat,
123};
124
125static TypeCategory type_category(const Type& type) {
126 switch (type.kind()) {
127 case Type::Kind::kVector_Kind:
128 case Type::Kind::kMatrix_Kind:
129 return type_category(type.componentType());
130 default:
131 if (type.fName == "bool") {
132 return TypeCategory::kBool;
133 } else if (type.fName == "int" || type.fName == "short") {
134 return TypeCategory::kSigned;
135 } else if (type.fName == "uint" || type.fName == "ushort") {
136 return TypeCategory::kUnsigned;
137 } else {
138 SkASSERT(type.fName == "float" || type.fName == "half");
139 return TypeCategory::kFloat;
140 }
141 ABORT("unsupported type: %s\n", type.description().c_str());
142 }
143}
144
Brian Osman0785db02019-05-24 14:19:11 -0400145// A "simple" Swizzle is based on a variable (or a compound variable like a struct or array), and
146// that references consecutive values, such that it can be implemented using normal load/store ops
147// with an offset. Note that all single-component swizzles (of suitable base types) are simple.
148static bool swizzle_is_simple(const Swizzle& s) {
149 switch (s.fBase->fKind) {
150 case Expression::kFieldAccess_Kind:
151 case Expression::kIndex_Kind:
152 case Expression::kVariableReference_Kind:
153 break;
154 default:
155 return false;
156 }
157
158 for (size_t i = 1; i < s.fComponents.size(); ++i) {
159 if (s.fComponents[i] != s.fComponents[i - 1] + 1) {
160 return false;
161 }
162 }
163 return true;
164}
165
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400166int ByteCodeGenerator::StackUsage(ByteCodeInstruction inst, int count_) {
167 // Ensures that we use count iff we're passed a non-default value. Most instructions have an
168 // implicit count, so the caller shouldn't need to worry about it (or count makes no sense).
169 // The asserts avoids callers thinking they're supplying useful information in that scenario,
170 // or failing to supply necessary information for the ops that need a count.
171 struct CountValue {
172 operator int() {
173 SkASSERT(val != ByteCodeGenerator::kUnusedStackCount);
174 SkDEBUGCODE(used = true);
175 return val;
176 }
177 ~CountValue() {
178 SkASSERT(used || val == ByteCodeGenerator::kUnusedStackCount);
179 }
180 int val;
181 SkDEBUGCODE(bool used = false;)
182 } count = { count_ };
183
184 switch (inst) {
185 // Unary functions/operators that don't change stack depth at all:
186#define VECTOR_UNARY_OP(base) \
187 case ByteCodeInstruction::base: \
188 case ByteCodeInstruction::base ## 2: \
189 case ByteCodeInstruction::base ## 3: \
190 case ByteCodeInstruction::base ## 4: \
191 return 0;
192
193 VECTOR_UNARY_OP(kConvertFtoI)
194 VECTOR_UNARY_OP(kConvertStoF)
195 VECTOR_UNARY_OP(kConvertUtoF)
196
197 VECTOR_UNARY_OP(kCos)
198 VECTOR_UNARY_OP(kSin)
199 VECTOR_UNARY_OP(kSqrt)
200 VECTOR_UNARY_OP(kTan)
201
202 VECTOR_UNARY_OP(kNegateF)
203 VECTOR_UNARY_OP(kNegateI)
204
Mike Reed634c9412019-07-18 13:20:04 -0400205 case ByteCodeInstruction::kInverse2x2:
206 case ByteCodeInstruction::kInverse3x3:
207 case ByteCodeInstruction::kInverse4x4: return 0;
208
Brian Osman869a3e82019-07-18 17:00:34 -0400209 case ByteCodeInstruction::kClampIndex: return 0;
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400210 case ByteCodeInstruction::kNotB: return 0;
211 case ByteCodeInstruction::kNegateFN: return 0;
212
213#undef VECTOR_UNARY_OP
214
215 // Binary functions/operators that do a 2 -> 1 reduction (possibly N times)
216#define VECTOR_BINARY_OP(base) \
217 case ByteCodeInstruction::base: return -1; \
218 case ByteCodeInstruction::base ## 2: return -2; \
219 case ByteCodeInstruction::base ## 3: return -3; \
220 case ByteCodeInstruction::base ## 4: return -4;
221
222#define VECTOR_MATRIX_BINARY_OP(base) \
223 VECTOR_BINARY_OP(base) \
224 case ByteCodeInstruction::base ## N: return -count;
225
226 case ByteCodeInstruction::kAndB: return -1;
227 case ByteCodeInstruction::kOrB: return -1;
228 case ByteCodeInstruction::kXorB: return -1;
229
230 VECTOR_BINARY_OP(kAddI)
231 VECTOR_MATRIX_BINARY_OP(kAddF)
232
233 VECTOR_BINARY_OP(kCompareIEQ)
234 VECTOR_MATRIX_BINARY_OP(kCompareFEQ)
235 VECTOR_BINARY_OP(kCompareINEQ)
236 VECTOR_MATRIX_BINARY_OP(kCompareFNEQ)
237 VECTOR_BINARY_OP(kCompareSGT)
238 VECTOR_BINARY_OP(kCompareUGT)
239 VECTOR_BINARY_OP(kCompareFGT)
240 VECTOR_BINARY_OP(kCompareSGTEQ)
241 VECTOR_BINARY_OP(kCompareUGTEQ)
242 VECTOR_BINARY_OP(kCompareFGTEQ)
243 VECTOR_BINARY_OP(kCompareSLT)
244 VECTOR_BINARY_OP(kCompareULT)
245 VECTOR_BINARY_OP(kCompareFLT)
246 VECTOR_BINARY_OP(kCompareSLTEQ)
247 VECTOR_BINARY_OP(kCompareULTEQ)
248 VECTOR_BINARY_OP(kCompareFLTEQ)
249
250 VECTOR_BINARY_OP(kDivideS)
251 VECTOR_BINARY_OP(kDivideU)
252 VECTOR_MATRIX_BINARY_OP(kDivideF)
253 VECTOR_BINARY_OP(kMultiplyI)
254 VECTOR_MATRIX_BINARY_OP(kMultiplyF)
255 VECTOR_BINARY_OP(kRemainderF)
256 VECTOR_BINARY_OP(kRemainderS)
257 VECTOR_BINARY_OP(kRemainderU)
258 VECTOR_BINARY_OP(kSubtractI)
259 VECTOR_MATRIX_BINARY_OP(kSubtractF)
260
261#undef VECTOR_BINARY_OP
262#undef VECTOR_MATRIX_BINARY_OP
263
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400264 // Ops that push or load data to grow the stack:
265 case ByteCodeInstruction::kDup:
266 case ByteCodeInstruction::kLoad:
267 case ByteCodeInstruction::kLoadGlobal:
268 case ByteCodeInstruction::kReadExternal:
269 case ByteCodeInstruction::kPushImmediate:
270 return 1;
271
272 case ByteCodeInstruction::kDup2:
273 case ByteCodeInstruction::kLoad2:
274 case ByteCodeInstruction::kLoadGlobal2:
275 case ByteCodeInstruction::kReadExternal2:
276 return 2;
277
278 case ByteCodeInstruction::kDup3:
279 case ByteCodeInstruction::kLoad3:
280 case ByteCodeInstruction::kLoadGlobal3:
281 case ByteCodeInstruction::kReadExternal3:
282 return 3;
283
284 case ByteCodeInstruction::kDup4:
285 case ByteCodeInstruction::kLoad4:
286 case ByteCodeInstruction::kLoadGlobal4:
287 case ByteCodeInstruction::kReadExternal4:
288 return 4;
289
290 case ByteCodeInstruction::kDupN:
291 case ByteCodeInstruction::kLoadSwizzle:
292 case ByteCodeInstruction::kLoadSwizzleGlobal:
293 return count;
294
295 // Pushes 'count' values, minus one for the 'address' that's consumed first
296 case ByteCodeInstruction::kLoadExtended:
297 case ByteCodeInstruction::kLoadExtendedGlobal:
298 return count - 1;
299
300 // Ops that pop or store data to shrink the stack:
301 case ByteCodeInstruction::kPop:
302 case ByteCodeInstruction::kStore:
303 case ByteCodeInstruction::kStoreGlobal:
304 case ByteCodeInstruction::kWriteExternal:
305 return -1;
306
307 case ByteCodeInstruction::kPop2:
308 case ByteCodeInstruction::kStore2:
309 case ByteCodeInstruction::kStoreGlobal2:
310 case ByteCodeInstruction::kWriteExternal2:
311 return -2;
312
313 case ByteCodeInstruction::kPop3:
314 case ByteCodeInstruction::kStore3:
315 case ByteCodeInstruction::kStoreGlobal3:
316 case ByteCodeInstruction::kWriteExternal3:
317 return -3;
318
319 case ByteCodeInstruction::kPop4:
320 case ByteCodeInstruction::kStore4:
321 case ByteCodeInstruction::kStoreGlobal4:
322 case ByteCodeInstruction::kWriteExternal4:
323 return -4;
324
325 case ByteCodeInstruction::kPopN:
326 case ByteCodeInstruction::kStoreSwizzle:
327 case ByteCodeInstruction::kStoreSwizzleGlobal:
328 return -count;
329
330 // Consumes 'count' values, plus one for the 'address'
331 case ByteCodeInstruction::kStoreExtended:
332 case ByteCodeInstruction::kStoreExtendedGlobal:
333 case ByteCodeInstruction::kStoreSwizzleIndirect:
334 case ByteCodeInstruction::kStoreSwizzleIndirectGlobal:
335 return -count - 1;
336
337 // Strange ops where the caller computes the delta for us:
338 case ByteCodeInstruction::kCallExternal:
339 case ByteCodeInstruction::kMatrixToMatrix:
340 case ByteCodeInstruction::kMatrixMultiply:
341 case ByteCodeInstruction::kReserve:
342 case ByteCodeInstruction::kReturn:
343 case ByteCodeInstruction::kScalarToMatrix:
344 case ByteCodeInstruction::kSwizzle:
345 return count;
346
347 // Miscellaneous
348
349 // kCall is net-zero. Max stack depth is adjusted in writeFunctionCall.
350 case ByteCodeInstruction::kCall: return 0;
351 case ByteCodeInstruction::kBranch: return 0;
352 case ByteCodeInstruction::kBranchIfAllFalse: return 0;
353
354 case ByteCodeInstruction::kMaskPush: return -1;
355 case ByteCodeInstruction::kMaskPop: return 0;
356 case ByteCodeInstruction::kMaskNegate: return 0;
357 case ByteCodeInstruction::kMaskBlend: return -count;
358
359 case ByteCodeInstruction::kLoopBegin: return 0;
360 case ByteCodeInstruction::kLoopNext: return 0;
361 case ByteCodeInstruction::kLoopMask: return -1;
362 case ByteCodeInstruction::kLoopEnd: return 0;
363 case ByteCodeInstruction::kLoopBreak: return 0;
364 case ByteCodeInstruction::kLoopContinue: return 0;
365
366 default:
Brian Osmanc7ec9e22019-07-16 08:49:11 -0400367 ABORT("unsupported instruction %d\n", (int)inst);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400368 return 0;
369 }
370}
371
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400372int ByteCodeGenerator::getLocation(const Variable& var) {
373 // given that we seldom have more than a couple of variables, linear search is probably the most
374 // efficient way to handle lookups
375 switch (var.fStorage) {
376 case Variable::kLocal_Storage: {
377 for (int i = fLocals.size() - 1; i >= 0; --i) {
378 if (fLocals[i] == &var) {
Brian Osman1091f022019-05-16 09:42:16 -0400379 SkASSERT(fParameterCount + i <= 255);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400380 return fParameterCount + i;
381 }
382 }
383 int result = fParameterCount + fLocals.size();
384 fLocals.push_back(&var);
Brian Osman07c117b2019-05-23 12:51:06 -0700385 for (int i = 0; i < SlotCount(var.fType) - 1; ++i) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400386 fLocals.push_back(nullptr);
387 }
Brian Osman1091f022019-05-16 09:42:16 -0400388 SkASSERT(result <= 255);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400389 return result;
390 }
391 case Variable::kParameter_Storage: {
392 int offset = 0;
393 for (const auto& p : fFunction->fDeclaration.fParameters) {
394 if (p == &var) {
Brian Osman1091f022019-05-16 09:42:16 -0400395 SkASSERT(offset <= 255);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400396 return offset;
397 }
Brian Osman07c117b2019-05-23 12:51:06 -0700398 offset += SlotCount(p->fType);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400399 }
400 SkASSERT(false);
Brian Osman1091f022019-05-16 09:42:16 -0400401 return 0;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400402 }
403 case Variable::kGlobal_Storage: {
404 int offset = 0;
405 for (const auto& e : fProgram) {
406 if (e.fKind == ProgramElement::kVar_Kind) {
407 VarDeclarations& decl = (VarDeclarations&) e;
408 for (const auto& v : decl.fVars) {
409 const Variable* declVar = ((VarDeclaration&) *v).fVar;
410 if (declVar->fModifiers.fLayout.fBuiltin >= 0) {
411 continue;
412 }
413 if (declVar == &var) {
Brian Osmanb7451292019-05-15 13:02:13 -0400414 SkASSERT(offset <= 255);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400415 return offset;
416 }
Brian Osman07c117b2019-05-23 12:51:06 -0700417 offset += SlotCount(declVar->fType);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400418 }
419 }
420 }
421 SkASSERT(false);
Brian Osman1091f022019-05-16 09:42:16 -0400422 return 0;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400423 }
424 default:
425 SkASSERT(false);
426 return 0;
427 }
428}
429
Brian Osman07c117b2019-05-23 12:51:06 -0700430int ByteCodeGenerator::getLocation(const Expression& expr, Variable::Storage* storage) {
431 switch (expr.fKind) {
432 case Expression::kFieldAccess_Kind: {
433 const FieldAccess& f = (const FieldAccess&)expr;
434 int baseAddr = this->getLocation(*f.fBase, storage);
435 int offset = 0;
436 for (int i = 0; i < f.fFieldIndex; ++i) {
437 offset += SlotCount(*f.fBase->fType.fields()[i].fType);
438 }
439 if (baseAddr < 0) {
Brian Osman86769292019-06-21 11:05:47 -0400440 if (offset != 0) {
441 this->write(ByteCodeInstruction::kPushImmediate);
442 this->write32(offset);
443 this->write(ByteCodeInstruction::kAddI);
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400444 this->write8(1);
Brian Osman86769292019-06-21 11:05:47 -0400445 }
Brian Osman07c117b2019-05-23 12:51:06 -0700446 return -1;
447 } else {
448 return baseAddr + offset;
449 }
450 }
451 case Expression::kIndex_Kind: {
452 const IndexExpression& i = (const IndexExpression&)expr;
453 int stride = SlotCount(i.fType);
Brian Osman869a3e82019-07-18 17:00:34 -0400454 int length = i.fBase->fType.columns();
455 SkASSERT(length <= 255);
Brian Osman07c117b2019-05-23 12:51:06 -0700456 int offset = -1;
457 if (i.fIndex->isConstant()) {
Brian Osman869a3e82019-07-18 17:00:34 -0400458 int64_t index = i.fIndex->getConstantInt();
459 if (index < 0 || index >= length) {
460 fErrors.error(i.fIndex->fOffset, "Array index out of bounds.");
461 return 0;
462 }
463 offset = index * stride;
Brian Osman07c117b2019-05-23 12:51:06 -0700464 } else {
Brian Osman86769292019-06-21 11:05:47 -0400465 if (i.fIndex->hasSideEffects()) {
466 // Having a side-effect in an indexer is technically safe for an rvalue,
467 // but with lvalues we have to evaluate the indexer twice, so make it an error.
468 fErrors.error(i.fIndex->fOffset,
469 "Index expressions with side-effects not supported in byte code.");
470 return 0;
471 }
Brian Osman07c117b2019-05-23 12:51:06 -0700472 this->writeExpression(*i.fIndex);
Brian Osman869a3e82019-07-18 17:00:34 -0400473 this->write(ByteCodeInstruction::kClampIndex);
474 this->write8(length);
Brian Osman86769292019-06-21 11:05:47 -0400475 if (stride != 1) {
476 this->write(ByteCodeInstruction::kPushImmediate);
477 this->write32(stride);
478 this->write(ByteCodeInstruction::kMultiplyI);
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400479 this->write8(1);
Brian Osman86769292019-06-21 11:05:47 -0400480 }
Brian Osman07c117b2019-05-23 12:51:06 -0700481 }
482 int baseAddr = this->getLocation(*i.fBase, storage);
Brian Osman86769292019-06-21 11:05:47 -0400483
484 // Are both components known statically?
Brian Osman07c117b2019-05-23 12:51:06 -0700485 if (baseAddr >= 0 && offset >= 0) {
486 return baseAddr + offset;
487 }
Brian Osman86769292019-06-21 11:05:47 -0400488
489 // At least one component is dynamic (and on the stack).
490
491 // If the other component is zero, we're done
492 if (baseAddr == 0 || offset == 0) {
493 return -1;
494 }
495
496 // Push the non-dynamic component (if any) to the stack, then add the two
Brian Osman07c117b2019-05-23 12:51:06 -0700497 if (baseAddr >= 0) {
498 this->write(ByteCodeInstruction::kPushImmediate);
499 this->write32(baseAddr);
500 }
501 if (offset >= 0) {
502 this->write(ByteCodeInstruction::kPushImmediate);
503 this->write32(offset);
504 }
505 this->write(ByteCodeInstruction::kAddI);
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400506 this->write8(1);
Brian Osman07c117b2019-05-23 12:51:06 -0700507 return -1;
508 }
Brian Osman0785db02019-05-24 14:19:11 -0400509 case Expression::kSwizzle_Kind: {
510 const Swizzle& s = (const Swizzle&)expr;
511 SkASSERT(swizzle_is_simple(s));
512 int baseAddr = this->getLocation(*s.fBase, storage);
513 int offset = s.fComponents[0];
514 if (baseAddr < 0) {
Brian Osman86769292019-06-21 11:05:47 -0400515 if (offset != 0) {
516 this->write(ByteCodeInstruction::kPushImmediate);
517 this->write32(offset);
518 this->write(ByteCodeInstruction::kAddI);
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400519 this->write8(1);
Brian Osman86769292019-06-21 11:05:47 -0400520 }
Brian Osman0785db02019-05-24 14:19:11 -0400521 return -1;
522 } else {
523 return baseAddr + offset;
524 }
525 }
Brian Osman07c117b2019-05-23 12:51:06 -0700526 case Expression::kVariableReference_Kind: {
527 const Variable& var = ((const VariableReference&)expr).fVariable;
528 *storage = var.fStorage;
529 return this->getLocation(var);
530 }
531 default:
532 SkASSERT(false);
533 return 0;
534 }
535}
536
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400537void ByteCodeGenerator::write8(uint8_t b) {
538 fCode->push_back(b);
539}
540
541void ByteCodeGenerator::write16(uint16_t i) {
Mike Klein76346ac2019-05-17 11:57:10 -0500542 size_t n = fCode->size();
543 fCode->resize(n+2);
544 memcpy(fCode->data() + n, &i, 2);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400545}
546
547void ByteCodeGenerator::write32(uint32_t i) {
Mike Klein76346ac2019-05-17 11:57:10 -0500548 size_t n = fCode->size();
549 fCode->resize(n+4);
550 memcpy(fCode->data() + n, &i, 4);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400551}
552
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400553void ByteCodeGenerator::write(ByteCodeInstruction i, int count) {
Brian Osman4a47da72019-07-12 11:30:32 -0400554 switch (i) {
555 case ByteCodeInstruction::kLoopBegin: this->enterLoop(); break;
556 case ByteCodeInstruction::kLoopEnd: this->exitLoop(); break;
557
558 case ByteCodeInstruction::kMaskPush: this->enterCondition(); break;
559 case ByteCodeInstruction::kMaskPop:
560 case ByteCodeInstruction::kMaskBlend: this->exitCondition(); break;
561 default: /* Do nothing */ break;
562 }
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400563 instruction val = (instruction) i;
564 size_t n = fCode->size();
565 fCode->resize(n + sizeof(val));
566 memcpy(fCode->data() + n, &val, sizeof(val));
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400567 fStackCount += StackUsage(i, count);
568 fMaxStackCount = std::max(fMaxStackCount, fStackCount);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400569}
570
Mike Klein76346ac2019-05-17 11:57:10 -0500571static ByteCodeInstruction vector_instruction(ByteCodeInstruction base, int count) {
Brian Osman07c117b2019-05-23 12:51:06 -0700572 SkASSERT(count >= 1 && count <= 4);
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400573 return ((ByteCodeInstruction) ((int) base + 1 - count));
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400574}
575
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400576void ByteCodeGenerator::writeTypedInstruction(const Type& type, ByteCodeInstruction s,
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400577 ByteCodeInstruction u, ByteCodeInstruction f,
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400578 int count, bool writeCount) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400579 switch (type_category(type)) {
580 case TypeCategory::kSigned:
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400581 this->write(vector_instruction(s, count));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400582 break;
583 case TypeCategory::kUnsigned:
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400584 this->write(vector_instruction(u, count));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400585 break;
Brian Osman1e855b22019-05-29 15:21:52 -0400586 case TypeCategory::kFloat: {
587 if (count > 4) {
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400588 this->write((ByteCodeInstruction)((int)f + 1), count);
Brian Osman1e855b22019-05-29 15:21:52 -0400589 } else {
590 this->write(vector_instruction(f, count));
591 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400592 break;
Brian Osman1e855b22019-05-29 15:21:52 -0400593 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400594 default:
595 SkASSERT(false);
596 }
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400597 if (writeCount) {
598 this->write8(count);
599 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400600}
601
Brian Osman3e29f1d2019-05-28 09:35:05 -0400602bool ByteCodeGenerator::writeBinaryExpression(const BinaryExpression& b, bool discard) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400603 if (b.fOperator == Token::Kind::EQ) {
604 std::unique_ptr<LValue> lvalue = this->getLValue(*b.fLeft);
605 this->writeExpression(*b.fRight);
Brian Osman3e29f1d2019-05-28 09:35:05 -0400606 lvalue->store(discard);
607 discard = false;
608 return discard;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400609 }
Brian Osman16e6fd52019-05-29 11:19:00 -0400610 const Type& lType = b.fLeft->fType;
611 const Type& rType = b.fRight->fType;
Brian Osman909231c2019-05-29 15:34:36 -0400612 bool lVecOrMtx = (lType.kind() == Type::kVector_Kind || lType.kind() == Type::kMatrix_Kind);
613 bool rVecOrMtx = (rType.kind() == Type::kVector_Kind || rType.kind() == Type::kMatrix_Kind);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400614 Token::Kind op;
615 std::unique_ptr<LValue> lvalue;
616 if (is_assignment(b.fOperator)) {
617 lvalue = this->getLValue(*b.fLeft);
618 lvalue->load();
619 op = remove_assignment(b.fOperator);
620 } else {
621 this->writeExpression(*b.fLeft);
622 op = b.fOperator;
Brian Osman909231c2019-05-29 15:34:36 -0400623 if (!lVecOrMtx && rVecOrMtx) {
Brian Osman16e6fd52019-05-29 11:19:00 -0400624 for (int i = SlotCount(rType); i > 1; --i) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400625 this->write(ByteCodeInstruction::kDup);
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400626 this->write8(1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400627 }
628 }
629 }
Ethan Nicholasd166d2e2019-09-23 11:43:45 -0400630 int count = std::max(SlotCount(lType), SlotCount(rType));
Brian Osmane5bbce22019-09-23 12:38:40 -0400631 SkDEBUGCODE(TypeCategory tc = type_category(lType));
Ethan Nicholasd166d2e2019-09-23 11:43:45 -0400632 switch (op) {
633 case Token::Kind::LOGICALAND: {
Brian Osmane5bbce22019-09-23 12:38:40 -0400634 SkASSERT(tc == SkSL::TypeCategory::kBool && count == 1);
Ethan Nicholasd166d2e2019-09-23 11:43:45 -0400635 this->write(ByteCodeInstruction::kDup);
636 this->write8(1);
637 this->write(ByteCodeInstruction::kMaskPush);
638 this->write(ByteCodeInstruction::kBranchIfAllFalse);
639 DeferredLocation falseLocation(this);
640 this->writeExpression(*b.fRight);
641 this->write(ByteCodeInstruction::kAndB);
642 falseLocation.set();
643 this->write(ByteCodeInstruction::kMaskPop);
644 return false;
645 }
646 case Token::Kind::LOGICALOR: {
Brian Osmane5bbce22019-09-23 12:38:40 -0400647 SkASSERT(tc == SkSL::TypeCategory::kBool && count == 1);
Ethan Nicholasd166d2e2019-09-23 11:43:45 -0400648 this->write(ByteCodeInstruction::kDup);
649 this->write8(1);
650 this->write(ByteCodeInstruction::kNotB);
651 this->write(ByteCodeInstruction::kMaskPush);
652 this->write(ByteCodeInstruction::kBranchIfAllFalse);
653 DeferredLocation falseLocation(this);
654 this->writeExpression(*b.fRight);
655 this->write(ByteCodeInstruction::kOrB);
656 falseLocation.set();
657 this->write(ByteCodeInstruction::kMaskPop);
658 return false;
659 }
660 default:
661 break;
662 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400663 this->writeExpression(*b.fRight);
Brian Osman909231c2019-05-29 15:34:36 -0400664 if (lVecOrMtx && !rVecOrMtx) {
Brian Osman16e6fd52019-05-29 11:19:00 -0400665 for (int i = SlotCount(lType); i > 1; --i) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400666 this->write(ByteCodeInstruction::kDup);
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400667 this->write8(1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400668 }
669 }
Brian Osman909231c2019-05-29 15:34:36 -0400670 // Special case for M*V, V*M, M*M (but not V*V!)
671 if (op == Token::Kind::STAR && lVecOrMtx && rVecOrMtx &&
672 !(lType.kind() == Type::kVector_Kind && rType.kind() == Type::kVector_Kind)) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400673 this->write(ByteCodeInstruction::kMatrixMultiply,
674 SlotCount(b.fType) - (SlotCount(lType) + SlotCount(rType)));
Brian Osman909231c2019-05-29 15:34:36 -0400675 int rCols = rType.columns(),
676 rRows = rType.rows(),
677 lCols = lType.columns(),
678 lRows = lType.rows();
679 // M*V treats the vector as a column
680 if (rType.kind() == Type::kVector_Kind) {
681 std::swap(rCols, rRows);
682 }
683 SkASSERT(lCols == rRows);
684 SkASSERT(SlotCount(b.fType) == lRows * rCols);
685 this->write8(lCols);
686 this->write8(lRows);
687 this->write8(rCols);
688 } else {
Brian Osman909231c2019-05-29 15:34:36 -0400689 switch (op) {
690 case Token::Kind::EQEQ:
691 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareIEQ,
692 ByteCodeInstruction::kCompareIEQ,
693 ByteCodeInstruction::kCompareFEQ,
694 count);
695 // Collapse to a single bool
696 for (int i = count; i > 1; --i) {
697 this->write(ByteCodeInstruction::kAndB);
698 }
699 break;
700 case Token::Kind::GT:
701 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSGT,
702 ByteCodeInstruction::kCompareUGT,
703 ByteCodeInstruction::kCompareFGT,
704 count);
705 break;
706 case Token::Kind::GTEQ:
707 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSGTEQ,
708 ByteCodeInstruction::kCompareUGTEQ,
709 ByteCodeInstruction::kCompareFGTEQ,
710 count);
711 break;
712 case Token::Kind::LT:
713 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSLT,
714 ByteCodeInstruction::kCompareULT,
715 ByteCodeInstruction::kCompareFLT,
716 count);
717 break;
718 case Token::Kind::LTEQ:
719 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSLTEQ,
720 ByteCodeInstruction::kCompareULTEQ,
721 ByteCodeInstruction::kCompareFLTEQ,
722 count);
723 break;
724 case Token::Kind::MINUS:
725 this->writeTypedInstruction(lType, ByteCodeInstruction::kSubtractI,
726 ByteCodeInstruction::kSubtractI,
727 ByteCodeInstruction::kSubtractF,
728 count);
729 break;
730 case Token::Kind::NEQ:
731 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareINEQ,
732 ByteCodeInstruction::kCompareINEQ,
733 ByteCodeInstruction::kCompareFNEQ,
734 count);
735 // Collapse to a single bool
736 for (int i = count; i > 1; --i) {
737 this->write(ByteCodeInstruction::kOrB);
738 }
739 break;
740 case Token::Kind::PERCENT:
741 this->writeTypedInstruction(lType, ByteCodeInstruction::kRemainderS,
742 ByteCodeInstruction::kRemainderU,
743 ByteCodeInstruction::kRemainderF,
744 count);
745 break;
746 case Token::Kind::PLUS:
747 this->writeTypedInstruction(lType, ByteCodeInstruction::kAddI,
748 ByteCodeInstruction::kAddI,
749 ByteCodeInstruction::kAddF,
750 count);
751 break;
752 case Token::Kind::SLASH:
753 this->writeTypedInstruction(lType, ByteCodeInstruction::kDivideS,
754 ByteCodeInstruction::kDivideU,
755 ByteCodeInstruction::kDivideF,
756 count);
757 break;
758 case Token::Kind::STAR:
759 this->writeTypedInstruction(lType, ByteCodeInstruction::kMultiplyI,
760 ByteCodeInstruction::kMultiplyI,
761 ByteCodeInstruction::kMultiplyF,
762 count);
763 break;
Brian Osman569f12f2019-06-13 11:23:57 -0400764
Brian Osman569f12f2019-06-13 11:23:57 -0400765 case Token::Kind::LOGICALXOR:
Brian Osmane5bbce22019-09-23 12:38:40 -0400766 SkASSERT(tc == SkSL::TypeCategory::kBool && count == 1);
767 this->write(ByteCodeInstruction::kXorB);
768 break;
769
770 case Token::Kind::BITWISEAND:
771 SkASSERT(count == 1 && (tc == SkSL::TypeCategory::kSigned ||
772 tc == SkSL::TypeCategory::kUnsigned));
773 this->write(ByteCodeInstruction::kAndB);
774 break;
775 case Token::Kind::BITWISEOR:
776 SkASSERT(count == 1 && (tc == SkSL::TypeCategory::kSigned ||
777 tc == SkSL::TypeCategory::kUnsigned));
778 this->write(ByteCodeInstruction::kOrB);
779 break;
780 case Token::Kind::BITWISEXOR:
781 SkASSERT(count == 1 && (tc == SkSL::TypeCategory::kSigned ||
782 tc == SkSL::TypeCategory::kUnsigned));
Brian Osman569f12f2019-06-13 11:23:57 -0400783 this->write(ByteCodeInstruction::kXorB);
784 break;
785
Brian Osman909231c2019-05-29 15:34:36 -0400786 default:
Brian Osmandb3dad22019-07-26 15:44:29 -0400787 fErrors.error(b.fOffset, SkSL::String::printf("Unsupported binary operator '%s'",
788 Compiler::OperatorName(op)));
789 break;
Brian Osman909231c2019-05-29 15:34:36 -0400790 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400791 }
792 if (lvalue) {
Brian Osman3e29f1d2019-05-28 09:35:05 -0400793 lvalue->store(discard);
794 discard = false;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400795 }
Brian Osman3e29f1d2019-05-28 09:35:05 -0400796 return discard;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400797}
798
799void ByteCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
800 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osman569f12f2019-06-13 11:23:57 -0400801 this->write32(b.fValue ? ~0 : 0);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400802}
803
804void ByteCodeGenerator::writeConstructor(const Constructor& c) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400805 for (const auto& arg : c.fArguments) {
806 this->writeExpression(*arg);
807 }
808 if (c.fArguments.size() == 1) {
Brian Osman29e013d2019-05-28 17:16:03 -0400809 const Type& inType = c.fArguments[0]->fType;
810 const Type& outType = c.fType;
811 TypeCategory inCategory = type_category(inType);
812 TypeCategory outCategory = type_category(outType);
813 int inCount = SlotCount(inType);
814 int outCount = SlotCount(outType);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400815 if (inCategory != outCategory) {
Brian Osmanc51d7912019-05-22 15:16:16 -0700816 SkASSERT(inCount == outCount);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400817 if (inCategory == TypeCategory::kFloat) {
818 SkASSERT(outCategory == TypeCategory::kSigned ||
819 outCategory == TypeCategory::kUnsigned);
Brian Osmanc51d7912019-05-22 15:16:16 -0700820 this->write(vector_instruction(ByteCodeInstruction::kConvertFtoI, outCount));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400821 } else if (outCategory == TypeCategory::kFloat) {
822 if (inCategory == TypeCategory::kSigned) {
Brian Osmanc51d7912019-05-22 15:16:16 -0700823 this->write(vector_instruction(ByteCodeInstruction::kConvertStoF, outCount));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400824 } else {
825 SkASSERT(inCategory == TypeCategory::kUnsigned);
Brian Osmanc51d7912019-05-22 15:16:16 -0700826 this->write(vector_instruction(ByteCodeInstruction::kConvertUtoF, outCount));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400827 }
828 } else {
829 SkASSERT(false);
830 }
831 }
Brian Osman29e013d2019-05-28 17:16:03 -0400832 if (inType.kind() == Type::kMatrix_Kind && outType.kind() == Type::kMatrix_Kind) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400833 this->write(ByteCodeInstruction::kMatrixToMatrix,
834 SlotCount(outType) - SlotCount(inType));
Brian Osman29e013d2019-05-28 17:16:03 -0400835 this->write8(inType.columns());
836 this->write8(inType.rows());
837 this->write8(outType.columns());
838 this->write8(outType.rows());
839 } else if (inCount != outCount) {
Brian Osmanc51d7912019-05-22 15:16:16 -0700840 SkASSERT(inCount == 1);
Brian Osman29e013d2019-05-28 17:16:03 -0400841 if (outType.kind() == Type::kMatrix_Kind) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400842 this->write(ByteCodeInstruction::kScalarToMatrix, SlotCount(outType) - 1);
Brian Osman29e013d2019-05-28 17:16:03 -0400843 this->write8(outType.columns());
844 this->write8(outType.rows());
845 } else {
846 SkASSERT(outType.kind() == Type::kVector_Kind);
847 for (; inCount != outCount; ++inCount) {
848 this->write(ByteCodeInstruction::kDup);
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400849 this->write8(1);
Brian Osman29e013d2019-05-28 17:16:03 -0400850 }
Brian Osmanc51d7912019-05-22 15:16:16 -0700851 }
852 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400853 }
854}
855
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400856void ByteCodeGenerator::writeExternalFunctionCall(const ExternalFunctionCall& f) {
857 int argumentCount = 0;
858 for (const auto& arg : f.fArguments) {
859 this->writeExpression(*arg);
Brian Osman07c117b2019-05-23 12:51:06 -0700860 argumentCount += SlotCount(arg->fType);
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400861 }
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400862 this->write(ByteCodeInstruction::kCallExternal, SlotCount(f.fType) - argumentCount);
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400863 SkASSERT(argumentCount <= 255);
864 this->write8(argumentCount);
Brian Osman07c117b2019-05-23 12:51:06 -0700865 this->write8(SlotCount(f.fType));
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400866 int index = fOutput->fExternalValues.size();
867 fOutput->fExternalValues.push_back(f.fFunction);
868 SkASSERT(index <= 255);
869 this->write8(index);
870}
871
Ethan Nicholas91164d12019-05-15 15:29:54 -0400872void ByteCodeGenerator::writeExternalValue(const ExternalValueReference& e) {
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400873 int count = SlotCount(e.fValue->type());
874 this->write(vector_instruction(ByteCodeInstruction::kReadExternal, count));
875 this->write8(count);
Ethan Nicholas91164d12019-05-15 15:29:54 -0400876 int index = fOutput->fExternalValues.size();
877 fOutput->fExternalValues.push_back(e.fValue);
878 SkASSERT(index <= 255);
879 this->write8(index);
880}
881
Brian Osman07c117b2019-05-23 12:51:06 -0700882void ByteCodeGenerator::writeVariableExpression(const Expression& expr) {
Brian Osman869a3e82019-07-18 17:00:34 -0400883 Variable::Storage storage = Variable::kLocal_Storage;
Brian Osman07c117b2019-05-23 12:51:06 -0700884 int location = this->getLocation(expr, &storage);
885 bool isGlobal = storage == Variable::kGlobal_Storage;
886 int count = SlotCount(expr.fType);
887 if (location < 0 || count > 4) {
888 if (location >= 0) {
889 this->write(ByteCodeInstruction::kPushImmediate);
890 this->write32(location);
891 }
892 this->write(isGlobal ? ByteCodeInstruction::kLoadExtendedGlobal
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400893 : ByteCodeInstruction::kLoadExtended,
894 count);
Brian Osman07c117b2019-05-23 12:51:06 -0700895 this->write8(count);
896 } else {
897 this->write(vector_instruction(isGlobal ? ByteCodeInstruction::kLoadGlobal
898 : ByteCodeInstruction::kLoad,
899 count));
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400900 this->write8(count);
Brian Osman07c117b2019-05-23 12:51:06 -0700901 this->write8(location);
902 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400903}
904
Brian Osmand30e0392019-06-14 14:05:14 -0400905static inline uint32_t float_to_bits(float x) {
906 uint32_t u;
907 memcpy(&u, &x, sizeof(uint32_t));
908 return u;
909}
910
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400911void ByteCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
912 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osmand30e0392019-06-14 14:05:14 -0400913 this->write32(float_to_bits(f.fValue));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400914}
915
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400916void ByteCodeGenerator::writeIntrinsicCall(const FunctionCall& c) {
917 auto found = fIntrinsics.find(c.fFunction.fName);
918 if (found == fIntrinsics.end()) {
919 fErrors.error(c.fOffset, "unsupported intrinsic function");
920 return;
921 }
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400922 int count = SlotCount(c.fArguments[0]->fType);
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400923 if (found->second.fIsSpecial) {
Brian Osmanb380e712019-07-24 17:02:39 -0400924 SpecialIntrinsic special = found->second.fValue.fSpecial;
925 switch (special) {
926 case SpecialIntrinsic::kDot: {
927 SkASSERT(c.fArguments.size() == 2);
928 SkASSERT(count == SlotCount(c.fArguments[1]->fType));
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400929 this->write(vector_instruction(ByteCodeInstruction::kMultiplyF, count));
930 this->write8(count);
Brian Osmanb380e712019-07-24 17:02:39 -0400931 for (int i = count; i > 1; --i) {
932 this->write(ByteCodeInstruction::kAddF);
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400933 this->write8(1);
Brian Osmanb380e712019-07-24 17:02:39 -0400934 }
935 break;
936 }
Brian Osmanb380e712019-07-24 17:02:39 -0400937 default:
938 SkASSERT(false);
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400939 }
940 } else {
941 switch (found->second.fValue.fInstruction) {
942 case ByteCodeInstruction::kCos:
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400943 case ByteCodeInstruction::kSin:
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400944 case ByteCodeInstruction::kTan:
945 SkASSERT(c.fArguments.size() > 0);
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400946 this->write(vector_instruction(found->second.fValue.fInstruction, count));
947 this->write8(count);
948 break;
949 case ByteCodeInstruction::kSqrt:
950 SkASSERT(c.fArguments.size() > 0);
951 this->write(vector_instruction(found->second.fValue.fInstruction, count));
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400952 break;
Mike Reed634c9412019-07-18 13:20:04 -0400953 case ByteCodeInstruction::kInverse2x2: {
954 SkASSERT(c.fArguments.size() > 0);
955 auto op = ByteCodeInstruction::kInverse2x2;
956 switch (count) {
957 case 4: break; // float2x2
958 case 9: op = ByteCodeInstruction::kInverse3x3; break;
959 case 16: op = ByteCodeInstruction::kInverse4x4; break;
960 default: SkASSERT(false);
961 }
962 this->write(op);
Brian Osmanb380e712019-07-24 17:02:39 -0400963 break;
964 }
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400965 default:
966 SkASSERT(false);
967 }
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400968 }
969}
970
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400971void ByteCodeGenerator::writeFunctionCall(const FunctionCall& f) {
Brian Osmand3494ed2019-06-20 15:41:34 -0400972 // Builtins have simple signatures...
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400973 if (f.fFunction.fBuiltin) {
Brian Osmand3494ed2019-06-20 15:41:34 -0400974 for (const auto& arg : f.fArguments) {
975 this->writeExpression(*arg);
976 }
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400977 this->writeIntrinsicCall(f);
978 return;
979 }
Brian Osmand3494ed2019-06-20 15:41:34 -0400980
Brian Osman6f5358f2019-07-09 14:17:23 -0400981 // Find the index of the function we're calling. We explicitly do not allow calls to functions
982 // before they're defined. This is an easy-to-understand rule that prevents recursion.
983 size_t idx;
984 for (idx = 0; idx < fFunctions.size(); ++idx) {
985 if (f.fFunction.matches(fFunctions[idx]->fDeclaration)) {
986 break;
987 }
988 }
989 if (idx > 255) {
990 fErrors.error(f.fOffset, "Function count limit exceeded");
991 return;
992 } else if (idx >= fFunctions.size()) {
993 fErrors.error(f.fOffset, "Call to undefined function");
994 return;
995 }
996
997 // We may need to deal with out parameters, so the sequence is tricky
Brian Osmand3494ed2019-06-20 15:41:34 -0400998 if (int returnCount = SlotCount(f.fType)) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400999 this->write(ByteCodeInstruction::kReserve, returnCount);
Brian Osmand3494ed2019-06-20 15:41:34 -04001000 this->write8(returnCount);
1001 }
1002
1003 int argCount = f.fArguments.size();
1004 std::vector<std::unique_ptr<LValue>> lvalues;
1005 for (int i = 0; i < argCount; ++i) {
1006 const auto& param = f.fFunction.fParameters[i];
1007 const auto& arg = f.fArguments[i];
1008 if (param->fModifiers.fFlags & Modifiers::kOut_Flag) {
1009 lvalues.emplace_back(this->getLValue(*arg));
1010 lvalues.back()->load();
1011 } else {
1012 this->writeExpression(*arg);
1013 }
1014 }
1015
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001016 // The space used by the call is based on the callee, but it also unwinds all of that before
1017 // we continue execution. We adjust our max stack depths below.
Brian Osman226668a2019-05-14 16:47:30 -04001018 this->write(ByteCodeInstruction::kCall);
Brian Osman6f5358f2019-07-09 14:17:23 -04001019 this->write8(idx);
Brian Osmand3494ed2019-06-20 15:41:34 -04001020
Brian Osman4a47da72019-07-12 11:30:32 -04001021 const ByteCodeFunction* callee = fOutput->fFunctions[idx].get();
1022 fMaxLoopCount = std::max(fMaxLoopCount, fLoopCount + callee->fLoopCount);
1023 fMaxConditionCount = std::max(fMaxConditionCount, fConditionCount + callee->fConditionCount);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001024 fMaxStackCount = std::max(fMaxStackCount, fStackCount + callee->fLocalCount
1025 + callee->fStackCount);
Brian Osman4a47da72019-07-12 11:30:32 -04001026
Brian Osmand3494ed2019-06-20 15:41:34 -04001027 // After the called function returns, the stack will still contain our arguments. We have to
1028 // pop them (storing any out parameters back to their lvalues as we go). We glob together slot
1029 // counts for all parameters that aren't out-params, so we can pop them in one big chunk.
1030 int popCount = 0;
1031 auto pop = [&]() {
1032 if (popCount > 4) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001033 this->write(ByteCodeInstruction::kPopN, popCount);
Brian Osmand3494ed2019-06-20 15:41:34 -04001034 this->write8(popCount);
1035 } else if (popCount > 0) {
1036 this->write(vector_instruction(ByteCodeInstruction::kPop, popCount));
1037 }
1038 popCount = 0;
1039 };
1040
1041 for (int i = argCount - 1; i >= 0; --i) {
1042 const auto& param = f.fFunction.fParameters[i];
1043 const auto& arg = f.fArguments[i];
1044 if (param->fModifiers.fFlags & Modifiers::kOut_Flag) {
1045 pop();
1046 lvalues.back()->store(true);
1047 lvalues.pop_back();
1048 } else {
1049 popCount += SlotCount(arg->fType);
1050 }
1051 }
1052 pop();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001053}
1054
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001055void ByteCodeGenerator::writeIntLiteral(const IntLiteral& i) {
1056 this->write(ByteCodeInstruction::kPushImmediate);
1057 this->write32(i.fValue);
1058}
1059
1060void ByteCodeGenerator::writeNullLiteral(const NullLiteral& n) {
1061 // not yet implemented
1062 abort();
1063}
1064
Brian Osman3e29f1d2019-05-28 09:35:05 -04001065bool ByteCodeGenerator::writePrefixExpression(const PrefixExpression& p, bool discard) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001066 switch (p.fOperator) {
1067 case Token::Kind::PLUSPLUS: // fall through
1068 case Token::Kind::MINUSMINUS: {
Brian Osman07c117b2019-05-23 12:51:06 -07001069 SkASSERT(SlotCount(p.fOperand->fType) == 1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001070 std::unique_ptr<LValue> lvalue = this->getLValue(*p.fOperand);
1071 lvalue->load();
1072 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osmand30e0392019-06-14 14:05:14 -04001073 this->write32(type_category(p.fType) == TypeCategory::kFloat ? float_to_bits(1.0f) : 1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001074 if (p.fOperator == Token::Kind::PLUSPLUS) {
1075 this->writeTypedInstruction(p.fType,
1076 ByteCodeInstruction::kAddI,
1077 ByteCodeInstruction::kAddI,
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001078 ByteCodeInstruction::kAddF,
1079 1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001080 } else {
1081 this->writeTypedInstruction(p.fType,
1082 ByteCodeInstruction::kSubtractI,
1083 ByteCodeInstruction::kSubtractI,
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001084 ByteCodeInstruction::kSubtractF,
1085 1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001086 }
Brian Osman3e29f1d2019-05-28 09:35:05 -04001087 lvalue->store(discard);
1088 discard = false;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001089 break;
1090 }
Ethan Nicholas354ecf32019-05-07 16:13:02 -04001091 case Token::Kind::MINUS: {
1092 this->writeExpression(*p.fOperand);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001093 this->writeTypedInstruction(p.fType,
Mike Klein12710912019-05-21 11:04:59 -05001094 ByteCodeInstruction::kNegateI,
1095 ByteCodeInstruction::kNegateI,
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001096 ByteCodeInstruction::kNegateF,
Ethan Nicholasc70027b2019-09-05 16:50:52 -04001097 SlotCount(p.fOperand->fType),
1098 false);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001099 break;
Ethan Nicholas354ecf32019-05-07 16:13:02 -04001100 }
Brian Osmane5bbce22019-09-23 12:38:40 -04001101 case Token::Kind::LOGICALNOT:
1102 case Token::Kind::BITWISENOT: {
1103 SkASSERT(SlotCount(p.fOperand->fType) == 1);
1104 SkDEBUGCODE(TypeCategory tc = type_category(p.fOperand->fType));
1105 SkASSERT((p.fOperator == Token::Kind::LOGICALNOT && tc == TypeCategory::kBool) ||
1106 (p.fOperator == Token::Kind::BITWISENOT && (tc == TypeCategory::kSigned ||
1107 tc == TypeCategory::kUnsigned)));
1108 this->writeExpression(*p.fOperand);
1109 this->write(ByteCodeInstruction::kNotB);
1110 break;
1111 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001112 default:
1113 SkASSERT(false);
1114 }
Brian Osman3e29f1d2019-05-28 09:35:05 -04001115 return discard;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001116}
1117
Brian Osman3e29f1d2019-05-28 09:35:05 -04001118bool ByteCodeGenerator::writePostfixExpression(const PostfixExpression& p, bool discard) {
Brian Osmanf3fa6002019-05-17 14:26:53 -04001119 switch (p.fOperator) {
1120 case Token::Kind::PLUSPLUS: // fall through
1121 case Token::Kind::MINUSMINUS: {
Brian Osman07c117b2019-05-23 12:51:06 -07001122 SkASSERT(SlotCount(p.fOperand->fType) == 1);
Brian Osmanf3fa6002019-05-17 14:26:53 -04001123 std::unique_ptr<LValue> lvalue = this->getLValue(*p.fOperand);
1124 lvalue->load();
Brian Osman52c1bf12019-07-18 13:12:19 -04001125 // If we're not supposed to discard the result, then make a copy *before* the +/-
Brian Osman3e29f1d2019-05-28 09:35:05 -04001126 if (!discard) {
1127 this->write(ByteCodeInstruction::kDup);
Ethan Nicholasc70027b2019-09-05 16:50:52 -04001128 this->write8(1);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001129 }
Brian Osmanf3fa6002019-05-17 14:26:53 -04001130 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osmand30e0392019-06-14 14:05:14 -04001131 this->write32(type_category(p.fType) == TypeCategory::kFloat ? float_to_bits(1.0f) : 1);
Brian Osmanf3fa6002019-05-17 14:26:53 -04001132 if (p.fOperator == Token::Kind::PLUSPLUS) {
1133 this->writeTypedInstruction(p.fType,
1134 ByteCodeInstruction::kAddI,
1135 ByteCodeInstruction::kAddI,
1136 ByteCodeInstruction::kAddF,
1137 1);
1138 } else {
1139 this->writeTypedInstruction(p.fType,
1140 ByteCodeInstruction::kSubtractI,
1141 ByteCodeInstruction::kSubtractI,
1142 ByteCodeInstruction::kSubtractF,
1143 1);
1144 }
Brian Osman52c1bf12019-07-18 13:12:19 -04001145 // Always consume the result as part of the store
1146 lvalue->store(true);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001147 discard = false;
Brian Osmanf3fa6002019-05-17 14:26:53 -04001148 break;
1149 }
1150 default:
1151 SkASSERT(false);
1152 }
Brian Osman3e29f1d2019-05-28 09:35:05 -04001153 return discard;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001154}
1155
1156void ByteCodeGenerator::writeSwizzle(const Swizzle& s) {
Brian Osman0785db02019-05-24 14:19:11 -04001157 if (swizzle_is_simple(s)) {
1158 this->writeVariableExpression(s);
1159 return;
1160 }
1161
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001162 switch (s.fBase->fKind) {
1163 case Expression::kVariableReference_Kind: {
1164 const Variable& var = ((VariableReference&) *s.fBase).fVariable;
Brian Osman1091f022019-05-16 09:42:16 -04001165 this->write(var.fStorage == Variable::kGlobal_Storage
1166 ? ByteCodeInstruction::kLoadSwizzleGlobal
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001167 : ByteCodeInstruction::kLoadSwizzle,
1168 s.fComponents.size());
Brian Osman1091f022019-05-16 09:42:16 -04001169 this->write8(this->getLocation(var));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001170 this->write8(s.fComponents.size());
1171 for (int c : s.fComponents) {
1172 this->write8(c);
1173 }
1174 break;
1175 }
1176 default:
1177 this->writeExpression(*s.fBase);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001178 this->write(ByteCodeInstruction::kSwizzle,
1179 s.fComponents.size() - s.fBase->fType.columns());
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001180 this->write8(s.fBase->fType.columns());
1181 this->write8(s.fComponents.size());
1182 for (int c : s.fComponents) {
1183 this->write8(c);
1184 }
1185 }
1186}
1187
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001188void ByteCodeGenerator::writeTernaryExpression(const TernaryExpression& t) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001189 int count = SlotCount(t.fType);
1190 SkASSERT(count == SlotCount(t.fIfTrue->fType));
1191 SkASSERT(count == SlotCount(t.fIfFalse->fType));
1192
Brian Osman4e93feb2019-05-16 15:38:00 -04001193 this->writeExpression(*t.fTest);
Brian Osman569f12f2019-06-13 11:23:57 -04001194 this->write(ByteCodeInstruction::kMaskPush);
Brian Osman4e93feb2019-05-16 15:38:00 -04001195 this->writeExpression(*t.fIfTrue);
Brian Osman569f12f2019-06-13 11:23:57 -04001196 this->write(ByteCodeInstruction::kMaskNegate);
1197 this->writeExpression(*t.fIfFalse);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001198 this->write(ByteCodeInstruction::kMaskBlend, count);
1199 this->write8(count);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001200}
1201
Brian Osman3e29f1d2019-05-28 09:35:05 -04001202void ByteCodeGenerator::writeExpression(const Expression& e, bool discard) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001203 switch (e.fKind) {
1204 case Expression::kBinary_Kind:
Brian Osman3e29f1d2019-05-28 09:35:05 -04001205 discard = this->writeBinaryExpression((BinaryExpression&) e, discard);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001206 break;
1207 case Expression::kBoolLiteral_Kind:
1208 this->writeBoolLiteral((BoolLiteral&) e);
1209 break;
1210 case Expression::kConstructor_Kind:
1211 this->writeConstructor((Constructor&) e);
1212 break;
Ethan Nicholas9e6a3932019-05-17 16:31:21 -04001213 case Expression::kExternalFunctionCall_Kind:
1214 this->writeExternalFunctionCall((ExternalFunctionCall&) e);
1215 break;
Ethan Nicholas91164d12019-05-15 15:29:54 -04001216 case Expression::kExternalValue_Kind:
1217 this->writeExternalValue((ExternalValueReference&) e);
1218 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001219 case Expression::kFieldAccess_Kind:
Brian Osman07c117b2019-05-23 12:51:06 -07001220 case Expression::kIndex_Kind:
1221 case Expression::kVariableReference_Kind:
1222 this->writeVariableExpression(e);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001223 break;
1224 case Expression::kFloatLiteral_Kind:
1225 this->writeFloatLiteral((FloatLiteral&) e);
1226 break;
1227 case Expression::kFunctionCall_Kind:
1228 this->writeFunctionCall((FunctionCall&) e);
1229 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001230 case Expression::kIntLiteral_Kind:
1231 this->writeIntLiteral((IntLiteral&) e);
1232 break;
1233 case Expression::kNullLiteral_Kind:
1234 this->writeNullLiteral((NullLiteral&) e);
1235 break;
1236 case Expression::kPrefix_Kind:
Brian Osman3e29f1d2019-05-28 09:35:05 -04001237 discard = this->writePrefixExpression((PrefixExpression&) e, discard);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001238 break;
1239 case Expression::kPostfix_Kind:
Brian Osman3e29f1d2019-05-28 09:35:05 -04001240 discard = this->writePostfixExpression((PostfixExpression&) e, discard);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001241 break;
1242 case Expression::kSwizzle_Kind:
1243 this->writeSwizzle((Swizzle&) e);
1244 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001245 case Expression::kTernary_Kind:
1246 this->writeTernaryExpression((TernaryExpression&) e);
1247 break;
1248 default:
1249 printf("unsupported expression %s\n", e.description().c_str());
1250 SkASSERT(false);
1251 }
Brian Osman3e29f1d2019-05-28 09:35:05 -04001252 if (discard) {
1253 int count = SlotCount(e.fType);
1254 if (count > 4) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001255 this->write(ByteCodeInstruction::kPopN, count);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001256 this->write8(count);
Brian Osmanfba386b2019-06-20 14:54:15 -04001257 } else if (count != 0) {
Brian Osman3e29f1d2019-05-28 09:35:05 -04001258 this->write(vector_instruction(ByteCodeInstruction::kPop, count));
1259 }
1260 discard = false;
1261 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001262}
1263
Ethan Nicholas91164d12019-05-15 15:29:54 -04001264class ByteCodeExternalValueLValue : public ByteCodeGenerator::LValue {
1265public:
1266 ByteCodeExternalValueLValue(ByteCodeGenerator* generator, ExternalValue& value, int index)
1267 : INHERITED(*generator)
Brian Osman07c117b2019-05-23 12:51:06 -07001268 , fCount(ByteCodeGenerator::SlotCount(value.type()))
Ethan Nicholas91164d12019-05-15 15:29:54 -04001269 , fIndex(index) {}
1270
1271 void load() override {
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001272 fGenerator.write(vector_instruction(ByteCodeInstruction::kReadExternal, fCount));
Ethan Nicholasc70027b2019-09-05 16:50:52 -04001273 fGenerator.write8(fCount);
Ethan Nicholas91164d12019-05-15 15:29:54 -04001274 fGenerator.write8(fIndex);
1275 }
1276
Brian Osman3e29f1d2019-05-28 09:35:05 -04001277 void store(bool discard) override {
1278 if (!discard) {
1279 fGenerator.write(vector_instruction(ByteCodeInstruction::kDup, fCount));
Ethan Nicholasc70027b2019-09-05 16:50:52 -04001280 fGenerator.write8(fCount);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001281 }
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001282 fGenerator.write(vector_instruction(ByteCodeInstruction::kWriteExternal, fCount));
Ethan Nicholasc70027b2019-09-05 16:50:52 -04001283 fGenerator.write8(fCount);
Ethan Nicholas91164d12019-05-15 15:29:54 -04001284 fGenerator.write8(fIndex);
1285 }
1286
1287private:
1288 typedef LValue INHERITED;
1289
1290 int fCount;
1291
1292 int fIndex;
1293};
1294
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001295class ByteCodeSwizzleLValue : public ByteCodeGenerator::LValue {
1296public:
1297 ByteCodeSwizzleLValue(ByteCodeGenerator* generator, const Swizzle& swizzle)
1298 : INHERITED(*generator)
Brian Osman07c117b2019-05-23 12:51:06 -07001299 , fSwizzle(swizzle) {}
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001300
1301 void load() override {
Brian Osman1091f022019-05-16 09:42:16 -04001302 fGenerator.writeSwizzle(fSwizzle);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001303 }
1304
Brian Osman3e29f1d2019-05-28 09:35:05 -04001305 void store(bool discard) override {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001306 int count = fSwizzle.fComponents.size();
Brian Osman3e29f1d2019-05-28 09:35:05 -04001307 if (!discard) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001308 fGenerator.write(vector_instruction(ByteCodeInstruction::kDup, count));
Ethan Nicholasc70027b2019-09-05 16:50:52 -04001309 fGenerator.write8(count);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001310 }
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(*fSwizzle.fBase, &storage);
1313 bool isGlobal = storage == Variable::kGlobal_Storage;
1314 if (location < 0) {
1315 fGenerator.write(isGlobal ? ByteCodeInstruction::kStoreSwizzleIndirectGlobal
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001316 : ByteCodeInstruction::kStoreSwizzleIndirect,
1317 count);
Brian Osman07c117b2019-05-23 12:51:06 -07001318 } else {
1319 fGenerator.write(isGlobal ? ByteCodeInstruction::kStoreSwizzleGlobal
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001320 : ByteCodeInstruction::kStoreSwizzle,
1321 count);
Brian Osman07c117b2019-05-23 12:51:06 -07001322 fGenerator.write8(location);
1323 }
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001324 fGenerator.write8(count);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001325 for (int c : fSwizzle.fComponents) {
1326 fGenerator.write8(c);
1327 }
1328 }
1329
1330private:
1331 const Swizzle& fSwizzle;
1332
1333 typedef LValue INHERITED;
1334};
1335
Brian Osman07c117b2019-05-23 12:51:06 -07001336class ByteCodeExpressionLValue : public ByteCodeGenerator::LValue {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001337public:
Brian Osman07c117b2019-05-23 12:51:06 -07001338 ByteCodeExpressionLValue(ByteCodeGenerator* generator, const Expression& expr)
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001339 : INHERITED(*generator)
Brian Osman07c117b2019-05-23 12:51:06 -07001340 , fExpression(expr) {}
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001341
1342 void load() override {
Brian Osman07c117b2019-05-23 12:51:06 -07001343 fGenerator.writeVariableExpression(fExpression);
Brian Osman1091f022019-05-16 09:42:16 -04001344 }
1345
Brian Osman3e29f1d2019-05-28 09:35:05 -04001346 void store(bool discard) override {
Brian Osman07c117b2019-05-23 12:51:06 -07001347 int count = ByteCodeGenerator::SlotCount(fExpression.fType);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001348 if (!discard) {
1349 if (count > 4) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001350 fGenerator.write(ByteCodeInstruction::kDupN, count);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001351 fGenerator.write8(count);
1352 } else {
1353 fGenerator.write(vector_instruction(ByteCodeInstruction::kDup, count));
Ethan Nicholasc70027b2019-09-05 16:50:52 -04001354 fGenerator.write8(count);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001355 }
Brian Osman07c117b2019-05-23 12:51:06 -07001356 }
Brian Osman869a3e82019-07-18 17:00:34 -04001357 Variable::Storage storage = Variable::kLocal_Storage;
Brian Osman07c117b2019-05-23 12:51:06 -07001358 int location = fGenerator.getLocation(fExpression, &storage);
1359 bool isGlobal = storage == Variable::kGlobal_Storage;
1360 if (location < 0 || count > 4) {
1361 if (location >= 0) {
1362 fGenerator.write(ByteCodeInstruction::kPushImmediate);
1363 fGenerator.write32(location);
1364 }
1365 fGenerator.write(isGlobal ? ByteCodeInstruction::kStoreExtendedGlobal
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001366 : ByteCodeInstruction::kStoreExtended,
1367 count);
Brian Osman07c117b2019-05-23 12:51:06 -07001368 fGenerator.write8(count);
1369 } else {
1370 fGenerator.write(vector_instruction(isGlobal ? ByteCodeInstruction::kStoreGlobal
1371 : ByteCodeInstruction::kStore,
1372 count));
1373 fGenerator.write8(location);
1374 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001375 }
1376
1377private:
1378 typedef LValue INHERITED;
1379
Brian Osman07c117b2019-05-23 12:51:06 -07001380 const Expression& fExpression;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001381};
1382
1383std::unique_ptr<ByteCodeGenerator::LValue> ByteCodeGenerator::getLValue(const Expression& e) {
1384 switch (e.fKind) {
Ethan Nicholas91164d12019-05-15 15:29:54 -04001385 case Expression::kExternalValue_Kind: {
1386 ExternalValue* value = ((ExternalValueReference&) e).fValue;
1387 int index = fOutput->fExternalValues.size();
1388 fOutput->fExternalValues.push_back(value);
1389 SkASSERT(index <= 255);
1390 return std::unique_ptr<LValue>(new ByteCodeExternalValueLValue(this, *value, index));
1391 }
Brian Osman07c117b2019-05-23 12:51:06 -07001392 case Expression::kFieldAccess_Kind:
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001393 case Expression::kIndex_Kind:
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001394 case Expression::kVariableReference_Kind:
Brian Osman07c117b2019-05-23 12:51:06 -07001395 return std::unique_ptr<LValue>(new ByteCodeExpressionLValue(this, e));
Brian Osman0785db02019-05-24 14:19:11 -04001396 case Expression::kSwizzle_Kind: {
1397 const Swizzle& s = (const Swizzle&) e;
1398 return swizzle_is_simple(s)
1399 ? std::unique_ptr<LValue>(new ByteCodeExpressionLValue(this, e))
1400 : std::unique_ptr<LValue>(new ByteCodeSwizzleLValue(this, s));
1401 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001402 case Expression::kTernary_Kind:
1403 default:
1404 printf("unsupported lvalue %s\n", e.description().c_str());
1405 return nullptr;
1406 }
1407}
1408
1409void ByteCodeGenerator::writeBlock(const Block& b) {
1410 for (const auto& s : b.fStatements) {
1411 this->writeStatement(*s);
1412 }
1413}
1414
1415void ByteCodeGenerator::setBreakTargets() {
1416 std::vector<DeferredLocation>& breaks = fBreakTargets.top();
1417 for (DeferredLocation& b : breaks) {
1418 b.set();
1419 }
1420 fBreakTargets.pop();
1421}
1422
1423void ByteCodeGenerator::setContinueTargets() {
1424 std::vector<DeferredLocation>& continues = fContinueTargets.top();
1425 for (DeferredLocation& c : continues) {
1426 c.set();
1427 }
1428 fContinueTargets.pop();
1429}
1430
1431void ByteCodeGenerator::writeBreakStatement(const BreakStatement& b) {
Brian Osman569f12f2019-06-13 11:23:57 -04001432 // TODO: Include BranchIfAllFalse to top-most LoopNext
1433 this->write(ByteCodeInstruction::kLoopBreak);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001434}
1435
1436void ByteCodeGenerator::writeContinueStatement(const ContinueStatement& c) {
Brian Osman569f12f2019-06-13 11:23:57 -04001437 // TODO: Include BranchIfAllFalse to top-most LoopNext
1438 this->write(ByteCodeInstruction::kLoopContinue);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001439}
1440
1441void ByteCodeGenerator::writeDoStatement(const DoStatement& d) {
Brian Osman569f12f2019-06-13 11:23:57 -04001442 this->write(ByteCodeInstruction::kLoopBegin);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001443 size_t start = fCode->size();
1444 this->writeStatement(*d.fStatement);
Brian Osman569f12f2019-06-13 11:23:57 -04001445 this->write(ByteCodeInstruction::kLoopNext);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001446 this->writeExpression(*d.fTest);
Brian Osman569f12f2019-06-13 11:23:57 -04001447 this->write(ByteCodeInstruction::kLoopMask);
1448 // TODO: Could shorten this with kBranchIfAnyTrue
1449 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1450 DeferredLocation endLocation(this);
1451 this->write(ByteCodeInstruction::kBranch);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001452 this->write16(start);
Brian Osman569f12f2019-06-13 11:23:57 -04001453 endLocation.set();
1454 this->write(ByteCodeInstruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001455}
1456
1457void ByteCodeGenerator::writeForStatement(const ForStatement& f) {
1458 fContinueTargets.emplace();
1459 fBreakTargets.emplace();
1460 if (f.fInitializer) {
1461 this->writeStatement(*f.fInitializer);
1462 }
Brian Osman569f12f2019-06-13 11:23:57 -04001463 this->write(ByteCodeInstruction::kLoopBegin);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001464 size_t start = fCode->size();
1465 if (f.fTest) {
1466 this->writeExpression(*f.fTest);
Brian Osman569f12f2019-06-13 11:23:57 -04001467 this->write(ByteCodeInstruction::kLoopMask);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001468 }
Brian Osman569f12f2019-06-13 11:23:57 -04001469 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1470 DeferredLocation endLocation(this);
1471 this->writeStatement(*f.fStatement);
1472 this->write(ByteCodeInstruction::kLoopNext);
1473 if (f.fNext) {
1474 this->writeExpression(*f.fNext, true);
1475 }
1476 this->write(ByteCodeInstruction::kBranch);
1477 this->write16(start);
1478 endLocation.set();
1479 this->write(ByteCodeInstruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001480}
1481
1482void ByteCodeGenerator::writeIfStatement(const IfStatement& i) {
Brian Osman569f12f2019-06-13 11:23:57 -04001483 this->writeExpression(*i.fTest);
1484 this->write(ByteCodeInstruction::kMaskPush);
1485 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1486 DeferredLocation falseLocation(this);
1487 this->writeStatement(*i.fIfTrue);
1488 falseLocation.set();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001489 if (i.fIfFalse) {
Brian Osman569f12f2019-06-13 11:23:57 -04001490 this->write(ByteCodeInstruction::kMaskNegate);
1491 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1492 DeferredLocation endLocation(this);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001493 this->writeStatement(*i.fIfFalse);
Mike Kleinb45ee832019-05-17 11:11:11 -05001494 endLocation.set();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001495 }
Brian Osman569f12f2019-06-13 11:23:57 -04001496 this->write(ByteCodeInstruction::kMaskPop);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001497}
1498
1499void ByteCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
Brian Osman4a47da72019-07-12 11:30:32 -04001500 if (fLoopCount || fConditionCount) {
1501 fErrors.error(r.fOffset, "return not allowed inside conditional or loop");
1502 return;
1503 }
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001504 int count = SlotCount(r.fExpression->fType);
Ethan Nicholas746035a2019-04-23 13:31:09 -04001505 this->writeExpression(*r.fExpression);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001506
1507 // Technically, the kReturn also pops fOutput->fLocalCount values from the stack, too, but we
1508 // haven't counted pushing those (they're outside the scope of our stack tracking). Instead,
1509 // we account for those in writeFunction().
1510
1511 // This is all fine because we don't allow conditional returns, so we only return once anyway.
1512 this->write(ByteCodeInstruction::kReturn, -count);
1513 this->write8(count);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001514}
1515
1516void ByteCodeGenerator::writeSwitchStatement(const SwitchStatement& r) {
1517 // not yet implemented
1518 abort();
1519}
1520
1521void ByteCodeGenerator::writeVarDeclarations(const VarDeclarations& v) {
1522 for (const auto& declStatement : v.fVars) {
1523 const VarDeclaration& decl = (VarDeclaration&) *declStatement;
1524 // we need to grab the location even if we don't use it, to ensure it
1525 // has been allocated
1526 int location = getLocation(*decl.fVar);
1527 if (decl.fValue) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001528 this->writeExpression(*decl.fValue);
Brian Osman07c117b2019-05-23 12:51:06 -07001529 int count = SlotCount(decl.fValue->fType);
1530 if (count > 4) {
1531 this->write(ByteCodeInstruction::kPushImmediate);
1532 this->write32(location);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001533 this->write(ByteCodeInstruction::kStoreExtended, count);
Brian Osman07c117b2019-05-23 12:51:06 -07001534 this->write8(count);
1535 } else {
1536 this->write(vector_instruction(ByteCodeInstruction::kStore, count));
1537 this->write8(location);
1538 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001539 }
1540 }
1541}
1542
1543void ByteCodeGenerator::writeWhileStatement(const WhileStatement& w) {
Brian Osman569f12f2019-06-13 11:23:57 -04001544 this->write(ByteCodeInstruction::kLoopBegin);
1545 size_t cond = fCode->size();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001546 this->writeExpression(*w.fTest);
Brian Osman569f12f2019-06-13 11:23:57 -04001547 this->write(ByteCodeInstruction::kLoopMask);
1548 this->write(ByteCodeInstruction::kBranchIfAllFalse);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001549 DeferredLocation endLocation(this);
1550 this->writeStatement(*w.fStatement);
Brian Osman569f12f2019-06-13 11:23:57 -04001551 this->write(ByteCodeInstruction::kLoopNext);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001552 this->write(ByteCodeInstruction::kBranch);
Brian Osman569f12f2019-06-13 11:23:57 -04001553 this->write16(cond);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001554 endLocation.set();
Brian Osman569f12f2019-06-13 11:23:57 -04001555 this->write(ByteCodeInstruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001556}
1557
1558void ByteCodeGenerator::writeStatement(const Statement& s) {
1559 switch (s.fKind) {
1560 case Statement::kBlock_Kind:
1561 this->writeBlock((Block&) s);
1562 break;
1563 case Statement::kBreak_Kind:
1564 this->writeBreakStatement((BreakStatement&) s);
1565 break;
1566 case Statement::kContinue_Kind:
1567 this->writeContinueStatement((ContinueStatement&) s);
1568 break;
1569 case Statement::kDiscard_Kind:
1570 // not yet implemented
1571 abort();
1572 case Statement::kDo_Kind:
1573 this->writeDoStatement((DoStatement&) s);
1574 break;
Brian Osman3e29f1d2019-05-28 09:35:05 -04001575 case Statement::kExpression_Kind:
1576 this->writeExpression(*((ExpressionStatement&) s).fExpression, true);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001577 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001578 case Statement::kFor_Kind:
1579 this->writeForStatement((ForStatement&) s);
1580 break;
1581 case Statement::kIf_Kind:
1582 this->writeIfStatement((IfStatement&) s);
1583 break;
1584 case Statement::kNop_Kind:
1585 break;
1586 case Statement::kReturn_Kind:
1587 this->writeReturnStatement((ReturnStatement&) s);
1588 break;
1589 case Statement::kSwitch_Kind:
1590 this->writeSwitchStatement((SwitchStatement&) s);
1591 break;
1592 case Statement::kVarDeclarations_Kind:
1593 this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration);
1594 break;
1595 case Statement::kWhile_Kind:
1596 this->writeWhileStatement((WhileStatement&) s);
1597 break;
1598 default:
1599 SkASSERT(false);
1600 }
1601}
1602
Brian Osman80164412019-06-07 13:00:23 -04001603ByteCodeFunction::ByteCodeFunction(const FunctionDeclaration* declaration)
1604 : fName(declaration->fName) {
1605 fParameterCount = 0;
1606 for (const auto& p : declaration->fParameters) {
1607 int slots = ByteCodeGenerator::SlotCount(p->fType);
1608 fParameters.push_back({ slots, (bool)(p->fModifiers.fFlags & Modifiers::kOut_Flag) });
1609 fParameterCount += slots;
1610 }
1611}
1612
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001613}