blob: acefb44ee0c74c516e7b31db902bfdeee643a769 [file] [log] [blame]
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001/*
2 * Copyright 2019 Google LLC
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "src/sksl/SkSLByteCodeGenerator.h"
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04009
Brian Osman95253bd2019-06-05 10:28:45 -040010#include <algorithm>
11
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040012namespace SkSL {
13
Ethan Nicholas82162ee2019-05-21 16:05:08 -040014ByteCodeGenerator::ByteCodeGenerator(const Context* context, const Program* program, ErrorReporter* errors,
15 ByteCode* output)
16 : INHERITED(program, errors, nullptr)
17 , fContext(*context)
Ethan Nicholasae9633b2019-05-24 12:46:34 -040018 , fOutput(output)
19 , fIntrinsics {
20 { "cos", ByteCodeInstruction::kCos },
21 { "cross", ByteCodeInstruction::kCross },
22 { "dot", SpecialIntrinsic::kDot },
23 { "sin", ByteCodeInstruction::kSin },
24 { "sqrt", ByteCodeInstruction::kSqrt },
25 { "tan", ByteCodeInstruction::kTan },
26 { "mix", ByteCodeInstruction::kMix },
27 } {}
28
Ethan Nicholas82162ee2019-05-21 16:05:08 -040029
Brian Osman07c117b2019-05-23 12:51:06 -070030int ByteCodeGenerator::SlotCount(const Type& type) {
Brian Osmanfba386b2019-06-20 14:54:15 -040031 if (type.kind() == Type::kOther_Kind) {
32 return 0;
33 } else if (type.kind() == Type::kStruct_Kind) {
Brian Osman07c117b2019-05-23 12:51:06 -070034 int slots = 0;
35 for (const auto& f : type.fields()) {
36 slots += SlotCount(*f.fType);
37 }
38 SkASSERT(slots <= 255);
39 return slots;
40 } else if (type.kind() == Type::kArray_Kind) {
41 int columns = type.columns();
42 SkASSERT(columns >= 0);
43 int slots = columns * SlotCount(type.componentType());
44 SkASSERT(slots <= 255);
45 return slots;
46 } else {
47 return type.columns() * type.rows();
48 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040049}
50
51bool ByteCodeGenerator::generateCode() {
52 for (const auto& e : fProgram) {
53 switch (e.fKind) {
54 case ProgramElement::kFunction_Kind: {
55 std::unique_ptr<ByteCodeFunction> f = this->writeFunction((FunctionDefinition&) e);
56 if (!f) {
57 return false;
58 }
59 fOutput->fFunctions.push_back(std::move(f));
Brian Osman80164412019-06-07 13:00:23 -040060 fFunctions.push_back(&(FunctionDefinition&)e);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040061 break;
62 }
63 case ProgramElement::kVar_Kind: {
64 VarDeclarations& decl = (VarDeclarations&) e;
65 for (const auto& v : decl.fVars) {
66 const Variable* declVar = ((VarDeclaration&) *v).fVar;
67 if (declVar->fModifiers.fLayout.fBuiltin >= 0) {
68 continue;
69 }
70 if (declVar->fModifiers.fFlags & Modifiers::kIn_Flag) {
Brian Osman07c117b2019-05-23 12:51:06 -070071 for (int i = SlotCount(declVar->fType); i > 0; --i) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040072 fOutput->fInputSlots.push_back(fOutput->fGlobalCount++);
73 }
74 } else {
Brian Osman07c117b2019-05-23 12:51:06 -070075 fOutput->fGlobalCount += SlotCount(declVar->fType);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040076 }
77 }
78 break;
79 }
80 default:
81 ; // ignore
82 }
83 }
Brian Osman6f5358f2019-07-09 14:17:23 -040084 return 0 == fErrors.errorCount();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040085}
86
87std::unique_ptr<ByteCodeFunction> ByteCodeGenerator::writeFunction(const FunctionDefinition& f) {
88 fFunction = &f;
Brian Osman226668a2019-05-14 16:47:30 -040089 std::unique_ptr<ByteCodeFunction> result(new ByteCodeFunction(&f.fDeclaration));
Brian Osman80164412019-06-07 13:00:23 -040090 fParameterCount = result->fParameterCount;
Brian Osman4a47da72019-07-12 11:30:32 -040091 fLoopCount = fMaxLoopCount = 0;
92 fConditionCount = fMaxConditionCount = 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 Osman4a47da72019-07-12 11:30:32 -040096 SkASSERT(fLoopCount == 0);
97 SkASSERT(fConditionCount == 0);
Ethan Nicholas7e603db2019-05-03 12:57:47 -040098 this->write(ByteCodeInstruction::kReturn);
99 this->write8(0);
Brian Osman4a47da72019-07-12 11:30:32 -0400100
101 result->fLocalCount = fLocals.size();
102 result->fConditionCount = fMaxConditionCount;
103 result->fLoopCount = fMaxLoopCount;
104
Ethan Nicholasdfcad062019-05-07 12:53:34 -0400105 const Type& returnType = f.fDeclaration.fReturnType;
106 if (returnType != *fContext.fVoid_Type) {
Brian Osman07c117b2019-05-23 12:51:06 -0700107 result->fReturnCount = SlotCount(returnType);
Ethan Nicholasdfcad062019-05-07 12:53:34 -0400108 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400109 fLocals.clear();
110 fFunction = nullptr;
111 return result;
112}
113
114enum class TypeCategory {
115 kBool,
116 kSigned,
117 kUnsigned,
118 kFloat,
119};
120
121static TypeCategory type_category(const Type& type) {
122 switch (type.kind()) {
123 case Type::Kind::kVector_Kind:
124 case Type::Kind::kMatrix_Kind:
125 return type_category(type.componentType());
126 default:
127 if (type.fName == "bool") {
128 return TypeCategory::kBool;
129 } else if (type.fName == "int" || type.fName == "short") {
130 return TypeCategory::kSigned;
131 } else if (type.fName == "uint" || type.fName == "ushort") {
132 return TypeCategory::kUnsigned;
133 } else {
134 SkASSERT(type.fName == "float" || type.fName == "half");
135 return TypeCategory::kFloat;
136 }
137 ABORT("unsupported type: %s\n", type.description().c_str());
138 }
139}
140
Brian Osman0785db02019-05-24 14:19:11 -0400141// A "simple" Swizzle is based on a variable (or a compound variable like a struct or array), and
142// that references consecutive values, such that it can be implemented using normal load/store ops
143// with an offset. Note that all single-component swizzles (of suitable base types) are simple.
144static bool swizzle_is_simple(const Swizzle& s) {
145 switch (s.fBase->fKind) {
146 case Expression::kFieldAccess_Kind:
147 case Expression::kIndex_Kind:
148 case Expression::kVariableReference_Kind:
149 break;
150 default:
151 return false;
152 }
153
154 for (size_t i = 1; i < s.fComponents.size(); ++i) {
155 if (s.fComponents[i] != s.fComponents[i - 1] + 1) {
156 return false;
157 }
158 }
159 return true;
160}
161
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400162int ByteCodeGenerator::getLocation(const Variable& var) {
163 // given that we seldom have more than a couple of variables, linear search is probably the most
164 // efficient way to handle lookups
165 switch (var.fStorage) {
166 case Variable::kLocal_Storage: {
167 for (int i = fLocals.size() - 1; i >= 0; --i) {
168 if (fLocals[i] == &var) {
Brian Osman1091f022019-05-16 09:42:16 -0400169 SkASSERT(fParameterCount + i <= 255);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400170 return fParameterCount + i;
171 }
172 }
173 int result = fParameterCount + fLocals.size();
174 fLocals.push_back(&var);
Brian Osman07c117b2019-05-23 12:51:06 -0700175 for (int i = 0; i < SlotCount(var.fType) - 1; ++i) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400176 fLocals.push_back(nullptr);
177 }
Brian Osman1091f022019-05-16 09:42:16 -0400178 SkASSERT(result <= 255);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400179 return result;
180 }
181 case Variable::kParameter_Storage: {
182 int offset = 0;
183 for (const auto& p : fFunction->fDeclaration.fParameters) {
184 if (p == &var) {
Brian Osman1091f022019-05-16 09:42:16 -0400185 SkASSERT(offset <= 255);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400186 return offset;
187 }
Brian Osman07c117b2019-05-23 12:51:06 -0700188 offset += SlotCount(p->fType);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400189 }
190 SkASSERT(false);
Brian Osman1091f022019-05-16 09:42:16 -0400191 return 0;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400192 }
193 case Variable::kGlobal_Storage: {
194 int offset = 0;
195 for (const auto& e : fProgram) {
196 if (e.fKind == ProgramElement::kVar_Kind) {
197 VarDeclarations& decl = (VarDeclarations&) e;
198 for (const auto& v : decl.fVars) {
199 const Variable* declVar = ((VarDeclaration&) *v).fVar;
200 if (declVar->fModifiers.fLayout.fBuiltin >= 0) {
201 continue;
202 }
203 if (declVar == &var) {
Brian Osmanb7451292019-05-15 13:02:13 -0400204 SkASSERT(offset <= 255);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400205 return offset;
206 }
Brian Osman07c117b2019-05-23 12:51:06 -0700207 offset += SlotCount(declVar->fType);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400208 }
209 }
210 }
211 SkASSERT(false);
Brian Osman1091f022019-05-16 09:42:16 -0400212 return 0;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400213 }
214 default:
215 SkASSERT(false);
216 return 0;
217 }
218}
219
Brian Osman07c117b2019-05-23 12:51:06 -0700220int ByteCodeGenerator::getLocation(const Expression& expr, Variable::Storage* storage) {
221 switch (expr.fKind) {
222 case Expression::kFieldAccess_Kind: {
223 const FieldAccess& f = (const FieldAccess&)expr;
224 int baseAddr = this->getLocation(*f.fBase, storage);
225 int offset = 0;
226 for (int i = 0; i < f.fFieldIndex; ++i) {
227 offset += SlotCount(*f.fBase->fType.fields()[i].fType);
228 }
229 if (baseAddr < 0) {
Brian Osman86769292019-06-21 11:05:47 -0400230 if (offset != 0) {
231 this->write(ByteCodeInstruction::kPushImmediate);
232 this->write32(offset);
233 this->write(ByteCodeInstruction::kAddI);
234 }
Brian Osman07c117b2019-05-23 12:51:06 -0700235 return -1;
236 } else {
237 return baseAddr + offset;
238 }
239 }
240 case Expression::kIndex_Kind: {
241 const IndexExpression& i = (const IndexExpression&)expr;
242 int stride = SlotCount(i.fType);
243 int offset = -1;
244 if (i.fIndex->isConstant()) {
245 offset = i.fIndex->getConstantInt() * stride;
246 } else {
Brian Osman86769292019-06-21 11:05:47 -0400247 if (i.fIndex->hasSideEffects()) {
248 // Having a side-effect in an indexer is technically safe for an rvalue,
249 // but with lvalues we have to evaluate the indexer twice, so make it an error.
250 fErrors.error(i.fIndex->fOffset,
251 "Index expressions with side-effects not supported in byte code.");
252 return 0;
253 }
Brian Osman07c117b2019-05-23 12:51:06 -0700254 this->writeExpression(*i.fIndex);
Brian Osman86769292019-06-21 11:05:47 -0400255 if (stride != 1) {
256 this->write(ByteCodeInstruction::kPushImmediate);
257 this->write32(stride);
258 this->write(ByteCodeInstruction::kMultiplyI);
259 }
Brian Osman07c117b2019-05-23 12:51:06 -0700260 }
261 int baseAddr = this->getLocation(*i.fBase, storage);
Brian Osman86769292019-06-21 11:05:47 -0400262
263 // Are both components known statically?
Brian Osman07c117b2019-05-23 12:51:06 -0700264 if (baseAddr >= 0 && offset >= 0) {
265 return baseAddr + offset;
266 }
Brian Osman86769292019-06-21 11:05:47 -0400267
268 // At least one component is dynamic (and on the stack).
269
270 // If the other component is zero, we're done
271 if (baseAddr == 0 || offset == 0) {
272 return -1;
273 }
274
275 // Push the non-dynamic component (if any) to the stack, then add the two
Brian Osman07c117b2019-05-23 12:51:06 -0700276 if (baseAddr >= 0) {
277 this->write(ByteCodeInstruction::kPushImmediate);
278 this->write32(baseAddr);
279 }
280 if (offset >= 0) {
281 this->write(ByteCodeInstruction::kPushImmediate);
282 this->write32(offset);
283 }
284 this->write(ByteCodeInstruction::kAddI);
285 return -1;
286 }
Brian Osman0785db02019-05-24 14:19:11 -0400287 case Expression::kSwizzle_Kind: {
288 const Swizzle& s = (const Swizzle&)expr;
289 SkASSERT(swizzle_is_simple(s));
290 int baseAddr = this->getLocation(*s.fBase, storage);
291 int offset = s.fComponents[0];
292 if (baseAddr < 0) {
Brian Osman86769292019-06-21 11:05:47 -0400293 if (offset != 0) {
294 this->write(ByteCodeInstruction::kPushImmediate);
295 this->write32(offset);
296 this->write(ByteCodeInstruction::kAddI);
297 }
Brian Osman0785db02019-05-24 14:19:11 -0400298 return -1;
299 } else {
300 return baseAddr + offset;
301 }
302 }
Brian Osman07c117b2019-05-23 12:51:06 -0700303 case Expression::kVariableReference_Kind: {
304 const Variable& var = ((const VariableReference&)expr).fVariable;
305 *storage = var.fStorage;
306 return this->getLocation(var);
307 }
308 default:
309 SkASSERT(false);
310 return 0;
311 }
312}
313
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400314void ByteCodeGenerator::write8(uint8_t b) {
315 fCode->push_back(b);
316}
317
318void ByteCodeGenerator::write16(uint16_t i) {
Mike Klein76346ac2019-05-17 11:57:10 -0500319 size_t n = fCode->size();
320 fCode->resize(n+2);
321 memcpy(fCode->data() + n, &i, 2);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400322}
323
324void ByteCodeGenerator::write32(uint32_t i) {
Mike Klein76346ac2019-05-17 11:57:10 -0500325 size_t n = fCode->size();
326 fCode->resize(n+4);
327 memcpy(fCode->data() + n, &i, 4);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400328}
329
330void ByteCodeGenerator::write(ByteCodeInstruction i) {
Brian Osman4a47da72019-07-12 11:30:32 -0400331 switch (i) {
332 case ByteCodeInstruction::kLoopBegin: this->enterLoop(); break;
333 case ByteCodeInstruction::kLoopEnd: this->exitLoop(); break;
334
335 case ByteCodeInstruction::kMaskPush: this->enterCondition(); break;
336 case ByteCodeInstruction::kMaskPop:
337 case ByteCodeInstruction::kMaskBlend: this->exitCondition(); break;
338 default: /* Do nothing */ break;
339 }
Mike Klein108e9352019-05-21 11:05:17 -0500340 this->write16((uint16_t)i);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400341}
342
Mike Klein76346ac2019-05-17 11:57:10 -0500343static ByteCodeInstruction vector_instruction(ByteCodeInstruction base, int count) {
Brian Osman07c117b2019-05-23 12:51:06 -0700344 SkASSERT(count >= 1 && count <= 4);
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400345 return ((ByteCodeInstruction) ((int) base + count - 1));
346}
347
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400348void ByteCodeGenerator::writeTypedInstruction(const Type& type, ByteCodeInstruction s,
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400349 ByteCodeInstruction u, ByteCodeInstruction f,
350 int count) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400351 switch (type_category(type)) {
352 case TypeCategory::kSigned:
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400353 this->write(vector_instruction(s, count));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400354 break;
355 case TypeCategory::kUnsigned:
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400356 this->write(vector_instruction(u, count));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400357 break;
Brian Osman1e855b22019-05-29 15:21:52 -0400358 case TypeCategory::kFloat: {
359 if (count > 4) {
360 this->write((ByteCodeInstruction)((int)f + 4));
361 this->write8(count);
362 } else {
363 this->write(vector_instruction(f, count));
364 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400365 break;
Brian Osman1e855b22019-05-29 15:21:52 -0400366 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400367 default:
368 SkASSERT(false);
369 }
370}
371
Brian Osman3e29f1d2019-05-28 09:35:05 -0400372bool ByteCodeGenerator::writeBinaryExpression(const BinaryExpression& b, bool discard) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400373 if (b.fOperator == Token::Kind::EQ) {
374 std::unique_ptr<LValue> lvalue = this->getLValue(*b.fLeft);
375 this->writeExpression(*b.fRight);
Brian Osman3e29f1d2019-05-28 09:35:05 -0400376 lvalue->store(discard);
377 discard = false;
378 return discard;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400379 }
Brian Osman16e6fd52019-05-29 11:19:00 -0400380 const Type& lType = b.fLeft->fType;
381 const Type& rType = b.fRight->fType;
Brian Osman909231c2019-05-29 15:34:36 -0400382 bool lVecOrMtx = (lType.kind() == Type::kVector_Kind || lType.kind() == Type::kMatrix_Kind);
383 bool rVecOrMtx = (rType.kind() == Type::kVector_Kind || rType.kind() == Type::kMatrix_Kind);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400384 Token::Kind op;
385 std::unique_ptr<LValue> lvalue;
386 if (is_assignment(b.fOperator)) {
387 lvalue = this->getLValue(*b.fLeft);
388 lvalue->load();
389 op = remove_assignment(b.fOperator);
390 } else {
391 this->writeExpression(*b.fLeft);
392 op = b.fOperator;
Brian Osman909231c2019-05-29 15:34:36 -0400393 if (!lVecOrMtx && rVecOrMtx) {
Brian Osman16e6fd52019-05-29 11:19:00 -0400394 for (int i = SlotCount(rType); i > 1; --i) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400395 this->write(ByteCodeInstruction::kDup);
396 }
397 }
398 }
399 this->writeExpression(*b.fRight);
Brian Osman909231c2019-05-29 15:34:36 -0400400 if (lVecOrMtx && !rVecOrMtx) {
Brian Osman16e6fd52019-05-29 11:19:00 -0400401 for (int i = SlotCount(lType); i > 1; --i) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400402 this->write(ByteCodeInstruction::kDup);
403 }
404 }
Brian Osman909231c2019-05-29 15:34:36 -0400405 // Special case for M*V, V*M, M*M (but not V*V!)
406 if (op == Token::Kind::STAR && lVecOrMtx && rVecOrMtx &&
407 !(lType.kind() == Type::kVector_Kind && rType.kind() == Type::kVector_Kind)) {
408 this->write(ByteCodeInstruction::kMatrixMultiply);
409 int rCols = rType.columns(),
410 rRows = rType.rows(),
411 lCols = lType.columns(),
412 lRows = lType.rows();
413 // M*V treats the vector as a column
414 if (rType.kind() == Type::kVector_Kind) {
415 std::swap(rCols, rRows);
416 }
417 SkASSERT(lCols == rRows);
418 SkASSERT(SlotCount(b.fType) == lRows * rCols);
419 this->write8(lCols);
420 this->write8(lRows);
421 this->write8(rCols);
422 } else {
423 int count = std::max(SlotCount(lType), SlotCount(rType));
424 switch (op) {
425 case Token::Kind::EQEQ:
426 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareIEQ,
427 ByteCodeInstruction::kCompareIEQ,
428 ByteCodeInstruction::kCompareFEQ,
429 count);
430 // Collapse to a single bool
431 for (int i = count; i > 1; --i) {
432 this->write(ByteCodeInstruction::kAndB);
433 }
434 break;
435 case Token::Kind::GT:
436 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSGT,
437 ByteCodeInstruction::kCompareUGT,
438 ByteCodeInstruction::kCompareFGT,
439 count);
440 break;
441 case Token::Kind::GTEQ:
442 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSGTEQ,
443 ByteCodeInstruction::kCompareUGTEQ,
444 ByteCodeInstruction::kCompareFGTEQ,
445 count);
446 break;
447 case Token::Kind::LT:
448 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSLT,
449 ByteCodeInstruction::kCompareULT,
450 ByteCodeInstruction::kCompareFLT,
451 count);
452 break;
453 case Token::Kind::LTEQ:
454 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSLTEQ,
455 ByteCodeInstruction::kCompareULTEQ,
456 ByteCodeInstruction::kCompareFLTEQ,
457 count);
458 break;
459 case Token::Kind::MINUS:
460 this->writeTypedInstruction(lType, ByteCodeInstruction::kSubtractI,
461 ByteCodeInstruction::kSubtractI,
462 ByteCodeInstruction::kSubtractF,
463 count);
464 break;
465 case Token::Kind::NEQ:
466 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareINEQ,
467 ByteCodeInstruction::kCompareINEQ,
468 ByteCodeInstruction::kCompareFNEQ,
469 count);
470 // Collapse to a single bool
471 for (int i = count; i > 1; --i) {
472 this->write(ByteCodeInstruction::kOrB);
473 }
474 break;
475 case Token::Kind::PERCENT:
476 this->writeTypedInstruction(lType, ByteCodeInstruction::kRemainderS,
477 ByteCodeInstruction::kRemainderU,
478 ByteCodeInstruction::kRemainderF,
479 count);
480 break;
481 case Token::Kind::PLUS:
482 this->writeTypedInstruction(lType, ByteCodeInstruction::kAddI,
483 ByteCodeInstruction::kAddI,
484 ByteCodeInstruction::kAddF,
485 count);
486 break;
487 case Token::Kind::SLASH:
488 this->writeTypedInstruction(lType, ByteCodeInstruction::kDivideS,
489 ByteCodeInstruction::kDivideU,
490 ByteCodeInstruction::kDivideF,
491 count);
492 break;
493 case Token::Kind::STAR:
494 this->writeTypedInstruction(lType, ByteCodeInstruction::kMultiplyI,
495 ByteCodeInstruction::kMultiplyI,
496 ByteCodeInstruction::kMultiplyF,
497 count);
498 break;
Brian Osman569f12f2019-06-13 11:23:57 -0400499
500 case Token::Kind::LOGICALAND:
501 SkASSERT(type_category(lType) == SkSL::TypeCategory::kBool && count == 1);
502 this->write(ByteCodeInstruction::kAndB);
503 break;
504 case Token::Kind::LOGICALNOT:
505 SkASSERT(type_category(lType) == SkSL::TypeCategory::kBool && count == 1);
506 this->write(ByteCodeInstruction::kNotB);
507 break;
508 case Token::Kind::LOGICALOR:
509 SkASSERT(type_category(lType) == SkSL::TypeCategory::kBool && count == 1);
510 this->write(ByteCodeInstruction::kOrB);
511 break;
512 case Token::Kind::LOGICALXOR:
513 SkASSERT(type_category(lType) == SkSL::TypeCategory::kBool && count == 1);
514 this->write(ByteCodeInstruction::kXorB);
515 break;
516
Brian Osman909231c2019-05-29 15:34:36 -0400517 default:
518 SkASSERT(false);
519 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400520 }
521 if (lvalue) {
Brian Osman3e29f1d2019-05-28 09:35:05 -0400522 lvalue->store(discard);
523 discard = false;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400524 }
Brian Osman3e29f1d2019-05-28 09:35:05 -0400525 return discard;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400526}
527
528void ByteCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
529 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osman569f12f2019-06-13 11:23:57 -0400530 this->write32(b.fValue ? ~0 : 0);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400531}
532
533void ByteCodeGenerator::writeConstructor(const Constructor& c) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400534 for (const auto& arg : c.fArguments) {
535 this->writeExpression(*arg);
536 }
537 if (c.fArguments.size() == 1) {
Brian Osman29e013d2019-05-28 17:16:03 -0400538 const Type& inType = c.fArguments[0]->fType;
539 const Type& outType = c.fType;
540 TypeCategory inCategory = type_category(inType);
541 TypeCategory outCategory = type_category(outType);
542 int inCount = SlotCount(inType);
543 int outCount = SlotCount(outType);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400544 if (inCategory != outCategory) {
Brian Osmanc51d7912019-05-22 15:16:16 -0700545 SkASSERT(inCount == outCount);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400546 if (inCategory == TypeCategory::kFloat) {
547 SkASSERT(outCategory == TypeCategory::kSigned ||
548 outCategory == TypeCategory::kUnsigned);
Brian Osmanc51d7912019-05-22 15:16:16 -0700549 this->write(vector_instruction(ByteCodeInstruction::kConvertFtoI, outCount));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400550 } else if (outCategory == TypeCategory::kFloat) {
551 if (inCategory == TypeCategory::kSigned) {
Brian Osmanc51d7912019-05-22 15:16:16 -0700552 this->write(vector_instruction(ByteCodeInstruction::kConvertStoF, outCount));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400553 } else {
554 SkASSERT(inCategory == TypeCategory::kUnsigned);
Brian Osmanc51d7912019-05-22 15:16:16 -0700555 this->write(vector_instruction(ByteCodeInstruction::kConvertUtoF, outCount));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400556 }
557 } else {
558 SkASSERT(false);
559 }
560 }
Brian Osman29e013d2019-05-28 17:16:03 -0400561 if (inType.kind() == Type::kMatrix_Kind && outType.kind() == Type::kMatrix_Kind) {
562 this->write(ByteCodeInstruction::kMatrixToMatrix);
563 this->write8(inType.columns());
564 this->write8(inType.rows());
565 this->write8(outType.columns());
566 this->write8(outType.rows());
567 } else if (inCount != outCount) {
Brian Osmanc51d7912019-05-22 15:16:16 -0700568 SkASSERT(inCount == 1);
Brian Osman29e013d2019-05-28 17:16:03 -0400569 if (outType.kind() == Type::kMatrix_Kind) {
570 this->write(ByteCodeInstruction::kScalarToMatrix);
571 this->write8(outType.columns());
572 this->write8(outType.rows());
573 } else {
574 SkASSERT(outType.kind() == Type::kVector_Kind);
575 for (; inCount != outCount; ++inCount) {
576 this->write(ByteCodeInstruction::kDup);
577 }
Brian Osmanc51d7912019-05-22 15:16:16 -0700578 }
579 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400580 }
581}
582
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400583void ByteCodeGenerator::writeExternalFunctionCall(const ExternalFunctionCall& f) {
584 int argumentCount = 0;
585 for (const auto& arg : f.fArguments) {
586 this->writeExpression(*arg);
Brian Osman07c117b2019-05-23 12:51:06 -0700587 argumentCount += SlotCount(arg->fType);
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400588 }
589 this->write(ByteCodeInstruction::kCallExternal);
590 SkASSERT(argumentCount <= 255);
591 this->write8(argumentCount);
Brian Osman07c117b2019-05-23 12:51:06 -0700592 this->write8(SlotCount(f.fType));
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400593 int index = fOutput->fExternalValues.size();
594 fOutput->fExternalValues.push_back(f.fFunction);
595 SkASSERT(index <= 255);
596 this->write8(index);
597}
598
Ethan Nicholas91164d12019-05-15 15:29:54 -0400599void ByteCodeGenerator::writeExternalValue(const ExternalValueReference& e) {
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400600 this->write(vector_instruction(ByteCodeInstruction::kReadExternal,
Brian Osman07c117b2019-05-23 12:51:06 -0700601 SlotCount(e.fValue->type())));
Ethan Nicholas91164d12019-05-15 15:29:54 -0400602 int index = fOutput->fExternalValues.size();
603 fOutput->fExternalValues.push_back(e.fValue);
604 SkASSERT(index <= 255);
605 this->write8(index);
606}
607
Brian Osman07c117b2019-05-23 12:51:06 -0700608void ByteCodeGenerator::writeVariableExpression(const Expression& expr) {
609 Variable::Storage storage;
610 int location = this->getLocation(expr, &storage);
611 bool isGlobal = storage == Variable::kGlobal_Storage;
612 int count = SlotCount(expr.fType);
613 if (location < 0 || count > 4) {
614 if (location >= 0) {
615 this->write(ByteCodeInstruction::kPushImmediate);
616 this->write32(location);
617 }
618 this->write(isGlobal ? ByteCodeInstruction::kLoadExtendedGlobal
619 : ByteCodeInstruction::kLoadExtended);
620 this->write8(count);
621 } else {
622 this->write(vector_instruction(isGlobal ? ByteCodeInstruction::kLoadGlobal
623 : ByteCodeInstruction::kLoad,
624 count));
625 this->write8(location);
626 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400627}
628
Brian Osmand30e0392019-06-14 14:05:14 -0400629static inline uint32_t float_to_bits(float x) {
630 uint32_t u;
631 memcpy(&u, &x, sizeof(uint32_t));
632 return u;
633}
634
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400635void ByteCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
636 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osmand30e0392019-06-14 14:05:14 -0400637 this->write32(float_to_bits(f.fValue));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400638}
639
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400640void ByteCodeGenerator::writeIntrinsicCall(const FunctionCall& c) {
641 auto found = fIntrinsics.find(c.fFunction.fName);
642 if (found == fIntrinsics.end()) {
643 fErrors.error(c.fOffset, "unsupported intrinsic function");
644 return;
645 }
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400646 if (found->second.fIsSpecial) {
647 SkASSERT(found->second.fValue.fSpecial == SpecialIntrinsic::kDot);
648 SkASSERT(c.fArguments.size() == 2);
649 SkASSERT(SlotCount(c.fArguments[0]->fType) == SlotCount(c.fArguments[1]->fType));
650 this->write((ByteCodeInstruction) ((int) ByteCodeInstruction::kMultiplyF +
651 SlotCount(c.fArguments[0]->fType) - 1));
652 for (int i = SlotCount(c.fArguments[0]->fType); i > 1; --i) {
653 this->write(ByteCodeInstruction::kAddF);
654 }
655 } else {
656 switch (found->second.fValue.fInstruction) {
657 case ByteCodeInstruction::kCos:
658 case ByteCodeInstruction::kMix:
659 case ByteCodeInstruction::kSin:
660 case ByteCodeInstruction::kSqrt:
661 case ByteCodeInstruction::kTan:
662 SkASSERT(c.fArguments.size() > 0);
663 this->write((ByteCodeInstruction) ((int) found->second.fValue.fInstruction +
664 SlotCount(c.fArguments[0]->fType) - 1));
665 break;
666 case ByteCodeInstruction::kCross:
667 this->write(found->second.fValue.fInstruction);
668 break;
669 default:
670 SkASSERT(false);
671 }
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400672 }
673}
674
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400675void ByteCodeGenerator::writeFunctionCall(const FunctionCall& f) {
Brian Osmand3494ed2019-06-20 15:41:34 -0400676 // Builtins have simple signatures...
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400677 if (f.fFunction.fBuiltin) {
Brian Osmand3494ed2019-06-20 15:41:34 -0400678 for (const auto& arg : f.fArguments) {
679 this->writeExpression(*arg);
680 }
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400681 this->writeIntrinsicCall(f);
682 return;
683 }
Brian Osmand3494ed2019-06-20 15:41:34 -0400684
Brian Osman6f5358f2019-07-09 14:17:23 -0400685 // Find the index of the function we're calling. We explicitly do not allow calls to functions
686 // before they're defined. This is an easy-to-understand rule that prevents recursion.
687 size_t idx;
688 for (idx = 0; idx < fFunctions.size(); ++idx) {
689 if (f.fFunction.matches(fFunctions[idx]->fDeclaration)) {
690 break;
691 }
692 }
693 if (idx > 255) {
694 fErrors.error(f.fOffset, "Function count limit exceeded");
695 return;
696 } else if (idx >= fFunctions.size()) {
697 fErrors.error(f.fOffset, "Call to undefined function");
698 return;
699 }
700
701 // We may need to deal with out parameters, so the sequence is tricky
Brian Osmand3494ed2019-06-20 15:41:34 -0400702 if (int returnCount = SlotCount(f.fType)) {
703 this->write(ByteCodeInstruction::kReserve);
704 this->write8(returnCount);
705 }
706
707 int argCount = f.fArguments.size();
708 std::vector<std::unique_ptr<LValue>> lvalues;
709 for (int i = 0; i < argCount; ++i) {
710 const auto& param = f.fFunction.fParameters[i];
711 const auto& arg = f.fArguments[i];
712 if (param->fModifiers.fFlags & Modifiers::kOut_Flag) {
713 lvalues.emplace_back(this->getLValue(*arg));
714 lvalues.back()->load();
715 } else {
716 this->writeExpression(*arg);
717 }
718 }
719
Brian Osman226668a2019-05-14 16:47:30 -0400720 this->write(ByteCodeInstruction::kCall);
Brian Osman6f5358f2019-07-09 14:17:23 -0400721 this->write8(idx);
Brian Osmand3494ed2019-06-20 15:41:34 -0400722
Brian Osman4a47da72019-07-12 11:30:32 -0400723 const ByteCodeFunction* callee = fOutput->fFunctions[idx].get();
724 fMaxLoopCount = std::max(fMaxLoopCount, fLoopCount + callee->fLoopCount);
725 fMaxConditionCount = std::max(fMaxConditionCount, fConditionCount + callee->fConditionCount);
726
Brian Osmand3494ed2019-06-20 15:41:34 -0400727 // After the called function returns, the stack will still contain our arguments. We have to
728 // pop them (storing any out parameters back to their lvalues as we go). We glob together slot
729 // counts for all parameters that aren't out-params, so we can pop them in one big chunk.
730 int popCount = 0;
731 auto pop = [&]() {
732 if (popCount > 4) {
733 this->write(ByteCodeInstruction::kPopN);
734 this->write8(popCount);
735 } else if (popCount > 0) {
736 this->write(vector_instruction(ByteCodeInstruction::kPop, popCount));
737 }
738 popCount = 0;
739 };
740
741 for (int i = argCount - 1; i >= 0; --i) {
742 const auto& param = f.fFunction.fParameters[i];
743 const auto& arg = f.fArguments[i];
744 if (param->fModifiers.fFlags & Modifiers::kOut_Flag) {
745 pop();
746 lvalues.back()->store(true);
747 lvalues.pop_back();
748 } else {
749 popCount += SlotCount(arg->fType);
750 }
751 }
752 pop();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400753}
754
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400755void ByteCodeGenerator::writeIntLiteral(const IntLiteral& i) {
756 this->write(ByteCodeInstruction::kPushImmediate);
757 this->write32(i.fValue);
758}
759
760void ByteCodeGenerator::writeNullLiteral(const NullLiteral& n) {
761 // not yet implemented
762 abort();
763}
764
Brian Osman3e29f1d2019-05-28 09:35:05 -0400765bool ByteCodeGenerator::writePrefixExpression(const PrefixExpression& p, bool discard) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400766 switch (p.fOperator) {
767 case Token::Kind::PLUSPLUS: // fall through
768 case Token::Kind::MINUSMINUS: {
Brian Osman07c117b2019-05-23 12:51:06 -0700769 SkASSERT(SlotCount(p.fOperand->fType) == 1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400770 std::unique_ptr<LValue> lvalue = this->getLValue(*p.fOperand);
771 lvalue->load();
772 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osmand30e0392019-06-14 14:05:14 -0400773 this->write32(type_category(p.fType) == TypeCategory::kFloat ? float_to_bits(1.0f) : 1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400774 if (p.fOperator == Token::Kind::PLUSPLUS) {
775 this->writeTypedInstruction(p.fType,
776 ByteCodeInstruction::kAddI,
777 ByteCodeInstruction::kAddI,
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400778 ByteCodeInstruction::kAddF,
779 1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400780 } else {
781 this->writeTypedInstruction(p.fType,
782 ByteCodeInstruction::kSubtractI,
783 ByteCodeInstruction::kSubtractI,
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400784 ByteCodeInstruction::kSubtractF,
785 1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400786 }
Brian Osman3e29f1d2019-05-28 09:35:05 -0400787 lvalue->store(discard);
788 discard = false;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400789 break;
790 }
Ethan Nicholas354ecf32019-05-07 16:13:02 -0400791 case Token::Kind::MINUS: {
792 this->writeExpression(*p.fOperand);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400793 this->writeTypedInstruction(p.fType,
Mike Klein12710912019-05-21 11:04:59 -0500794 ByteCodeInstruction::kNegateI,
795 ByteCodeInstruction::kNegateI,
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400796 ByteCodeInstruction::kNegateF,
Brian Osman07c117b2019-05-23 12:51:06 -0700797 SlotCount(p.fOperand->fType));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400798 break;
Ethan Nicholas354ecf32019-05-07 16:13:02 -0400799 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400800 default:
801 SkASSERT(false);
802 }
Brian Osman3e29f1d2019-05-28 09:35:05 -0400803 return discard;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400804}
805
Brian Osman3e29f1d2019-05-28 09:35:05 -0400806bool ByteCodeGenerator::writePostfixExpression(const PostfixExpression& p, bool discard) {
Brian Osmanf3fa6002019-05-17 14:26:53 -0400807 switch (p.fOperator) {
808 case Token::Kind::PLUSPLUS: // fall through
809 case Token::Kind::MINUSMINUS: {
Brian Osman07c117b2019-05-23 12:51:06 -0700810 SkASSERT(SlotCount(p.fOperand->fType) == 1);
Brian Osmanf3fa6002019-05-17 14:26:53 -0400811 std::unique_ptr<LValue> lvalue = this->getLValue(*p.fOperand);
812 lvalue->load();
Brian Osman3e29f1d2019-05-28 09:35:05 -0400813 if (!discard) {
814 this->write(ByteCodeInstruction::kDup);
815 }
Brian Osmanf3fa6002019-05-17 14:26:53 -0400816 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osmand30e0392019-06-14 14:05:14 -0400817 this->write32(type_category(p.fType) == TypeCategory::kFloat ? float_to_bits(1.0f) : 1);
Brian Osmanf3fa6002019-05-17 14:26:53 -0400818 if (p.fOperator == Token::Kind::PLUSPLUS) {
819 this->writeTypedInstruction(p.fType,
820 ByteCodeInstruction::kAddI,
821 ByteCodeInstruction::kAddI,
822 ByteCodeInstruction::kAddF,
823 1);
824 } else {
825 this->writeTypedInstruction(p.fType,
826 ByteCodeInstruction::kSubtractI,
827 ByteCodeInstruction::kSubtractI,
828 ByteCodeInstruction::kSubtractF,
829 1);
830 }
Brian Osman3e29f1d2019-05-28 09:35:05 -0400831 lvalue->store(discard);
Brian Osmanf3fa6002019-05-17 14:26:53 -0400832 this->write(ByteCodeInstruction::kPop);
Brian Osman3e29f1d2019-05-28 09:35:05 -0400833 discard = false;
Brian Osmanf3fa6002019-05-17 14:26:53 -0400834 break;
835 }
836 default:
837 SkASSERT(false);
838 }
Brian Osman3e29f1d2019-05-28 09:35:05 -0400839 return discard;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400840}
841
842void ByteCodeGenerator::writeSwizzle(const Swizzle& s) {
Brian Osman0785db02019-05-24 14:19:11 -0400843 if (swizzle_is_simple(s)) {
844 this->writeVariableExpression(s);
845 return;
846 }
847
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400848 switch (s.fBase->fKind) {
849 case Expression::kVariableReference_Kind: {
850 const Variable& var = ((VariableReference&) *s.fBase).fVariable;
Brian Osman1091f022019-05-16 09:42:16 -0400851 this->write(var.fStorage == Variable::kGlobal_Storage
852 ? ByteCodeInstruction::kLoadSwizzleGlobal
853 : ByteCodeInstruction::kLoadSwizzle);
854 this->write8(this->getLocation(var));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400855 this->write8(s.fComponents.size());
856 for (int c : s.fComponents) {
857 this->write8(c);
858 }
859 break;
860 }
861 default:
862 this->writeExpression(*s.fBase);
863 this->write(ByteCodeInstruction::kSwizzle);
864 this->write8(s.fBase->fType.columns());
865 this->write8(s.fComponents.size());
866 for (int c : s.fComponents) {
867 this->write8(c);
868 }
869 }
870}
871
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400872void ByteCodeGenerator::writeTernaryExpression(const TernaryExpression& t) {
Brian Osman4e93feb2019-05-16 15:38:00 -0400873 this->writeExpression(*t.fTest);
Brian Osman569f12f2019-06-13 11:23:57 -0400874 this->write(ByteCodeInstruction::kMaskPush);
Brian Osman4e93feb2019-05-16 15:38:00 -0400875 this->writeExpression(*t.fIfTrue);
Brian Osman569f12f2019-06-13 11:23:57 -0400876 this->write(ByteCodeInstruction::kMaskNegate);
877 this->writeExpression(*t.fIfFalse);
878 this->write(ByteCodeInstruction::kMaskBlend);
879 this->write8(SlotCount(t.fType));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400880}
881
Brian Osman3e29f1d2019-05-28 09:35:05 -0400882void ByteCodeGenerator::writeExpression(const Expression& e, bool discard) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400883 switch (e.fKind) {
884 case Expression::kBinary_Kind:
Brian Osman3e29f1d2019-05-28 09:35:05 -0400885 discard = this->writeBinaryExpression((BinaryExpression&) e, discard);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400886 break;
887 case Expression::kBoolLiteral_Kind:
888 this->writeBoolLiteral((BoolLiteral&) e);
889 break;
890 case Expression::kConstructor_Kind:
891 this->writeConstructor((Constructor&) e);
892 break;
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400893 case Expression::kExternalFunctionCall_Kind:
894 this->writeExternalFunctionCall((ExternalFunctionCall&) e);
895 break;
Ethan Nicholas91164d12019-05-15 15:29:54 -0400896 case Expression::kExternalValue_Kind:
897 this->writeExternalValue((ExternalValueReference&) e);
898 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400899 case Expression::kFieldAccess_Kind:
Brian Osman07c117b2019-05-23 12:51:06 -0700900 case Expression::kIndex_Kind:
901 case Expression::kVariableReference_Kind:
902 this->writeVariableExpression(e);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400903 break;
904 case Expression::kFloatLiteral_Kind:
905 this->writeFloatLiteral((FloatLiteral&) e);
906 break;
907 case Expression::kFunctionCall_Kind:
908 this->writeFunctionCall((FunctionCall&) e);
909 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400910 case Expression::kIntLiteral_Kind:
911 this->writeIntLiteral((IntLiteral&) e);
912 break;
913 case Expression::kNullLiteral_Kind:
914 this->writeNullLiteral((NullLiteral&) e);
915 break;
916 case Expression::kPrefix_Kind:
Brian Osman3e29f1d2019-05-28 09:35:05 -0400917 discard = this->writePrefixExpression((PrefixExpression&) e, discard);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400918 break;
919 case Expression::kPostfix_Kind:
Brian Osman3e29f1d2019-05-28 09:35:05 -0400920 discard = this->writePostfixExpression((PostfixExpression&) e, discard);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400921 break;
922 case Expression::kSwizzle_Kind:
923 this->writeSwizzle((Swizzle&) e);
924 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400925 case Expression::kTernary_Kind:
926 this->writeTernaryExpression((TernaryExpression&) e);
927 break;
928 default:
929 printf("unsupported expression %s\n", e.description().c_str());
930 SkASSERT(false);
931 }
Brian Osman3e29f1d2019-05-28 09:35:05 -0400932 if (discard) {
933 int count = SlotCount(e.fType);
934 if (count > 4) {
935 this->write(ByteCodeInstruction::kPopN);
936 this->write8(count);
Brian Osmanfba386b2019-06-20 14:54:15 -0400937 } else if (count != 0) {
Brian Osman3e29f1d2019-05-28 09:35:05 -0400938 this->write(vector_instruction(ByteCodeInstruction::kPop, count));
939 }
940 discard = false;
941 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400942}
943
Ethan Nicholas91164d12019-05-15 15:29:54 -0400944class ByteCodeExternalValueLValue : public ByteCodeGenerator::LValue {
945public:
946 ByteCodeExternalValueLValue(ByteCodeGenerator* generator, ExternalValue& value, int index)
947 : INHERITED(*generator)
Brian Osman07c117b2019-05-23 12:51:06 -0700948 , fCount(ByteCodeGenerator::SlotCount(value.type()))
Ethan Nicholas91164d12019-05-15 15:29:54 -0400949 , fIndex(index) {}
950
951 void load() override {
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400952 fGenerator.write(vector_instruction(ByteCodeInstruction::kReadExternal, fCount));
Ethan Nicholas91164d12019-05-15 15:29:54 -0400953 fGenerator.write8(fIndex);
954 }
955
Brian Osman3e29f1d2019-05-28 09:35:05 -0400956 void store(bool discard) override {
957 if (!discard) {
958 fGenerator.write(vector_instruction(ByteCodeInstruction::kDup, fCount));
959 }
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400960 fGenerator.write(vector_instruction(ByteCodeInstruction::kWriteExternal, fCount));
Ethan Nicholas91164d12019-05-15 15:29:54 -0400961 fGenerator.write8(fIndex);
962 }
963
964private:
965 typedef LValue INHERITED;
966
967 int fCount;
968
969 int fIndex;
970};
971
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400972class ByteCodeSwizzleLValue : public ByteCodeGenerator::LValue {
973public:
974 ByteCodeSwizzleLValue(ByteCodeGenerator* generator, const Swizzle& swizzle)
975 : INHERITED(*generator)
Brian Osman07c117b2019-05-23 12:51:06 -0700976 , fSwizzle(swizzle) {}
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400977
978 void load() override {
Brian Osman1091f022019-05-16 09:42:16 -0400979 fGenerator.writeSwizzle(fSwizzle);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400980 }
981
Brian Osman3e29f1d2019-05-28 09:35:05 -0400982 void store(bool discard) override {
983 if (!discard) {
984 fGenerator.write(vector_instruction(ByteCodeInstruction::kDup,
985 fSwizzle.fComponents.size()));
986 }
Brian Osman07c117b2019-05-23 12:51:06 -0700987 Variable::Storage storage;
988 int location = fGenerator.getLocation(*fSwizzle.fBase, &storage);
989 bool isGlobal = storage == Variable::kGlobal_Storage;
990 if (location < 0) {
991 fGenerator.write(isGlobal ? ByteCodeInstruction::kStoreSwizzleIndirectGlobal
992 : ByteCodeInstruction::kStoreSwizzleIndirect);
993 } else {
994 fGenerator.write(isGlobal ? ByteCodeInstruction::kStoreSwizzleGlobal
995 : ByteCodeInstruction::kStoreSwizzle);
996 fGenerator.write8(location);
997 }
Brian Osman1091f022019-05-16 09:42:16 -0400998 fGenerator.write8(fSwizzle.fComponents.size());
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400999 for (int c : fSwizzle.fComponents) {
1000 fGenerator.write8(c);
1001 }
1002 }
1003
1004private:
1005 const Swizzle& fSwizzle;
1006
1007 typedef LValue INHERITED;
1008};
1009
Brian Osman07c117b2019-05-23 12:51:06 -07001010class ByteCodeExpressionLValue : public ByteCodeGenerator::LValue {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001011public:
Brian Osman07c117b2019-05-23 12:51:06 -07001012 ByteCodeExpressionLValue(ByteCodeGenerator* generator, const Expression& expr)
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001013 : INHERITED(*generator)
Brian Osman07c117b2019-05-23 12:51:06 -07001014 , fExpression(expr) {}
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001015
1016 void load() override {
Brian Osman07c117b2019-05-23 12:51:06 -07001017 fGenerator.writeVariableExpression(fExpression);
Brian Osman1091f022019-05-16 09:42:16 -04001018 }
1019
Brian Osman3e29f1d2019-05-28 09:35:05 -04001020 void store(bool discard) override {
Brian Osman07c117b2019-05-23 12:51:06 -07001021 int count = ByteCodeGenerator::SlotCount(fExpression.fType);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001022 if (!discard) {
1023 if (count > 4) {
1024 fGenerator.write(ByteCodeInstruction::kDupN);
1025 fGenerator.write8(count);
1026 } else {
1027 fGenerator.write(vector_instruction(ByteCodeInstruction::kDup, count));
1028 }
Brian Osman07c117b2019-05-23 12:51:06 -07001029 }
1030 Variable::Storage storage;
1031 int location = fGenerator.getLocation(fExpression, &storage);
1032 bool isGlobal = storage == Variable::kGlobal_Storage;
1033 if (location < 0 || count > 4) {
1034 if (location >= 0) {
1035 fGenerator.write(ByteCodeInstruction::kPushImmediate);
1036 fGenerator.write32(location);
1037 }
1038 fGenerator.write(isGlobal ? ByteCodeInstruction::kStoreExtendedGlobal
1039 : ByteCodeInstruction::kStoreExtended);
1040 fGenerator.write8(count);
1041 } else {
1042 fGenerator.write(vector_instruction(isGlobal ? ByteCodeInstruction::kStoreGlobal
1043 : ByteCodeInstruction::kStore,
1044 count));
1045 fGenerator.write8(location);
1046 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001047 }
1048
1049private:
1050 typedef LValue INHERITED;
1051
Brian Osman07c117b2019-05-23 12:51:06 -07001052 const Expression& fExpression;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001053};
1054
1055std::unique_ptr<ByteCodeGenerator::LValue> ByteCodeGenerator::getLValue(const Expression& e) {
1056 switch (e.fKind) {
Ethan Nicholas91164d12019-05-15 15:29:54 -04001057 case Expression::kExternalValue_Kind: {
1058 ExternalValue* value = ((ExternalValueReference&) e).fValue;
1059 int index = fOutput->fExternalValues.size();
1060 fOutput->fExternalValues.push_back(value);
1061 SkASSERT(index <= 255);
1062 return std::unique_ptr<LValue>(new ByteCodeExternalValueLValue(this, *value, index));
1063 }
Brian Osman07c117b2019-05-23 12:51:06 -07001064 case Expression::kFieldAccess_Kind:
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001065 case Expression::kIndex_Kind:
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001066 case Expression::kVariableReference_Kind:
Brian Osman07c117b2019-05-23 12:51:06 -07001067 return std::unique_ptr<LValue>(new ByteCodeExpressionLValue(this, e));
Brian Osman0785db02019-05-24 14:19:11 -04001068 case Expression::kSwizzle_Kind: {
1069 const Swizzle& s = (const Swizzle&) e;
1070 return swizzle_is_simple(s)
1071 ? std::unique_ptr<LValue>(new ByteCodeExpressionLValue(this, e))
1072 : std::unique_ptr<LValue>(new ByteCodeSwizzleLValue(this, s));
1073 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001074 case Expression::kTernary_Kind:
1075 default:
1076 printf("unsupported lvalue %s\n", e.description().c_str());
1077 return nullptr;
1078 }
1079}
1080
1081void ByteCodeGenerator::writeBlock(const Block& b) {
1082 for (const auto& s : b.fStatements) {
1083 this->writeStatement(*s);
1084 }
1085}
1086
1087void ByteCodeGenerator::setBreakTargets() {
1088 std::vector<DeferredLocation>& breaks = fBreakTargets.top();
1089 for (DeferredLocation& b : breaks) {
1090 b.set();
1091 }
1092 fBreakTargets.pop();
1093}
1094
1095void ByteCodeGenerator::setContinueTargets() {
1096 std::vector<DeferredLocation>& continues = fContinueTargets.top();
1097 for (DeferredLocation& c : continues) {
1098 c.set();
1099 }
1100 fContinueTargets.pop();
1101}
1102
1103void ByteCodeGenerator::writeBreakStatement(const BreakStatement& b) {
Brian Osman569f12f2019-06-13 11:23:57 -04001104 // TODO: Include BranchIfAllFalse to top-most LoopNext
1105 this->write(ByteCodeInstruction::kLoopBreak);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001106}
1107
1108void ByteCodeGenerator::writeContinueStatement(const ContinueStatement& c) {
Brian Osman569f12f2019-06-13 11:23:57 -04001109 // TODO: Include BranchIfAllFalse to top-most LoopNext
1110 this->write(ByteCodeInstruction::kLoopContinue);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001111}
1112
1113void ByteCodeGenerator::writeDoStatement(const DoStatement& d) {
Brian Osman569f12f2019-06-13 11:23:57 -04001114 this->write(ByteCodeInstruction::kLoopBegin);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001115 size_t start = fCode->size();
1116 this->writeStatement(*d.fStatement);
Brian Osman569f12f2019-06-13 11:23:57 -04001117 this->write(ByteCodeInstruction::kLoopNext);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001118 this->writeExpression(*d.fTest);
Brian Osman569f12f2019-06-13 11:23:57 -04001119 this->write(ByteCodeInstruction::kLoopMask);
1120 // TODO: Could shorten this with kBranchIfAnyTrue
1121 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1122 DeferredLocation endLocation(this);
1123 this->write(ByteCodeInstruction::kBranch);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001124 this->write16(start);
Brian Osman569f12f2019-06-13 11:23:57 -04001125 endLocation.set();
1126 this->write(ByteCodeInstruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001127}
1128
1129void ByteCodeGenerator::writeForStatement(const ForStatement& f) {
1130 fContinueTargets.emplace();
1131 fBreakTargets.emplace();
1132 if (f.fInitializer) {
1133 this->writeStatement(*f.fInitializer);
1134 }
Brian Osman569f12f2019-06-13 11:23:57 -04001135 this->write(ByteCodeInstruction::kLoopBegin);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001136 size_t start = fCode->size();
1137 if (f.fTest) {
1138 this->writeExpression(*f.fTest);
Brian Osman569f12f2019-06-13 11:23:57 -04001139 this->write(ByteCodeInstruction::kLoopMask);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001140 }
Brian Osman569f12f2019-06-13 11:23:57 -04001141 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1142 DeferredLocation endLocation(this);
1143 this->writeStatement(*f.fStatement);
1144 this->write(ByteCodeInstruction::kLoopNext);
1145 if (f.fNext) {
1146 this->writeExpression(*f.fNext, true);
1147 }
1148 this->write(ByteCodeInstruction::kBranch);
1149 this->write16(start);
1150 endLocation.set();
1151 this->write(ByteCodeInstruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001152}
1153
1154void ByteCodeGenerator::writeIfStatement(const IfStatement& i) {
Brian Osman569f12f2019-06-13 11:23:57 -04001155 this->writeExpression(*i.fTest);
1156 this->write(ByteCodeInstruction::kMaskPush);
1157 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1158 DeferredLocation falseLocation(this);
1159 this->writeStatement(*i.fIfTrue);
1160 falseLocation.set();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001161 if (i.fIfFalse) {
Brian Osman569f12f2019-06-13 11:23:57 -04001162 this->write(ByteCodeInstruction::kMaskNegate);
1163 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1164 DeferredLocation endLocation(this);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001165 this->writeStatement(*i.fIfFalse);
Mike Kleinb45ee832019-05-17 11:11:11 -05001166 endLocation.set();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001167 }
Brian Osman569f12f2019-06-13 11:23:57 -04001168 this->write(ByteCodeInstruction::kMaskPop);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001169}
1170
1171void ByteCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
Brian Osman4a47da72019-07-12 11:30:32 -04001172 if (fLoopCount || fConditionCount) {
1173 fErrors.error(r.fOffset, "return not allowed inside conditional or loop");
1174 return;
1175 }
Ethan Nicholas746035a2019-04-23 13:31:09 -04001176 this->writeExpression(*r.fExpression);
1177 this->write(ByteCodeInstruction::kReturn);
Brian Osman07c117b2019-05-23 12:51:06 -07001178 this->write8(SlotCount(r.fExpression->fType));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001179}
1180
1181void ByteCodeGenerator::writeSwitchStatement(const SwitchStatement& r) {
1182 // not yet implemented
1183 abort();
1184}
1185
1186void ByteCodeGenerator::writeVarDeclarations(const VarDeclarations& v) {
1187 for (const auto& declStatement : v.fVars) {
1188 const VarDeclaration& decl = (VarDeclaration&) *declStatement;
1189 // we need to grab the location even if we don't use it, to ensure it
1190 // has been allocated
1191 int location = getLocation(*decl.fVar);
1192 if (decl.fValue) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001193 this->writeExpression(*decl.fValue);
Brian Osman07c117b2019-05-23 12:51:06 -07001194 int count = SlotCount(decl.fValue->fType);
1195 if (count > 4) {
1196 this->write(ByteCodeInstruction::kPushImmediate);
1197 this->write32(location);
1198 this->write(ByteCodeInstruction::kStoreExtended);
1199 this->write8(count);
1200 } else {
1201 this->write(vector_instruction(ByteCodeInstruction::kStore, count));
1202 this->write8(location);
1203 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001204 }
1205 }
1206}
1207
1208void ByteCodeGenerator::writeWhileStatement(const WhileStatement& w) {
Brian Osman569f12f2019-06-13 11:23:57 -04001209 this->write(ByteCodeInstruction::kLoopBegin);
1210 size_t cond = fCode->size();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001211 this->writeExpression(*w.fTest);
Brian Osman569f12f2019-06-13 11:23:57 -04001212 this->write(ByteCodeInstruction::kLoopMask);
1213 this->write(ByteCodeInstruction::kBranchIfAllFalse);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001214 DeferredLocation endLocation(this);
1215 this->writeStatement(*w.fStatement);
Brian Osman569f12f2019-06-13 11:23:57 -04001216 this->write(ByteCodeInstruction::kLoopNext);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001217 this->write(ByteCodeInstruction::kBranch);
Brian Osman569f12f2019-06-13 11:23:57 -04001218 this->write16(cond);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001219 endLocation.set();
Brian Osman569f12f2019-06-13 11:23:57 -04001220 this->write(ByteCodeInstruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001221}
1222
1223void ByteCodeGenerator::writeStatement(const Statement& s) {
1224 switch (s.fKind) {
1225 case Statement::kBlock_Kind:
1226 this->writeBlock((Block&) s);
1227 break;
1228 case Statement::kBreak_Kind:
1229 this->writeBreakStatement((BreakStatement&) s);
1230 break;
1231 case Statement::kContinue_Kind:
1232 this->writeContinueStatement((ContinueStatement&) s);
1233 break;
1234 case Statement::kDiscard_Kind:
1235 // not yet implemented
1236 abort();
1237 case Statement::kDo_Kind:
1238 this->writeDoStatement((DoStatement&) s);
1239 break;
Brian Osman3e29f1d2019-05-28 09:35:05 -04001240 case Statement::kExpression_Kind:
1241 this->writeExpression(*((ExpressionStatement&) s).fExpression, true);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001242 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001243 case Statement::kFor_Kind:
1244 this->writeForStatement((ForStatement&) s);
1245 break;
1246 case Statement::kIf_Kind:
1247 this->writeIfStatement((IfStatement&) s);
1248 break;
1249 case Statement::kNop_Kind:
1250 break;
1251 case Statement::kReturn_Kind:
1252 this->writeReturnStatement((ReturnStatement&) s);
1253 break;
1254 case Statement::kSwitch_Kind:
1255 this->writeSwitchStatement((SwitchStatement&) s);
1256 break;
1257 case Statement::kVarDeclarations_Kind:
1258 this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration);
1259 break;
1260 case Statement::kWhile_Kind:
1261 this->writeWhileStatement((WhileStatement&) s);
1262 break;
1263 default:
1264 SkASSERT(false);
1265 }
1266}
1267
Brian Osman80164412019-06-07 13:00:23 -04001268ByteCodeFunction::ByteCodeFunction(const FunctionDeclaration* declaration)
1269 : fName(declaration->fName) {
1270 fParameterCount = 0;
1271 for (const auto& p : declaration->fParameters) {
1272 int slots = ByteCodeGenerator::SlotCount(p->fType);
1273 fParameters.push_back({ slots, (bool)(p->fModifiers.fFlags & Modifiers::kOut_Flag) });
1274 fParameterCount += slots;
1275 }
1276}
1277
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001278}