blob: e86dd8638b4351c91a6437c897977e593bb21232 [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 Osman226668a2019-05-14 16:47:30 -040084 for (auto& call : fCallTargets) {
85 if (!call.set()) {
86 return false;
87 }
88 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040089 return true;
90}
91
92std::unique_ptr<ByteCodeFunction> ByteCodeGenerator::writeFunction(const FunctionDefinition& f) {
93 fFunction = &f;
Brian Osman226668a2019-05-14 16:47:30 -040094 std::unique_ptr<ByteCodeFunction> result(new ByteCodeFunction(&f.fDeclaration));
Brian Osman80164412019-06-07 13:00:23 -040095 fParameterCount = result->fParameterCount;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040096 fCode = &result->fCode;
97 this->writeStatement(*f.fBody);
Ethan Nicholas7e603db2019-05-03 12:57:47 -040098 this->write(ByteCodeInstruction::kReturn);
99 this->write8(0);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400100 result->fLocalCount = fLocals.size();
Ethan Nicholasdfcad062019-05-07 12:53:34 -0400101 const Type& returnType = f.fDeclaration.fReturnType;
102 if (returnType != *fContext.fVoid_Type) {
Brian Osman07c117b2019-05-23 12:51:06 -0700103 result->fReturnCount = SlotCount(returnType);
Ethan Nicholasdfcad062019-05-07 12:53:34 -0400104 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400105 fLocals.clear();
106 fFunction = nullptr;
107 return result;
108}
109
110enum class TypeCategory {
111 kBool,
112 kSigned,
113 kUnsigned,
114 kFloat,
115};
116
117static TypeCategory type_category(const Type& type) {
118 switch (type.kind()) {
119 case Type::Kind::kVector_Kind:
120 case Type::Kind::kMatrix_Kind:
121 return type_category(type.componentType());
122 default:
123 if (type.fName == "bool") {
124 return TypeCategory::kBool;
125 } else if (type.fName == "int" || type.fName == "short") {
126 return TypeCategory::kSigned;
127 } else if (type.fName == "uint" || type.fName == "ushort") {
128 return TypeCategory::kUnsigned;
129 } else {
130 SkASSERT(type.fName == "float" || type.fName == "half");
131 return TypeCategory::kFloat;
132 }
133 ABORT("unsupported type: %s\n", type.description().c_str());
134 }
135}
136
Brian Osman0785db02019-05-24 14:19:11 -0400137// A "simple" Swizzle is based on a variable (or a compound variable like a struct or array), and
138// that references consecutive values, such that it can be implemented using normal load/store ops
139// with an offset. Note that all single-component swizzles (of suitable base types) are simple.
140static bool swizzle_is_simple(const Swizzle& s) {
141 switch (s.fBase->fKind) {
142 case Expression::kFieldAccess_Kind:
143 case Expression::kIndex_Kind:
144 case Expression::kVariableReference_Kind:
145 break;
146 default:
147 return false;
148 }
149
150 for (size_t i = 1; i < s.fComponents.size(); ++i) {
151 if (s.fComponents[i] != s.fComponents[i - 1] + 1) {
152 return false;
153 }
154 }
155 return true;
156}
157
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400158int ByteCodeGenerator::getLocation(const Variable& var) {
159 // given that we seldom have more than a couple of variables, linear search is probably the most
160 // efficient way to handle lookups
161 switch (var.fStorage) {
162 case Variable::kLocal_Storage: {
163 for (int i = fLocals.size() - 1; i >= 0; --i) {
164 if (fLocals[i] == &var) {
Brian Osman1091f022019-05-16 09:42:16 -0400165 SkASSERT(fParameterCount + i <= 255);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400166 return fParameterCount + i;
167 }
168 }
169 int result = fParameterCount + fLocals.size();
170 fLocals.push_back(&var);
Brian Osman07c117b2019-05-23 12:51:06 -0700171 for (int i = 0; i < SlotCount(var.fType) - 1; ++i) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400172 fLocals.push_back(nullptr);
173 }
Brian Osman1091f022019-05-16 09:42:16 -0400174 SkASSERT(result <= 255);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400175 return result;
176 }
177 case Variable::kParameter_Storage: {
178 int offset = 0;
179 for (const auto& p : fFunction->fDeclaration.fParameters) {
180 if (p == &var) {
Brian Osman1091f022019-05-16 09:42:16 -0400181 SkASSERT(offset <= 255);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400182 return offset;
183 }
Brian Osman07c117b2019-05-23 12:51:06 -0700184 offset += SlotCount(p->fType);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400185 }
186 SkASSERT(false);
Brian Osman1091f022019-05-16 09:42:16 -0400187 return 0;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400188 }
189 case Variable::kGlobal_Storage: {
190 int offset = 0;
191 for (const auto& e : fProgram) {
192 if (e.fKind == ProgramElement::kVar_Kind) {
193 VarDeclarations& decl = (VarDeclarations&) e;
194 for (const auto& v : decl.fVars) {
195 const Variable* declVar = ((VarDeclaration&) *v).fVar;
196 if (declVar->fModifiers.fLayout.fBuiltin >= 0) {
197 continue;
198 }
199 if (declVar == &var) {
Brian Osmanb7451292019-05-15 13:02:13 -0400200 SkASSERT(offset <= 255);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400201 return offset;
202 }
Brian Osman07c117b2019-05-23 12:51:06 -0700203 offset += SlotCount(declVar->fType);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400204 }
205 }
206 }
207 SkASSERT(false);
Brian Osman1091f022019-05-16 09:42:16 -0400208 return 0;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400209 }
210 default:
211 SkASSERT(false);
212 return 0;
213 }
214}
215
Brian Osman07c117b2019-05-23 12:51:06 -0700216int ByteCodeGenerator::getLocation(const Expression& expr, Variable::Storage* storage) {
217 switch (expr.fKind) {
218 case Expression::kFieldAccess_Kind: {
219 const FieldAccess& f = (const FieldAccess&)expr;
220 int baseAddr = this->getLocation(*f.fBase, storage);
221 int offset = 0;
222 for (int i = 0; i < f.fFieldIndex; ++i) {
223 offset += SlotCount(*f.fBase->fType.fields()[i].fType);
224 }
225 if (baseAddr < 0) {
Brian Osman86769292019-06-21 11:05:47 -0400226 if (offset != 0) {
227 this->write(ByteCodeInstruction::kPushImmediate);
228 this->write32(offset);
229 this->write(ByteCodeInstruction::kAddI);
230 }
Brian Osman07c117b2019-05-23 12:51:06 -0700231 return -1;
232 } else {
233 return baseAddr + offset;
234 }
235 }
236 case Expression::kIndex_Kind: {
237 const IndexExpression& i = (const IndexExpression&)expr;
238 int stride = SlotCount(i.fType);
239 int offset = -1;
240 if (i.fIndex->isConstant()) {
241 offset = i.fIndex->getConstantInt() * stride;
242 } else {
Brian Osman86769292019-06-21 11:05:47 -0400243 if (i.fIndex->hasSideEffects()) {
244 // Having a side-effect in an indexer is technically safe for an rvalue,
245 // but with lvalues we have to evaluate the indexer twice, so make it an error.
246 fErrors.error(i.fIndex->fOffset,
247 "Index expressions with side-effects not supported in byte code.");
248 return 0;
249 }
Brian Osman07c117b2019-05-23 12:51:06 -0700250 this->writeExpression(*i.fIndex);
Brian Osman86769292019-06-21 11:05:47 -0400251 if (stride != 1) {
252 this->write(ByteCodeInstruction::kPushImmediate);
253 this->write32(stride);
254 this->write(ByteCodeInstruction::kMultiplyI);
255 }
Brian Osman07c117b2019-05-23 12:51:06 -0700256 }
257 int baseAddr = this->getLocation(*i.fBase, storage);
Brian Osman86769292019-06-21 11:05:47 -0400258
259 // Are both components known statically?
Brian Osman07c117b2019-05-23 12:51:06 -0700260 if (baseAddr >= 0 && offset >= 0) {
261 return baseAddr + offset;
262 }
Brian Osman86769292019-06-21 11:05:47 -0400263
264 // At least one component is dynamic (and on the stack).
265
266 // If the other component is zero, we're done
267 if (baseAddr == 0 || offset == 0) {
268 return -1;
269 }
270
271 // Push the non-dynamic component (if any) to the stack, then add the two
Brian Osman07c117b2019-05-23 12:51:06 -0700272 if (baseAddr >= 0) {
273 this->write(ByteCodeInstruction::kPushImmediate);
274 this->write32(baseAddr);
275 }
276 if (offset >= 0) {
277 this->write(ByteCodeInstruction::kPushImmediate);
278 this->write32(offset);
279 }
280 this->write(ByteCodeInstruction::kAddI);
281 return -1;
282 }
Brian Osman0785db02019-05-24 14:19:11 -0400283 case Expression::kSwizzle_Kind: {
284 const Swizzle& s = (const Swizzle&)expr;
285 SkASSERT(swizzle_is_simple(s));
286 int baseAddr = this->getLocation(*s.fBase, storage);
287 int offset = s.fComponents[0];
288 if (baseAddr < 0) {
Brian Osman86769292019-06-21 11:05:47 -0400289 if (offset != 0) {
290 this->write(ByteCodeInstruction::kPushImmediate);
291 this->write32(offset);
292 this->write(ByteCodeInstruction::kAddI);
293 }
Brian Osman0785db02019-05-24 14:19:11 -0400294 return -1;
295 } else {
296 return baseAddr + offset;
297 }
298 }
Brian Osman07c117b2019-05-23 12:51:06 -0700299 case Expression::kVariableReference_Kind: {
300 const Variable& var = ((const VariableReference&)expr).fVariable;
301 *storage = var.fStorage;
302 return this->getLocation(var);
303 }
304 default:
305 SkASSERT(false);
306 return 0;
307 }
308}
309
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400310void ByteCodeGenerator::write8(uint8_t b) {
311 fCode->push_back(b);
312}
313
314void ByteCodeGenerator::write16(uint16_t i) {
Mike Klein76346ac2019-05-17 11:57:10 -0500315 size_t n = fCode->size();
316 fCode->resize(n+2);
317 memcpy(fCode->data() + n, &i, 2);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400318}
319
320void ByteCodeGenerator::write32(uint32_t i) {
Mike Klein76346ac2019-05-17 11:57:10 -0500321 size_t n = fCode->size();
322 fCode->resize(n+4);
323 memcpy(fCode->data() + n, &i, 4);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400324}
325
326void ByteCodeGenerator::write(ByteCodeInstruction i) {
Mike Klein108e9352019-05-21 11:05:17 -0500327 this->write16((uint16_t)i);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400328}
329
Mike Klein76346ac2019-05-17 11:57:10 -0500330static ByteCodeInstruction vector_instruction(ByteCodeInstruction base, int count) {
Brian Osman07c117b2019-05-23 12:51:06 -0700331 SkASSERT(count >= 1 && count <= 4);
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400332 return ((ByteCodeInstruction) ((int) base + count - 1));
333}
334
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400335void ByteCodeGenerator::writeTypedInstruction(const Type& type, ByteCodeInstruction s,
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400336 ByteCodeInstruction u, ByteCodeInstruction f,
337 int count) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400338 switch (type_category(type)) {
339 case TypeCategory::kSigned:
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400340 this->write(vector_instruction(s, count));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400341 break;
342 case TypeCategory::kUnsigned:
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400343 this->write(vector_instruction(u, count));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400344 break;
Brian Osman1e855b22019-05-29 15:21:52 -0400345 case TypeCategory::kFloat: {
346 if (count > 4) {
347 this->write((ByteCodeInstruction)((int)f + 4));
348 this->write8(count);
349 } else {
350 this->write(vector_instruction(f, count));
351 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400352 break;
Brian Osman1e855b22019-05-29 15:21:52 -0400353 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400354 default:
355 SkASSERT(false);
356 }
357}
358
Brian Osman3e29f1d2019-05-28 09:35:05 -0400359bool ByteCodeGenerator::writeBinaryExpression(const BinaryExpression& b, bool discard) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400360 if (b.fOperator == Token::Kind::EQ) {
361 std::unique_ptr<LValue> lvalue = this->getLValue(*b.fLeft);
362 this->writeExpression(*b.fRight);
Brian Osman3e29f1d2019-05-28 09:35:05 -0400363 lvalue->store(discard);
364 discard = false;
365 return discard;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400366 }
Brian Osman16e6fd52019-05-29 11:19:00 -0400367 const Type& lType = b.fLeft->fType;
368 const Type& rType = b.fRight->fType;
Brian Osman909231c2019-05-29 15:34:36 -0400369 bool lVecOrMtx = (lType.kind() == Type::kVector_Kind || lType.kind() == Type::kMatrix_Kind);
370 bool rVecOrMtx = (rType.kind() == Type::kVector_Kind || rType.kind() == Type::kMatrix_Kind);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400371 Token::Kind op;
372 std::unique_ptr<LValue> lvalue;
373 if (is_assignment(b.fOperator)) {
374 lvalue = this->getLValue(*b.fLeft);
375 lvalue->load();
376 op = remove_assignment(b.fOperator);
377 } else {
378 this->writeExpression(*b.fLeft);
379 op = b.fOperator;
Brian Osman909231c2019-05-29 15:34:36 -0400380 if (!lVecOrMtx && rVecOrMtx) {
Brian Osman16e6fd52019-05-29 11:19:00 -0400381 for (int i = SlotCount(rType); i > 1; --i) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400382 this->write(ByteCodeInstruction::kDup);
383 }
384 }
385 }
386 this->writeExpression(*b.fRight);
Brian Osman909231c2019-05-29 15:34:36 -0400387 if (lVecOrMtx && !rVecOrMtx) {
Brian Osman16e6fd52019-05-29 11:19:00 -0400388 for (int i = SlotCount(lType); i > 1; --i) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400389 this->write(ByteCodeInstruction::kDup);
390 }
391 }
Brian Osman909231c2019-05-29 15:34:36 -0400392 // Special case for M*V, V*M, M*M (but not V*V!)
393 if (op == Token::Kind::STAR && lVecOrMtx && rVecOrMtx &&
394 !(lType.kind() == Type::kVector_Kind && rType.kind() == Type::kVector_Kind)) {
395 this->write(ByteCodeInstruction::kMatrixMultiply);
396 int rCols = rType.columns(),
397 rRows = rType.rows(),
398 lCols = lType.columns(),
399 lRows = lType.rows();
400 // M*V treats the vector as a column
401 if (rType.kind() == Type::kVector_Kind) {
402 std::swap(rCols, rRows);
403 }
404 SkASSERT(lCols == rRows);
405 SkASSERT(SlotCount(b.fType) == lRows * rCols);
406 this->write8(lCols);
407 this->write8(lRows);
408 this->write8(rCols);
409 } else {
410 int count = std::max(SlotCount(lType), SlotCount(rType));
411 switch (op) {
412 case Token::Kind::EQEQ:
413 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareIEQ,
414 ByteCodeInstruction::kCompareIEQ,
415 ByteCodeInstruction::kCompareFEQ,
416 count);
417 // Collapse to a single bool
418 for (int i = count; i > 1; --i) {
419 this->write(ByteCodeInstruction::kAndB);
420 }
421 break;
422 case Token::Kind::GT:
423 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSGT,
424 ByteCodeInstruction::kCompareUGT,
425 ByteCodeInstruction::kCompareFGT,
426 count);
427 break;
428 case Token::Kind::GTEQ:
429 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSGTEQ,
430 ByteCodeInstruction::kCompareUGTEQ,
431 ByteCodeInstruction::kCompareFGTEQ,
432 count);
433 break;
434 case Token::Kind::LT:
435 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSLT,
436 ByteCodeInstruction::kCompareULT,
437 ByteCodeInstruction::kCompareFLT,
438 count);
439 break;
440 case Token::Kind::LTEQ:
441 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSLTEQ,
442 ByteCodeInstruction::kCompareULTEQ,
443 ByteCodeInstruction::kCompareFLTEQ,
444 count);
445 break;
446 case Token::Kind::MINUS:
447 this->writeTypedInstruction(lType, ByteCodeInstruction::kSubtractI,
448 ByteCodeInstruction::kSubtractI,
449 ByteCodeInstruction::kSubtractF,
450 count);
451 break;
452 case Token::Kind::NEQ:
453 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareINEQ,
454 ByteCodeInstruction::kCompareINEQ,
455 ByteCodeInstruction::kCompareFNEQ,
456 count);
457 // Collapse to a single bool
458 for (int i = count; i > 1; --i) {
459 this->write(ByteCodeInstruction::kOrB);
460 }
461 break;
462 case Token::Kind::PERCENT:
463 this->writeTypedInstruction(lType, ByteCodeInstruction::kRemainderS,
464 ByteCodeInstruction::kRemainderU,
465 ByteCodeInstruction::kRemainderF,
466 count);
467 break;
468 case Token::Kind::PLUS:
469 this->writeTypedInstruction(lType, ByteCodeInstruction::kAddI,
470 ByteCodeInstruction::kAddI,
471 ByteCodeInstruction::kAddF,
472 count);
473 break;
474 case Token::Kind::SLASH:
475 this->writeTypedInstruction(lType, ByteCodeInstruction::kDivideS,
476 ByteCodeInstruction::kDivideU,
477 ByteCodeInstruction::kDivideF,
478 count);
479 break;
480 case Token::Kind::STAR:
481 this->writeTypedInstruction(lType, ByteCodeInstruction::kMultiplyI,
482 ByteCodeInstruction::kMultiplyI,
483 ByteCodeInstruction::kMultiplyF,
484 count);
485 break;
Brian Osman569f12f2019-06-13 11:23:57 -0400486
487 case Token::Kind::LOGICALAND:
488 SkASSERT(type_category(lType) == SkSL::TypeCategory::kBool && count == 1);
489 this->write(ByteCodeInstruction::kAndB);
490 break;
491 case Token::Kind::LOGICALNOT:
492 SkASSERT(type_category(lType) == SkSL::TypeCategory::kBool && count == 1);
493 this->write(ByteCodeInstruction::kNotB);
494 break;
495 case Token::Kind::LOGICALOR:
496 SkASSERT(type_category(lType) == SkSL::TypeCategory::kBool && count == 1);
497 this->write(ByteCodeInstruction::kOrB);
498 break;
499 case Token::Kind::LOGICALXOR:
500 SkASSERT(type_category(lType) == SkSL::TypeCategory::kBool && count == 1);
501 this->write(ByteCodeInstruction::kXorB);
502 break;
503
Brian Osman909231c2019-05-29 15:34:36 -0400504 default:
505 SkASSERT(false);
506 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400507 }
508 if (lvalue) {
Brian Osman3e29f1d2019-05-28 09:35:05 -0400509 lvalue->store(discard);
510 discard = false;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400511 }
Brian Osman3e29f1d2019-05-28 09:35:05 -0400512 return discard;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400513}
514
515void ByteCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
516 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osman569f12f2019-06-13 11:23:57 -0400517 this->write32(b.fValue ? ~0 : 0);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400518}
519
520void ByteCodeGenerator::writeConstructor(const Constructor& c) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400521 for (const auto& arg : c.fArguments) {
522 this->writeExpression(*arg);
523 }
524 if (c.fArguments.size() == 1) {
Brian Osman29e013d2019-05-28 17:16:03 -0400525 const Type& inType = c.fArguments[0]->fType;
526 const Type& outType = c.fType;
527 TypeCategory inCategory = type_category(inType);
528 TypeCategory outCategory = type_category(outType);
529 int inCount = SlotCount(inType);
530 int outCount = SlotCount(outType);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400531 if (inCategory != outCategory) {
Brian Osmanc51d7912019-05-22 15:16:16 -0700532 SkASSERT(inCount == outCount);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400533 if (inCategory == TypeCategory::kFloat) {
534 SkASSERT(outCategory == TypeCategory::kSigned ||
535 outCategory == TypeCategory::kUnsigned);
Brian Osmanc51d7912019-05-22 15:16:16 -0700536 this->write(vector_instruction(ByteCodeInstruction::kConvertFtoI, outCount));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400537 } else if (outCategory == TypeCategory::kFloat) {
538 if (inCategory == TypeCategory::kSigned) {
Brian Osmanc51d7912019-05-22 15:16:16 -0700539 this->write(vector_instruction(ByteCodeInstruction::kConvertStoF, outCount));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400540 } else {
541 SkASSERT(inCategory == TypeCategory::kUnsigned);
Brian Osmanc51d7912019-05-22 15:16:16 -0700542 this->write(vector_instruction(ByteCodeInstruction::kConvertUtoF, outCount));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400543 }
544 } else {
545 SkASSERT(false);
546 }
547 }
Brian Osman29e013d2019-05-28 17:16:03 -0400548 if (inType.kind() == Type::kMatrix_Kind && outType.kind() == Type::kMatrix_Kind) {
549 this->write(ByteCodeInstruction::kMatrixToMatrix);
550 this->write8(inType.columns());
551 this->write8(inType.rows());
552 this->write8(outType.columns());
553 this->write8(outType.rows());
554 } else if (inCount != outCount) {
Brian Osmanc51d7912019-05-22 15:16:16 -0700555 SkASSERT(inCount == 1);
Brian Osman29e013d2019-05-28 17:16:03 -0400556 if (outType.kind() == Type::kMatrix_Kind) {
557 this->write(ByteCodeInstruction::kScalarToMatrix);
558 this->write8(outType.columns());
559 this->write8(outType.rows());
560 } else {
561 SkASSERT(outType.kind() == Type::kVector_Kind);
562 for (; inCount != outCount; ++inCount) {
563 this->write(ByteCodeInstruction::kDup);
564 }
Brian Osmanc51d7912019-05-22 15:16:16 -0700565 }
566 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400567 }
568}
569
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400570void ByteCodeGenerator::writeExternalFunctionCall(const ExternalFunctionCall& f) {
571 int argumentCount = 0;
572 for (const auto& arg : f.fArguments) {
573 this->writeExpression(*arg);
Brian Osman07c117b2019-05-23 12:51:06 -0700574 argumentCount += SlotCount(arg->fType);
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400575 }
576 this->write(ByteCodeInstruction::kCallExternal);
577 SkASSERT(argumentCount <= 255);
578 this->write8(argumentCount);
Brian Osman07c117b2019-05-23 12:51:06 -0700579 this->write8(SlotCount(f.fType));
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400580 int index = fOutput->fExternalValues.size();
581 fOutput->fExternalValues.push_back(f.fFunction);
582 SkASSERT(index <= 255);
583 this->write8(index);
584}
585
Ethan Nicholas91164d12019-05-15 15:29:54 -0400586void ByteCodeGenerator::writeExternalValue(const ExternalValueReference& e) {
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400587 this->write(vector_instruction(ByteCodeInstruction::kReadExternal,
Brian Osman07c117b2019-05-23 12:51:06 -0700588 SlotCount(e.fValue->type())));
Ethan Nicholas91164d12019-05-15 15:29:54 -0400589 int index = fOutput->fExternalValues.size();
590 fOutput->fExternalValues.push_back(e.fValue);
591 SkASSERT(index <= 255);
592 this->write8(index);
593}
594
Brian Osman07c117b2019-05-23 12:51:06 -0700595void ByteCodeGenerator::writeVariableExpression(const Expression& expr) {
596 Variable::Storage storage;
597 int location = this->getLocation(expr, &storage);
598 bool isGlobal = storage == Variable::kGlobal_Storage;
599 int count = SlotCount(expr.fType);
600 if (location < 0 || count > 4) {
601 if (location >= 0) {
602 this->write(ByteCodeInstruction::kPushImmediate);
603 this->write32(location);
604 }
605 this->write(isGlobal ? ByteCodeInstruction::kLoadExtendedGlobal
606 : ByteCodeInstruction::kLoadExtended);
607 this->write8(count);
608 } else {
609 this->write(vector_instruction(isGlobal ? ByteCodeInstruction::kLoadGlobal
610 : ByteCodeInstruction::kLoad,
611 count));
612 this->write8(location);
613 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400614}
615
Brian Osmand30e0392019-06-14 14:05:14 -0400616static inline uint32_t float_to_bits(float x) {
617 uint32_t u;
618 memcpy(&u, &x, sizeof(uint32_t));
619 return u;
620}
621
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400622void ByteCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
623 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osmand30e0392019-06-14 14:05:14 -0400624 this->write32(float_to_bits(f.fValue));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400625}
626
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400627void ByteCodeGenerator::writeIntrinsicCall(const FunctionCall& c) {
628 auto found = fIntrinsics.find(c.fFunction.fName);
629 if (found == fIntrinsics.end()) {
630 fErrors.error(c.fOffset, "unsupported intrinsic function");
631 return;
632 }
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400633 if (found->second.fIsSpecial) {
634 SkASSERT(found->second.fValue.fSpecial == SpecialIntrinsic::kDot);
635 SkASSERT(c.fArguments.size() == 2);
636 SkASSERT(SlotCount(c.fArguments[0]->fType) == SlotCount(c.fArguments[1]->fType));
637 this->write((ByteCodeInstruction) ((int) ByteCodeInstruction::kMultiplyF +
638 SlotCount(c.fArguments[0]->fType) - 1));
639 for (int i = SlotCount(c.fArguments[0]->fType); i > 1; --i) {
640 this->write(ByteCodeInstruction::kAddF);
641 }
642 } else {
643 switch (found->second.fValue.fInstruction) {
644 case ByteCodeInstruction::kCos:
645 case ByteCodeInstruction::kMix:
646 case ByteCodeInstruction::kSin:
647 case ByteCodeInstruction::kSqrt:
648 case ByteCodeInstruction::kTan:
649 SkASSERT(c.fArguments.size() > 0);
650 this->write((ByteCodeInstruction) ((int) found->second.fValue.fInstruction +
651 SlotCount(c.fArguments[0]->fType) - 1));
652 break;
653 case ByteCodeInstruction::kCross:
654 this->write(found->second.fValue.fInstruction);
655 break;
656 default:
657 SkASSERT(false);
658 }
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400659 }
660}
661
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400662void ByteCodeGenerator::writeFunctionCall(const FunctionCall& f) {
Brian Osmand3494ed2019-06-20 15:41:34 -0400663 // Builtins have simple signatures...
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400664 if (f.fFunction.fBuiltin) {
Brian Osmand3494ed2019-06-20 15:41:34 -0400665 for (const auto& arg : f.fArguments) {
666 this->writeExpression(*arg);
667 }
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400668 this->writeIntrinsicCall(f);
669 return;
670 }
Brian Osmand3494ed2019-06-20 15:41:34 -0400671
672 // Otherwise, we may need to deal with out parameters, so the sequence is trickier...
673 if (int returnCount = SlotCount(f.fType)) {
674 this->write(ByteCodeInstruction::kReserve);
675 this->write8(returnCount);
676 }
677
678 int argCount = f.fArguments.size();
679 std::vector<std::unique_ptr<LValue>> lvalues;
680 for (int i = 0; i < argCount; ++i) {
681 const auto& param = f.fFunction.fParameters[i];
682 const auto& arg = f.fArguments[i];
683 if (param->fModifiers.fFlags & Modifiers::kOut_Flag) {
684 lvalues.emplace_back(this->getLValue(*arg));
685 lvalues.back()->load();
686 } else {
687 this->writeExpression(*arg);
688 }
689 }
690
Brian Osman226668a2019-05-14 16:47:30 -0400691 this->write(ByteCodeInstruction::kCall);
692 fCallTargets.emplace_back(this, f.fFunction);
Brian Osmand3494ed2019-06-20 15:41:34 -0400693
694 // After the called function returns, the stack will still contain our arguments. We have to
695 // pop them (storing any out parameters back to their lvalues as we go). We glob together slot
696 // counts for all parameters that aren't out-params, so we can pop them in one big chunk.
697 int popCount = 0;
698 auto pop = [&]() {
699 if (popCount > 4) {
700 this->write(ByteCodeInstruction::kPopN);
701 this->write8(popCount);
702 } else if (popCount > 0) {
703 this->write(vector_instruction(ByteCodeInstruction::kPop, popCount));
704 }
705 popCount = 0;
706 };
707
708 for (int i = argCount - 1; i >= 0; --i) {
709 const auto& param = f.fFunction.fParameters[i];
710 const auto& arg = f.fArguments[i];
711 if (param->fModifiers.fFlags & Modifiers::kOut_Flag) {
712 pop();
713 lvalues.back()->store(true);
714 lvalues.pop_back();
715 } else {
716 popCount += SlotCount(arg->fType);
717 }
718 }
719 pop();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400720}
721
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400722void ByteCodeGenerator::writeIntLiteral(const IntLiteral& i) {
723 this->write(ByteCodeInstruction::kPushImmediate);
724 this->write32(i.fValue);
725}
726
727void ByteCodeGenerator::writeNullLiteral(const NullLiteral& n) {
728 // not yet implemented
729 abort();
730}
731
Brian Osman3e29f1d2019-05-28 09:35:05 -0400732bool ByteCodeGenerator::writePrefixExpression(const PrefixExpression& p, bool discard) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400733 switch (p.fOperator) {
734 case Token::Kind::PLUSPLUS: // fall through
735 case Token::Kind::MINUSMINUS: {
Brian Osman07c117b2019-05-23 12:51:06 -0700736 SkASSERT(SlotCount(p.fOperand->fType) == 1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400737 std::unique_ptr<LValue> lvalue = this->getLValue(*p.fOperand);
738 lvalue->load();
739 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osmand30e0392019-06-14 14:05:14 -0400740 this->write32(type_category(p.fType) == TypeCategory::kFloat ? float_to_bits(1.0f) : 1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400741 if (p.fOperator == Token::Kind::PLUSPLUS) {
742 this->writeTypedInstruction(p.fType,
743 ByteCodeInstruction::kAddI,
744 ByteCodeInstruction::kAddI,
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400745 ByteCodeInstruction::kAddF,
746 1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400747 } else {
748 this->writeTypedInstruction(p.fType,
749 ByteCodeInstruction::kSubtractI,
750 ByteCodeInstruction::kSubtractI,
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400751 ByteCodeInstruction::kSubtractF,
752 1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400753 }
Brian Osman3e29f1d2019-05-28 09:35:05 -0400754 lvalue->store(discard);
755 discard = false;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400756 break;
757 }
Ethan Nicholas354ecf32019-05-07 16:13:02 -0400758 case Token::Kind::MINUS: {
759 this->writeExpression(*p.fOperand);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400760 this->writeTypedInstruction(p.fType,
Mike Klein12710912019-05-21 11:04:59 -0500761 ByteCodeInstruction::kNegateI,
762 ByteCodeInstruction::kNegateI,
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400763 ByteCodeInstruction::kNegateF,
Brian Osman07c117b2019-05-23 12:51:06 -0700764 SlotCount(p.fOperand->fType));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400765 break;
Ethan Nicholas354ecf32019-05-07 16:13:02 -0400766 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400767 default:
768 SkASSERT(false);
769 }
Brian Osman3e29f1d2019-05-28 09:35:05 -0400770 return discard;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400771}
772
Brian Osman3e29f1d2019-05-28 09:35:05 -0400773bool ByteCodeGenerator::writePostfixExpression(const PostfixExpression& p, bool discard) {
Brian Osmanf3fa6002019-05-17 14:26:53 -0400774 switch (p.fOperator) {
775 case Token::Kind::PLUSPLUS: // fall through
776 case Token::Kind::MINUSMINUS: {
Brian Osman07c117b2019-05-23 12:51:06 -0700777 SkASSERT(SlotCount(p.fOperand->fType) == 1);
Brian Osmanf3fa6002019-05-17 14:26:53 -0400778 std::unique_ptr<LValue> lvalue = this->getLValue(*p.fOperand);
779 lvalue->load();
Brian Osman3e29f1d2019-05-28 09:35:05 -0400780 if (!discard) {
781 this->write(ByteCodeInstruction::kDup);
782 }
Brian Osmanf3fa6002019-05-17 14:26:53 -0400783 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osmand30e0392019-06-14 14:05:14 -0400784 this->write32(type_category(p.fType) == TypeCategory::kFloat ? float_to_bits(1.0f) : 1);
Brian Osmanf3fa6002019-05-17 14:26:53 -0400785 if (p.fOperator == Token::Kind::PLUSPLUS) {
786 this->writeTypedInstruction(p.fType,
787 ByteCodeInstruction::kAddI,
788 ByteCodeInstruction::kAddI,
789 ByteCodeInstruction::kAddF,
790 1);
791 } else {
792 this->writeTypedInstruction(p.fType,
793 ByteCodeInstruction::kSubtractI,
794 ByteCodeInstruction::kSubtractI,
795 ByteCodeInstruction::kSubtractF,
796 1);
797 }
Brian Osman3e29f1d2019-05-28 09:35:05 -0400798 lvalue->store(discard);
Brian Osmanf3fa6002019-05-17 14:26:53 -0400799 this->write(ByteCodeInstruction::kPop);
Brian Osman3e29f1d2019-05-28 09:35:05 -0400800 discard = false;
Brian Osmanf3fa6002019-05-17 14:26:53 -0400801 break;
802 }
803 default:
804 SkASSERT(false);
805 }
Brian Osman3e29f1d2019-05-28 09:35:05 -0400806 return discard;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400807}
808
809void ByteCodeGenerator::writeSwizzle(const Swizzle& s) {
Brian Osman0785db02019-05-24 14:19:11 -0400810 if (swizzle_is_simple(s)) {
811 this->writeVariableExpression(s);
812 return;
813 }
814
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400815 switch (s.fBase->fKind) {
816 case Expression::kVariableReference_Kind: {
817 const Variable& var = ((VariableReference&) *s.fBase).fVariable;
Brian Osman1091f022019-05-16 09:42:16 -0400818 this->write(var.fStorage == Variable::kGlobal_Storage
819 ? ByteCodeInstruction::kLoadSwizzleGlobal
820 : ByteCodeInstruction::kLoadSwizzle);
821 this->write8(this->getLocation(var));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400822 this->write8(s.fComponents.size());
823 for (int c : s.fComponents) {
824 this->write8(c);
825 }
826 break;
827 }
828 default:
829 this->writeExpression(*s.fBase);
830 this->write(ByteCodeInstruction::kSwizzle);
831 this->write8(s.fBase->fType.columns());
832 this->write8(s.fComponents.size());
833 for (int c : s.fComponents) {
834 this->write8(c);
835 }
836 }
837}
838
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400839void ByteCodeGenerator::writeTernaryExpression(const TernaryExpression& t) {
Brian Osman4e93feb2019-05-16 15:38:00 -0400840 this->writeExpression(*t.fTest);
Brian Osman569f12f2019-06-13 11:23:57 -0400841 this->write(ByteCodeInstruction::kMaskPush);
Brian Osman4e93feb2019-05-16 15:38:00 -0400842 this->writeExpression(*t.fIfTrue);
Brian Osman569f12f2019-06-13 11:23:57 -0400843 this->write(ByteCodeInstruction::kMaskNegate);
844 this->writeExpression(*t.fIfFalse);
845 this->write(ByteCodeInstruction::kMaskBlend);
846 this->write8(SlotCount(t.fType));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400847}
848
Brian Osman3e29f1d2019-05-28 09:35:05 -0400849void ByteCodeGenerator::writeExpression(const Expression& e, bool discard) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400850 switch (e.fKind) {
851 case Expression::kBinary_Kind:
Brian Osman3e29f1d2019-05-28 09:35:05 -0400852 discard = this->writeBinaryExpression((BinaryExpression&) e, discard);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400853 break;
854 case Expression::kBoolLiteral_Kind:
855 this->writeBoolLiteral((BoolLiteral&) e);
856 break;
857 case Expression::kConstructor_Kind:
858 this->writeConstructor((Constructor&) e);
859 break;
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400860 case Expression::kExternalFunctionCall_Kind:
861 this->writeExternalFunctionCall((ExternalFunctionCall&) e);
862 break;
Ethan Nicholas91164d12019-05-15 15:29:54 -0400863 case Expression::kExternalValue_Kind:
864 this->writeExternalValue((ExternalValueReference&) e);
865 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400866 case Expression::kFieldAccess_Kind:
Brian Osman07c117b2019-05-23 12:51:06 -0700867 case Expression::kIndex_Kind:
868 case Expression::kVariableReference_Kind:
869 this->writeVariableExpression(e);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400870 break;
871 case Expression::kFloatLiteral_Kind:
872 this->writeFloatLiteral((FloatLiteral&) e);
873 break;
874 case Expression::kFunctionCall_Kind:
875 this->writeFunctionCall((FunctionCall&) e);
876 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400877 case Expression::kIntLiteral_Kind:
878 this->writeIntLiteral((IntLiteral&) e);
879 break;
880 case Expression::kNullLiteral_Kind:
881 this->writeNullLiteral((NullLiteral&) e);
882 break;
883 case Expression::kPrefix_Kind:
Brian Osman3e29f1d2019-05-28 09:35:05 -0400884 discard = this->writePrefixExpression((PrefixExpression&) e, discard);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400885 break;
886 case Expression::kPostfix_Kind:
Brian Osman3e29f1d2019-05-28 09:35:05 -0400887 discard = this->writePostfixExpression((PostfixExpression&) e, discard);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400888 break;
889 case Expression::kSwizzle_Kind:
890 this->writeSwizzle((Swizzle&) e);
891 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400892 case Expression::kTernary_Kind:
893 this->writeTernaryExpression((TernaryExpression&) e);
894 break;
895 default:
896 printf("unsupported expression %s\n", e.description().c_str());
897 SkASSERT(false);
898 }
Brian Osman3e29f1d2019-05-28 09:35:05 -0400899 if (discard) {
900 int count = SlotCount(e.fType);
901 if (count > 4) {
902 this->write(ByteCodeInstruction::kPopN);
903 this->write8(count);
Brian Osmanfba386b2019-06-20 14:54:15 -0400904 } else if (count != 0) {
Brian Osman3e29f1d2019-05-28 09:35:05 -0400905 this->write(vector_instruction(ByteCodeInstruction::kPop, count));
906 }
907 discard = false;
908 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400909}
910
Ethan Nicholas91164d12019-05-15 15:29:54 -0400911class ByteCodeExternalValueLValue : public ByteCodeGenerator::LValue {
912public:
913 ByteCodeExternalValueLValue(ByteCodeGenerator* generator, ExternalValue& value, int index)
914 : INHERITED(*generator)
Brian Osman07c117b2019-05-23 12:51:06 -0700915 , fCount(ByteCodeGenerator::SlotCount(value.type()))
Ethan Nicholas91164d12019-05-15 15:29:54 -0400916 , fIndex(index) {}
917
918 void load() override {
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400919 fGenerator.write(vector_instruction(ByteCodeInstruction::kReadExternal, fCount));
Ethan Nicholas91164d12019-05-15 15:29:54 -0400920 fGenerator.write8(fIndex);
921 }
922
Brian Osman3e29f1d2019-05-28 09:35:05 -0400923 void store(bool discard) override {
924 if (!discard) {
925 fGenerator.write(vector_instruction(ByteCodeInstruction::kDup, fCount));
926 }
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400927 fGenerator.write(vector_instruction(ByteCodeInstruction::kWriteExternal, fCount));
Ethan Nicholas91164d12019-05-15 15:29:54 -0400928 fGenerator.write8(fIndex);
929 }
930
931private:
932 typedef LValue INHERITED;
933
934 int fCount;
935
936 int fIndex;
937};
938
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400939class ByteCodeSwizzleLValue : public ByteCodeGenerator::LValue {
940public:
941 ByteCodeSwizzleLValue(ByteCodeGenerator* generator, const Swizzle& swizzle)
942 : INHERITED(*generator)
Brian Osman07c117b2019-05-23 12:51:06 -0700943 , fSwizzle(swizzle) {}
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400944
945 void load() override {
Brian Osman1091f022019-05-16 09:42:16 -0400946 fGenerator.writeSwizzle(fSwizzle);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400947 }
948
Brian Osman3e29f1d2019-05-28 09:35:05 -0400949 void store(bool discard) override {
950 if (!discard) {
951 fGenerator.write(vector_instruction(ByteCodeInstruction::kDup,
952 fSwizzle.fComponents.size()));
953 }
Brian Osman07c117b2019-05-23 12:51:06 -0700954 Variable::Storage storage;
955 int location = fGenerator.getLocation(*fSwizzle.fBase, &storage);
956 bool isGlobal = storage == Variable::kGlobal_Storage;
957 if (location < 0) {
958 fGenerator.write(isGlobal ? ByteCodeInstruction::kStoreSwizzleIndirectGlobal
959 : ByteCodeInstruction::kStoreSwizzleIndirect);
960 } else {
961 fGenerator.write(isGlobal ? ByteCodeInstruction::kStoreSwizzleGlobal
962 : ByteCodeInstruction::kStoreSwizzle);
963 fGenerator.write8(location);
964 }
Brian Osman1091f022019-05-16 09:42:16 -0400965 fGenerator.write8(fSwizzle.fComponents.size());
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400966 for (int c : fSwizzle.fComponents) {
967 fGenerator.write8(c);
968 }
969 }
970
971private:
972 const Swizzle& fSwizzle;
973
974 typedef LValue INHERITED;
975};
976
Brian Osman07c117b2019-05-23 12:51:06 -0700977class ByteCodeExpressionLValue : public ByteCodeGenerator::LValue {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400978public:
Brian Osman07c117b2019-05-23 12:51:06 -0700979 ByteCodeExpressionLValue(ByteCodeGenerator* generator, const Expression& expr)
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400980 : INHERITED(*generator)
Brian Osman07c117b2019-05-23 12:51:06 -0700981 , fExpression(expr) {}
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400982
983 void load() override {
Brian Osman07c117b2019-05-23 12:51:06 -0700984 fGenerator.writeVariableExpression(fExpression);
Brian Osman1091f022019-05-16 09:42:16 -0400985 }
986
Brian Osman3e29f1d2019-05-28 09:35:05 -0400987 void store(bool discard) override {
Brian Osman07c117b2019-05-23 12:51:06 -0700988 int count = ByteCodeGenerator::SlotCount(fExpression.fType);
Brian Osman3e29f1d2019-05-28 09:35:05 -0400989 if (!discard) {
990 if (count > 4) {
991 fGenerator.write(ByteCodeInstruction::kDupN);
992 fGenerator.write8(count);
993 } else {
994 fGenerator.write(vector_instruction(ByteCodeInstruction::kDup, count));
995 }
Brian Osman07c117b2019-05-23 12:51:06 -0700996 }
997 Variable::Storage storage;
998 int location = fGenerator.getLocation(fExpression, &storage);
999 bool isGlobal = storage == Variable::kGlobal_Storage;
1000 if (location < 0 || count > 4) {
1001 if (location >= 0) {
1002 fGenerator.write(ByteCodeInstruction::kPushImmediate);
1003 fGenerator.write32(location);
1004 }
1005 fGenerator.write(isGlobal ? ByteCodeInstruction::kStoreExtendedGlobal
1006 : ByteCodeInstruction::kStoreExtended);
1007 fGenerator.write8(count);
1008 } else {
1009 fGenerator.write(vector_instruction(isGlobal ? ByteCodeInstruction::kStoreGlobal
1010 : ByteCodeInstruction::kStore,
1011 count));
1012 fGenerator.write8(location);
1013 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001014 }
1015
1016private:
1017 typedef LValue INHERITED;
1018
Brian Osman07c117b2019-05-23 12:51:06 -07001019 const Expression& fExpression;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001020};
1021
1022std::unique_ptr<ByteCodeGenerator::LValue> ByteCodeGenerator::getLValue(const Expression& e) {
1023 switch (e.fKind) {
Ethan Nicholas91164d12019-05-15 15:29:54 -04001024 case Expression::kExternalValue_Kind: {
1025 ExternalValue* value = ((ExternalValueReference&) e).fValue;
1026 int index = fOutput->fExternalValues.size();
1027 fOutput->fExternalValues.push_back(value);
1028 SkASSERT(index <= 255);
1029 return std::unique_ptr<LValue>(new ByteCodeExternalValueLValue(this, *value, index));
1030 }
Brian Osman07c117b2019-05-23 12:51:06 -07001031 case Expression::kFieldAccess_Kind:
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001032 case Expression::kIndex_Kind:
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001033 case Expression::kVariableReference_Kind:
Brian Osman07c117b2019-05-23 12:51:06 -07001034 return std::unique_ptr<LValue>(new ByteCodeExpressionLValue(this, e));
Brian Osman0785db02019-05-24 14:19:11 -04001035 case Expression::kSwizzle_Kind: {
1036 const Swizzle& s = (const Swizzle&) e;
1037 return swizzle_is_simple(s)
1038 ? std::unique_ptr<LValue>(new ByteCodeExpressionLValue(this, e))
1039 : std::unique_ptr<LValue>(new ByteCodeSwizzleLValue(this, s));
1040 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001041 case Expression::kTernary_Kind:
1042 default:
1043 printf("unsupported lvalue %s\n", e.description().c_str());
1044 return nullptr;
1045 }
1046}
1047
1048void ByteCodeGenerator::writeBlock(const Block& b) {
1049 for (const auto& s : b.fStatements) {
1050 this->writeStatement(*s);
1051 }
1052}
1053
1054void ByteCodeGenerator::setBreakTargets() {
1055 std::vector<DeferredLocation>& breaks = fBreakTargets.top();
1056 for (DeferredLocation& b : breaks) {
1057 b.set();
1058 }
1059 fBreakTargets.pop();
1060}
1061
1062void ByteCodeGenerator::setContinueTargets() {
1063 std::vector<DeferredLocation>& continues = fContinueTargets.top();
1064 for (DeferredLocation& c : continues) {
1065 c.set();
1066 }
1067 fContinueTargets.pop();
1068}
1069
1070void ByteCodeGenerator::writeBreakStatement(const BreakStatement& b) {
Brian Osman569f12f2019-06-13 11:23:57 -04001071 // TODO: Include BranchIfAllFalse to top-most LoopNext
1072 this->write(ByteCodeInstruction::kLoopBreak);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001073}
1074
1075void ByteCodeGenerator::writeContinueStatement(const ContinueStatement& c) {
Brian Osman569f12f2019-06-13 11:23:57 -04001076 // TODO: Include BranchIfAllFalse to top-most LoopNext
1077 this->write(ByteCodeInstruction::kLoopContinue);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001078}
1079
1080void ByteCodeGenerator::writeDoStatement(const DoStatement& d) {
Brian Osman569f12f2019-06-13 11:23:57 -04001081 this->write(ByteCodeInstruction::kLoopBegin);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001082 size_t start = fCode->size();
1083 this->writeStatement(*d.fStatement);
Brian Osman569f12f2019-06-13 11:23:57 -04001084 this->write(ByteCodeInstruction::kLoopNext);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001085 this->writeExpression(*d.fTest);
Brian Osman569f12f2019-06-13 11:23:57 -04001086 this->write(ByteCodeInstruction::kLoopMask);
1087 // TODO: Could shorten this with kBranchIfAnyTrue
1088 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1089 DeferredLocation endLocation(this);
1090 this->write(ByteCodeInstruction::kBranch);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001091 this->write16(start);
Brian Osman569f12f2019-06-13 11:23:57 -04001092 endLocation.set();
1093 this->write(ByteCodeInstruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001094}
1095
1096void ByteCodeGenerator::writeForStatement(const ForStatement& f) {
1097 fContinueTargets.emplace();
1098 fBreakTargets.emplace();
1099 if (f.fInitializer) {
1100 this->writeStatement(*f.fInitializer);
1101 }
Brian Osman569f12f2019-06-13 11:23:57 -04001102 this->write(ByteCodeInstruction::kLoopBegin);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001103 size_t start = fCode->size();
1104 if (f.fTest) {
1105 this->writeExpression(*f.fTest);
Brian Osman569f12f2019-06-13 11:23:57 -04001106 this->write(ByteCodeInstruction::kLoopMask);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001107 }
Brian Osman569f12f2019-06-13 11:23:57 -04001108 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1109 DeferredLocation endLocation(this);
1110 this->writeStatement(*f.fStatement);
1111 this->write(ByteCodeInstruction::kLoopNext);
1112 if (f.fNext) {
1113 this->writeExpression(*f.fNext, true);
1114 }
1115 this->write(ByteCodeInstruction::kBranch);
1116 this->write16(start);
1117 endLocation.set();
1118 this->write(ByteCodeInstruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001119}
1120
1121void ByteCodeGenerator::writeIfStatement(const IfStatement& i) {
Brian Osman569f12f2019-06-13 11:23:57 -04001122 this->writeExpression(*i.fTest);
1123 this->write(ByteCodeInstruction::kMaskPush);
1124 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1125 DeferredLocation falseLocation(this);
1126 this->writeStatement(*i.fIfTrue);
1127 falseLocation.set();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001128 if (i.fIfFalse) {
Brian Osman569f12f2019-06-13 11:23:57 -04001129 this->write(ByteCodeInstruction::kMaskNegate);
1130 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1131 DeferredLocation endLocation(this);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001132 this->writeStatement(*i.fIfFalse);
Mike Kleinb45ee832019-05-17 11:11:11 -05001133 endLocation.set();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001134 }
Brian Osman569f12f2019-06-13 11:23:57 -04001135 this->write(ByteCodeInstruction::kMaskPop);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001136}
1137
1138void ByteCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
Ethan Nicholas746035a2019-04-23 13:31:09 -04001139 this->writeExpression(*r.fExpression);
1140 this->write(ByteCodeInstruction::kReturn);
Brian Osman07c117b2019-05-23 12:51:06 -07001141 this->write8(SlotCount(r.fExpression->fType));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001142}
1143
1144void ByteCodeGenerator::writeSwitchStatement(const SwitchStatement& r) {
1145 // not yet implemented
1146 abort();
1147}
1148
1149void ByteCodeGenerator::writeVarDeclarations(const VarDeclarations& v) {
1150 for (const auto& declStatement : v.fVars) {
1151 const VarDeclaration& decl = (VarDeclaration&) *declStatement;
1152 // we need to grab the location even if we don't use it, to ensure it
1153 // has been allocated
1154 int location = getLocation(*decl.fVar);
1155 if (decl.fValue) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001156 this->writeExpression(*decl.fValue);
Brian Osman07c117b2019-05-23 12:51:06 -07001157 int count = SlotCount(decl.fValue->fType);
1158 if (count > 4) {
1159 this->write(ByteCodeInstruction::kPushImmediate);
1160 this->write32(location);
1161 this->write(ByteCodeInstruction::kStoreExtended);
1162 this->write8(count);
1163 } else {
1164 this->write(vector_instruction(ByteCodeInstruction::kStore, count));
1165 this->write8(location);
1166 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001167 }
1168 }
1169}
1170
1171void ByteCodeGenerator::writeWhileStatement(const WhileStatement& w) {
Brian Osman569f12f2019-06-13 11:23:57 -04001172 this->write(ByteCodeInstruction::kLoopBegin);
1173 size_t cond = fCode->size();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001174 this->writeExpression(*w.fTest);
Brian Osman569f12f2019-06-13 11:23:57 -04001175 this->write(ByteCodeInstruction::kLoopMask);
1176 this->write(ByteCodeInstruction::kBranchIfAllFalse);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001177 DeferredLocation endLocation(this);
1178 this->writeStatement(*w.fStatement);
Brian Osman569f12f2019-06-13 11:23:57 -04001179 this->write(ByteCodeInstruction::kLoopNext);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001180 this->write(ByteCodeInstruction::kBranch);
Brian Osman569f12f2019-06-13 11:23:57 -04001181 this->write16(cond);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001182 endLocation.set();
Brian Osman569f12f2019-06-13 11:23:57 -04001183 this->write(ByteCodeInstruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001184}
1185
1186void ByteCodeGenerator::writeStatement(const Statement& s) {
1187 switch (s.fKind) {
1188 case Statement::kBlock_Kind:
1189 this->writeBlock((Block&) s);
1190 break;
1191 case Statement::kBreak_Kind:
1192 this->writeBreakStatement((BreakStatement&) s);
1193 break;
1194 case Statement::kContinue_Kind:
1195 this->writeContinueStatement((ContinueStatement&) s);
1196 break;
1197 case Statement::kDiscard_Kind:
1198 // not yet implemented
1199 abort();
1200 case Statement::kDo_Kind:
1201 this->writeDoStatement((DoStatement&) s);
1202 break;
Brian Osman3e29f1d2019-05-28 09:35:05 -04001203 case Statement::kExpression_Kind:
1204 this->writeExpression(*((ExpressionStatement&) s).fExpression, true);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001205 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001206 case Statement::kFor_Kind:
1207 this->writeForStatement((ForStatement&) s);
1208 break;
1209 case Statement::kIf_Kind:
1210 this->writeIfStatement((IfStatement&) s);
1211 break;
1212 case Statement::kNop_Kind:
1213 break;
1214 case Statement::kReturn_Kind:
1215 this->writeReturnStatement((ReturnStatement&) s);
1216 break;
1217 case Statement::kSwitch_Kind:
1218 this->writeSwitchStatement((SwitchStatement&) s);
1219 break;
1220 case Statement::kVarDeclarations_Kind:
1221 this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration);
1222 break;
1223 case Statement::kWhile_Kind:
1224 this->writeWhileStatement((WhileStatement&) s);
1225 break;
1226 default:
1227 SkASSERT(false);
1228 }
1229}
1230
Brian Osman80164412019-06-07 13:00:23 -04001231ByteCodeFunction::ByteCodeFunction(const FunctionDeclaration* declaration)
1232 : fName(declaration->fName) {
1233 fParameterCount = 0;
1234 for (const auto& p : declaration->fParameters) {
1235 int slots = ByteCodeGenerator::SlotCount(p->fType);
1236 fParameters.push_back({ slots, (bool)(p->fModifiers.fFlags & Modifiers::kOut_Flag) });
1237 fParameterCount += slots;
1238 }
1239}
1240
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001241}