blob: b44b6c9f0e25bb7d528c4f956eb2ec4bafe92d42 [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;
Brian Osman4c2146f2019-09-24 09:39:38 -0400212 case ByteCodeInstruction::kShiftLeft: return 0;
213 case ByteCodeInstruction::kShiftRightS: return 0;
214 case ByteCodeInstruction::kShiftRightU: return 0;
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400215
216#undef VECTOR_UNARY_OP
217
218 // Binary functions/operators that do a 2 -> 1 reduction (possibly N times)
219#define VECTOR_BINARY_OP(base) \
220 case ByteCodeInstruction::base: return -1; \
221 case ByteCodeInstruction::base ## 2: return -2; \
222 case ByteCodeInstruction::base ## 3: return -3; \
223 case ByteCodeInstruction::base ## 4: return -4;
224
225#define VECTOR_MATRIX_BINARY_OP(base) \
226 VECTOR_BINARY_OP(base) \
227 case ByteCodeInstruction::base ## N: return -count;
228
229 case ByteCodeInstruction::kAndB: return -1;
230 case ByteCodeInstruction::kOrB: return -1;
231 case ByteCodeInstruction::kXorB: return -1;
232
233 VECTOR_BINARY_OP(kAddI)
234 VECTOR_MATRIX_BINARY_OP(kAddF)
235
236 VECTOR_BINARY_OP(kCompareIEQ)
237 VECTOR_MATRIX_BINARY_OP(kCompareFEQ)
238 VECTOR_BINARY_OP(kCompareINEQ)
239 VECTOR_MATRIX_BINARY_OP(kCompareFNEQ)
240 VECTOR_BINARY_OP(kCompareSGT)
241 VECTOR_BINARY_OP(kCompareUGT)
242 VECTOR_BINARY_OP(kCompareFGT)
243 VECTOR_BINARY_OP(kCompareSGTEQ)
244 VECTOR_BINARY_OP(kCompareUGTEQ)
245 VECTOR_BINARY_OP(kCompareFGTEQ)
246 VECTOR_BINARY_OP(kCompareSLT)
247 VECTOR_BINARY_OP(kCompareULT)
248 VECTOR_BINARY_OP(kCompareFLT)
249 VECTOR_BINARY_OP(kCompareSLTEQ)
250 VECTOR_BINARY_OP(kCompareULTEQ)
251 VECTOR_BINARY_OP(kCompareFLTEQ)
252
253 VECTOR_BINARY_OP(kDivideS)
254 VECTOR_BINARY_OP(kDivideU)
255 VECTOR_MATRIX_BINARY_OP(kDivideF)
256 VECTOR_BINARY_OP(kMultiplyI)
257 VECTOR_MATRIX_BINARY_OP(kMultiplyF)
258 VECTOR_BINARY_OP(kRemainderF)
259 VECTOR_BINARY_OP(kRemainderS)
260 VECTOR_BINARY_OP(kRemainderU)
261 VECTOR_BINARY_OP(kSubtractI)
262 VECTOR_MATRIX_BINARY_OP(kSubtractF)
263
264#undef VECTOR_BINARY_OP
265#undef VECTOR_MATRIX_BINARY_OP
266
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400267 // Ops that push or load data to grow the stack:
268 case ByteCodeInstruction::kDup:
269 case ByteCodeInstruction::kLoad:
270 case ByteCodeInstruction::kLoadGlobal:
271 case ByteCodeInstruction::kReadExternal:
272 case ByteCodeInstruction::kPushImmediate:
273 return 1;
274
275 case ByteCodeInstruction::kDup2:
276 case ByteCodeInstruction::kLoad2:
277 case ByteCodeInstruction::kLoadGlobal2:
278 case ByteCodeInstruction::kReadExternal2:
279 return 2;
280
281 case ByteCodeInstruction::kDup3:
282 case ByteCodeInstruction::kLoad3:
283 case ByteCodeInstruction::kLoadGlobal3:
284 case ByteCodeInstruction::kReadExternal3:
285 return 3;
286
287 case ByteCodeInstruction::kDup4:
288 case ByteCodeInstruction::kLoad4:
289 case ByteCodeInstruction::kLoadGlobal4:
290 case ByteCodeInstruction::kReadExternal4:
291 return 4;
292
293 case ByteCodeInstruction::kDupN:
294 case ByteCodeInstruction::kLoadSwizzle:
295 case ByteCodeInstruction::kLoadSwizzleGlobal:
296 return count;
297
298 // Pushes 'count' values, minus one for the 'address' that's consumed first
299 case ByteCodeInstruction::kLoadExtended:
300 case ByteCodeInstruction::kLoadExtendedGlobal:
301 return count - 1;
302
303 // Ops that pop or store data to shrink the stack:
304 case ByteCodeInstruction::kPop:
305 case ByteCodeInstruction::kStore:
306 case ByteCodeInstruction::kStoreGlobal:
307 case ByteCodeInstruction::kWriteExternal:
308 return -1;
309
310 case ByteCodeInstruction::kPop2:
311 case ByteCodeInstruction::kStore2:
312 case ByteCodeInstruction::kStoreGlobal2:
313 case ByteCodeInstruction::kWriteExternal2:
314 return -2;
315
316 case ByteCodeInstruction::kPop3:
317 case ByteCodeInstruction::kStore3:
318 case ByteCodeInstruction::kStoreGlobal3:
319 case ByteCodeInstruction::kWriteExternal3:
320 return -3;
321
322 case ByteCodeInstruction::kPop4:
323 case ByteCodeInstruction::kStore4:
324 case ByteCodeInstruction::kStoreGlobal4:
325 case ByteCodeInstruction::kWriteExternal4:
326 return -4;
327
328 case ByteCodeInstruction::kPopN:
329 case ByteCodeInstruction::kStoreSwizzle:
330 case ByteCodeInstruction::kStoreSwizzleGlobal:
331 return -count;
332
333 // Consumes 'count' values, plus one for the 'address'
334 case ByteCodeInstruction::kStoreExtended:
335 case ByteCodeInstruction::kStoreExtendedGlobal:
336 case ByteCodeInstruction::kStoreSwizzleIndirect:
337 case ByteCodeInstruction::kStoreSwizzleIndirectGlobal:
338 return -count - 1;
339
340 // Strange ops where the caller computes the delta for us:
341 case ByteCodeInstruction::kCallExternal:
342 case ByteCodeInstruction::kMatrixToMatrix:
343 case ByteCodeInstruction::kMatrixMultiply:
344 case ByteCodeInstruction::kReserve:
345 case ByteCodeInstruction::kReturn:
346 case ByteCodeInstruction::kScalarToMatrix:
347 case ByteCodeInstruction::kSwizzle:
348 return count;
349
350 // Miscellaneous
351
352 // kCall is net-zero. Max stack depth is adjusted in writeFunctionCall.
353 case ByteCodeInstruction::kCall: return 0;
354 case ByteCodeInstruction::kBranch: return 0;
355 case ByteCodeInstruction::kBranchIfAllFalse: return 0;
356
357 case ByteCodeInstruction::kMaskPush: return -1;
358 case ByteCodeInstruction::kMaskPop: return 0;
359 case ByteCodeInstruction::kMaskNegate: return 0;
360 case ByteCodeInstruction::kMaskBlend: return -count;
361
362 case ByteCodeInstruction::kLoopBegin: return 0;
363 case ByteCodeInstruction::kLoopNext: return 0;
364 case ByteCodeInstruction::kLoopMask: return -1;
365 case ByteCodeInstruction::kLoopEnd: return 0;
366 case ByteCodeInstruction::kLoopBreak: return 0;
367 case ByteCodeInstruction::kLoopContinue: return 0;
368
369 default:
Brian Osmanc7ec9e22019-07-16 08:49:11 -0400370 ABORT("unsupported instruction %d\n", (int)inst);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400371 return 0;
372 }
373}
374
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400375int ByteCodeGenerator::getLocation(const Variable& var) {
376 // given that we seldom have more than a couple of variables, linear search is probably the most
377 // efficient way to handle lookups
378 switch (var.fStorage) {
379 case Variable::kLocal_Storage: {
380 for (int i = fLocals.size() - 1; i >= 0; --i) {
381 if (fLocals[i] == &var) {
Brian Osman1091f022019-05-16 09:42:16 -0400382 SkASSERT(fParameterCount + i <= 255);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400383 return fParameterCount + i;
384 }
385 }
386 int result = fParameterCount + fLocals.size();
387 fLocals.push_back(&var);
Brian Osman07c117b2019-05-23 12:51:06 -0700388 for (int i = 0; i < SlotCount(var.fType) - 1; ++i) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400389 fLocals.push_back(nullptr);
390 }
Brian Osman1091f022019-05-16 09:42:16 -0400391 SkASSERT(result <= 255);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400392 return result;
393 }
394 case Variable::kParameter_Storage: {
395 int offset = 0;
396 for (const auto& p : fFunction->fDeclaration.fParameters) {
397 if (p == &var) {
Brian Osman1091f022019-05-16 09:42:16 -0400398 SkASSERT(offset <= 255);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400399 return offset;
400 }
Brian Osman07c117b2019-05-23 12:51:06 -0700401 offset += SlotCount(p->fType);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400402 }
403 SkASSERT(false);
Brian Osman1091f022019-05-16 09:42:16 -0400404 return 0;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400405 }
406 case Variable::kGlobal_Storage: {
407 int offset = 0;
408 for (const auto& e : fProgram) {
409 if (e.fKind == ProgramElement::kVar_Kind) {
410 VarDeclarations& decl = (VarDeclarations&) e;
411 for (const auto& v : decl.fVars) {
412 const Variable* declVar = ((VarDeclaration&) *v).fVar;
413 if (declVar->fModifiers.fLayout.fBuiltin >= 0) {
414 continue;
415 }
416 if (declVar == &var) {
Brian Osmanb7451292019-05-15 13:02:13 -0400417 SkASSERT(offset <= 255);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400418 return offset;
419 }
Brian Osman07c117b2019-05-23 12:51:06 -0700420 offset += SlotCount(declVar->fType);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400421 }
422 }
423 }
424 SkASSERT(false);
Brian Osman1091f022019-05-16 09:42:16 -0400425 return 0;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400426 }
427 default:
428 SkASSERT(false);
429 return 0;
430 }
431}
432
Brian Osman07c117b2019-05-23 12:51:06 -0700433int ByteCodeGenerator::getLocation(const Expression& expr, Variable::Storage* storage) {
434 switch (expr.fKind) {
435 case Expression::kFieldAccess_Kind: {
436 const FieldAccess& f = (const FieldAccess&)expr;
437 int baseAddr = this->getLocation(*f.fBase, storage);
438 int offset = 0;
439 for (int i = 0; i < f.fFieldIndex; ++i) {
440 offset += SlotCount(*f.fBase->fType.fields()[i].fType);
441 }
442 if (baseAddr < 0) {
Brian Osman86769292019-06-21 11:05:47 -0400443 if (offset != 0) {
444 this->write(ByteCodeInstruction::kPushImmediate);
445 this->write32(offset);
446 this->write(ByteCodeInstruction::kAddI);
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400447 this->write8(1);
Brian Osman86769292019-06-21 11:05:47 -0400448 }
Brian Osman07c117b2019-05-23 12:51:06 -0700449 return -1;
450 } else {
451 return baseAddr + offset;
452 }
453 }
454 case Expression::kIndex_Kind: {
455 const IndexExpression& i = (const IndexExpression&)expr;
456 int stride = SlotCount(i.fType);
Brian Osman869a3e82019-07-18 17:00:34 -0400457 int length = i.fBase->fType.columns();
458 SkASSERT(length <= 255);
Brian Osman07c117b2019-05-23 12:51:06 -0700459 int offset = -1;
460 if (i.fIndex->isConstant()) {
Brian Osman869a3e82019-07-18 17:00:34 -0400461 int64_t index = i.fIndex->getConstantInt();
462 if (index < 0 || index >= length) {
463 fErrors.error(i.fIndex->fOffset, "Array index out of bounds.");
464 return 0;
465 }
466 offset = index * stride;
Brian Osman07c117b2019-05-23 12:51:06 -0700467 } else {
Brian Osman86769292019-06-21 11:05:47 -0400468 if (i.fIndex->hasSideEffects()) {
469 // Having a side-effect in an indexer is technically safe for an rvalue,
470 // but with lvalues we have to evaluate the indexer twice, so make it an error.
471 fErrors.error(i.fIndex->fOffset,
472 "Index expressions with side-effects not supported in byte code.");
473 return 0;
474 }
Brian Osman07c117b2019-05-23 12:51:06 -0700475 this->writeExpression(*i.fIndex);
Brian Osman869a3e82019-07-18 17:00:34 -0400476 this->write(ByteCodeInstruction::kClampIndex);
477 this->write8(length);
Brian Osman86769292019-06-21 11:05:47 -0400478 if (stride != 1) {
479 this->write(ByteCodeInstruction::kPushImmediate);
480 this->write32(stride);
481 this->write(ByteCodeInstruction::kMultiplyI);
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400482 this->write8(1);
Brian Osman86769292019-06-21 11:05:47 -0400483 }
Brian Osman07c117b2019-05-23 12:51:06 -0700484 }
485 int baseAddr = this->getLocation(*i.fBase, storage);
Brian Osman86769292019-06-21 11:05:47 -0400486
487 // Are both components known statically?
Brian Osman07c117b2019-05-23 12:51:06 -0700488 if (baseAddr >= 0 && offset >= 0) {
489 return baseAddr + offset;
490 }
Brian Osman86769292019-06-21 11:05:47 -0400491
492 // At least one component is dynamic (and on the stack).
493
494 // If the other component is zero, we're done
495 if (baseAddr == 0 || offset == 0) {
496 return -1;
497 }
498
499 // Push the non-dynamic component (if any) to the stack, then add the two
Brian Osman07c117b2019-05-23 12:51:06 -0700500 if (baseAddr >= 0) {
501 this->write(ByteCodeInstruction::kPushImmediate);
502 this->write32(baseAddr);
503 }
504 if (offset >= 0) {
505 this->write(ByteCodeInstruction::kPushImmediate);
506 this->write32(offset);
507 }
508 this->write(ByteCodeInstruction::kAddI);
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400509 this->write8(1);
Brian Osman07c117b2019-05-23 12:51:06 -0700510 return -1;
511 }
Brian Osman0785db02019-05-24 14:19:11 -0400512 case Expression::kSwizzle_Kind: {
513 const Swizzle& s = (const Swizzle&)expr;
514 SkASSERT(swizzle_is_simple(s));
515 int baseAddr = this->getLocation(*s.fBase, storage);
516 int offset = s.fComponents[0];
517 if (baseAddr < 0) {
Brian Osman86769292019-06-21 11:05:47 -0400518 if (offset != 0) {
519 this->write(ByteCodeInstruction::kPushImmediate);
520 this->write32(offset);
521 this->write(ByteCodeInstruction::kAddI);
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400522 this->write8(1);
Brian Osman86769292019-06-21 11:05:47 -0400523 }
Brian Osman0785db02019-05-24 14:19:11 -0400524 return -1;
525 } else {
526 return baseAddr + offset;
527 }
528 }
Brian Osman07c117b2019-05-23 12:51:06 -0700529 case Expression::kVariableReference_Kind: {
530 const Variable& var = ((const VariableReference&)expr).fVariable;
531 *storage = var.fStorage;
532 return this->getLocation(var);
533 }
534 default:
535 SkASSERT(false);
536 return 0;
537 }
538}
539
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400540void ByteCodeGenerator::write8(uint8_t b) {
541 fCode->push_back(b);
542}
543
544void ByteCodeGenerator::write16(uint16_t i) {
Mike Klein76346ac2019-05-17 11:57:10 -0500545 size_t n = fCode->size();
546 fCode->resize(n+2);
547 memcpy(fCode->data() + n, &i, 2);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400548}
549
550void ByteCodeGenerator::write32(uint32_t i) {
Mike Klein76346ac2019-05-17 11:57:10 -0500551 size_t n = fCode->size();
552 fCode->resize(n+4);
553 memcpy(fCode->data() + n, &i, 4);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400554}
555
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400556void ByteCodeGenerator::write(ByteCodeInstruction i, int count) {
Brian Osman4a47da72019-07-12 11:30:32 -0400557 switch (i) {
558 case ByteCodeInstruction::kLoopBegin: this->enterLoop(); break;
559 case ByteCodeInstruction::kLoopEnd: this->exitLoop(); break;
560
561 case ByteCodeInstruction::kMaskPush: this->enterCondition(); break;
562 case ByteCodeInstruction::kMaskPop:
563 case ByteCodeInstruction::kMaskBlend: this->exitCondition(); break;
564 default: /* Do nothing */ break;
565 }
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400566 instruction val = (instruction) i;
567 size_t n = fCode->size();
568 fCode->resize(n + sizeof(val));
569 memcpy(fCode->data() + n, &val, sizeof(val));
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400570 fStackCount += StackUsage(i, count);
571 fMaxStackCount = std::max(fMaxStackCount, fStackCount);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400572}
573
Mike Klein76346ac2019-05-17 11:57:10 -0500574static ByteCodeInstruction vector_instruction(ByteCodeInstruction base, int count) {
Brian Osman07c117b2019-05-23 12:51:06 -0700575 SkASSERT(count >= 1 && count <= 4);
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400576 return ((ByteCodeInstruction) ((int) base + 1 - count));
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400577}
578
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400579void ByteCodeGenerator::writeTypedInstruction(const Type& type, ByteCodeInstruction s,
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400580 ByteCodeInstruction u, ByteCodeInstruction f,
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400581 int count, bool writeCount) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400582 switch (type_category(type)) {
583 case TypeCategory::kSigned:
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400584 this->write(vector_instruction(s, count));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400585 break;
586 case TypeCategory::kUnsigned:
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400587 this->write(vector_instruction(u, count));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400588 break;
Brian Osman1e855b22019-05-29 15:21:52 -0400589 case TypeCategory::kFloat: {
590 if (count > 4) {
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400591 this->write((ByteCodeInstruction)((int)f + 1), count);
Brian Osman1e855b22019-05-29 15:21:52 -0400592 } else {
593 this->write(vector_instruction(f, count));
594 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400595 break;
Brian Osman1e855b22019-05-29 15:21:52 -0400596 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400597 default:
598 SkASSERT(false);
599 }
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400600 if (writeCount) {
601 this->write8(count);
602 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400603}
604
Brian Osman3e29f1d2019-05-28 09:35:05 -0400605bool ByteCodeGenerator::writeBinaryExpression(const BinaryExpression& b, bool discard) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400606 if (b.fOperator == Token::Kind::EQ) {
607 std::unique_ptr<LValue> lvalue = this->getLValue(*b.fLeft);
608 this->writeExpression(*b.fRight);
Brian Osman3e29f1d2019-05-28 09:35:05 -0400609 lvalue->store(discard);
610 discard = false;
611 return discard;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400612 }
Brian Osman16e6fd52019-05-29 11:19:00 -0400613 const Type& lType = b.fLeft->fType;
614 const Type& rType = b.fRight->fType;
Brian Osman909231c2019-05-29 15:34:36 -0400615 bool lVecOrMtx = (lType.kind() == Type::kVector_Kind || lType.kind() == Type::kMatrix_Kind);
616 bool rVecOrMtx = (rType.kind() == Type::kVector_Kind || rType.kind() == Type::kMatrix_Kind);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400617 Token::Kind op;
618 std::unique_ptr<LValue> lvalue;
619 if (is_assignment(b.fOperator)) {
620 lvalue = this->getLValue(*b.fLeft);
621 lvalue->load();
622 op = remove_assignment(b.fOperator);
623 } else {
624 this->writeExpression(*b.fLeft);
625 op = b.fOperator;
Brian Osman909231c2019-05-29 15:34:36 -0400626 if (!lVecOrMtx && rVecOrMtx) {
Brian Osman16e6fd52019-05-29 11:19:00 -0400627 for (int i = SlotCount(rType); i > 1; --i) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400628 this->write(ByteCodeInstruction::kDup);
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400629 this->write8(1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400630 }
631 }
632 }
Ethan Nicholasd166d2e2019-09-23 11:43:45 -0400633 int count = std::max(SlotCount(lType), SlotCount(rType));
Brian Osmane5bbce22019-09-23 12:38:40 -0400634 SkDEBUGCODE(TypeCategory tc = type_category(lType));
Ethan Nicholasd166d2e2019-09-23 11:43:45 -0400635 switch (op) {
636 case Token::Kind::LOGICALAND: {
Brian Osmane5bbce22019-09-23 12:38:40 -0400637 SkASSERT(tc == SkSL::TypeCategory::kBool && count == 1);
Ethan Nicholasd166d2e2019-09-23 11:43:45 -0400638 this->write(ByteCodeInstruction::kDup);
639 this->write8(1);
640 this->write(ByteCodeInstruction::kMaskPush);
641 this->write(ByteCodeInstruction::kBranchIfAllFalse);
642 DeferredLocation falseLocation(this);
643 this->writeExpression(*b.fRight);
644 this->write(ByteCodeInstruction::kAndB);
645 falseLocation.set();
646 this->write(ByteCodeInstruction::kMaskPop);
647 return false;
648 }
649 case Token::Kind::LOGICALOR: {
Brian Osmane5bbce22019-09-23 12:38:40 -0400650 SkASSERT(tc == SkSL::TypeCategory::kBool && count == 1);
Ethan Nicholasd166d2e2019-09-23 11:43:45 -0400651 this->write(ByteCodeInstruction::kDup);
652 this->write8(1);
653 this->write(ByteCodeInstruction::kNotB);
654 this->write(ByteCodeInstruction::kMaskPush);
655 this->write(ByteCodeInstruction::kBranchIfAllFalse);
656 DeferredLocation falseLocation(this);
657 this->writeExpression(*b.fRight);
658 this->write(ByteCodeInstruction::kOrB);
659 falseLocation.set();
660 this->write(ByteCodeInstruction::kMaskPop);
661 return false;
662 }
Brian Osman4c2146f2019-09-24 09:39:38 -0400663 case Token::Kind::SHL:
664 case Token::Kind::SHR: {
665 SkASSERT(count == 1 && (tc == SkSL::TypeCategory::kSigned ||
666 tc == SkSL::TypeCategory::kUnsigned));
667 if (!b.fRight->isConstant()) {
668 fErrors.error(b.fRight->fOffset, "Shift amounts must be constant");
669 return false;
670 }
671 int64_t shift = b.fRight->getConstantInt();
672 if (shift < 0 || shift > 31) {
673 fErrors.error(b.fRight->fOffset, "Shift amount out of range");
674 return false;
675 }
676
677 if (op == Token::Kind::SHL) {
678 this->write(ByteCodeInstruction::kShiftLeft);
679 } else {
680 this->write(type_category(lType) == TypeCategory::kSigned
681 ? ByteCodeInstruction::kShiftRightS
682 : ByteCodeInstruction::kShiftRightU);
683 }
684 this->write8(shift);
685 return false;
686 }
687
Ethan Nicholasd166d2e2019-09-23 11:43:45 -0400688 default:
689 break;
690 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400691 this->writeExpression(*b.fRight);
Brian Osman909231c2019-05-29 15:34:36 -0400692 if (lVecOrMtx && !rVecOrMtx) {
Brian Osman16e6fd52019-05-29 11:19:00 -0400693 for (int i = SlotCount(lType); i > 1; --i) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400694 this->write(ByteCodeInstruction::kDup);
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400695 this->write8(1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400696 }
697 }
Brian Osman909231c2019-05-29 15:34:36 -0400698 // Special case for M*V, V*M, M*M (but not V*V!)
699 if (op == Token::Kind::STAR && lVecOrMtx && rVecOrMtx &&
700 !(lType.kind() == Type::kVector_Kind && rType.kind() == Type::kVector_Kind)) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400701 this->write(ByteCodeInstruction::kMatrixMultiply,
702 SlotCount(b.fType) - (SlotCount(lType) + SlotCount(rType)));
Brian Osman909231c2019-05-29 15:34:36 -0400703 int rCols = rType.columns(),
704 rRows = rType.rows(),
705 lCols = lType.columns(),
706 lRows = lType.rows();
707 // M*V treats the vector as a column
708 if (rType.kind() == Type::kVector_Kind) {
709 std::swap(rCols, rRows);
710 }
711 SkASSERT(lCols == rRows);
712 SkASSERT(SlotCount(b.fType) == lRows * rCols);
713 this->write8(lCols);
714 this->write8(lRows);
715 this->write8(rCols);
716 } else {
Brian Osman909231c2019-05-29 15:34:36 -0400717 switch (op) {
718 case Token::Kind::EQEQ:
719 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareIEQ,
720 ByteCodeInstruction::kCompareIEQ,
721 ByteCodeInstruction::kCompareFEQ,
722 count);
723 // Collapse to a single bool
724 for (int i = count; i > 1; --i) {
725 this->write(ByteCodeInstruction::kAndB);
726 }
727 break;
728 case Token::Kind::GT:
729 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSGT,
730 ByteCodeInstruction::kCompareUGT,
731 ByteCodeInstruction::kCompareFGT,
732 count);
733 break;
734 case Token::Kind::GTEQ:
735 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSGTEQ,
736 ByteCodeInstruction::kCompareUGTEQ,
737 ByteCodeInstruction::kCompareFGTEQ,
738 count);
739 break;
740 case Token::Kind::LT:
741 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSLT,
742 ByteCodeInstruction::kCompareULT,
743 ByteCodeInstruction::kCompareFLT,
744 count);
745 break;
746 case Token::Kind::LTEQ:
747 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSLTEQ,
748 ByteCodeInstruction::kCompareULTEQ,
749 ByteCodeInstruction::kCompareFLTEQ,
750 count);
751 break;
752 case Token::Kind::MINUS:
753 this->writeTypedInstruction(lType, ByteCodeInstruction::kSubtractI,
754 ByteCodeInstruction::kSubtractI,
755 ByteCodeInstruction::kSubtractF,
756 count);
757 break;
758 case Token::Kind::NEQ:
759 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareINEQ,
760 ByteCodeInstruction::kCompareINEQ,
761 ByteCodeInstruction::kCompareFNEQ,
762 count);
763 // Collapse to a single bool
764 for (int i = count; i > 1; --i) {
765 this->write(ByteCodeInstruction::kOrB);
766 }
767 break;
768 case Token::Kind::PERCENT:
769 this->writeTypedInstruction(lType, ByteCodeInstruction::kRemainderS,
770 ByteCodeInstruction::kRemainderU,
771 ByteCodeInstruction::kRemainderF,
772 count);
773 break;
774 case Token::Kind::PLUS:
775 this->writeTypedInstruction(lType, ByteCodeInstruction::kAddI,
776 ByteCodeInstruction::kAddI,
777 ByteCodeInstruction::kAddF,
778 count);
779 break;
780 case Token::Kind::SLASH:
781 this->writeTypedInstruction(lType, ByteCodeInstruction::kDivideS,
782 ByteCodeInstruction::kDivideU,
783 ByteCodeInstruction::kDivideF,
784 count);
785 break;
786 case Token::Kind::STAR:
787 this->writeTypedInstruction(lType, ByteCodeInstruction::kMultiplyI,
788 ByteCodeInstruction::kMultiplyI,
789 ByteCodeInstruction::kMultiplyF,
790 count);
791 break;
Brian Osman569f12f2019-06-13 11:23:57 -0400792
Brian Osman569f12f2019-06-13 11:23:57 -0400793 case Token::Kind::LOGICALXOR:
Brian Osmane5bbce22019-09-23 12:38:40 -0400794 SkASSERT(tc == SkSL::TypeCategory::kBool && count == 1);
795 this->write(ByteCodeInstruction::kXorB);
796 break;
797
798 case Token::Kind::BITWISEAND:
799 SkASSERT(count == 1 && (tc == SkSL::TypeCategory::kSigned ||
800 tc == SkSL::TypeCategory::kUnsigned));
801 this->write(ByteCodeInstruction::kAndB);
802 break;
803 case Token::Kind::BITWISEOR:
804 SkASSERT(count == 1 && (tc == SkSL::TypeCategory::kSigned ||
805 tc == SkSL::TypeCategory::kUnsigned));
806 this->write(ByteCodeInstruction::kOrB);
807 break;
808 case Token::Kind::BITWISEXOR:
809 SkASSERT(count == 1 && (tc == SkSL::TypeCategory::kSigned ||
810 tc == SkSL::TypeCategory::kUnsigned));
Brian Osman569f12f2019-06-13 11:23:57 -0400811 this->write(ByteCodeInstruction::kXorB);
812 break;
813
Brian Osman909231c2019-05-29 15:34:36 -0400814 default:
Brian Osmandb3dad22019-07-26 15:44:29 -0400815 fErrors.error(b.fOffset, SkSL::String::printf("Unsupported binary operator '%s'",
816 Compiler::OperatorName(op)));
817 break;
Brian Osman909231c2019-05-29 15:34:36 -0400818 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400819 }
820 if (lvalue) {
Brian Osman3e29f1d2019-05-28 09:35:05 -0400821 lvalue->store(discard);
822 discard = false;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400823 }
Brian Osman3e29f1d2019-05-28 09:35:05 -0400824 return discard;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400825}
826
827void ByteCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
828 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osman569f12f2019-06-13 11:23:57 -0400829 this->write32(b.fValue ? ~0 : 0);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400830}
831
832void ByteCodeGenerator::writeConstructor(const Constructor& c) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400833 for (const auto& arg : c.fArguments) {
834 this->writeExpression(*arg);
835 }
836 if (c.fArguments.size() == 1) {
Brian Osman29e013d2019-05-28 17:16:03 -0400837 const Type& inType = c.fArguments[0]->fType;
838 const Type& outType = c.fType;
839 TypeCategory inCategory = type_category(inType);
840 TypeCategory outCategory = type_category(outType);
841 int inCount = SlotCount(inType);
842 int outCount = SlotCount(outType);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400843 if (inCategory != outCategory) {
Brian Osmanc51d7912019-05-22 15:16:16 -0700844 SkASSERT(inCount == outCount);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400845 if (inCategory == TypeCategory::kFloat) {
846 SkASSERT(outCategory == TypeCategory::kSigned ||
847 outCategory == TypeCategory::kUnsigned);
Brian Osmanc51d7912019-05-22 15:16:16 -0700848 this->write(vector_instruction(ByteCodeInstruction::kConvertFtoI, outCount));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400849 } else if (outCategory == TypeCategory::kFloat) {
850 if (inCategory == TypeCategory::kSigned) {
Brian Osmanc51d7912019-05-22 15:16:16 -0700851 this->write(vector_instruction(ByteCodeInstruction::kConvertStoF, outCount));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400852 } else {
853 SkASSERT(inCategory == TypeCategory::kUnsigned);
Brian Osmanc51d7912019-05-22 15:16:16 -0700854 this->write(vector_instruction(ByteCodeInstruction::kConvertUtoF, outCount));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400855 }
856 } else {
857 SkASSERT(false);
858 }
859 }
Brian Osman29e013d2019-05-28 17:16:03 -0400860 if (inType.kind() == Type::kMatrix_Kind && outType.kind() == Type::kMatrix_Kind) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400861 this->write(ByteCodeInstruction::kMatrixToMatrix,
862 SlotCount(outType) - SlotCount(inType));
Brian Osman29e013d2019-05-28 17:16:03 -0400863 this->write8(inType.columns());
864 this->write8(inType.rows());
865 this->write8(outType.columns());
866 this->write8(outType.rows());
867 } else if (inCount != outCount) {
Brian Osmanc51d7912019-05-22 15:16:16 -0700868 SkASSERT(inCount == 1);
Brian Osman29e013d2019-05-28 17:16:03 -0400869 if (outType.kind() == Type::kMatrix_Kind) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400870 this->write(ByteCodeInstruction::kScalarToMatrix, SlotCount(outType) - 1);
Brian Osman29e013d2019-05-28 17:16:03 -0400871 this->write8(outType.columns());
872 this->write8(outType.rows());
873 } else {
874 SkASSERT(outType.kind() == Type::kVector_Kind);
875 for (; inCount != outCount; ++inCount) {
876 this->write(ByteCodeInstruction::kDup);
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400877 this->write8(1);
Brian Osman29e013d2019-05-28 17:16:03 -0400878 }
Brian Osmanc51d7912019-05-22 15:16:16 -0700879 }
880 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400881 }
882}
883
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400884void ByteCodeGenerator::writeExternalFunctionCall(const ExternalFunctionCall& f) {
885 int argumentCount = 0;
886 for (const auto& arg : f.fArguments) {
887 this->writeExpression(*arg);
Brian Osman07c117b2019-05-23 12:51:06 -0700888 argumentCount += SlotCount(arg->fType);
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400889 }
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400890 this->write(ByteCodeInstruction::kCallExternal, SlotCount(f.fType) - argumentCount);
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400891 SkASSERT(argumentCount <= 255);
892 this->write8(argumentCount);
Brian Osman07c117b2019-05-23 12:51:06 -0700893 this->write8(SlotCount(f.fType));
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400894 int index = fOutput->fExternalValues.size();
895 fOutput->fExternalValues.push_back(f.fFunction);
896 SkASSERT(index <= 255);
897 this->write8(index);
898}
899
Ethan Nicholas91164d12019-05-15 15:29:54 -0400900void ByteCodeGenerator::writeExternalValue(const ExternalValueReference& e) {
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400901 int count = SlotCount(e.fValue->type());
902 this->write(vector_instruction(ByteCodeInstruction::kReadExternal, count));
903 this->write8(count);
Ethan Nicholas91164d12019-05-15 15:29:54 -0400904 int index = fOutput->fExternalValues.size();
905 fOutput->fExternalValues.push_back(e.fValue);
906 SkASSERT(index <= 255);
907 this->write8(index);
908}
909
Brian Osman07c117b2019-05-23 12:51:06 -0700910void ByteCodeGenerator::writeVariableExpression(const Expression& expr) {
Brian Osman869a3e82019-07-18 17:00:34 -0400911 Variable::Storage storage = Variable::kLocal_Storage;
Brian Osman07c117b2019-05-23 12:51:06 -0700912 int location = this->getLocation(expr, &storage);
913 bool isGlobal = storage == Variable::kGlobal_Storage;
914 int count = SlotCount(expr.fType);
915 if (location < 0 || count > 4) {
916 if (location >= 0) {
917 this->write(ByteCodeInstruction::kPushImmediate);
918 this->write32(location);
919 }
920 this->write(isGlobal ? ByteCodeInstruction::kLoadExtendedGlobal
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400921 : ByteCodeInstruction::kLoadExtended,
922 count);
Brian Osman07c117b2019-05-23 12:51:06 -0700923 this->write8(count);
924 } else {
925 this->write(vector_instruction(isGlobal ? ByteCodeInstruction::kLoadGlobal
926 : ByteCodeInstruction::kLoad,
927 count));
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400928 this->write8(count);
Brian Osman07c117b2019-05-23 12:51:06 -0700929 this->write8(location);
930 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400931}
932
Brian Osmand30e0392019-06-14 14:05:14 -0400933static inline uint32_t float_to_bits(float x) {
934 uint32_t u;
935 memcpy(&u, &x, sizeof(uint32_t));
936 return u;
937}
938
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400939void ByteCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
940 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osmand30e0392019-06-14 14:05:14 -0400941 this->write32(float_to_bits(f.fValue));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400942}
943
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400944void ByteCodeGenerator::writeIntrinsicCall(const FunctionCall& c) {
945 auto found = fIntrinsics.find(c.fFunction.fName);
946 if (found == fIntrinsics.end()) {
947 fErrors.error(c.fOffset, "unsupported intrinsic function");
948 return;
949 }
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400950 int count = SlotCount(c.fArguments[0]->fType);
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400951 if (found->second.fIsSpecial) {
Brian Osmanb380e712019-07-24 17:02:39 -0400952 SpecialIntrinsic special = found->second.fValue.fSpecial;
953 switch (special) {
954 case SpecialIntrinsic::kDot: {
955 SkASSERT(c.fArguments.size() == 2);
956 SkASSERT(count == SlotCount(c.fArguments[1]->fType));
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400957 this->write(vector_instruction(ByteCodeInstruction::kMultiplyF, count));
958 this->write8(count);
Brian Osmanb380e712019-07-24 17:02:39 -0400959 for (int i = count; i > 1; --i) {
960 this->write(ByteCodeInstruction::kAddF);
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400961 this->write8(1);
Brian Osmanb380e712019-07-24 17:02:39 -0400962 }
963 break;
964 }
Brian Osmanb380e712019-07-24 17:02:39 -0400965 default:
966 SkASSERT(false);
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400967 }
968 } else {
969 switch (found->second.fValue.fInstruction) {
970 case ByteCodeInstruction::kCos:
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400971 case ByteCodeInstruction::kSin:
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400972 case ByteCodeInstruction::kTan:
973 SkASSERT(c.fArguments.size() > 0);
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400974 this->write(vector_instruction(found->second.fValue.fInstruction, count));
975 this->write8(count);
976 break;
977 case ByteCodeInstruction::kSqrt:
978 SkASSERT(c.fArguments.size() > 0);
979 this->write(vector_instruction(found->second.fValue.fInstruction, count));
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400980 break;
Mike Reed634c9412019-07-18 13:20:04 -0400981 case ByteCodeInstruction::kInverse2x2: {
982 SkASSERT(c.fArguments.size() > 0);
983 auto op = ByteCodeInstruction::kInverse2x2;
984 switch (count) {
985 case 4: break; // float2x2
986 case 9: op = ByteCodeInstruction::kInverse3x3; break;
987 case 16: op = ByteCodeInstruction::kInverse4x4; break;
988 default: SkASSERT(false);
989 }
990 this->write(op);
Brian Osmanb380e712019-07-24 17:02:39 -0400991 break;
992 }
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400993 default:
994 SkASSERT(false);
995 }
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400996 }
997}
998
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400999void ByteCodeGenerator::writeFunctionCall(const FunctionCall& f) {
Brian Osmand3494ed2019-06-20 15:41:34 -04001000 // Builtins have simple signatures...
Ethan Nicholas82162ee2019-05-21 16:05:08 -04001001 if (f.fFunction.fBuiltin) {
Brian Osmand3494ed2019-06-20 15:41:34 -04001002 for (const auto& arg : f.fArguments) {
1003 this->writeExpression(*arg);
1004 }
Ethan Nicholas82162ee2019-05-21 16:05:08 -04001005 this->writeIntrinsicCall(f);
1006 return;
1007 }
Brian Osmand3494ed2019-06-20 15:41:34 -04001008
Brian Osman6f5358f2019-07-09 14:17:23 -04001009 // Find the index of the function we're calling. We explicitly do not allow calls to functions
1010 // before they're defined. This is an easy-to-understand rule that prevents recursion.
1011 size_t idx;
1012 for (idx = 0; idx < fFunctions.size(); ++idx) {
1013 if (f.fFunction.matches(fFunctions[idx]->fDeclaration)) {
1014 break;
1015 }
1016 }
1017 if (idx > 255) {
1018 fErrors.error(f.fOffset, "Function count limit exceeded");
1019 return;
1020 } else if (idx >= fFunctions.size()) {
1021 fErrors.error(f.fOffset, "Call to undefined function");
1022 return;
1023 }
1024
1025 // We may need to deal with out parameters, so the sequence is tricky
Brian Osmand3494ed2019-06-20 15:41:34 -04001026 if (int returnCount = SlotCount(f.fType)) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001027 this->write(ByteCodeInstruction::kReserve, returnCount);
Brian Osmand3494ed2019-06-20 15:41:34 -04001028 this->write8(returnCount);
1029 }
1030
1031 int argCount = f.fArguments.size();
1032 std::vector<std::unique_ptr<LValue>> lvalues;
1033 for (int i = 0; i < argCount; ++i) {
1034 const auto& param = f.fFunction.fParameters[i];
1035 const auto& arg = f.fArguments[i];
1036 if (param->fModifiers.fFlags & Modifiers::kOut_Flag) {
1037 lvalues.emplace_back(this->getLValue(*arg));
1038 lvalues.back()->load();
1039 } else {
1040 this->writeExpression(*arg);
1041 }
1042 }
1043
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001044 // The space used by the call is based on the callee, but it also unwinds all of that before
1045 // we continue execution. We adjust our max stack depths below.
Brian Osman226668a2019-05-14 16:47:30 -04001046 this->write(ByteCodeInstruction::kCall);
Brian Osman6f5358f2019-07-09 14:17:23 -04001047 this->write8(idx);
Brian Osmand3494ed2019-06-20 15:41:34 -04001048
Brian Osman4a47da72019-07-12 11:30:32 -04001049 const ByteCodeFunction* callee = fOutput->fFunctions[idx].get();
1050 fMaxLoopCount = std::max(fMaxLoopCount, fLoopCount + callee->fLoopCount);
1051 fMaxConditionCount = std::max(fMaxConditionCount, fConditionCount + callee->fConditionCount);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001052 fMaxStackCount = std::max(fMaxStackCount, fStackCount + callee->fLocalCount
1053 + callee->fStackCount);
Brian Osman4a47da72019-07-12 11:30:32 -04001054
Brian Osmand3494ed2019-06-20 15:41:34 -04001055 // After the called function returns, the stack will still contain our arguments. We have to
1056 // pop them (storing any out parameters back to their lvalues as we go). We glob together slot
1057 // counts for all parameters that aren't out-params, so we can pop them in one big chunk.
1058 int popCount = 0;
1059 auto pop = [&]() {
1060 if (popCount > 4) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001061 this->write(ByteCodeInstruction::kPopN, popCount);
Brian Osmand3494ed2019-06-20 15:41:34 -04001062 this->write8(popCount);
1063 } else if (popCount > 0) {
1064 this->write(vector_instruction(ByteCodeInstruction::kPop, popCount));
1065 }
1066 popCount = 0;
1067 };
1068
1069 for (int i = argCount - 1; i >= 0; --i) {
1070 const auto& param = f.fFunction.fParameters[i];
1071 const auto& arg = f.fArguments[i];
1072 if (param->fModifiers.fFlags & Modifiers::kOut_Flag) {
1073 pop();
1074 lvalues.back()->store(true);
1075 lvalues.pop_back();
1076 } else {
1077 popCount += SlotCount(arg->fType);
1078 }
1079 }
1080 pop();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001081}
1082
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001083void ByteCodeGenerator::writeIntLiteral(const IntLiteral& i) {
1084 this->write(ByteCodeInstruction::kPushImmediate);
1085 this->write32(i.fValue);
1086}
1087
1088void ByteCodeGenerator::writeNullLiteral(const NullLiteral& n) {
1089 // not yet implemented
1090 abort();
1091}
1092
Brian Osman3e29f1d2019-05-28 09:35:05 -04001093bool ByteCodeGenerator::writePrefixExpression(const PrefixExpression& p, bool discard) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001094 switch (p.fOperator) {
1095 case Token::Kind::PLUSPLUS: // fall through
1096 case Token::Kind::MINUSMINUS: {
Brian Osman07c117b2019-05-23 12:51:06 -07001097 SkASSERT(SlotCount(p.fOperand->fType) == 1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001098 std::unique_ptr<LValue> lvalue = this->getLValue(*p.fOperand);
1099 lvalue->load();
1100 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osmand30e0392019-06-14 14:05:14 -04001101 this->write32(type_category(p.fType) == TypeCategory::kFloat ? float_to_bits(1.0f) : 1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001102 if (p.fOperator == Token::Kind::PLUSPLUS) {
1103 this->writeTypedInstruction(p.fType,
1104 ByteCodeInstruction::kAddI,
1105 ByteCodeInstruction::kAddI,
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001106 ByteCodeInstruction::kAddF,
1107 1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001108 } else {
1109 this->writeTypedInstruction(p.fType,
1110 ByteCodeInstruction::kSubtractI,
1111 ByteCodeInstruction::kSubtractI,
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001112 ByteCodeInstruction::kSubtractF,
1113 1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001114 }
Brian Osman3e29f1d2019-05-28 09:35:05 -04001115 lvalue->store(discard);
1116 discard = false;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001117 break;
1118 }
Ethan Nicholas354ecf32019-05-07 16:13:02 -04001119 case Token::Kind::MINUS: {
1120 this->writeExpression(*p.fOperand);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001121 this->writeTypedInstruction(p.fType,
Mike Klein12710912019-05-21 11:04:59 -05001122 ByteCodeInstruction::kNegateI,
1123 ByteCodeInstruction::kNegateI,
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001124 ByteCodeInstruction::kNegateF,
Ethan Nicholasc70027b2019-09-05 16:50:52 -04001125 SlotCount(p.fOperand->fType),
1126 false);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001127 break;
Ethan Nicholas354ecf32019-05-07 16:13:02 -04001128 }
Brian Osmane5bbce22019-09-23 12:38:40 -04001129 case Token::Kind::LOGICALNOT:
1130 case Token::Kind::BITWISENOT: {
1131 SkASSERT(SlotCount(p.fOperand->fType) == 1);
1132 SkDEBUGCODE(TypeCategory tc = type_category(p.fOperand->fType));
1133 SkASSERT((p.fOperator == Token::Kind::LOGICALNOT && tc == TypeCategory::kBool) ||
1134 (p.fOperator == Token::Kind::BITWISENOT && (tc == TypeCategory::kSigned ||
1135 tc == TypeCategory::kUnsigned)));
1136 this->writeExpression(*p.fOperand);
1137 this->write(ByteCodeInstruction::kNotB);
1138 break;
1139 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001140 default:
1141 SkASSERT(false);
1142 }
Brian Osman3e29f1d2019-05-28 09:35:05 -04001143 return discard;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001144}
1145
Brian Osman3e29f1d2019-05-28 09:35:05 -04001146bool ByteCodeGenerator::writePostfixExpression(const PostfixExpression& p, bool discard) {
Brian Osmanf3fa6002019-05-17 14:26:53 -04001147 switch (p.fOperator) {
1148 case Token::Kind::PLUSPLUS: // fall through
1149 case Token::Kind::MINUSMINUS: {
Brian Osman07c117b2019-05-23 12:51:06 -07001150 SkASSERT(SlotCount(p.fOperand->fType) == 1);
Brian Osmanf3fa6002019-05-17 14:26:53 -04001151 std::unique_ptr<LValue> lvalue = this->getLValue(*p.fOperand);
1152 lvalue->load();
Brian Osman52c1bf12019-07-18 13:12:19 -04001153 // If we're not supposed to discard the result, then make a copy *before* the +/-
Brian Osman3e29f1d2019-05-28 09:35:05 -04001154 if (!discard) {
1155 this->write(ByteCodeInstruction::kDup);
Ethan Nicholasc70027b2019-09-05 16:50:52 -04001156 this->write8(1);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001157 }
Brian Osmanf3fa6002019-05-17 14:26:53 -04001158 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osmand30e0392019-06-14 14:05:14 -04001159 this->write32(type_category(p.fType) == TypeCategory::kFloat ? float_to_bits(1.0f) : 1);
Brian Osmanf3fa6002019-05-17 14:26:53 -04001160 if (p.fOperator == Token::Kind::PLUSPLUS) {
1161 this->writeTypedInstruction(p.fType,
1162 ByteCodeInstruction::kAddI,
1163 ByteCodeInstruction::kAddI,
1164 ByteCodeInstruction::kAddF,
1165 1);
1166 } else {
1167 this->writeTypedInstruction(p.fType,
1168 ByteCodeInstruction::kSubtractI,
1169 ByteCodeInstruction::kSubtractI,
1170 ByteCodeInstruction::kSubtractF,
1171 1);
1172 }
Brian Osman52c1bf12019-07-18 13:12:19 -04001173 // Always consume the result as part of the store
1174 lvalue->store(true);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001175 discard = false;
Brian Osmanf3fa6002019-05-17 14:26:53 -04001176 break;
1177 }
1178 default:
1179 SkASSERT(false);
1180 }
Brian Osman3e29f1d2019-05-28 09:35:05 -04001181 return discard;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001182}
1183
1184void ByteCodeGenerator::writeSwizzle(const Swizzle& s) {
Brian Osman0785db02019-05-24 14:19:11 -04001185 if (swizzle_is_simple(s)) {
1186 this->writeVariableExpression(s);
1187 return;
1188 }
1189
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001190 switch (s.fBase->fKind) {
1191 case Expression::kVariableReference_Kind: {
1192 const Variable& var = ((VariableReference&) *s.fBase).fVariable;
Brian Osman1091f022019-05-16 09:42:16 -04001193 this->write(var.fStorage == Variable::kGlobal_Storage
1194 ? ByteCodeInstruction::kLoadSwizzleGlobal
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001195 : ByteCodeInstruction::kLoadSwizzle,
1196 s.fComponents.size());
Brian Osman1091f022019-05-16 09:42:16 -04001197 this->write8(this->getLocation(var));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001198 this->write8(s.fComponents.size());
1199 for (int c : s.fComponents) {
1200 this->write8(c);
1201 }
1202 break;
1203 }
1204 default:
1205 this->writeExpression(*s.fBase);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001206 this->write(ByteCodeInstruction::kSwizzle,
1207 s.fComponents.size() - s.fBase->fType.columns());
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001208 this->write8(s.fBase->fType.columns());
1209 this->write8(s.fComponents.size());
1210 for (int c : s.fComponents) {
1211 this->write8(c);
1212 }
1213 }
1214}
1215
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001216void ByteCodeGenerator::writeTernaryExpression(const TernaryExpression& t) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001217 int count = SlotCount(t.fType);
1218 SkASSERT(count == SlotCount(t.fIfTrue->fType));
1219 SkASSERT(count == SlotCount(t.fIfFalse->fType));
1220
Brian Osman4e93feb2019-05-16 15:38:00 -04001221 this->writeExpression(*t.fTest);
Brian Osman569f12f2019-06-13 11:23:57 -04001222 this->write(ByteCodeInstruction::kMaskPush);
Brian Osman4e93feb2019-05-16 15:38:00 -04001223 this->writeExpression(*t.fIfTrue);
Brian Osman569f12f2019-06-13 11:23:57 -04001224 this->write(ByteCodeInstruction::kMaskNegate);
1225 this->writeExpression(*t.fIfFalse);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001226 this->write(ByteCodeInstruction::kMaskBlend, count);
1227 this->write8(count);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001228}
1229
Brian Osman3e29f1d2019-05-28 09:35:05 -04001230void ByteCodeGenerator::writeExpression(const Expression& e, bool discard) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001231 switch (e.fKind) {
1232 case Expression::kBinary_Kind:
Brian Osman3e29f1d2019-05-28 09:35:05 -04001233 discard = this->writeBinaryExpression((BinaryExpression&) e, discard);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001234 break;
1235 case Expression::kBoolLiteral_Kind:
1236 this->writeBoolLiteral((BoolLiteral&) e);
1237 break;
1238 case Expression::kConstructor_Kind:
1239 this->writeConstructor((Constructor&) e);
1240 break;
Ethan Nicholas9e6a3932019-05-17 16:31:21 -04001241 case Expression::kExternalFunctionCall_Kind:
1242 this->writeExternalFunctionCall((ExternalFunctionCall&) e);
1243 break;
Ethan Nicholas91164d12019-05-15 15:29:54 -04001244 case Expression::kExternalValue_Kind:
1245 this->writeExternalValue((ExternalValueReference&) e);
1246 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001247 case Expression::kFieldAccess_Kind:
Brian Osman07c117b2019-05-23 12:51:06 -07001248 case Expression::kIndex_Kind:
1249 case Expression::kVariableReference_Kind:
1250 this->writeVariableExpression(e);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001251 break;
1252 case Expression::kFloatLiteral_Kind:
1253 this->writeFloatLiteral((FloatLiteral&) e);
1254 break;
1255 case Expression::kFunctionCall_Kind:
1256 this->writeFunctionCall((FunctionCall&) e);
1257 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001258 case Expression::kIntLiteral_Kind:
1259 this->writeIntLiteral((IntLiteral&) e);
1260 break;
1261 case Expression::kNullLiteral_Kind:
1262 this->writeNullLiteral((NullLiteral&) e);
1263 break;
1264 case Expression::kPrefix_Kind:
Brian Osman3e29f1d2019-05-28 09:35:05 -04001265 discard = this->writePrefixExpression((PrefixExpression&) e, discard);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001266 break;
1267 case Expression::kPostfix_Kind:
Brian Osman3e29f1d2019-05-28 09:35:05 -04001268 discard = this->writePostfixExpression((PostfixExpression&) e, discard);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001269 break;
1270 case Expression::kSwizzle_Kind:
1271 this->writeSwizzle((Swizzle&) e);
1272 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001273 case Expression::kTernary_Kind:
1274 this->writeTernaryExpression((TernaryExpression&) e);
1275 break;
1276 default:
1277 printf("unsupported expression %s\n", e.description().c_str());
1278 SkASSERT(false);
1279 }
Brian Osman3e29f1d2019-05-28 09:35:05 -04001280 if (discard) {
1281 int count = SlotCount(e.fType);
1282 if (count > 4) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001283 this->write(ByteCodeInstruction::kPopN, count);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001284 this->write8(count);
Brian Osmanfba386b2019-06-20 14:54:15 -04001285 } else if (count != 0) {
Brian Osman3e29f1d2019-05-28 09:35:05 -04001286 this->write(vector_instruction(ByteCodeInstruction::kPop, count));
1287 }
1288 discard = false;
1289 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001290}
1291
Ethan Nicholas91164d12019-05-15 15:29:54 -04001292class ByteCodeExternalValueLValue : public ByteCodeGenerator::LValue {
1293public:
1294 ByteCodeExternalValueLValue(ByteCodeGenerator* generator, ExternalValue& value, int index)
1295 : INHERITED(*generator)
Brian Osman07c117b2019-05-23 12:51:06 -07001296 , fCount(ByteCodeGenerator::SlotCount(value.type()))
Ethan Nicholas91164d12019-05-15 15:29:54 -04001297 , fIndex(index) {}
1298
1299 void load() override {
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001300 fGenerator.write(vector_instruction(ByteCodeInstruction::kReadExternal, fCount));
Ethan Nicholasc70027b2019-09-05 16:50:52 -04001301 fGenerator.write8(fCount);
Ethan Nicholas91164d12019-05-15 15:29:54 -04001302 fGenerator.write8(fIndex);
1303 }
1304
Brian Osman3e29f1d2019-05-28 09:35:05 -04001305 void store(bool discard) override {
1306 if (!discard) {
1307 fGenerator.write(vector_instruction(ByteCodeInstruction::kDup, fCount));
Ethan Nicholasc70027b2019-09-05 16:50:52 -04001308 fGenerator.write8(fCount);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001309 }
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001310 fGenerator.write(vector_instruction(ByteCodeInstruction::kWriteExternal, fCount));
Ethan Nicholasc70027b2019-09-05 16:50:52 -04001311 fGenerator.write8(fCount);
Ethan Nicholas91164d12019-05-15 15:29:54 -04001312 fGenerator.write8(fIndex);
1313 }
1314
1315private:
1316 typedef LValue INHERITED;
1317
1318 int fCount;
1319
1320 int fIndex;
1321};
1322
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001323class ByteCodeSwizzleLValue : public ByteCodeGenerator::LValue {
1324public:
1325 ByteCodeSwizzleLValue(ByteCodeGenerator* generator, const Swizzle& swizzle)
1326 : INHERITED(*generator)
Brian Osman07c117b2019-05-23 12:51:06 -07001327 , fSwizzle(swizzle) {}
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001328
1329 void load() override {
Brian Osman1091f022019-05-16 09:42:16 -04001330 fGenerator.writeSwizzle(fSwizzle);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001331 }
1332
Brian Osman3e29f1d2019-05-28 09:35:05 -04001333 void store(bool discard) override {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001334 int count = fSwizzle.fComponents.size();
Brian Osman3e29f1d2019-05-28 09:35:05 -04001335 if (!discard) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001336 fGenerator.write(vector_instruction(ByteCodeInstruction::kDup, count));
Ethan Nicholasc70027b2019-09-05 16:50:52 -04001337 fGenerator.write8(count);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001338 }
Brian Osman869a3e82019-07-18 17:00:34 -04001339 Variable::Storage storage = Variable::kLocal_Storage;
Brian Osman07c117b2019-05-23 12:51:06 -07001340 int location = fGenerator.getLocation(*fSwizzle.fBase, &storage);
1341 bool isGlobal = storage == Variable::kGlobal_Storage;
1342 if (location < 0) {
1343 fGenerator.write(isGlobal ? ByteCodeInstruction::kStoreSwizzleIndirectGlobal
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001344 : ByteCodeInstruction::kStoreSwizzleIndirect,
1345 count);
Brian Osman07c117b2019-05-23 12:51:06 -07001346 } else {
1347 fGenerator.write(isGlobal ? ByteCodeInstruction::kStoreSwizzleGlobal
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001348 : ByteCodeInstruction::kStoreSwizzle,
1349 count);
Brian Osman07c117b2019-05-23 12:51:06 -07001350 fGenerator.write8(location);
1351 }
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001352 fGenerator.write8(count);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001353 for (int c : fSwizzle.fComponents) {
1354 fGenerator.write8(c);
1355 }
1356 }
1357
1358private:
1359 const Swizzle& fSwizzle;
1360
1361 typedef LValue INHERITED;
1362};
1363
Brian Osman07c117b2019-05-23 12:51:06 -07001364class ByteCodeExpressionLValue : public ByteCodeGenerator::LValue {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001365public:
Brian Osman07c117b2019-05-23 12:51:06 -07001366 ByteCodeExpressionLValue(ByteCodeGenerator* generator, const Expression& expr)
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001367 : INHERITED(*generator)
Brian Osman07c117b2019-05-23 12:51:06 -07001368 , fExpression(expr) {}
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001369
1370 void load() override {
Brian Osman07c117b2019-05-23 12:51:06 -07001371 fGenerator.writeVariableExpression(fExpression);
Brian Osman1091f022019-05-16 09:42:16 -04001372 }
1373
Brian Osman3e29f1d2019-05-28 09:35:05 -04001374 void store(bool discard) override {
Brian Osman07c117b2019-05-23 12:51:06 -07001375 int count = ByteCodeGenerator::SlotCount(fExpression.fType);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001376 if (!discard) {
1377 if (count > 4) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001378 fGenerator.write(ByteCodeInstruction::kDupN, count);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001379 fGenerator.write8(count);
1380 } else {
1381 fGenerator.write(vector_instruction(ByteCodeInstruction::kDup, count));
Ethan Nicholasc70027b2019-09-05 16:50:52 -04001382 fGenerator.write8(count);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001383 }
Brian Osman07c117b2019-05-23 12:51:06 -07001384 }
Brian Osman869a3e82019-07-18 17:00:34 -04001385 Variable::Storage storage = Variable::kLocal_Storage;
Brian Osman07c117b2019-05-23 12:51:06 -07001386 int location = fGenerator.getLocation(fExpression, &storage);
1387 bool isGlobal = storage == Variable::kGlobal_Storage;
1388 if (location < 0 || count > 4) {
1389 if (location >= 0) {
1390 fGenerator.write(ByteCodeInstruction::kPushImmediate);
1391 fGenerator.write32(location);
1392 }
1393 fGenerator.write(isGlobal ? ByteCodeInstruction::kStoreExtendedGlobal
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001394 : ByteCodeInstruction::kStoreExtended,
1395 count);
Brian Osman07c117b2019-05-23 12:51:06 -07001396 fGenerator.write8(count);
1397 } else {
1398 fGenerator.write(vector_instruction(isGlobal ? ByteCodeInstruction::kStoreGlobal
1399 : ByteCodeInstruction::kStore,
1400 count));
1401 fGenerator.write8(location);
1402 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001403 }
1404
1405private:
1406 typedef LValue INHERITED;
1407
Brian Osman07c117b2019-05-23 12:51:06 -07001408 const Expression& fExpression;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001409};
1410
1411std::unique_ptr<ByteCodeGenerator::LValue> ByteCodeGenerator::getLValue(const Expression& e) {
1412 switch (e.fKind) {
Ethan Nicholas91164d12019-05-15 15:29:54 -04001413 case Expression::kExternalValue_Kind: {
1414 ExternalValue* value = ((ExternalValueReference&) e).fValue;
1415 int index = fOutput->fExternalValues.size();
1416 fOutput->fExternalValues.push_back(value);
1417 SkASSERT(index <= 255);
1418 return std::unique_ptr<LValue>(new ByteCodeExternalValueLValue(this, *value, index));
1419 }
Brian Osman07c117b2019-05-23 12:51:06 -07001420 case Expression::kFieldAccess_Kind:
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001421 case Expression::kIndex_Kind:
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001422 case Expression::kVariableReference_Kind:
Brian Osman07c117b2019-05-23 12:51:06 -07001423 return std::unique_ptr<LValue>(new ByteCodeExpressionLValue(this, e));
Brian Osman0785db02019-05-24 14:19:11 -04001424 case Expression::kSwizzle_Kind: {
1425 const Swizzle& s = (const Swizzle&) e;
1426 return swizzle_is_simple(s)
1427 ? std::unique_ptr<LValue>(new ByteCodeExpressionLValue(this, e))
1428 : std::unique_ptr<LValue>(new ByteCodeSwizzleLValue(this, s));
1429 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001430 case Expression::kTernary_Kind:
1431 default:
1432 printf("unsupported lvalue %s\n", e.description().c_str());
1433 return nullptr;
1434 }
1435}
1436
1437void ByteCodeGenerator::writeBlock(const Block& b) {
1438 for (const auto& s : b.fStatements) {
1439 this->writeStatement(*s);
1440 }
1441}
1442
1443void ByteCodeGenerator::setBreakTargets() {
1444 std::vector<DeferredLocation>& breaks = fBreakTargets.top();
1445 for (DeferredLocation& b : breaks) {
1446 b.set();
1447 }
1448 fBreakTargets.pop();
1449}
1450
1451void ByteCodeGenerator::setContinueTargets() {
1452 std::vector<DeferredLocation>& continues = fContinueTargets.top();
1453 for (DeferredLocation& c : continues) {
1454 c.set();
1455 }
1456 fContinueTargets.pop();
1457}
1458
1459void ByteCodeGenerator::writeBreakStatement(const BreakStatement& b) {
Brian Osman569f12f2019-06-13 11:23:57 -04001460 // TODO: Include BranchIfAllFalse to top-most LoopNext
1461 this->write(ByteCodeInstruction::kLoopBreak);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001462}
1463
1464void ByteCodeGenerator::writeContinueStatement(const ContinueStatement& c) {
Brian Osman569f12f2019-06-13 11:23:57 -04001465 // TODO: Include BranchIfAllFalse to top-most LoopNext
1466 this->write(ByteCodeInstruction::kLoopContinue);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001467}
1468
1469void ByteCodeGenerator::writeDoStatement(const DoStatement& d) {
Brian Osman569f12f2019-06-13 11:23:57 -04001470 this->write(ByteCodeInstruction::kLoopBegin);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001471 size_t start = fCode->size();
1472 this->writeStatement(*d.fStatement);
Brian Osman569f12f2019-06-13 11:23:57 -04001473 this->write(ByteCodeInstruction::kLoopNext);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001474 this->writeExpression(*d.fTest);
Brian Osman569f12f2019-06-13 11:23:57 -04001475 this->write(ByteCodeInstruction::kLoopMask);
1476 // TODO: Could shorten this with kBranchIfAnyTrue
1477 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1478 DeferredLocation endLocation(this);
1479 this->write(ByteCodeInstruction::kBranch);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001480 this->write16(start);
Brian Osman569f12f2019-06-13 11:23:57 -04001481 endLocation.set();
1482 this->write(ByteCodeInstruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001483}
1484
1485void ByteCodeGenerator::writeForStatement(const ForStatement& f) {
1486 fContinueTargets.emplace();
1487 fBreakTargets.emplace();
1488 if (f.fInitializer) {
1489 this->writeStatement(*f.fInitializer);
1490 }
Brian Osman569f12f2019-06-13 11:23:57 -04001491 this->write(ByteCodeInstruction::kLoopBegin);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001492 size_t start = fCode->size();
1493 if (f.fTest) {
1494 this->writeExpression(*f.fTest);
Brian Osman569f12f2019-06-13 11:23:57 -04001495 this->write(ByteCodeInstruction::kLoopMask);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001496 }
Brian Osman569f12f2019-06-13 11:23:57 -04001497 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1498 DeferredLocation endLocation(this);
1499 this->writeStatement(*f.fStatement);
1500 this->write(ByteCodeInstruction::kLoopNext);
1501 if (f.fNext) {
1502 this->writeExpression(*f.fNext, true);
1503 }
1504 this->write(ByteCodeInstruction::kBranch);
1505 this->write16(start);
1506 endLocation.set();
1507 this->write(ByteCodeInstruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001508}
1509
1510void ByteCodeGenerator::writeIfStatement(const IfStatement& i) {
Brian Osman569f12f2019-06-13 11:23:57 -04001511 this->writeExpression(*i.fTest);
1512 this->write(ByteCodeInstruction::kMaskPush);
1513 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1514 DeferredLocation falseLocation(this);
1515 this->writeStatement(*i.fIfTrue);
1516 falseLocation.set();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001517 if (i.fIfFalse) {
Brian Osman569f12f2019-06-13 11:23:57 -04001518 this->write(ByteCodeInstruction::kMaskNegate);
1519 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1520 DeferredLocation endLocation(this);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001521 this->writeStatement(*i.fIfFalse);
Mike Kleinb45ee832019-05-17 11:11:11 -05001522 endLocation.set();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001523 }
Brian Osman569f12f2019-06-13 11:23:57 -04001524 this->write(ByteCodeInstruction::kMaskPop);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001525}
1526
1527void ByteCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
Brian Osman4a47da72019-07-12 11:30:32 -04001528 if (fLoopCount || fConditionCount) {
1529 fErrors.error(r.fOffset, "return not allowed inside conditional or loop");
1530 return;
1531 }
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001532 int count = SlotCount(r.fExpression->fType);
Ethan Nicholas746035a2019-04-23 13:31:09 -04001533 this->writeExpression(*r.fExpression);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001534
1535 // Technically, the kReturn also pops fOutput->fLocalCount values from the stack, too, but we
1536 // haven't counted pushing those (they're outside the scope of our stack tracking). Instead,
1537 // we account for those in writeFunction().
1538
1539 // This is all fine because we don't allow conditional returns, so we only return once anyway.
1540 this->write(ByteCodeInstruction::kReturn, -count);
1541 this->write8(count);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001542}
1543
1544void ByteCodeGenerator::writeSwitchStatement(const SwitchStatement& r) {
1545 // not yet implemented
1546 abort();
1547}
1548
1549void ByteCodeGenerator::writeVarDeclarations(const VarDeclarations& v) {
1550 for (const auto& declStatement : v.fVars) {
1551 const VarDeclaration& decl = (VarDeclaration&) *declStatement;
1552 // we need to grab the location even if we don't use it, to ensure it
1553 // has been allocated
1554 int location = getLocation(*decl.fVar);
1555 if (decl.fValue) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001556 this->writeExpression(*decl.fValue);
Brian Osman07c117b2019-05-23 12:51:06 -07001557 int count = SlotCount(decl.fValue->fType);
1558 if (count > 4) {
1559 this->write(ByteCodeInstruction::kPushImmediate);
1560 this->write32(location);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001561 this->write(ByteCodeInstruction::kStoreExtended, count);
Brian Osman07c117b2019-05-23 12:51:06 -07001562 this->write8(count);
1563 } else {
1564 this->write(vector_instruction(ByteCodeInstruction::kStore, count));
1565 this->write8(location);
1566 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001567 }
1568 }
1569}
1570
1571void ByteCodeGenerator::writeWhileStatement(const WhileStatement& w) {
Brian Osman569f12f2019-06-13 11:23:57 -04001572 this->write(ByteCodeInstruction::kLoopBegin);
1573 size_t cond = fCode->size();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001574 this->writeExpression(*w.fTest);
Brian Osman569f12f2019-06-13 11:23:57 -04001575 this->write(ByteCodeInstruction::kLoopMask);
1576 this->write(ByteCodeInstruction::kBranchIfAllFalse);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001577 DeferredLocation endLocation(this);
1578 this->writeStatement(*w.fStatement);
Brian Osman569f12f2019-06-13 11:23:57 -04001579 this->write(ByteCodeInstruction::kLoopNext);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001580 this->write(ByteCodeInstruction::kBranch);
Brian Osman569f12f2019-06-13 11:23:57 -04001581 this->write16(cond);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001582 endLocation.set();
Brian Osman569f12f2019-06-13 11:23:57 -04001583 this->write(ByteCodeInstruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001584}
1585
1586void ByteCodeGenerator::writeStatement(const Statement& s) {
1587 switch (s.fKind) {
1588 case Statement::kBlock_Kind:
1589 this->writeBlock((Block&) s);
1590 break;
1591 case Statement::kBreak_Kind:
1592 this->writeBreakStatement((BreakStatement&) s);
1593 break;
1594 case Statement::kContinue_Kind:
1595 this->writeContinueStatement((ContinueStatement&) s);
1596 break;
1597 case Statement::kDiscard_Kind:
1598 // not yet implemented
1599 abort();
1600 case Statement::kDo_Kind:
1601 this->writeDoStatement((DoStatement&) s);
1602 break;
Brian Osman3e29f1d2019-05-28 09:35:05 -04001603 case Statement::kExpression_Kind:
1604 this->writeExpression(*((ExpressionStatement&) s).fExpression, true);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001605 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001606 case Statement::kFor_Kind:
1607 this->writeForStatement((ForStatement&) s);
1608 break;
1609 case Statement::kIf_Kind:
1610 this->writeIfStatement((IfStatement&) s);
1611 break;
1612 case Statement::kNop_Kind:
1613 break;
1614 case Statement::kReturn_Kind:
1615 this->writeReturnStatement((ReturnStatement&) s);
1616 break;
1617 case Statement::kSwitch_Kind:
1618 this->writeSwitchStatement((SwitchStatement&) s);
1619 break;
1620 case Statement::kVarDeclarations_Kind:
1621 this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration);
1622 break;
1623 case Statement::kWhile_Kind:
1624 this->writeWhileStatement((WhileStatement&) s);
1625 break;
1626 default:
1627 SkASSERT(false);
1628 }
1629}
1630
Brian Osman80164412019-06-07 13:00:23 -04001631ByteCodeFunction::ByteCodeFunction(const FunctionDeclaration* declaration)
1632 : fName(declaration->fName) {
1633 fParameterCount = 0;
1634 for (const auto& p : declaration->fParameters) {
1635 int slots = ByteCodeGenerator::SlotCount(p->fType);
1636 fParameters.push_back({ slots, (bool)(p->fModifiers.fFlags & Modifiers::kOut_Flag) });
1637 fParameterCount += slots;
1638 }
1639}
1640
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001641}