blob: acfbac5a1ba749e26fec37c858bceb80fdbabf4f [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 }
Ethan Nicholas31cff272019-09-26 13:04:48 -040069 // if you trip this assert, it means the program has raw 'in' variables. You
70 // should either specialize the program (Compiler::specialize) to bake in the
71 // final values of the 'in' variables, or not use 'in' variables (maybe you
72 // meant to use 'uniform' instead?).
73// SkASSERT(!(declVar->fModifiers.fFlags & Modifiers::kIn_Flag));
74 if (declVar->fModifiers.fFlags & Modifiers::kUniform_Flag) {
Brian Osman07c117b2019-05-23 12:51:06 -070075 for (int i = SlotCount(declVar->fType); i > 0; --i) {
Brian Osman9b8b4552019-09-30 13:23:14 -040076 fOutput->fUniformSlots.push_back(fOutput->fGlobalCount++);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040077 }
78 } else {
Brian Osman07c117b2019-05-23 12:51:06 -070079 fOutput->fGlobalCount += SlotCount(declVar->fType);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040080 }
81 }
82 break;
83 }
84 default:
85 ; // ignore
86 }
87 }
Brian Osman6f5358f2019-07-09 14:17:23 -040088 return 0 == fErrors.errorCount();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040089}
90
91std::unique_ptr<ByteCodeFunction> ByteCodeGenerator::writeFunction(const FunctionDefinition& f) {
92 fFunction = &f;
Brian Osman226668a2019-05-14 16:47:30 -040093 std::unique_ptr<ByteCodeFunction> result(new ByteCodeFunction(&f.fDeclaration));
Brian Osman80164412019-06-07 13:00:23 -040094 fParameterCount = result->fParameterCount;
Brian Osman4a47da72019-07-12 11:30:32 -040095 fLoopCount = fMaxLoopCount = 0;
96 fConditionCount = fMaxConditionCount = 0;
Brian Osmanaa2ca3f2019-07-15 13:24:48 -040097 fStackCount = fMaxStackCount = 0;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040098 fCode = &result->fCode;
Brian Osman4a47da72019-07-12 11:30:32 -040099
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400100 this->writeStatement(*f.fBody);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400101 if (0 == fErrors.errorCount()) {
102 SkASSERT(fLoopCount == 0);
103 SkASSERT(fConditionCount == 0);
104 SkASSERT(fStackCount == 0);
105 }
106 this->write(ByteCodeInstruction::kReturn, 0);
Ethan Nicholas7e603db2019-05-03 12:57:47 -0400107 this->write8(0);
Brian Osman4a47da72019-07-12 11:30:32 -0400108
109 result->fLocalCount = fLocals.size();
110 result->fConditionCount = fMaxConditionCount;
111 result->fLoopCount = fMaxLoopCount;
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400112 result->fStackCount = fMaxStackCount;
Brian Osman4a47da72019-07-12 11:30:32 -0400113
Ethan Nicholasdfcad062019-05-07 12:53:34 -0400114 const Type& returnType = f.fDeclaration.fReturnType;
115 if (returnType != *fContext.fVoid_Type) {
Brian Osman07c117b2019-05-23 12:51:06 -0700116 result->fReturnCount = SlotCount(returnType);
Ethan Nicholasdfcad062019-05-07 12:53:34 -0400117 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400118 fLocals.clear();
119 fFunction = nullptr;
120 return result;
121}
122
123enum class TypeCategory {
124 kBool,
125 kSigned,
126 kUnsigned,
127 kFloat,
128};
129
130static TypeCategory type_category(const Type& type) {
131 switch (type.kind()) {
132 case Type::Kind::kVector_Kind:
133 case Type::Kind::kMatrix_Kind:
134 return type_category(type.componentType());
135 default:
136 if (type.fName == "bool") {
137 return TypeCategory::kBool;
138 } else if (type.fName == "int" || type.fName == "short") {
139 return TypeCategory::kSigned;
140 } else if (type.fName == "uint" || type.fName == "ushort") {
141 return TypeCategory::kUnsigned;
142 } else {
143 SkASSERT(type.fName == "float" || type.fName == "half");
144 return TypeCategory::kFloat;
145 }
146 ABORT("unsupported type: %s\n", type.description().c_str());
147 }
148}
149
Brian Osman0785db02019-05-24 14:19:11 -0400150// A "simple" Swizzle is based on a variable (or a compound variable like a struct or array), and
151// that references consecutive values, such that it can be implemented using normal load/store ops
152// with an offset. Note that all single-component swizzles (of suitable base types) are simple.
153static bool swizzle_is_simple(const Swizzle& s) {
154 switch (s.fBase->fKind) {
155 case Expression::kFieldAccess_Kind:
156 case Expression::kIndex_Kind:
157 case Expression::kVariableReference_Kind:
158 break;
159 default:
160 return false;
161 }
162
163 for (size_t i = 1; i < s.fComponents.size(); ++i) {
164 if (s.fComponents[i] != s.fComponents[i - 1] + 1) {
165 return false;
166 }
167 }
168 return true;
169}
170
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400171int ByteCodeGenerator::StackUsage(ByteCodeInstruction inst, int count_) {
172 // Ensures that we use count iff we're passed a non-default value. Most instructions have an
173 // implicit count, so the caller shouldn't need to worry about it (or count makes no sense).
174 // The asserts avoids callers thinking they're supplying useful information in that scenario,
175 // or failing to supply necessary information for the ops that need a count.
176 struct CountValue {
177 operator int() {
178 SkASSERT(val != ByteCodeGenerator::kUnusedStackCount);
179 SkDEBUGCODE(used = true);
180 return val;
181 }
182 ~CountValue() {
183 SkASSERT(used || val == ByteCodeGenerator::kUnusedStackCount);
184 }
185 int val;
186 SkDEBUGCODE(bool used = false;)
187 } count = { count_ };
188
189 switch (inst) {
190 // Unary functions/operators that don't change stack depth at all:
191#define VECTOR_UNARY_OP(base) \
192 case ByteCodeInstruction::base: \
193 case ByteCodeInstruction::base ## 2: \
194 case ByteCodeInstruction::base ## 3: \
195 case ByteCodeInstruction::base ## 4: \
196 return 0;
197
198 VECTOR_UNARY_OP(kConvertFtoI)
199 VECTOR_UNARY_OP(kConvertStoF)
200 VECTOR_UNARY_OP(kConvertUtoF)
201
202 VECTOR_UNARY_OP(kCos)
203 VECTOR_UNARY_OP(kSin)
204 VECTOR_UNARY_OP(kSqrt)
205 VECTOR_UNARY_OP(kTan)
206
207 VECTOR_UNARY_OP(kNegateF)
208 VECTOR_UNARY_OP(kNegateI)
209
Mike Reed634c9412019-07-18 13:20:04 -0400210 case ByteCodeInstruction::kInverse2x2:
211 case ByteCodeInstruction::kInverse3x3:
212 case ByteCodeInstruction::kInverse4x4: return 0;
213
Brian Osman869a3e82019-07-18 17:00:34 -0400214 case ByteCodeInstruction::kClampIndex: return 0;
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400215 case ByteCodeInstruction::kNotB: return 0;
216 case ByteCodeInstruction::kNegateFN: return 0;
Brian Osman4c2146f2019-09-24 09:39:38 -0400217 case ByteCodeInstruction::kShiftLeft: return 0;
218 case ByteCodeInstruction::kShiftRightS: return 0;
219 case ByteCodeInstruction::kShiftRightU: return 0;
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400220
221#undef VECTOR_UNARY_OP
222
223 // Binary functions/operators that do a 2 -> 1 reduction (possibly N times)
224#define VECTOR_BINARY_OP(base) \
225 case ByteCodeInstruction::base: return -1; \
226 case ByteCodeInstruction::base ## 2: return -2; \
227 case ByteCodeInstruction::base ## 3: return -3; \
228 case ByteCodeInstruction::base ## 4: return -4;
229
230#define VECTOR_MATRIX_BINARY_OP(base) \
231 VECTOR_BINARY_OP(base) \
232 case ByteCodeInstruction::base ## N: return -count;
233
234 case ByteCodeInstruction::kAndB: return -1;
235 case ByteCodeInstruction::kOrB: return -1;
236 case ByteCodeInstruction::kXorB: return -1;
237
238 VECTOR_BINARY_OP(kAddI)
239 VECTOR_MATRIX_BINARY_OP(kAddF)
240
241 VECTOR_BINARY_OP(kCompareIEQ)
242 VECTOR_MATRIX_BINARY_OP(kCompareFEQ)
243 VECTOR_BINARY_OP(kCompareINEQ)
244 VECTOR_MATRIX_BINARY_OP(kCompareFNEQ)
245 VECTOR_BINARY_OP(kCompareSGT)
246 VECTOR_BINARY_OP(kCompareUGT)
247 VECTOR_BINARY_OP(kCompareFGT)
248 VECTOR_BINARY_OP(kCompareSGTEQ)
249 VECTOR_BINARY_OP(kCompareUGTEQ)
250 VECTOR_BINARY_OP(kCompareFGTEQ)
251 VECTOR_BINARY_OP(kCompareSLT)
252 VECTOR_BINARY_OP(kCompareULT)
253 VECTOR_BINARY_OP(kCompareFLT)
254 VECTOR_BINARY_OP(kCompareSLTEQ)
255 VECTOR_BINARY_OP(kCompareULTEQ)
256 VECTOR_BINARY_OP(kCompareFLTEQ)
257
258 VECTOR_BINARY_OP(kDivideS)
259 VECTOR_BINARY_OP(kDivideU)
260 VECTOR_MATRIX_BINARY_OP(kDivideF)
261 VECTOR_BINARY_OP(kMultiplyI)
262 VECTOR_MATRIX_BINARY_OP(kMultiplyF)
263 VECTOR_BINARY_OP(kRemainderF)
264 VECTOR_BINARY_OP(kRemainderS)
265 VECTOR_BINARY_OP(kRemainderU)
266 VECTOR_BINARY_OP(kSubtractI)
267 VECTOR_MATRIX_BINARY_OP(kSubtractF)
268
269#undef VECTOR_BINARY_OP
270#undef VECTOR_MATRIX_BINARY_OP
271
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400272 // Ops that push or load data to grow the stack:
273 case ByteCodeInstruction::kDup:
274 case ByteCodeInstruction::kLoad:
275 case ByteCodeInstruction::kLoadGlobal:
276 case ByteCodeInstruction::kReadExternal:
277 case ByteCodeInstruction::kPushImmediate:
278 return 1;
279
280 case ByteCodeInstruction::kDup2:
281 case ByteCodeInstruction::kLoad2:
282 case ByteCodeInstruction::kLoadGlobal2:
283 case ByteCodeInstruction::kReadExternal2:
284 return 2;
285
286 case ByteCodeInstruction::kDup3:
287 case ByteCodeInstruction::kLoad3:
288 case ByteCodeInstruction::kLoadGlobal3:
289 case ByteCodeInstruction::kReadExternal3:
290 return 3;
291
292 case ByteCodeInstruction::kDup4:
293 case ByteCodeInstruction::kLoad4:
294 case ByteCodeInstruction::kLoadGlobal4:
295 case ByteCodeInstruction::kReadExternal4:
296 return 4;
297
298 case ByteCodeInstruction::kDupN:
299 case ByteCodeInstruction::kLoadSwizzle:
300 case ByteCodeInstruction::kLoadSwizzleGlobal:
301 return count;
302
303 // Pushes 'count' values, minus one for the 'address' that's consumed first
304 case ByteCodeInstruction::kLoadExtended:
305 case ByteCodeInstruction::kLoadExtendedGlobal:
306 return count - 1;
307
308 // Ops that pop or store data to shrink the stack:
309 case ByteCodeInstruction::kPop:
310 case ByteCodeInstruction::kStore:
311 case ByteCodeInstruction::kStoreGlobal:
312 case ByteCodeInstruction::kWriteExternal:
313 return -1;
314
315 case ByteCodeInstruction::kPop2:
316 case ByteCodeInstruction::kStore2:
317 case ByteCodeInstruction::kStoreGlobal2:
318 case ByteCodeInstruction::kWriteExternal2:
319 return -2;
320
321 case ByteCodeInstruction::kPop3:
322 case ByteCodeInstruction::kStore3:
323 case ByteCodeInstruction::kStoreGlobal3:
324 case ByteCodeInstruction::kWriteExternal3:
325 return -3;
326
327 case ByteCodeInstruction::kPop4:
328 case ByteCodeInstruction::kStore4:
329 case ByteCodeInstruction::kStoreGlobal4:
330 case ByteCodeInstruction::kWriteExternal4:
331 return -4;
332
333 case ByteCodeInstruction::kPopN:
334 case ByteCodeInstruction::kStoreSwizzle:
335 case ByteCodeInstruction::kStoreSwizzleGlobal:
336 return -count;
337
338 // Consumes 'count' values, plus one for the 'address'
339 case ByteCodeInstruction::kStoreExtended:
340 case ByteCodeInstruction::kStoreExtendedGlobal:
341 case ByteCodeInstruction::kStoreSwizzleIndirect:
342 case ByteCodeInstruction::kStoreSwizzleIndirectGlobal:
343 return -count - 1;
344
345 // Strange ops where the caller computes the delta for us:
346 case ByteCodeInstruction::kCallExternal:
347 case ByteCodeInstruction::kMatrixToMatrix:
348 case ByteCodeInstruction::kMatrixMultiply:
349 case ByteCodeInstruction::kReserve:
350 case ByteCodeInstruction::kReturn:
351 case ByteCodeInstruction::kScalarToMatrix:
352 case ByteCodeInstruction::kSwizzle:
353 return count;
354
355 // Miscellaneous
356
357 // kCall is net-zero. Max stack depth is adjusted in writeFunctionCall.
358 case ByteCodeInstruction::kCall: return 0;
359 case ByteCodeInstruction::kBranch: return 0;
360 case ByteCodeInstruction::kBranchIfAllFalse: return 0;
361
362 case ByteCodeInstruction::kMaskPush: return -1;
363 case ByteCodeInstruction::kMaskPop: return 0;
364 case ByteCodeInstruction::kMaskNegate: return 0;
365 case ByteCodeInstruction::kMaskBlend: return -count;
366
367 case ByteCodeInstruction::kLoopBegin: return 0;
368 case ByteCodeInstruction::kLoopNext: return 0;
369 case ByteCodeInstruction::kLoopMask: return -1;
370 case ByteCodeInstruction::kLoopEnd: return 0;
371 case ByteCodeInstruction::kLoopBreak: return 0;
372 case ByteCodeInstruction::kLoopContinue: return 0;
373
374 default:
Brian Osmanc7ec9e22019-07-16 08:49:11 -0400375 ABORT("unsupported instruction %d\n", (int)inst);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400376 return 0;
377 }
378}
379
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400380int ByteCodeGenerator::getLocation(const Variable& var) {
381 // given that we seldom have more than a couple of variables, linear search is probably the most
382 // efficient way to handle lookups
383 switch (var.fStorage) {
384 case Variable::kLocal_Storage: {
385 for (int i = fLocals.size() - 1; i >= 0; --i) {
386 if (fLocals[i] == &var) {
Brian Osman1091f022019-05-16 09:42:16 -0400387 SkASSERT(fParameterCount + i <= 255);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400388 return fParameterCount + i;
389 }
390 }
391 int result = fParameterCount + fLocals.size();
392 fLocals.push_back(&var);
Brian Osman07c117b2019-05-23 12:51:06 -0700393 for (int i = 0; i < SlotCount(var.fType) - 1; ++i) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400394 fLocals.push_back(nullptr);
395 }
Brian Osman1091f022019-05-16 09:42:16 -0400396 SkASSERT(result <= 255);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400397 return result;
398 }
399 case Variable::kParameter_Storage: {
400 int offset = 0;
401 for (const auto& p : fFunction->fDeclaration.fParameters) {
402 if (p == &var) {
Brian Osman1091f022019-05-16 09:42:16 -0400403 SkASSERT(offset <= 255);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400404 return offset;
405 }
Brian Osman07c117b2019-05-23 12:51:06 -0700406 offset += SlotCount(p->fType);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400407 }
408 SkASSERT(false);
Brian Osman1091f022019-05-16 09:42:16 -0400409 return 0;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400410 }
411 case Variable::kGlobal_Storage: {
412 int offset = 0;
413 for (const auto& e : fProgram) {
414 if (e.fKind == ProgramElement::kVar_Kind) {
415 VarDeclarations& decl = (VarDeclarations&) e;
416 for (const auto& v : decl.fVars) {
417 const Variable* declVar = ((VarDeclaration&) *v).fVar;
418 if (declVar->fModifiers.fLayout.fBuiltin >= 0) {
419 continue;
420 }
421 if (declVar == &var) {
Brian Osmanb7451292019-05-15 13:02:13 -0400422 SkASSERT(offset <= 255);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400423 return offset;
424 }
Brian Osman07c117b2019-05-23 12:51:06 -0700425 offset += SlotCount(declVar->fType);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400426 }
427 }
428 }
429 SkASSERT(false);
Brian Osman1091f022019-05-16 09:42:16 -0400430 return 0;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400431 }
432 default:
433 SkASSERT(false);
434 return 0;
435 }
436}
437
Brian Osman07c117b2019-05-23 12:51:06 -0700438int ByteCodeGenerator::getLocation(const Expression& expr, Variable::Storage* storage) {
439 switch (expr.fKind) {
440 case Expression::kFieldAccess_Kind: {
441 const FieldAccess& f = (const FieldAccess&)expr;
442 int baseAddr = this->getLocation(*f.fBase, storage);
443 int offset = 0;
444 for (int i = 0; i < f.fFieldIndex; ++i) {
445 offset += SlotCount(*f.fBase->fType.fields()[i].fType);
446 }
447 if (baseAddr < 0) {
Brian Osman86769292019-06-21 11:05:47 -0400448 if (offset != 0) {
449 this->write(ByteCodeInstruction::kPushImmediate);
450 this->write32(offset);
451 this->write(ByteCodeInstruction::kAddI);
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400452 this->write8(1);
Brian Osman86769292019-06-21 11:05:47 -0400453 }
Brian Osman07c117b2019-05-23 12:51:06 -0700454 return -1;
455 } else {
456 return baseAddr + offset;
457 }
458 }
459 case Expression::kIndex_Kind: {
460 const IndexExpression& i = (const IndexExpression&)expr;
461 int stride = SlotCount(i.fType);
Brian Osman869a3e82019-07-18 17:00:34 -0400462 int length = i.fBase->fType.columns();
463 SkASSERT(length <= 255);
Brian Osman07c117b2019-05-23 12:51:06 -0700464 int offset = -1;
465 if (i.fIndex->isConstant()) {
Brian Osman869a3e82019-07-18 17:00:34 -0400466 int64_t index = i.fIndex->getConstantInt();
467 if (index < 0 || index >= length) {
468 fErrors.error(i.fIndex->fOffset, "Array index out of bounds.");
469 return 0;
470 }
471 offset = index * stride;
Brian Osman07c117b2019-05-23 12:51:06 -0700472 } else {
Brian Osman86769292019-06-21 11:05:47 -0400473 if (i.fIndex->hasSideEffects()) {
474 // Having a side-effect in an indexer is technically safe for an rvalue,
475 // but with lvalues we have to evaluate the indexer twice, so make it an error.
476 fErrors.error(i.fIndex->fOffset,
477 "Index expressions with side-effects not supported in byte code.");
478 return 0;
479 }
Brian Osman07c117b2019-05-23 12:51:06 -0700480 this->writeExpression(*i.fIndex);
Brian Osman869a3e82019-07-18 17:00:34 -0400481 this->write(ByteCodeInstruction::kClampIndex);
482 this->write8(length);
Brian Osman86769292019-06-21 11:05:47 -0400483 if (stride != 1) {
484 this->write(ByteCodeInstruction::kPushImmediate);
485 this->write32(stride);
486 this->write(ByteCodeInstruction::kMultiplyI);
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400487 this->write8(1);
Brian Osman86769292019-06-21 11:05:47 -0400488 }
Brian Osman07c117b2019-05-23 12:51:06 -0700489 }
490 int baseAddr = this->getLocation(*i.fBase, storage);
Brian Osman86769292019-06-21 11:05:47 -0400491
492 // Are both components known statically?
Brian Osman07c117b2019-05-23 12:51:06 -0700493 if (baseAddr >= 0 && offset >= 0) {
494 return baseAddr + offset;
495 }
Brian Osman86769292019-06-21 11:05:47 -0400496
497 // At least one component is dynamic (and on the stack).
498
499 // If the other component is zero, we're done
500 if (baseAddr == 0 || offset == 0) {
501 return -1;
502 }
503
504 // Push the non-dynamic component (if any) to the stack, then add the two
Brian Osman07c117b2019-05-23 12:51:06 -0700505 if (baseAddr >= 0) {
506 this->write(ByteCodeInstruction::kPushImmediate);
507 this->write32(baseAddr);
508 }
509 if (offset >= 0) {
510 this->write(ByteCodeInstruction::kPushImmediate);
511 this->write32(offset);
512 }
513 this->write(ByteCodeInstruction::kAddI);
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400514 this->write8(1);
Brian Osman07c117b2019-05-23 12:51:06 -0700515 return -1;
516 }
Brian Osman0785db02019-05-24 14:19:11 -0400517 case Expression::kSwizzle_Kind: {
518 const Swizzle& s = (const Swizzle&)expr;
519 SkASSERT(swizzle_is_simple(s));
520 int baseAddr = this->getLocation(*s.fBase, storage);
521 int offset = s.fComponents[0];
522 if (baseAddr < 0) {
Brian Osman86769292019-06-21 11:05:47 -0400523 if (offset != 0) {
524 this->write(ByteCodeInstruction::kPushImmediate);
525 this->write32(offset);
526 this->write(ByteCodeInstruction::kAddI);
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400527 this->write8(1);
Brian Osman86769292019-06-21 11:05:47 -0400528 }
Brian Osman0785db02019-05-24 14:19:11 -0400529 return -1;
530 } else {
531 return baseAddr + offset;
532 }
533 }
Brian Osman07c117b2019-05-23 12:51:06 -0700534 case Expression::kVariableReference_Kind: {
535 const Variable& var = ((const VariableReference&)expr).fVariable;
536 *storage = var.fStorage;
537 return this->getLocation(var);
538 }
539 default:
540 SkASSERT(false);
541 return 0;
542 }
543}
544
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400545void ByteCodeGenerator::write8(uint8_t b) {
546 fCode->push_back(b);
547}
548
549void ByteCodeGenerator::write16(uint16_t i) {
Mike Klein76346ac2019-05-17 11:57:10 -0500550 size_t n = fCode->size();
551 fCode->resize(n+2);
552 memcpy(fCode->data() + n, &i, 2);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400553}
554
555void ByteCodeGenerator::write32(uint32_t i) {
Mike Klein76346ac2019-05-17 11:57:10 -0500556 size_t n = fCode->size();
557 fCode->resize(n+4);
558 memcpy(fCode->data() + n, &i, 4);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400559}
560
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400561void ByteCodeGenerator::write(ByteCodeInstruction i, int count) {
Brian Osman4a47da72019-07-12 11:30:32 -0400562 switch (i) {
563 case ByteCodeInstruction::kLoopBegin: this->enterLoop(); break;
564 case ByteCodeInstruction::kLoopEnd: this->exitLoop(); break;
565
566 case ByteCodeInstruction::kMaskPush: this->enterCondition(); break;
567 case ByteCodeInstruction::kMaskPop:
568 case ByteCodeInstruction::kMaskBlend: this->exitCondition(); break;
569 default: /* Do nothing */ break;
570 }
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400571 instruction val = (instruction) i;
572 size_t n = fCode->size();
573 fCode->resize(n + sizeof(val));
574 memcpy(fCode->data() + n, &val, sizeof(val));
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400575 fStackCount += StackUsage(i, count);
576 fMaxStackCount = std::max(fMaxStackCount, fStackCount);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400577}
578
Mike Klein76346ac2019-05-17 11:57:10 -0500579static ByteCodeInstruction vector_instruction(ByteCodeInstruction base, int count) {
Brian Osman07c117b2019-05-23 12:51:06 -0700580 SkASSERT(count >= 1 && count <= 4);
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400581 return ((ByteCodeInstruction) ((int) base + 1 - count));
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400582}
583
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400584void ByteCodeGenerator::writeTypedInstruction(const Type& type, ByteCodeInstruction s,
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400585 ByteCodeInstruction u, ByteCodeInstruction f,
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400586 int count, bool writeCount) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400587 switch (type_category(type)) {
588 case TypeCategory::kSigned:
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400589 this->write(vector_instruction(s, count));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400590 break;
591 case TypeCategory::kUnsigned:
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400592 this->write(vector_instruction(u, count));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400593 break;
Brian Osman1e855b22019-05-29 15:21:52 -0400594 case TypeCategory::kFloat: {
595 if (count > 4) {
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400596 this->write((ByteCodeInstruction)((int)f + 1), count);
Brian Osman1e855b22019-05-29 15:21:52 -0400597 } else {
598 this->write(vector_instruction(f, count));
599 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400600 break;
Brian Osman1e855b22019-05-29 15:21:52 -0400601 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400602 default:
603 SkASSERT(false);
604 }
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400605 if (writeCount) {
606 this->write8(count);
607 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400608}
609
Brian Osman3e29f1d2019-05-28 09:35:05 -0400610bool ByteCodeGenerator::writeBinaryExpression(const BinaryExpression& b, bool discard) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400611 if (b.fOperator == Token::Kind::EQ) {
612 std::unique_ptr<LValue> lvalue = this->getLValue(*b.fLeft);
613 this->writeExpression(*b.fRight);
Brian Osman3e29f1d2019-05-28 09:35:05 -0400614 lvalue->store(discard);
615 discard = false;
616 return discard;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400617 }
Brian Osman16e6fd52019-05-29 11:19:00 -0400618 const Type& lType = b.fLeft->fType;
619 const Type& rType = b.fRight->fType;
Brian Osman909231c2019-05-29 15:34:36 -0400620 bool lVecOrMtx = (lType.kind() == Type::kVector_Kind || lType.kind() == Type::kMatrix_Kind);
621 bool rVecOrMtx = (rType.kind() == Type::kVector_Kind || rType.kind() == Type::kMatrix_Kind);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400622 Token::Kind op;
623 std::unique_ptr<LValue> lvalue;
624 if (is_assignment(b.fOperator)) {
625 lvalue = this->getLValue(*b.fLeft);
626 lvalue->load();
627 op = remove_assignment(b.fOperator);
628 } else {
629 this->writeExpression(*b.fLeft);
630 op = b.fOperator;
Brian Osman909231c2019-05-29 15:34:36 -0400631 if (!lVecOrMtx && rVecOrMtx) {
Brian Osman16e6fd52019-05-29 11:19:00 -0400632 for (int i = SlotCount(rType); i > 1; --i) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400633 this->write(ByteCodeInstruction::kDup);
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400634 this->write8(1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400635 }
636 }
637 }
Ethan Nicholasd166d2e2019-09-23 11:43:45 -0400638 int count = std::max(SlotCount(lType), SlotCount(rType));
Brian Osmane5bbce22019-09-23 12:38:40 -0400639 SkDEBUGCODE(TypeCategory tc = type_category(lType));
Ethan Nicholasd166d2e2019-09-23 11:43:45 -0400640 switch (op) {
641 case Token::Kind::LOGICALAND: {
Brian Osmane5bbce22019-09-23 12:38:40 -0400642 SkASSERT(tc == SkSL::TypeCategory::kBool && count == 1);
Ethan Nicholasd166d2e2019-09-23 11:43:45 -0400643 this->write(ByteCodeInstruction::kDup);
644 this->write8(1);
645 this->write(ByteCodeInstruction::kMaskPush);
646 this->write(ByteCodeInstruction::kBranchIfAllFalse);
647 DeferredLocation falseLocation(this);
648 this->writeExpression(*b.fRight);
649 this->write(ByteCodeInstruction::kAndB);
650 falseLocation.set();
651 this->write(ByteCodeInstruction::kMaskPop);
652 return false;
653 }
654 case Token::Kind::LOGICALOR: {
Brian Osmane5bbce22019-09-23 12:38:40 -0400655 SkASSERT(tc == SkSL::TypeCategory::kBool && count == 1);
Ethan Nicholasd166d2e2019-09-23 11:43:45 -0400656 this->write(ByteCodeInstruction::kDup);
657 this->write8(1);
658 this->write(ByteCodeInstruction::kNotB);
659 this->write(ByteCodeInstruction::kMaskPush);
660 this->write(ByteCodeInstruction::kBranchIfAllFalse);
661 DeferredLocation falseLocation(this);
662 this->writeExpression(*b.fRight);
663 this->write(ByteCodeInstruction::kOrB);
664 falseLocation.set();
665 this->write(ByteCodeInstruction::kMaskPop);
666 return false;
667 }
Brian Osman4c2146f2019-09-24 09:39:38 -0400668 case Token::Kind::SHL:
669 case Token::Kind::SHR: {
670 SkASSERT(count == 1 && (tc == SkSL::TypeCategory::kSigned ||
671 tc == SkSL::TypeCategory::kUnsigned));
672 if (!b.fRight->isConstant()) {
673 fErrors.error(b.fRight->fOffset, "Shift amounts must be constant");
674 return false;
675 }
676 int64_t shift = b.fRight->getConstantInt();
677 if (shift < 0 || shift > 31) {
678 fErrors.error(b.fRight->fOffset, "Shift amount out of range");
679 return false;
680 }
681
682 if (op == Token::Kind::SHL) {
683 this->write(ByteCodeInstruction::kShiftLeft);
684 } else {
685 this->write(type_category(lType) == TypeCategory::kSigned
686 ? ByteCodeInstruction::kShiftRightS
687 : ByteCodeInstruction::kShiftRightU);
688 }
689 this->write8(shift);
690 return false;
691 }
692
Ethan Nicholasd166d2e2019-09-23 11:43:45 -0400693 default:
694 break;
695 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400696 this->writeExpression(*b.fRight);
Brian Osman909231c2019-05-29 15:34:36 -0400697 if (lVecOrMtx && !rVecOrMtx) {
Brian Osman16e6fd52019-05-29 11:19:00 -0400698 for (int i = SlotCount(lType); i > 1; --i) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400699 this->write(ByteCodeInstruction::kDup);
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400700 this->write8(1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400701 }
702 }
Brian Osman909231c2019-05-29 15:34:36 -0400703 // Special case for M*V, V*M, M*M (but not V*V!)
704 if (op == Token::Kind::STAR && lVecOrMtx && rVecOrMtx &&
705 !(lType.kind() == Type::kVector_Kind && rType.kind() == Type::kVector_Kind)) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400706 this->write(ByteCodeInstruction::kMatrixMultiply,
707 SlotCount(b.fType) - (SlotCount(lType) + SlotCount(rType)));
Brian Osman909231c2019-05-29 15:34:36 -0400708 int rCols = rType.columns(),
709 rRows = rType.rows(),
710 lCols = lType.columns(),
711 lRows = lType.rows();
712 // M*V treats the vector as a column
713 if (rType.kind() == Type::kVector_Kind) {
714 std::swap(rCols, rRows);
715 }
716 SkASSERT(lCols == rRows);
717 SkASSERT(SlotCount(b.fType) == lRows * rCols);
718 this->write8(lCols);
719 this->write8(lRows);
720 this->write8(rCols);
721 } else {
Brian Osman909231c2019-05-29 15:34:36 -0400722 switch (op) {
723 case Token::Kind::EQEQ:
724 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareIEQ,
725 ByteCodeInstruction::kCompareIEQ,
726 ByteCodeInstruction::kCompareFEQ,
727 count);
728 // Collapse to a single bool
729 for (int i = count; i > 1; --i) {
730 this->write(ByteCodeInstruction::kAndB);
731 }
732 break;
733 case Token::Kind::GT:
734 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSGT,
735 ByteCodeInstruction::kCompareUGT,
736 ByteCodeInstruction::kCompareFGT,
737 count);
738 break;
739 case Token::Kind::GTEQ:
740 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSGTEQ,
741 ByteCodeInstruction::kCompareUGTEQ,
742 ByteCodeInstruction::kCompareFGTEQ,
743 count);
744 break;
745 case Token::Kind::LT:
746 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSLT,
747 ByteCodeInstruction::kCompareULT,
748 ByteCodeInstruction::kCompareFLT,
749 count);
750 break;
751 case Token::Kind::LTEQ:
752 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSLTEQ,
753 ByteCodeInstruction::kCompareULTEQ,
754 ByteCodeInstruction::kCompareFLTEQ,
755 count);
756 break;
757 case Token::Kind::MINUS:
758 this->writeTypedInstruction(lType, ByteCodeInstruction::kSubtractI,
759 ByteCodeInstruction::kSubtractI,
760 ByteCodeInstruction::kSubtractF,
761 count);
762 break;
763 case Token::Kind::NEQ:
764 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareINEQ,
765 ByteCodeInstruction::kCompareINEQ,
766 ByteCodeInstruction::kCompareFNEQ,
767 count);
768 // Collapse to a single bool
769 for (int i = count; i > 1; --i) {
770 this->write(ByteCodeInstruction::kOrB);
771 }
772 break;
773 case Token::Kind::PERCENT:
774 this->writeTypedInstruction(lType, ByteCodeInstruction::kRemainderS,
775 ByteCodeInstruction::kRemainderU,
776 ByteCodeInstruction::kRemainderF,
777 count);
778 break;
779 case Token::Kind::PLUS:
780 this->writeTypedInstruction(lType, ByteCodeInstruction::kAddI,
781 ByteCodeInstruction::kAddI,
782 ByteCodeInstruction::kAddF,
783 count);
784 break;
785 case Token::Kind::SLASH:
786 this->writeTypedInstruction(lType, ByteCodeInstruction::kDivideS,
787 ByteCodeInstruction::kDivideU,
788 ByteCodeInstruction::kDivideF,
789 count);
790 break;
791 case Token::Kind::STAR:
792 this->writeTypedInstruction(lType, ByteCodeInstruction::kMultiplyI,
793 ByteCodeInstruction::kMultiplyI,
794 ByteCodeInstruction::kMultiplyF,
795 count);
796 break;
Brian Osman569f12f2019-06-13 11:23:57 -0400797
Brian Osman569f12f2019-06-13 11:23:57 -0400798 case Token::Kind::LOGICALXOR:
Brian Osmane5bbce22019-09-23 12:38:40 -0400799 SkASSERT(tc == SkSL::TypeCategory::kBool && count == 1);
800 this->write(ByteCodeInstruction::kXorB);
801 break;
802
803 case Token::Kind::BITWISEAND:
804 SkASSERT(count == 1 && (tc == SkSL::TypeCategory::kSigned ||
805 tc == SkSL::TypeCategory::kUnsigned));
806 this->write(ByteCodeInstruction::kAndB);
807 break;
808 case Token::Kind::BITWISEOR:
809 SkASSERT(count == 1 && (tc == SkSL::TypeCategory::kSigned ||
810 tc == SkSL::TypeCategory::kUnsigned));
811 this->write(ByteCodeInstruction::kOrB);
812 break;
813 case Token::Kind::BITWISEXOR:
814 SkASSERT(count == 1 && (tc == SkSL::TypeCategory::kSigned ||
815 tc == SkSL::TypeCategory::kUnsigned));
Brian Osman569f12f2019-06-13 11:23:57 -0400816 this->write(ByteCodeInstruction::kXorB);
817 break;
818
Brian Osman909231c2019-05-29 15:34:36 -0400819 default:
Brian Osmandb3dad22019-07-26 15:44:29 -0400820 fErrors.error(b.fOffset, SkSL::String::printf("Unsupported binary operator '%s'",
821 Compiler::OperatorName(op)));
822 break;
Brian Osman909231c2019-05-29 15:34:36 -0400823 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400824 }
825 if (lvalue) {
Brian Osman3e29f1d2019-05-28 09:35:05 -0400826 lvalue->store(discard);
827 discard = false;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400828 }
Brian Osman3e29f1d2019-05-28 09:35:05 -0400829 return discard;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400830}
831
832void ByteCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
833 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osman569f12f2019-06-13 11:23:57 -0400834 this->write32(b.fValue ? ~0 : 0);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400835}
836
837void ByteCodeGenerator::writeConstructor(const Constructor& c) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400838 for (const auto& arg : c.fArguments) {
839 this->writeExpression(*arg);
840 }
841 if (c.fArguments.size() == 1) {
Brian Osman29e013d2019-05-28 17:16:03 -0400842 const Type& inType = c.fArguments[0]->fType;
843 const Type& outType = c.fType;
844 TypeCategory inCategory = type_category(inType);
845 TypeCategory outCategory = type_category(outType);
846 int inCount = SlotCount(inType);
847 int outCount = SlotCount(outType);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400848 if (inCategory != outCategory) {
Brian Osmanc51d7912019-05-22 15:16:16 -0700849 SkASSERT(inCount == outCount);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400850 if (inCategory == TypeCategory::kFloat) {
851 SkASSERT(outCategory == TypeCategory::kSigned ||
852 outCategory == TypeCategory::kUnsigned);
Brian Osmanc51d7912019-05-22 15:16:16 -0700853 this->write(vector_instruction(ByteCodeInstruction::kConvertFtoI, outCount));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400854 } else if (outCategory == TypeCategory::kFloat) {
855 if (inCategory == TypeCategory::kSigned) {
Brian Osmanc51d7912019-05-22 15:16:16 -0700856 this->write(vector_instruction(ByteCodeInstruction::kConvertStoF, outCount));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400857 } else {
858 SkASSERT(inCategory == TypeCategory::kUnsigned);
Brian Osmanc51d7912019-05-22 15:16:16 -0700859 this->write(vector_instruction(ByteCodeInstruction::kConvertUtoF, outCount));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400860 }
861 } else {
862 SkASSERT(false);
863 }
864 }
Brian Osman29e013d2019-05-28 17:16:03 -0400865 if (inType.kind() == Type::kMatrix_Kind && outType.kind() == Type::kMatrix_Kind) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400866 this->write(ByteCodeInstruction::kMatrixToMatrix,
867 SlotCount(outType) - SlotCount(inType));
Brian Osman29e013d2019-05-28 17:16:03 -0400868 this->write8(inType.columns());
869 this->write8(inType.rows());
870 this->write8(outType.columns());
871 this->write8(outType.rows());
872 } else if (inCount != outCount) {
Brian Osmanc51d7912019-05-22 15:16:16 -0700873 SkASSERT(inCount == 1);
Brian Osman29e013d2019-05-28 17:16:03 -0400874 if (outType.kind() == Type::kMatrix_Kind) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400875 this->write(ByteCodeInstruction::kScalarToMatrix, SlotCount(outType) - 1);
Brian Osman29e013d2019-05-28 17:16:03 -0400876 this->write8(outType.columns());
877 this->write8(outType.rows());
878 } else {
879 SkASSERT(outType.kind() == Type::kVector_Kind);
880 for (; inCount != outCount; ++inCount) {
881 this->write(ByteCodeInstruction::kDup);
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400882 this->write8(1);
Brian Osman29e013d2019-05-28 17:16:03 -0400883 }
Brian Osmanc51d7912019-05-22 15:16:16 -0700884 }
885 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400886 }
887}
888
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400889void ByteCodeGenerator::writeExternalFunctionCall(const ExternalFunctionCall& f) {
890 int argumentCount = 0;
891 for (const auto& arg : f.fArguments) {
892 this->writeExpression(*arg);
Brian Osman07c117b2019-05-23 12:51:06 -0700893 argumentCount += SlotCount(arg->fType);
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400894 }
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400895 this->write(ByteCodeInstruction::kCallExternal, SlotCount(f.fType) - argumentCount);
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400896 SkASSERT(argumentCount <= 255);
897 this->write8(argumentCount);
Brian Osman07c117b2019-05-23 12:51:06 -0700898 this->write8(SlotCount(f.fType));
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400899 int index = fOutput->fExternalValues.size();
900 fOutput->fExternalValues.push_back(f.fFunction);
901 SkASSERT(index <= 255);
902 this->write8(index);
903}
904
Ethan Nicholas91164d12019-05-15 15:29:54 -0400905void ByteCodeGenerator::writeExternalValue(const ExternalValueReference& e) {
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400906 int count = SlotCount(e.fValue->type());
907 this->write(vector_instruction(ByteCodeInstruction::kReadExternal, count));
908 this->write8(count);
Ethan Nicholas91164d12019-05-15 15:29:54 -0400909 int index = fOutput->fExternalValues.size();
910 fOutput->fExternalValues.push_back(e.fValue);
911 SkASSERT(index <= 255);
912 this->write8(index);
913}
914
Brian Osman07c117b2019-05-23 12:51:06 -0700915void ByteCodeGenerator::writeVariableExpression(const Expression& expr) {
Brian Osman869a3e82019-07-18 17:00:34 -0400916 Variable::Storage storage = Variable::kLocal_Storage;
Brian Osman07c117b2019-05-23 12:51:06 -0700917 int location = this->getLocation(expr, &storage);
918 bool isGlobal = storage == Variable::kGlobal_Storage;
919 int count = SlotCount(expr.fType);
920 if (location < 0 || count > 4) {
921 if (location >= 0) {
922 this->write(ByteCodeInstruction::kPushImmediate);
923 this->write32(location);
924 }
925 this->write(isGlobal ? ByteCodeInstruction::kLoadExtendedGlobal
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400926 : ByteCodeInstruction::kLoadExtended,
927 count);
Brian Osman07c117b2019-05-23 12:51:06 -0700928 this->write8(count);
929 } else {
930 this->write(vector_instruction(isGlobal ? ByteCodeInstruction::kLoadGlobal
931 : ByteCodeInstruction::kLoad,
932 count));
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400933 this->write8(count);
Brian Osman07c117b2019-05-23 12:51:06 -0700934 this->write8(location);
935 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400936}
937
Brian Osmand30e0392019-06-14 14:05:14 -0400938static inline uint32_t float_to_bits(float x) {
939 uint32_t u;
940 memcpy(&u, &x, sizeof(uint32_t));
941 return u;
942}
943
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400944void ByteCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
945 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osmand30e0392019-06-14 14:05:14 -0400946 this->write32(float_to_bits(f.fValue));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400947}
948
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400949void ByteCodeGenerator::writeIntrinsicCall(const FunctionCall& c) {
950 auto found = fIntrinsics.find(c.fFunction.fName);
951 if (found == fIntrinsics.end()) {
952 fErrors.error(c.fOffset, "unsupported intrinsic function");
953 return;
954 }
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400955 int count = SlotCount(c.fArguments[0]->fType);
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400956 if (found->second.fIsSpecial) {
Brian Osmanb380e712019-07-24 17:02:39 -0400957 SpecialIntrinsic special = found->second.fValue.fSpecial;
958 switch (special) {
959 case SpecialIntrinsic::kDot: {
960 SkASSERT(c.fArguments.size() == 2);
961 SkASSERT(count == SlotCount(c.fArguments[1]->fType));
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400962 this->write(vector_instruction(ByteCodeInstruction::kMultiplyF, count));
963 this->write8(count);
Brian Osmanb380e712019-07-24 17:02:39 -0400964 for (int i = count; i > 1; --i) {
965 this->write(ByteCodeInstruction::kAddF);
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400966 this->write8(1);
Brian Osmanb380e712019-07-24 17:02:39 -0400967 }
968 break;
969 }
Brian Osmanb380e712019-07-24 17:02:39 -0400970 default:
971 SkASSERT(false);
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400972 }
973 } else {
974 switch (found->second.fValue.fInstruction) {
975 case ByteCodeInstruction::kCos:
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400976 case ByteCodeInstruction::kSin:
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400977 case ByteCodeInstruction::kTan:
978 SkASSERT(c.fArguments.size() > 0);
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400979 this->write(vector_instruction(found->second.fValue.fInstruction, count));
980 this->write8(count);
981 break;
982 case ByteCodeInstruction::kSqrt:
983 SkASSERT(c.fArguments.size() > 0);
984 this->write(vector_instruction(found->second.fValue.fInstruction, count));
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400985 break;
Mike Reed634c9412019-07-18 13:20:04 -0400986 case ByteCodeInstruction::kInverse2x2: {
987 SkASSERT(c.fArguments.size() > 0);
988 auto op = ByteCodeInstruction::kInverse2x2;
989 switch (count) {
990 case 4: break; // float2x2
991 case 9: op = ByteCodeInstruction::kInverse3x3; break;
992 case 16: op = ByteCodeInstruction::kInverse4x4; break;
993 default: SkASSERT(false);
994 }
995 this->write(op);
Brian Osmanb380e712019-07-24 17:02:39 -0400996 break;
997 }
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400998 default:
999 SkASSERT(false);
1000 }
Ethan Nicholas82162ee2019-05-21 16:05:08 -04001001 }
1002}
1003
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001004void ByteCodeGenerator::writeFunctionCall(const FunctionCall& f) {
Brian Osmand3494ed2019-06-20 15:41:34 -04001005 // Builtins have simple signatures...
Ethan Nicholas82162ee2019-05-21 16:05:08 -04001006 if (f.fFunction.fBuiltin) {
Brian Osmand3494ed2019-06-20 15:41:34 -04001007 for (const auto& arg : f.fArguments) {
1008 this->writeExpression(*arg);
1009 }
Ethan Nicholas82162ee2019-05-21 16:05:08 -04001010 this->writeIntrinsicCall(f);
1011 return;
1012 }
Brian Osmand3494ed2019-06-20 15:41:34 -04001013
Brian Osman6f5358f2019-07-09 14:17:23 -04001014 // Find the index of the function we're calling. We explicitly do not allow calls to functions
1015 // before they're defined. This is an easy-to-understand rule that prevents recursion.
1016 size_t idx;
1017 for (idx = 0; idx < fFunctions.size(); ++idx) {
1018 if (f.fFunction.matches(fFunctions[idx]->fDeclaration)) {
1019 break;
1020 }
1021 }
1022 if (idx > 255) {
1023 fErrors.error(f.fOffset, "Function count limit exceeded");
1024 return;
1025 } else if (idx >= fFunctions.size()) {
1026 fErrors.error(f.fOffset, "Call to undefined function");
1027 return;
1028 }
1029
1030 // We may need to deal with out parameters, so the sequence is tricky
Brian Osmand3494ed2019-06-20 15:41:34 -04001031 if (int returnCount = SlotCount(f.fType)) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001032 this->write(ByteCodeInstruction::kReserve, returnCount);
Brian Osmand3494ed2019-06-20 15:41:34 -04001033 this->write8(returnCount);
1034 }
1035
1036 int argCount = f.fArguments.size();
1037 std::vector<std::unique_ptr<LValue>> lvalues;
1038 for (int i = 0; i < argCount; ++i) {
1039 const auto& param = f.fFunction.fParameters[i];
1040 const auto& arg = f.fArguments[i];
1041 if (param->fModifiers.fFlags & Modifiers::kOut_Flag) {
1042 lvalues.emplace_back(this->getLValue(*arg));
1043 lvalues.back()->load();
1044 } else {
1045 this->writeExpression(*arg);
1046 }
1047 }
1048
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001049 // The space used by the call is based on the callee, but it also unwinds all of that before
1050 // we continue execution. We adjust our max stack depths below.
Brian Osman226668a2019-05-14 16:47:30 -04001051 this->write(ByteCodeInstruction::kCall);
Brian Osman6f5358f2019-07-09 14:17:23 -04001052 this->write8(idx);
Brian Osmand3494ed2019-06-20 15:41:34 -04001053
Brian Osman4a47da72019-07-12 11:30:32 -04001054 const ByteCodeFunction* callee = fOutput->fFunctions[idx].get();
1055 fMaxLoopCount = std::max(fMaxLoopCount, fLoopCount + callee->fLoopCount);
1056 fMaxConditionCount = std::max(fMaxConditionCount, fConditionCount + callee->fConditionCount);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001057 fMaxStackCount = std::max(fMaxStackCount, fStackCount + callee->fLocalCount
1058 + callee->fStackCount);
Brian Osman4a47da72019-07-12 11:30:32 -04001059
Brian Osmand3494ed2019-06-20 15:41:34 -04001060 // After the called function returns, the stack will still contain our arguments. We have to
1061 // pop them (storing any out parameters back to their lvalues as we go). We glob together slot
1062 // counts for all parameters that aren't out-params, so we can pop them in one big chunk.
1063 int popCount = 0;
1064 auto pop = [&]() {
1065 if (popCount > 4) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001066 this->write(ByteCodeInstruction::kPopN, popCount);
Brian Osmand3494ed2019-06-20 15:41:34 -04001067 this->write8(popCount);
1068 } else if (popCount > 0) {
1069 this->write(vector_instruction(ByteCodeInstruction::kPop, popCount));
1070 }
1071 popCount = 0;
1072 };
1073
1074 for (int i = argCount - 1; i >= 0; --i) {
1075 const auto& param = f.fFunction.fParameters[i];
1076 const auto& arg = f.fArguments[i];
1077 if (param->fModifiers.fFlags & Modifiers::kOut_Flag) {
1078 pop();
1079 lvalues.back()->store(true);
1080 lvalues.pop_back();
1081 } else {
1082 popCount += SlotCount(arg->fType);
1083 }
1084 }
1085 pop();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001086}
1087
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001088void ByteCodeGenerator::writeIntLiteral(const IntLiteral& i) {
1089 this->write(ByteCodeInstruction::kPushImmediate);
1090 this->write32(i.fValue);
1091}
1092
1093void ByteCodeGenerator::writeNullLiteral(const NullLiteral& n) {
1094 // not yet implemented
1095 abort();
1096}
1097
Brian Osman3e29f1d2019-05-28 09:35:05 -04001098bool ByteCodeGenerator::writePrefixExpression(const PrefixExpression& p, bool discard) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001099 switch (p.fOperator) {
1100 case Token::Kind::PLUSPLUS: // fall through
1101 case Token::Kind::MINUSMINUS: {
Brian Osman07c117b2019-05-23 12:51:06 -07001102 SkASSERT(SlotCount(p.fOperand->fType) == 1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001103 std::unique_ptr<LValue> lvalue = this->getLValue(*p.fOperand);
1104 lvalue->load();
1105 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osmand30e0392019-06-14 14:05:14 -04001106 this->write32(type_category(p.fType) == TypeCategory::kFloat ? float_to_bits(1.0f) : 1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001107 if (p.fOperator == Token::Kind::PLUSPLUS) {
1108 this->writeTypedInstruction(p.fType,
1109 ByteCodeInstruction::kAddI,
1110 ByteCodeInstruction::kAddI,
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001111 ByteCodeInstruction::kAddF,
1112 1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001113 } else {
1114 this->writeTypedInstruction(p.fType,
1115 ByteCodeInstruction::kSubtractI,
1116 ByteCodeInstruction::kSubtractI,
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001117 ByteCodeInstruction::kSubtractF,
1118 1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001119 }
Brian Osman3e29f1d2019-05-28 09:35:05 -04001120 lvalue->store(discard);
1121 discard = false;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001122 break;
1123 }
Ethan Nicholas354ecf32019-05-07 16:13:02 -04001124 case Token::Kind::MINUS: {
1125 this->writeExpression(*p.fOperand);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001126 this->writeTypedInstruction(p.fType,
Mike Klein12710912019-05-21 11:04:59 -05001127 ByteCodeInstruction::kNegateI,
1128 ByteCodeInstruction::kNegateI,
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001129 ByteCodeInstruction::kNegateF,
Ethan Nicholasc70027b2019-09-05 16:50:52 -04001130 SlotCount(p.fOperand->fType),
1131 false);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001132 break;
Ethan Nicholas354ecf32019-05-07 16:13:02 -04001133 }
Brian Osmane5bbce22019-09-23 12:38:40 -04001134 case Token::Kind::LOGICALNOT:
1135 case Token::Kind::BITWISENOT: {
1136 SkASSERT(SlotCount(p.fOperand->fType) == 1);
1137 SkDEBUGCODE(TypeCategory tc = type_category(p.fOperand->fType));
1138 SkASSERT((p.fOperator == Token::Kind::LOGICALNOT && tc == TypeCategory::kBool) ||
1139 (p.fOperator == Token::Kind::BITWISENOT && (tc == TypeCategory::kSigned ||
1140 tc == TypeCategory::kUnsigned)));
1141 this->writeExpression(*p.fOperand);
1142 this->write(ByteCodeInstruction::kNotB);
1143 break;
1144 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001145 default:
1146 SkASSERT(false);
1147 }
Brian Osman3e29f1d2019-05-28 09:35:05 -04001148 return discard;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001149}
1150
Brian Osman3e29f1d2019-05-28 09:35:05 -04001151bool ByteCodeGenerator::writePostfixExpression(const PostfixExpression& p, bool discard) {
Brian Osmanf3fa6002019-05-17 14:26:53 -04001152 switch (p.fOperator) {
1153 case Token::Kind::PLUSPLUS: // fall through
1154 case Token::Kind::MINUSMINUS: {
Brian Osman07c117b2019-05-23 12:51:06 -07001155 SkASSERT(SlotCount(p.fOperand->fType) == 1);
Brian Osmanf3fa6002019-05-17 14:26:53 -04001156 std::unique_ptr<LValue> lvalue = this->getLValue(*p.fOperand);
1157 lvalue->load();
Brian Osman52c1bf12019-07-18 13:12:19 -04001158 // If we're not supposed to discard the result, then make a copy *before* the +/-
Brian Osman3e29f1d2019-05-28 09:35:05 -04001159 if (!discard) {
1160 this->write(ByteCodeInstruction::kDup);
Ethan Nicholasc70027b2019-09-05 16:50:52 -04001161 this->write8(1);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001162 }
Brian Osmanf3fa6002019-05-17 14:26:53 -04001163 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osmand30e0392019-06-14 14:05:14 -04001164 this->write32(type_category(p.fType) == TypeCategory::kFloat ? float_to_bits(1.0f) : 1);
Brian Osmanf3fa6002019-05-17 14:26:53 -04001165 if (p.fOperator == Token::Kind::PLUSPLUS) {
1166 this->writeTypedInstruction(p.fType,
1167 ByteCodeInstruction::kAddI,
1168 ByteCodeInstruction::kAddI,
1169 ByteCodeInstruction::kAddF,
1170 1);
1171 } else {
1172 this->writeTypedInstruction(p.fType,
1173 ByteCodeInstruction::kSubtractI,
1174 ByteCodeInstruction::kSubtractI,
1175 ByteCodeInstruction::kSubtractF,
1176 1);
1177 }
Brian Osman52c1bf12019-07-18 13:12:19 -04001178 // Always consume the result as part of the store
1179 lvalue->store(true);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001180 discard = false;
Brian Osmanf3fa6002019-05-17 14:26:53 -04001181 break;
1182 }
1183 default:
1184 SkASSERT(false);
1185 }
Brian Osman3e29f1d2019-05-28 09:35:05 -04001186 return discard;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001187}
1188
1189void ByteCodeGenerator::writeSwizzle(const Swizzle& s) {
Brian Osman0785db02019-05-24 14:19:11 -04001190 if (swizzle_is_simple(s)) {
1191 this->writeVariableExpression(s);
1192 return;
1193 }
1194
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001195 switch (s.fBase->fKind) {
1196 case Expression::kVariableReference_Kind: {
1197 const Variable& var = ((VariableReference&) *s.fBase).fVariable;
Brian Osman1091f022019-05-16 09:42:16 -04001198 this->write(var.fStorage == Variable::kGlobal_Storage
1199 ? ByteCodeInstruction::kLoadSwizzleGlobal
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001200 : ByteCodeInstruction::kLoadSwizzle,
1201 s.fComponents.size());
Brian Osman1091f022019-05-16 09:42:16 -04001202 this->write8(this->getLocation(var));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001203 this->write8(s.fComponents.size());
1204 for (int c : s.fComponents) {
1205 this->write8(c);
1206 }
1207 break;
1208 }
1209 default:
1210 this->writeExpression(*s.fBase);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001211 this->write(ByteCodeInstruction::kSwizzle,
1212 s.fComponents.size() - s.fBase->fType.columns());
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001213 this->write8(s.fBase->fType.columns());
1214 this->write8(s.fComponents.size());
1215 for (int c : s.fComponents) {
1216 this->write8(c);
1217 }
1218 }
1219}
1220
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001221void ByteCodeGenerator::writeTernaryExpression(const TernaryExpression& t) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001222 int count = SlotCount(t.fType);
1223 SkASSERT(count == SlotCount(t.fIfTrue->fType));
1224 SkASSERT(count == SlotCount(t.fIfFalse->fType));
1225
Brian Osman4e93feb2019-05-16 15:38:00 -04001226 this->writeExpression(*t.fTest);
Brian Osman569f12f2019-06-13 11:23:57 -04001227 this->write(ByteCodeInstruction::kMaskPush);
Brian Osman4e93feb2019-05-16 15:38:00 -04001228 this->writeExpression(*t.fIfTrue);
Brian Osman569f12f2019-06-13 11:23:57 -04001229 this->write(ByteCodeInstruction::kMaskNegate);
1230 this->writeExpression(*t.fIfFalse);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001231 this->write(ByteCodeInstruction::kMaskBlend, count);
1232 this->write8(count);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001233}
1234
Brian Osman3e29f1d2019-05-28 09:35:05 -04001235void ByteCodeGenerator::writeExpression(const Expression& e, bool discard) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001236 switch (e.fKind) {
1237 case Expression::kBinary_Kind:
Brian Osman3e29f1d2019-05-28 09:35:05 -04001238 discard = this->writeBinaryExpression((BinaryExpression&) e, discard);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001239 break;
1240 case Expression::kBoolLiteral_Kind:
1241 this->writeBoolLiteral((BoolLiteral&) e);
1242 break;
1243 case Expression::kConstructor_Kind:
1244 this->writeConstructor((Constructor&) e);
1245 break;
Ethan Nicholas9e6a3932019-05-17 16:31:21 -04001246 case Expression::kExternalFunctionCall_Kind:
1247 this->writeExternalFunctionCall((ExternalFunctionCall&) e);
1248 break;
Ethan Nicholas91164d12019-05-15 15:29:54 -04001249 case Expression::kExternalValue_Kind:
1250 this->writeExternalValue((ExternalValueReference&) e);
1251 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001252 case Expression::kFieldAccess_Kind:
Brian Osman07c117b2019-05-23 12:51:06 -07001253 case Expression::kIndex_Kind:
1254 case Expression::kVariableReference_Kind:
1255 this->writeVariableExpression(e);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001256 break;
1257 case Expression::kFloatLiteral_Kind:
1258 this->writeFloatLiteral((FloatLiteral&) e);
1259 break;
1260 case Expression::kFunctionCall_Kind:
1261 this->writeFunctionCall((FunctionCall&) e);
1262 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001263 case Expression::kIntLiteral_Kind:
1264 this->writeIntLiteral((IntLiteral&) e);
1265 break;
1266 case Expression::kNullLiteral_Kind:
1267 this->writeNullLiteral((NullLiteral&) e);
1268 break;
1269 case Expression::kPrefix_Kind:
Brian Osman3e29f1d2019-05-28 09:35:05 -04001270 discard = this->writePrefixExpression((PrefixExpression&) e, discard);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001271 break;
1272 case Expression::kPostfix_Kind:
Brian Osman3e29f1d2019-05-28 09:35:05 -04001273 discard = this->writePostfixExpression((PostfixExpression&) e, discard);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001274 break;
1275 case Expression::kSwizzle_Kind:
1276 this->writeSwizzle((Swizzle&) e);
1277 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001278 case Expression::kTernary_Kind:
1279 this->writeTernaryExpression((TernaryExpression&) e);
1280 break;
1281 default:
1282 printf("unsupported expression %s\n", e.description().c_str());
1283 SkASSERT(false);
1284 }
Brian Osman3e29f1d2019-05-28 09:35:05 -04001285 if (discard) {
1286 int count = SlotCount(e.fType);
1287 if (count > 4) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001288 this->write(ByteCodeInstruction::kPopN, count);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001289 this->write8(count);
Brian Osmanfba386b2019-06-20 14:54:15 -04001290 } else if (count != 0) {
Brian Osman3e29f1d2019-05-28 09:35:05 -04001291 this->write(vector_instruction(ByteCodeInstruction::kPop, count));
1292 }
1293 discard = false;
1294 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001295}
1296
Ethan Nicholas91164d12019-05-15 15:29:54 -04001297class ByteCodeExternalValueLValue : public ByteCodeGenerator::LValue {
1298public:
1299 ByteCodeExternalValueLValue(ByteCodeGenerator* generator, ExternalValue& value, int index)
1300 : INHERITED(*generator)
Brian Osman07c117b2019-05-23 12:51:06 -07001301 , fCount(ByteCodeGenerator::SlotCount(value.type()))
Ethan Nicholas91164d12019-05-15 15:29:54 -04001302 , fIndex(index) {}
1303
1304 void load() override {
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001305 fGenerator.write(vector_instruction(ByteCodeInstruction::kReadExternal, fCount));
Ethan Nicholasc70027b2019-09-05 16:50:52 -04001306 fGenerator.write8(fCount);
Ethan Nicholas91164d12019-05-15 15:29:54 -04001307 fGenerator.write8(fIndex);
1308 }
1309
Brian Osman3e29f1d2019-05-28 09:35:05 -04001310 void store(bool discard) override {
1311 if (!discard) {
1312 fGenerator.write(vector_instruction(ByteCodeInstruction::kDup, fCount));
Ethan Nicholasc70027b2019-09-05 16:50:52 -04001313 fGenerator.write8(fCount);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001314 }
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001315 fGenerator.write(vector_instruction(ByteCodeInstruction::kWriteExternal, fCount));
Ethan Nicholasc70027b2019-09-05 16:50:52 -04001316 fGenerator.write8(fCount);
Ethan Nicholas91164d12019-05-15 15:29:54 -04001317 fGenerator.write8(fIndex);
1318 }
1319
1320private:
1321 typedef LValue INHERITED;
1322
1323 int fCount;
1324
1325 int fIndex;
1326};
1327
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001328class ByteCodeSwizzleLValue : public ByteCodeGenerator::LValue {
1329public:
1330 ByteCodeSwizzleLValue(ByteCodeGenerator* generator, const Swizzle& swizzle)
1331 : INHERITED(*generator)
Brian Osman07c117b2019-05-23 12:51:06 -07001332 , fSwizzle(swizzle) {}
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001333
1334 void load() override {
Brian Osman1091f022019-05-16 09:42:16 -04001335 fGenerator.writeSwizzle(fSwizzle);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001336 }
1337
Brian Osman3e29f1d2019-05-28 09:35:05 -04001338 void store(bool discard) override {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001339 int count = fSwizzle.fComponents.size();
Brian Osman3e29f1d2019-05-28 09:35:05 -04001340 if (!discard) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001341 fGenerator.write(vector_instruction(ByteCodeInstruction::kDup, count));
Ethan Nicholasc70027b2019-09-05 16:50:52 -04001342 fGenerator.write8(count);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001343 }
Brian Osman869a3e82019-07-18 17:00:34 -04001344 Variable::Storage storage = Variable::kLocal_Storage;
Brian Osman07c117b2019-05-23 12:51:06 -07001345 int location = fGenerator.getLocation(*fSwizzle.fBase, &storage);
1346 bool isGlobal = storage == Variable::kGlobal_Storage;
1347 if (location < 0) {
1348 fGenerator.write(isGlobal ? ByteCodeInstruction::kStoreSwizzleIndirectGlobal
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001349 : ByteCodeInstruction::kStoreSwizzleIndirect,
1350 count);
Brian Osman07c117b2019-05-23 12:51:06 -07001351 } else {
1352 fGenerator.write(isGlobal ? ByteCodeInstruction::kStoreSwizzleGlobal
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001353 : ByteCodeInstruction::kStoreSwizzle,
1354 count);
Brian Osman07c117b2019-05-23 12:51:06 -07001355 fGenerator.write8(location);
1356 }
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001357 fGenerator.write8(count);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001358 for (int c : fSwizzle.fComponents) {
1359 fGenerator.write8(c);
1360 }
1361 }
1362
1363private:
1364 const Swizzle& fSwizzle;
1365
1366 typedef LValue INHERITED;
1367};
1368
Brian Osman07c117b2019-05-23 12:51:06 -07001369class ByteCodeExpressionLValue : public ByteCodeGenerator::LValue {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001370public:
Brian Osman07c117b2019-05-23 12:51:06 -07001371 ByteCodeExpressionLValue(ByteCodeGenerator* generator, const Expression& expr)
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001372 : INHERITED(*generator)
Brian Osman07c117b2019-05-23 12:51:06 -07001373 , fExpression(expr) {}
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001374
1375 void load() override {
Brian Osman07c117b2019-05-23 12:51:06 -07001376 fGenerator.writeVariableExpression(fExpression);
Brian Osman1091f022019-05-16 09:42:16 -04001377 }
1378
Brian Osman3e29f1d2019-05-28 09:35:05 -04001379 void store(bool discard) override {
Brian Osman07c117b2019-05-23 12:51:06 -07001380 int count = ByteCodeGenerator::SlotCount(fExpression.fType);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001381 if (!discard) {
1382 if (count > 4) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001383 fGenerator.write(ByteCodeInstruction::kDupN, count);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001384 fGenerator.write8(count);
1385 } else {
1386 fGenerator.write(vector_instruction(ByteCodeInstruction::kDup, count));
Ethan Nicholasc70027b2019-09-05 16:50:52 -04001387 fGenerator.write8(count);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001388 }
Brian Osman07c117b2019-05-23 12:51:06 -07001389 }
Brian Osman869a3e82019-07-18 17:00:34 -04001390 Variable::Storage storage = Variable::kLocal_Storage;
Brian Osman07c117b2019-05-23 12:51:06 -07001391 int location = fGenerator.getLocation(fExpression, &storage);
1392 bool isGlobal = storage == Variable::kGlobal_Storage;
1393 if (location < 0 || count > 4) {
1394 if (location >= 0) {
1395 fGenerator.write(ByteCodeInstruction::kPushImmediate);
1396 fGenerator.write32(location);
1397 }
1398 fGenerator.write(isGlobal ? ByteCodeInstruction::kStoreExtendedGlobal
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001399 : ByteCodeInstruction::kStoreExtended,
1400 count);
Brian Osman07c117b2019-05-23 12:51:06 -07001401 fGenerator.write8(count);
1402 } else {
1403 fGenerator.write(vector_instruction(isGlobal ? ByteCodeInstruction::kStoreGlobal
1404 : ByteCodeInstruction::kStore,
1405 count));
1406 fGenerator.write8(location);
1407 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001408 }
1409
1410private:
1411 typedef LValue INHERITED;
1412
Brian Osman07c117b2019-05-23 12:51:06 -07001413 const Expression& fExpression;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001414};
1415
1416std::unique_ptr<ByteCodeGenerator::LValue> ByteCodeGenerator::getLValue(const Expression& e) {
1417 switch (e.fKind) {
Ethan Nicholas91164d12019-05-15 15:29:54 -04001418 case Expression::kExternalValue_Kind: {
1419 ExternalValue* value = ((ExternalValueReference&) e).fValue;
1420 int index = fOutput->fExternalValues.size();
1421 fOutput->fExternalValues.push_back(value);
1422 SkASSERT(index <= 255);
1423 return std::unique_ptr<LValue>(new ByteCodeExternalValueLValue(this, *value, index));
1424 }
Brian Osman07c117b2019-05-23 12:51:06 -07001425 case Expression::kFieldAccess_Kind:
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001426 case Expression::kIndex_Kind:
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001427 case Expression::kVariableReference_Kind:
Brian Osman07c117b2019-05-23 12:51:06 -07001428 return std::unique_ptr<LValue>(new ByteCodeExpressionLValue(this, e));
Brian Osman0785db02019-05-24 14:19:11 -04001429 case Expression::kSwizzle_Kind: {
1430 const Swizzle& s = (const Swizzle&) e;
1431 return swizzle_is_simple(s)
1432 ? std::unique_ptr<LValue>(new ByteCodeExpressionLValue(this, e))
1433 : std::unique_ptr<LValue>(new ByteCodeSwizzleLValue(this, s));
1434 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001435 case Expression::kTernary_Kind:
1436 default:
1437 printf("unsupported lvalue %s\n", e.description().c_str());
1438 return nullptr;
1439 }
1440}
1441
1442void ByteCodeGenerator::writeBlock(const Block& b) {
1443 for (const auto& s : b.fStatements) {
1444 this->writeStatement(*s);
1445 }
1446}
1447
1448void ByteCodeGenerator::setBreakTargets() {
1449 std::vector<DeferredLocation>& breaks = fBreakTargets.top();
1450 for (DeferredLocation& b : breaks) {
1451 b.set();
1452 }
1453 fBreakTargets.pop();
1454}
1455
1456void ByteCodeGenerator::setContinueTargets() {
1457 std::vector<DeferredLocation>& continues = fContinueTargets.top();
1458 for (DeferredLocation& c : continues) {
1459 c.set();
1460 }
1461 fContinueTargets.pop();
1462}
1463
1464void ByteCodeGenerator::writeBreakStatement(const BreakStatement& b) {
Brian Osman569f12f2019-06-13 11:23:57 -04001465 // TODO: Include BranchIfAllFalse to top-most LoopNext
1466 this->write(ByteCodeInstruction::kLoopBreak);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001467}
1468
1469void ByteCodeGenerator::writeContinueStatement(const ContinueStatement& c) {
Brian Osman569f12f2019-06-13 11:23:57 -04001470 // TODO: Include BranchIfAllFalse to top-most LoopNext
1471 this->write(ByteCodeInstruction::kLoopContinue);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001472}
1473
1474void ByteCodeGenerator::writeDoStatement(const DoStatement& d) {
Brian Osman569f12f2019-06-13 11:23:57 -04001475 this->write(ByteCodeInstruction::kLoopBegin);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001476 size_t start = fCode->size();
1477 this->writeStatement(*d.fStatement);
Brian Osman569f12f2019-06-13 11:23:57 -04001478 this->write(ByteCodeInstruction::kLoopNext);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001479 this->writeExpression(*d.fTest);
Brian Osman569f12f2019-06-13 11:23:57 -04001480 this->write(ByteCodeInstruction::kLoopMask);
1481 // TODO: Could shorten this with kBranchIfAnyTrue
1482 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1483 DeferredLocation endLocation(this);
1484 this->write(ByteCodeInstruction::kBranch);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001485 this->write16(start);
Brian Osman569f12f2019-06-13 11:23:57 -04001486 endLocation.set();
1487 this->write(ByteCodeInstruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001488}
1489
1490void ByteCodeGenerator::writeForStatement(const ForStatement& f) {
1491 fContinueTargets.emplace();
1492 fBreakTargets.emplace();
1493 if (f.fInitializer) {
1494 this->writeStatement(*f.fInitializer);
1495 }
Brian Osman569f12f2019-06-13 11:23:57 -04001496 this->write(ByteCodeInstruction::kLoopBegin);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001497 size_t start = fCode->size();
1498 if (f.fTest) {
1499 this->writeExpression(*f.fTest);
Brian Osman569f12f2019-06-13 11:23:57 -04001500 this->write(ByteCodeInstruction::kLoopMask);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001501 }
Brian Osman569f12f2019-06-13 11:23:57 -04001502 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1503 DeferredLocation endLocation(this);
1504 this->writeStatement(*f.fStatement);
1505 this->write(ByteCodeInstruction::kLoopNext);
1506 if (f.fNext) {
1507 this->writeExpression(*f.fNext, true);
1508 }
1509 this->write(ByteCodeInstruction::kBranch);
1510 this->write16(start);
1511 endLocation.set();
1512 this->write(ByteCodeInstruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001513}
1514
1515void ByteCodeGenerator::writeIfStatement(const IfStatement& i) {
Brian Osman569f12f2019-06-13 11:23:57 -04001516 this->writeExpression(*i.fTest);
1517 this->write(ByteCodeInstruction::kMaskPush);
1518 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1519 DeferredLocation falseLocation(this);
1520 this->writeStatement(*i.fIfTrue);
1521 falseLocation.set();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001522 if (i.fIfFalse) {
Brian Osman569f12f2019-06-13 11:23:57 -04001523 this->write(ByteCodeInstruction::kMaskNegate);
1524 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1525 DeferredLocation endLocation(this);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001526 this->writeStatement(*i.fIfFalse);
Mike Kleinb45ee832019-05-17 11:11:11 -05001527 endLocation.set();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001528 }
Brian Osman569f12f2019-06-13 11:23:57 -04001529 this->write(ByteCodeInstruction::kMaskPop);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001530}
1531
1532void ByteCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
Brian Osman4a47da72019-07-12 11:30:32 -04001533 if (fLoopCount || fConditionCount) {
1534 fErrors.error(r.fOffset, "return not allowed inside conditional or loop");
1535 return;
1536 }
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001537 int count = SlotCount(r.fExpression->fType);
Ethan Nicholas746035a2019-04-23 13:31:09 -04001538 this->writeExpression(*r.fExpression);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001539
1540 // Technically, the kReturn also pops fOutput->fLocalCount values from the stack, too, but we
1541 // haven't counted pushing those (they're outside the scope of our stack tracking). Instead,
1542 // we account for those in writeFunction().
1543
1544 // This is all fine because we don't allow conditional returns, so we only return once anyway.
1545 this->write(ByteCodeInstruction::kReturn, -count);
1546 this->write8(count);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001547}
1548
1549void ByteCodeGenerator::writeSwitchStatement(const SwitchStatement& r) {
1550 // not yet implemented
1551 abort();
1552}
1553
1554void ByteCodeGenerator::writeVarDeclarations(const VarDeclarations& v) {
1555 for (const auto& declStatement : v.fVars) {
1556 const VarDeclaration& decl = (VarDeclaration&) *declStatement;
1557 // we need to grab the location even if we don't use it, to ensure it
1558 // has been allocated
1559 int location = getLocation(*decl.fVar);
1560 if (decl.fValue) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001561 this->writeExpression(*decl.fValue);
Brian Osman07c117b2019-05-23 12:51:06 -07001562 int count = SlotCount(decl.fValue->fType);
1563 if (count > 4) {
1564 this->write(ByteCodeInstruction::kPushImmediate);
1565 this->write32(location);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001566 this->write(ByteCodeInstruction::kStoreExtended, count);
Brian Osman07c117b2019-05-23 12:51:06 -07001567 this->write8(count);
1568 } else {
1569 this->write(vector_instruction(ByteCodeInstruction::kStore, count));
1570 this->write8(location);
1571 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001572 }
1573 }
1574}
1575
1576void ByteCodeGenerator::writeWhileStatement(const WhileStatement& w) {
Brian Osman569f12f2019-06-13 11:23:57 -04001577 this->write(ByteCodeInstruction::kLoopBegin);
1578 size_t cond = fCode->size();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001579 this->writeExpression(*w.fTest);
Brian Osman569f12f2019-06-13 11:23:57 -04001580 this->write(ByteCodeInstruction::kLoopMask);
1581 this->write(ByteCodeInstruction::kBranchIfAllFalse);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001582 DeferredLocation endLocation(this);
1583 this->writeStatement(*w.fStatement);
Brian Osman569f12f2019-06-13 11:23:57 -04001584 this->write(ByteCodeInstruction::kLoopNext);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001585 this->write(ByteCodeInstruction::kBranch);
Brian Osman569f12f2019-06-13 11:23:57 -04001586 this->write16(cond);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001587 endLocation.set();
Brian Osman569f12f2019-06-13 11:23:57 -04001588 this->write(ByteCodeInstruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001589}
1590
1591void ByteCodeGenerator::writeStatement(const Statement& s) {
1592 switch (s.fKind) {
1593 case Statement::kBlock_Kind:
1594 this->writeBlock((Block&) s);
1595 break;
1596 case Statement::kBreak_Kind:
1597 this->writeBreakStatement((BreakStatement&) s);
1598 break;
1599 case Statement::kContinue_Kind:
1600 this->writeContinueStatement((ContinueStatement&) s);
1601 break;
1602 case Statement::kDiscard_Kind:
1603 // not yet implemented
1604 abort();
1605 case Statement::kDo_Kind:
1606 this->writeDoStatement((DoStatement&) s);
1607 break;
Brian Osman3e29f1d2019-05-28 09:35:05 -04001608 case Statement::kExpression_Kind:
1609 this->writeExpression(*((ExpressionStatement&) s).fExpression, true);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001610 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001611 case Statement::kFor_Kind:
1612 this->writeForStatement((ForStatement&) s);
1613 break;
1614 case Statement::kIf_Kind:
1615 this->writeIfStatement((IfStatement&) s);
1616 break;
1617 case Statement::kNop_Kind:
1618 break;
1619 case Statement::kReturn_Kind:
1620 this->writeReturnStatement((ReturnStatement&) s);
1621 break;
1622 case Statement::kSwitch_Kind:
1623 this->writeSwitchStatement((SwitchStatement&) s);
1624 break;
1625 case Statement::kVarDeclarations_Kind:
1626 this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration);
1627 break;
1628 case Statement::kWhile_Kind:
1629 this->writeWhileStatement((WhileStatement&) s);
1630 break;
1631 default:
1632 SkASSERT(false);
1633 }
1634}
1635
Brian Osman80164412019-06-07 13:00:23 -04001636ByteCodeFunction::ByteCodeFunction(const FunctionDeclaration* declaration)
1637 : fName(declaration->fName) {
1638 fParameterCount = 0;
1639 for (const auto& p : declaration->fParameters) {
1640 int slots = ByteCodeGenerator::SlotCount(p->fType);
1641 fParameters.push_back({ slots, (bool)(p->fModifiers.fFlags & Modifiers::kOut_Flag) });
1642 fParameterCount += slots;
1643 }
1644}
1645
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001646}