blob: 961569d7cc44c44e5c13f9e720dd1cdccbb9e491 [file] [log] [blame]
Brian Osmanb380e712019-07-24 17:02:39 -04001/*
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04002 * Copyright 2019 Google LLC
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "src/sksl/SkSLByteCodeGenerator.h"
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04009
Brian Osman95253bd2019-06-05 10:28:45 -040010#include <algorithm>
11
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040012namespace SkSL {
13
Brian Osman5b431132019-10-15 16:41:18 -040014static TypeCategory type_category(const Type& type) {
15 switch (type.kind()) {
16 case Type::Kind::kVector_Kind:
17 case Type::Kind::kMatrix_Kind:
18 return type_category(type.componentType());
19 default:
20 if (type.fName == "bool") {
21 return TypeCategory::kBool;
22 } else if (type.fName == "int" || type.fName == "short") {
23 return TypeCategory::kSigned;
24 } else if (type.fName == "uint" || type.fName == "ushort") {
25 return TypeCategory::kUnsigned;
26 } else {
27 SkASSERT(type.fName == "float" || type.fName == "half");
28 return TypeCategory::kFloat;
29 }
Ethan Nicholas2a099da2020-01-02 14:40:54 -050030 ABORT("unsupported type: %s\n", type.displayName().c_str());
Brian Osman5b431132019-10-15 16:41:18 -040031 }
32}
33
34
Ethan Nicholas82162ee2019-05-21 16:05:08 -040035ByteCodeGenerator::ByteCodeGenerator(const Context* context, const Program* program, ErrorReporter* errors,
36 ByteCode* output)
37 : INHERITED(program, errors, nullptr)
38 , fContext(*context)
Ethan Nicholasae9633b2019-05-24 12:46:34 -040039 , fOutput(output)
40 , fIntrinsics {
Brian Osman886af0d2019-07-26 15:12:56 -040041 { "cos", ByteCodeInstruction::kCos },
42 { "dot", SpecialIntrinsic::kDot },
43 { "inverse", ByteCodeInstruction::kInverse2x2 },
44 { "sin", ByteCodeInstruction::kSin },
45 { "sqrt", ByteCodeInstruction::kSqrt },
46 { "tan", ByteCodeInstruction::kTan },
Ethan Nicholasae9633b2019-05-24 12:46:34 -040047 } {}
48
Ethan Nicholas82162ee2019-05-21 16:05:08 -040049
Brian Osman07c117b2019-05-23 12:51:06 -070050int ByteCodeGenerator::SlotCount(const Type& type) {
Brian Osmanfba386b2019-06-20 14:54:15 -040051 if (type.kind() == Type::kOther_Kind) {
52 return 0;
53 } else if (type.kind() == Type::kStruct_Kind) {
Brian Osman07c117b2019-05-23 12:51:06 -070054 int slots = 0;
55 for (const auto& f : type.fields()) {
56 slots += SlotCount(*f.fType);
57 }
58 SkASSERT(slots <= 255);
59 return slots;
60 } else if (type.kind() == Type::kArray_Kind) {
61 int columns = type.columns();
62 SkASSERT(columns >= 0);
63 int slots = columns * SlotCount(type.componentType());
64 SkASSERT(slots <= 255);
65 return slots;
66 } else {
67 return type.columns() * type.rows();
68 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040069}
70
Brian Osman1c110a02019-10-01 14:53:32 -040071static inline bool is_uniform(const SkSL::Variable& var) {
72 return var.fModifiers.fFlags & Modifiers::kUniform_Flag;
73}
74
Brian Osman5b431132019-10-15 16:41:18 -040075void ByteCodeGenerator::gatherUniforms(const Type& type, const String& name) {
76 if (type.kind() == Type::kOther_Kind) {
77 return;
78 } else if (type.kind() == Type::kStruct_Kind) {
79 for (const auto& f : type.fields()) {
80 this->gatherUniforms(*f.fType, name + "." + f.fName);
81 }
82 } else if (type.kind() == Type::kArray_Kind) {
83 for (int i = 0; i < type.columns(); ++i) {
84 this->gatherUniforms(type.componentType(), String::printf("%s[%d]", name.c_str(), i));
85 }
86 } else {
87 fOutput->fUniforms.push_back({ name, type_category(type), type.rows(), type.columns(),
88 fOutput->fUniformSlotCount });
89 fOutput->fUniformSlotCount += type.columns() * type.rows();
90 }
91}
92
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040093bool ByteCodeGenerator::generateCode() {
94 for (const auto& e : fProgram) {
95 switch (e.fKind) {
96 case ProgramElement::kFunction_Kind: {
97 std::unique_ptr<ByteCodeFunction> f = this->writeFunction((FunctionDefinition&) e);
98 if (!f) {
99 return false;
100 }
101 fOutput->fFunctions.push_back(std::move(f));
Brian Osman80164412019-06-07 13:00:23 -0400102 fFunctions.push_back(&(FunctionDefinition&)e);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400103 break;
104 }
105 case ProgramElement::kVar_Kind: {
106 VarDeclarations& decl = (VarDeclarations&) e;
107 for (const auto& v : decl.fVars) {
108 const Variable* declVar = ((VarDeclaration&) *v).fVar;
109 if (declVar->fModifiers.fLayout.fBuiltin >= 0) {
110 continue;
111 }
Ethan Nicholas31cff272019-09-26 13:04:48 -0400112 // if you trip this assert, it means the program has raw 'in' variables. You
113 // should either specialize the program (Compiler::specialize) to bake in the
114 // final values of the 'in' variables, or not use 'in' variables (maybe you
115 // meant to use 'uniform' instead?).
Brian Osman7481a392019-10-02 13:11:59 -0400116 SkASSERT(!(declVar->fModifiers.fFlags & Modifiers::kIn_Flag));
Brian Osman1c110a02019-10-01 14:53:32 -0400117 if (is_uniform(*declVar)) {
Brian Osman5b431132019-10-15 16:41:18 -0400118 this->gatherUniforms(declVar->fType, declVar->fName);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400119 } else {
Brian Osman1c110a02019-10-01 14:53:32 -0400120 fOutput->fGlobalSlotCount += SlotCount(declVar->fType);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400121 }
122 }
123 break;
124 }
125 default:
126 ; // ignore
127 }
128 }
Brian Osman6f5358f2019-07-09 14:17:23 -0400129 return 0 == fErrors.errorCount();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400130}
131
132std::unique_ptr<ByteCodeFunction> ByteCodeGenerator::writeFunction(const FunctionDefinition& f) {
133 fFunction = &f;
Brian Osman226668a2019-05-14 16:47:30 -0400134 std::unique_ptr<ByteCodeFunction> result(new ByteCodeFunction(&f.fDeclaration));
Brian Osman80164412019-06-07 13:00:23 -0400135 fParameterCount = result->fParameterCount;
Brian Osman4a47da72019-07-12 11:30:32 -0400136 fLoopCount = fMaxLoopCount = 0;
137 fConditionCount = fMaxConditionCount = 0;
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400138 fStackCount = fMaxStackCount = 0;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400139 fCode = &result->fCode;
Brian Osman4a47da72019-07-12 11:30:32 -0400140
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400141 this->writeStatement(*f.fBody);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400142 if (0 == fErrors.errorCount()) {
143 SkASSERT(fLoopCount == 0);
144 SkASSERT(fConditionCount == 0);
145 SkASSERT(fStackCount == 0);
146 }
147 this->write(ByteCodeInstruction::kReturn, 0);
Ethan Nicholas7e603db2019-05-03 12:57:47 -0400148 this->write8(0);
Brian Osman4a47da72019-07-12 11:30:32 -0400149
150 result->fLocalCount = fLocals.size();
151 result->fConditionCount = fMaxConditionCount;
152 result->fLoopCount = fMaxLoopCount;
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400153 result->fStackCount = fMaxStackCount;
Brian Osman4a47da72019-07-12 11:30:32 -0400154
Ethan Nicholasdfcad062019-05-07 12:53:34 -0400155 const Type& returnType = f.fDeclaration.fReturnType;
156 if (returnType != *fContext.fVoid_Type) {
Brian Osman07c117b2019-05-23 12:51:06 -0700157 result->fReturnCount = SlotCount(returnType);
Ethan Nicholasdfcad062019-05-07 12:53:34 -0400158 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400159 fLocals.clear();
160 fFunction = nullptr;
161 return result;
162}
163
Brian Osman0785db02019-05-24 14:19:11 -0400164// A "simple" Swizzle is based on a variable (or a compound variable like a struct or array), and
165// that references consecutive values, such that it can be implemented using normal load/store ops
166// with an offset. Note that all single-component swizzles (of suitable base types) are simple.
167static bool swizzle_is_simple(const Swizzle& s) {
168 switch (s.fBase->fKind) {
169 case Expression::kFieldAccess_Kind:
170 case Expression::kIndex_Kind:
171 case Expression::kVariableReference_Kind:
172 break;
173 default:
174 return false;
175 }
176
177 for (size_t i = 1; i < s.fComponents.size(); ++i) {
178 if (s.fComponents[i] != s.fComponents[i - 1] + 1) {
179 return false;
180 }
181 }
182 return true;
183}
184
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400185int ByteCodeGenerator::StackUsage(ByteCodeInstruction inst, int count_) {
186 // Ensures that we use count iff we're passed a non-default value. Most instructions have an
187 // implicit count, so the caller shouldn't need to worry about it (or count makes no sense).
188 // The asserts avoids callers thinking they're supplying useful information in that scenario,
189 // or failing to supply necessary information for the ops that need a count.
190 struct CountValue {
191 operator int() {
192 SkASSERT(val != ByteCodeGenerator::kUnusedStackCount);
193 SkDEBUGCODE(used = true);
194 return val;
195 }
196 ~CountValue() {
197 SkASSERT(used || val == ByteCodeGenerator::kUnusedStackCount);
198 }
199 int val;
200 SkDEBUGCODE(bool used = false;)
201 } count = { count_ };
202
203 switch (inst) {
204 // Unary functions/operators that don't change stack depth at all:
205#define VECTOR_UNARY_OP(base) \
206 case ByteCodeInstruction::base: \
207 case ByteCodeInstruction::base ## 2: \
208 case ByteCodeInstruction::base ## 3: \
209 case ByteCodeInstruction::base ## 4: \
210 return 0;
211
212 VECTOR_UNARY_OP(kConvertFtoI)
213 VECTOR_UNARY_OP(kConvertStoF)
214 VECTOR_UNARY_OP(kConvertUtoF)
215
216 VECTOR_UNARY_OP(kCos)
217 VECTOR_UNARY_OP(kSin)
218 VECTOR_UNARY_OP(kSqrt)
219 VECTOR_UNARY_OP(kTan)
220
221 VECTOR_UNARY_OP(kNegateF)
222 VECTOR_UNARY_OP(kNegateI)
223
Mike Reed634c9412019-07-18 13:20:04 -0400224 case ByteCodeInstruction::kInverse2x2:
225 case ByteCodeInstruction::kInverse3x3:
226 case ByteCodeInstruction::kInverse4x4: return 0;
227
Brian Osman869a3e82019-07-18 17:00:34 -0400228 case ByteCodeInstruction::kClampIndex: return 0;
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400229 case ByteCodeInstruction::kNotB: return 0;
230 case ByteCodeInstruction::kNegateFN: return 0;
Brian Osman4c2146f2019-09-24 09:39:38 -0400231 case ByteCodeInstruction::kShiftLeft: return 0;
232 case ByteCodeInstruction::kShiftRightS: return 0;
233 case ByteCodeInstruction::kShiftRightU: return 0;
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400234
235#undef VECTOR_UNARY_OP
236
237 // Binary functions/operators that do a 2 -> 1 reduction (possibly N times)
238#define VECTOR_BINARY_OP(base) \
239 case ByteCodeInstruction::base: return -1; \
240 case ByteCodeInstruction::base ## 2: return -2; \
241 case ByteCodeInstruction::base ## 3: return -3; \
242 case ByteCodeInstruction::base ## 4: return -4;
243
244#define VECTOR_MATRIX_BINARY_OP(base) \
245 VECTOR_BINARY_OP(base) \
246 case ByteCodeInstruction::base ## N: return -count;
247
248 case ByteCodeInstruction::kAndB: return -1;
249 case ByteCodeInstruction::kOrB: return -1;
250 case ByteCodeInstruction::kXorB: return -1;
251
252 VECTOR_BINARY_OP(kAddI)
253 VECTOR_MATRIX_BINARY_OP(kAddF)
254
255 VECTOR_BINARY_OP(kCompareIEQ)
256 VECTOR_MATRIX_BINARY_OP(kCompareFEQ)
257 VECTOR_BINARY_OP(kCompareINEQ)
258 VECTOR_MATRIX_BINARY_OP(kCompareFNEQ)
259 VECTOR_BINARY_OP(kCompareSGT)
260 VECTOR_BINARY_OP(kCompareUGT)
261 VECTOR_BINARY_OP(kCompareFGT)
262 VECTOR_BINARY_OP(kCompareSGTEQ)
263 VECTOR_BINARY_OP(kCompareUGTEQ)
264 VECTOR_BINARY_OP(kCompareFGTEQ)
265 VECTOR_BINARY_OP(kCompareSLT)
266 VECTOR_BINARY_OP(kCompareULT)
267 VECTOR_BINARY_OP(kCompareFLT)
268 VECTOR_BINARY_OP(kCompareSLTEQ)
269 VECTOR_BINARY_OP(kCompareULTEQ)
270 VECTOR_BINARY_OP(kCompareFLTEQ)
271
272 VECTOR_BINARY_OP(kDivideS)
273 VECTOR_BINARY_OP(kDivideU)
274 VECTOR_MATRIX_BINARY_OP(kDivideF)
275 VECTOR_BINARY_OP(kMultiplyI)
276 VECTOR_MATRIX_BINARY_OP(kMultiplyF)
277 VECTOR_BINARY_OP(kRemainderF)
278 VECTOR_BINARY_OP(kRemainderS)
279 VECTOR_BINARY_OP(kRemainderU)
280 VECTOR_BINARY_OP(kSubtractI)
281 VECTOR_MATRIX_BINARY_OP(kSubtractF)
282
283#undef VECTOR_BINARY_OP
284#undef VECTOR_MATRIX_BINARY_OP
285
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400286 // Ops that push or load data to grow the stack:
287 case ByteCodeInstruction::kDup:
288 case ByteCodeInstruction::kLoad:
289 case ByteCodeInstruction::kLoadGlobal:
Brian Osman1c110a02019-10-01 14:53:32 -0400290 case ByteCodeInstruction::kLoadUniform:
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400291 case ByteCodeInstruction::kReadExternal:
292 case ByteCodeInstruction::kPushImmediate:
293 return 1;
294
295 case ByteCodeInstruction::kDup2:
296 case ByteCodeInstruction::kLoad2:
297 case ByteCodeInstruction::kLoadGlobal2:
Brian Osman1c110a02019-10-01 14:53:32 -0400298 case ByteCodeInstruction::kLoadUniform2:
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400299 case ByteCodeInstruction::kReadExternal2:
300 return 2;
301
302 case ByteCodeInstruction::kDup3:
303 case ByteCodeInstruction::kLoad3:
304 case ByteCodeInstruction::kLoadGlobal3:
Brian Osman1c110a02019-10-01 14:53:32 -0400305 case ByteCodeInstruction::kLoadUniform3:
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400306 case ByteCodeInstruction::kReadExternal3:
307 return 3;
308
309 case ByteCodeInstruction::kDup4:
310 case ByteCodeInstruction::kLoad4:
311 case ByteCodeInstruction::kLoadGlobal4:
Brian Osman1c110a02019-10-01 14:53:32 -0400312 case ByteCodeInstruction::kLoadUniform4:
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400313 case ByteCodeInstruction::kReadExternal4:
314 return 4;
315
316 case ByteCodeInstruction::kDupN:
317 case ByteCodeInstruction::kLoadSwizzle:
318 case ByteCodeInstruction::kLoadSwizzleGlobal:
Brian Osman1c110a02019-10-01 14:53:32 -0400319 case ByteCodeInstruction::kLoadSwizzleUniform:
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400320 return count;
321
322 // Pushes 'count' values, minus one for the 'address' that's consumed first
323 case ByteCodeInstruction::kLoadExtended:
324 case ByteCodeInstruction::kLoadExtendedGlobal:
Brian Osman1c110a02019-10-01 14:53:32 -0400325 case ByteCodeInstruction::kLoadExtendedUniform:
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400326 return count - 1;
327
328 // Ops that pop or store data to shrink the stack:
329 case ByteCodeInstruction::kPop:
330 case ByteCodeInstruction::kStore:
331 case ByteCodeInstruction::kStoreGlobal:
332 case ByteCodeInstruction::kWriteExternal:
333 return -1;
334
335 case ByteCodeInstruction::kPop2:
336 case ByteCodeInstruction::kStore2:
337 case ByteCodeInstruction::kStoreGlobal2:
338 case ByteCodeInstruction::kWriteExternal2:
339 return -2;
340
341 case ByteCodeInstruction::kPop3:
342 case ByteCodeInstruction::kStore3:
343 case ByteCodeInstruction::kStoreGlobal3:
344 case ByteCodeInstruction::kWriteExternal3:
345 return -3;
346
347 case ByteCodeInstruction::kPop4:
348 case ByteCodeInstruction::kStore4:
349 case ByteCodeInstruction::kStoreGlobal4:
350 case ByteCodeInstruction::kWriteExternal4:
351 return -4;
352
353 case ByteCodeInstruction::kPopN:
354 case ByteCodeInstruction::kStoreSwizzle:
355 case ByteCodeInstruction::kStoreSwizzleGlobal:
356 return -count;
357
358 // Consumes 'count' values, plus one for the 'address'
359 case ByteCodeInstruction::kStoreExtended:
360 case ByteCodeInstruction::kStoreExtendedGlobal:
361 case ByteCodeInstruction::kStoreSwizzleIndirect:
362 case ByteCodeInstruction::kStoreSwizzleIndirectGlobal:
363 return -count - 1;
364
365 // Strange ops where the caller computes the delta for us:
366 case ByteCodeInstruction::kCallExternal:
367 case ByteCodeInstruction::kMatrixToMatrix:
368 case ByteCodeInstruction::kMatrixMultiply:
369 case ByteCodeInstruction::kReserve:
370 case ByteCodeInstruction::kReturn:
371 case ByteCodeInstruction::kScalarToMatrix:
372 case ByteCodeInstruction::kSwizzle:
373 return count;
374
375 // Miscellaneous
376
377 // kCall is net-zero. Max stack depth is adjusted in writeFunctionCall.
378 case ByteCodeInstruction::kCall: return 0;
379 case ByteCodeInstruction::kBranch: return 0;
380 case ByteCodeInstruction::kBranchIfAllFalse: return 0;
381
382 case ByteCodeInstruction::kMaskPush: return -1;
383 case ByteCodeInstruction::kMaskPop: return 0;
384 case ByteCodeInstruction::kMaskNegate: return 0;
385 case ByteCodeInstruction::kMaskBlend: return -count;
386
387 case ByteCodeInstruction::kLoopBegin: return 0;
388 case ByteCodeInstruction::kLoopNext: return 0;
389 case ByteCodeInstruction::kLoopMask: return -1;
390 case ByteCodeInstruction::kLoopEnd: return 0;
391 case ByteCodeInstruction::kLoopBreak: return 0;
392 case ByteCodeInstruction::kLoopContinue: return 0;
393
394 default:
Brian Osmanc7ec9e22019-07-16 08:49:11 -0400395 ABORT("unsupported instruction %d\n", (int)inst);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400396 return 0;
397 }
398}
399
Brian Osman1c110a02019-10-01 14:53:32 -0400400ByteCodeGenerator::Location ByteCodeGenerator::getLocation(const Variable& var) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400401 // given that we seldom have more than a couple of variables, linear search is probably the most
402 // efficient way to handle lookups
403 switch (var.fStorage) {
404 case Variable::kLocal_Storage: {
405 for (int i = fLocals.size() - 1; i >= 0; --i) {
406 if (fLocals[i] == &var) {
Brian Osman1091f022019-05-16 09:42:16 -0400407 SkASSERT(fParameterCount + i <= 255);
Brian Osman1c110a02019-10-01 14:53:32 -0400408 return { fParameterCount + i, Storage::kLocal };
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400409 }
410 }
411 int result = fParameterCount + fLocals.size();
412 fLocals.push_back(&var);
Brian Osman07c117b2019-05-23 12:51:06 -0700413 for (int i = 0; i < SlotCount(var.fType) - 1; ++i) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400414 fLocals.push_back(nullptr);
415 }
Brian Osman1091f022019-05-16 09:42:16 -0400416 SkASSERT(result <= 255);
Brian Osman1c110a02019-10-01 14:53:32 -0400417 return { result, Storage::kLocal };
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400418 }
419 case Variable::kParameter_Storage: {
420 int offset = 0;
421 for (const auto& p : fFunction->fDeclaration.fParameters) {
422 if (p == &var) {
Brian Osman1091f022019-05-16 09:42:16 -0400423 SkASSERT(offset <= 255);
Brian Osman1c110a02019-10-01 14:53:32 -0400424 return { offset, Storage::kLocal };
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400425 }
Brian Osman07c117b2019-05-23 12:51:06 -0700426 offset += SlotCount(p->fType);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400427 }
428 SkASSERT(false);
Brian Osman1c110a02019-10-01 14:53:32 -0400429 return Location::MakeInvalid();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400430 }
431 case Variable::kGlobal_Storage: {
432 int offset = 0;
Brian Osman1c110a02019-10-01 14:53:32 -0400433 bool isUniform = is_uniform(var);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400434 for (const auto& e : fProgram) {
435 if (e.fKind == ProgramElement::kVar_Kind) {
436 VarDeclarations& decl = (VarDeclarations&) e;
437 for (const auto& v : decl.fVars) {
438 const Variable* declVar = ((VarDeclaration&) *v).fVar;
439 if (declVar->fModifiers.fLayout.fBuiltin >= 0) {
440 continue;
441 }
Brian Osman1c110a02019-10-01 14:53:32 -0400442 if (isUniform != is_uniform(*declVar)) {
443 continue;
444 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400445 if (declVar == &var) {
Brian Osmanb7451292019-05-15 13:02:13 -0400446 SkASSERT(offset <= 255);
Brian Osman1c110a02019-10-01 14:53:32 -0400447 return { offset, isUniform ? Storage::kUniform : Storage::kGlobal };
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400448 }
Brian Osman07c117b2019-05-23 12:51:06 -0700449 offset += SlotCount(declVar->fType);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400450 }
451 }
452 }
453 SkASSERT(false);
Brian Osman1c110a02019-10-01 14:53:32 -0400454 return Location::MakeInvalid();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400455 }
456 default:
457 SkASSERT(false);
Brian Osman1c110a02019-10-01 14:53:32 -0400458 return Location::MakeInvalid();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400459 }
460}
461
Brian Osman1c110a02019-10-01 14:53:32 -0400462ByteCodeGenerator::Location ByteCodeGenerator::getLocation(const Expression& expr) {
Brian Osman07c117b2019-05-23 12:51:06 -0700463 switch (expr.fKind) {
464 case Expression::kFieldAccess_Kind: {
465 const FieldAccess& f = (const FieldAccess&)expr;
Brian Osman1c110a02019-10-01 14:53:32 -0400466 Location baseLoc = this->getLocation(*f.fBase);
Brian Osman07c117b2019-05-23 12:51:06 -0700467 int offset = 0;
468 for (int i = 0; i < f.fFieldIndex; ++i) {
469 offset += SlotCount(*f.fBase->fType.fields()[i].fType);
470 }
Brian Osman1c110a02019-10-01 14:53:32 -0400471 if (baseLoc.isOnStack()) {
Brian Osman86769292019-06-21 11:05:47 -0400472 if (offset != 0) {
473 this->write(ByteCodeInstruction::kPushImmediate);
474 this->write32(offset);
475 this->write(ByteCodeInstruction::kAddI);
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400476 this->write8(1);
Brian Osman86769292019-06-21 11:05:47 -0400477 }
Brian Osman1c110a02019-10-01 14:53:32 -0400478 return baseLoc;
Brian Osman07c117b2019-05-23 12:51:06 -0700479 } else {
Brian Osman1c110a02019-10-01 14:53:32 -0400480 return baseLoc + offset;
Brian Osman07c117b2019-05-23 12:51:06 -0700481 }
482 }
483 case Expression::kIndex_Kind: {
484 const IndexExpression& i = (const IndexExpression&)expr;
485 int stride = SlotCount(i.fType);
Brian Osman869a3e82019-07-18 17:00:34 -0400486 int length = i.fBase->fType.columns();
487 SkASSERT(length <= 255);
Brian Osman07c117b2019-05-23 12:51:06 -0700488 int offset = -1;
489 if (i.fIndex->isConstant()) {
Brian Osman869a3e82019-07-18 17:00:34 -0400490 int64_t index = i.fIndex->getConstantInt();
491 if (index < 0 || index >= length) {
492 fErrors.error(i.fIndex->fOffset, "Array index out of bounds.");
Brian Osman1c110a02019-10-01 14:53:32 -0400493 return Location::MakeInvalid();
Brian Osman869a3e82019-07-18 17:00:34 -0400494 }
495 offset = index * stride;
Brian Osman07c117b2019-05-23 12:51:06 -0700496 } else {
Brian Osman86769292019-06-21 11:05:47 -0400497 if (i.fIndex->hasSideEffects()) {
498 // Having a side-effect in an indexer is technically safe for an rvalue,
499 // but with lvalues we have to evaluate the indexer twice, so make it an error.
500 fErrors.error(i.fIndex->fOffset,
501 "Index expressions with side-effects not supported in byte code.");
Brian Osman1c110a02019-10-01 14:53:32 -0400502 return Location::MakeInvalid();
Brian Osman86769292019-06-21 11:05:47 -0400503 }
Brian Osman07c117b2019-05-23 12:51:06 -0700504 this->writeExpression(*i.fIndex);
Brian Osman869a3e82019-07-18 17:00:34 -0400505 this->write(ByteCodeInstruction::kClampIndex);
506 this->write8(length);
Brian Osman86769292019-06-21 11:05:47 -0400507 if (stride != 1) {
508 this->write(ByteCodeInstruction::kPushImmediate);
509 this->write32(stride);
510 this->write(ByteCodeInstruction::kMultiplyI);
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400511 this->write8(1);
Brian Osman86769292019-06-21 11:05:47 -0400512 }
Brian Osman07c117b2019-05-23 12:51:06 -0700513 }
Brian Osman1c110a02019-10-01 14:53:32 -0400514 Location baseLoc = this->getLocation(*i.fBase);
Brian Osman86769292019-06-21 11:05:47 -0400515
516 // Are both components known statically?
Brian Osman1c110a02019-10-01 14:53:32 -0400517 if (!baseLoc.isOnStack() && offset >= 0) {
518 return baseLoc + offset;
Brian Osman07c117b2019-05-23 12:51:06 -0700519 }
Brian Osman86769292019-06-21 11:05:47 -0400520
521 // At least one component is dynamic (and on the stack).
522
523 // If the other component is zero, we're done
Brian Osman1c110a02019-10-01 14:53:32 -0400524 if (baseLoc.fSlot == 0 || offset == 0) {
525 return baseLoc.makeOnStack();
Brian Osman86769292019-06-21 11:05:47 -0400526 }
527
528 // Push the non-dynamic component (if any) to the stack, then add the two
Brian Osman1c110a02019-10-01 14:53:32 -0400529 if (!baseLoc.isOnStack()) {
Brian Osman07c117b2019-05-23 12:51:06 -0700530 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osman1c110a02019-10-01 14:53:32 -0400531 this->write32(baseLoc.fSlot);
Brian Osman07c117b2019-05-23 12:51:06 -0700532 }
533 if (offset >= 0) {
534 this->write(ByteCodeInstruction::kPushImmediate);
535 this->write32(offset);
536 }
537 this->write(ByteCodeInstruction::kAddI);
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400538 this->write8(1);
Brian Osman1c110a02019-10-01 14:53:32 -0400539 return baseLoc.makeOnStack();
Brian Osman07c117b2019-05-23 12:51:06 -0700540 }
Brian Osman0785db02019-05-24 14:19:11 -0400541 case Expression::kSwizzle_Kind: {
542 const Swizzle& s = (const Swizzle&)expr;
543 SkASSERT(swizzle_is_simple(s));
Brian Osman1c110a02019-10-01 14:53:32 -0400544 Location baseLoc = this->getLocation(*s.fBase);
Brian Osman0785db02019-05-24 14:19:11 -0400545 int offset = s.fComponents[0];
Brian Osman1c110a02019-10-01 14:53:32 -0400546 if (baseLoc.isOnStack()) {
Brian Osman86769292019-06-21 11:05:47 -0400547 if (offset != 0) {
548 this->write(ByteCodeInstruction::kPushImmediate);
549 this->write32(offset);
550 this->write(ByteCodeInstruction::kAddI);
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400551 this->write8(1);
Brian Osman86769292019-06-21 11:05:47 -0400552 }
Brian Osman1c110a02019-10-01 14:53:32 -0400553 return baseLoc;
Brian Osman0785db02019-05-24 14:19:11 -0400554 } else {
Brian Osman1c110a02019-10-01 14:53:32 -0400555 return baseLoc + offset;
Brian Osman0785db02019-05-24 14:19:11 -0400556 }
557 }
Brian Osman07c117b2019-05-23 12:51:06 -0700558 case Expression::kVariableReference_Kind: {
559 const Variable& var = ((const VariableReference&)expr).fVariable;
Brian Osman07c117b2019-05-23 12:51:06 -0700560 return this->getLocation(var);
561 }
562 default:
563 SkASSERT(false);
Brian Osman1c110a02019-10-01 14:53:32 -0400564 return Location::MakeInvalid();
Brian Osman07c117b2019-05-23 12:51:06 -0700565 }
566}
567
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400568void ByteCodeGenerator::write8(uint8_t b) {
569 fCode->push_back(b);
570}
571
572void ByteCodeGenerator::write16(uint16_t i) {
Mike Klein76346ac2019-05-17 11:57:10 -0500573 size_t n = fCode->size();
574 fCode->resize(n+2);
575 memcpy(fCode->data() + n, &i, 2);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400576}
577
578void ByteCodeGenerator::write32(uint32_t i) {
Mike Klein76346ac2019-05-17 11:57:10 -0500579 size_t n = fCode->size();
580 fCode->resize(n+4);
581 memcpy(fCode->data() + n, &i, 4);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400582}
583
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400584void ByteCodeGenerator::write(ByteCodeInstruction i, int count) {
Brian Osman4a47da72019-07-12 11:30:32 -0400585 switch (i) {
586 case ByteCodeInstruction::kLoopBegin: this->enterLoop(); break;
587 case ByteCodeInstruction::kLoopEnd: this->exitLoop(); break;
588
589 case ByteCodeInstruction::kMaskPush: this->enterCondition(); break;
590 case ByteCodeInstruction::kMaskPop:
591 case ByteCodeInstruction::kMaskBlend: this->exitCondition(); break;
592 default: /* Do nothing */ break;
593 }
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400594 instruction val = (instruction) i;
595 size_t n = fCode->size();
596 fCode->resize(n + sizeof(val));
597 memcpy(fCode->data() + n, &val, sizeof(val));
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400598 fStackCount += StackUsage(i, count);
599 fMaxStackCount = std::max(fMaxStackCount, fStackCount);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400600}
601
Mike Klein76346ac2019-05-17 11:57:10 -0500602static ByteCodeInstruction vector_instruction(ByteCodeInstruction base, int count) {
Brian Osman07c117b2019-05-23 12:51:06 -0700603 SkASSERT(count >= 1 && count <= 4);
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400604 return ((ByteCodeInstruction) ((int) base + 1 - count));
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400605}
606
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400607void ByteCodeGenerator::writeTypedInstruction(const Type& type, ByteCodeInstruction s,
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400608 ByteCodeInstruction u, ByteCodeInstruction f,
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400609 int count, bool writeCount) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400610 switch (type_category(type)) {
611 case TypeCategory::kSigned:
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400612 this->write(vector_instruction(s, count));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400613 break;
614 case TypeCategory::kUnsigned:
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400615 this->write(vector_instruction(u, count));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400616 break;
Brian Osman1e855b22019-05-29 15:21:52 -0400617 case TypeCategory::kFloat: {
618 if (count > 4) {
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400619 this->write((ByteCodeInstruction)((int)f + 1), count);
Brian Osman1e855b22019-05-29 15:21:52 -0400620 } else {
621 this->write(vector_instruction(f, count));
622 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400623 break;
Brian Osman1e855b22019-05-29 15:21:52 -0400624 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400625 default:
626 SkASSERT(false);
627 }
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400628 if (writeCount) {
629 this->write8(count);
630 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400631}
632
Brian Osman3e29f1d2019-05-28 09:35:05 -0400633bool ByteCodeGenerator::writeBinaryExpression(const BinaryExpression& b, bool discard) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400634 if (b.fOperator == Token::Kind::EQ) {
635 std::unique_ptr<LValue> lvalue = this->getLValue(*b.fLeft);
636 this->writeExpression(*b.fRight);
Brian Osman3e29f1d2019-05-28 09:35:05 -0400637 lvalue->store(discard);
638 discard = false;
639 return discard;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400640 }
Brian Osman16e6fd52019-05-29 11:19:00 -0400641 const Type& lType = b.fLeft->fType;
642 const Type& rType = b.fRight->fType;
Brian Osman909231c2019-05-29 15:34:36 -0400643 bool lVecOrMtx = (lType.kind() == Type::kVector_Kind || lType.kind() == Type::kMatrix_Kind);
644 bool rVecOrMtx = (rType.kind() == Type::kVector_Kind || rType.kind() == Type::kMatrix_Kind);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400645 Token::Kind op;
646 std::unique_ptr<LValue> lvalue;
647 if (is_assignment(b.fOperator)) {
648 lvalue = this->getLValue(*b.fLeft);
649 lvalue->load();
650 op = remove_assignment(b.fOperator);
651 } else {
652 this->writeExpression(*b.fLeft);
653 op = b.fOperator;
Brian Osman909231c2019-05-29 15:34:36 -0400654 if (!lVecOrMtx && rVecOrMtx) {
Brian Osman16e6fd52019-05-29 11:19:00 -0400655 for (int i = SlotCount(rType); i > 1; --i) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400656 this->write(ByteCodeInstruction::kDup);
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400657 this->write8(1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400658 }
659 }
660 }
Ethan Nicholasd166d2e2019-09-23 11:43:45 -0400661 int count = std::max(SlotCount(lType), SlotCount(rType));
Brian Osmane5bbce22019-09-23 12:38:40 -0400662 SkDEBUGCODE(TypeCategory tc = type_category(lType));
Ethan Nicholasd166d2e2019-09-23 11:43:45 -0400663 switch (op) {
664 case Token::Kind::LOGICALAND: {
Brian Osmane5bbce22019-09-23 12:38:40 -0400665 SkASSERT(tc == SkSL::TypeCategory::kBool && count == 1);
Ethan Nicholasd166d2e2019-09-23 11:43:45 -0400666 this->write(ByteCodeInstruction::kDup);
667 this->write8(1);
668 this->write(ByteCodeInstruction::kMaskPush);
669 this->write(ByteCodeInstruction::kBranchIfAllFalse);
670 DeferredLocation falseLocation(this);
671 this->writeExpression(*b.fRight);
672 this->write(ByteCodeInstruction::kAndB);
673 falseLocation.set();
674 this->write(ByteCodeInstruction::kMaskPop);
675 return false;
676 }
677 case Token::Kind::LOGICALOR: {
Brian Osmane5bbce22019-09-23 12:38:40 -0400678 SkASSERT(tc == SkSL::TypeCategory::kBool && count == 1);
Ethan Nicholasd166d2e2019-09-23 11:43:45 -0400679 this->write(ByteCodeInstruction::kDup);
680 this->write8(1);
681 this->write(ByteCodeInstruction::kNotB);
682 this->write(ByteCodeInstruction::kMaskPush);
683 this->write(ByteCodeInstruction::kBranchIfAllFalse);
684 DeferredLocation falseLocation(this);
685 this->writeExpression(*b.fRight);
686 this->write(ByteCodeInstruction::kOrB);
687 falseLocation.set();
688 this->write(ByteCodeInstruction::kMaskPop);
689 return false;
690 }
Brian Osman4c2146f2019-09-24 09:39:38 -0400691 case Token::Kind::SHL:
692 case Token::Kind::SHR: {
693 SkASSERT(count == 1 && (tc == SkSL::TypeCategory::kSigned ||
694 tc == SkSL::TypeCategory::kUnsigned));
695 if (!b.fRight->isConstant()) {
696 fErrors.error(b.fRight->fOffset, "Shift amounts must be constant");
697 return false;
698 }
699 int64_t shift = b.fRight->getConstantInt();
700 if (shift < 0 || shift > 31) {
701 fErrors.error(b.fRight->fOffset, "Shift amount out of range");
702 return false;
703 }
704
705 if (op == Token::Kind::SHL) {
706 this->write(ByteCodeInstruction::kShiftLeft);
707 } else {
708 this->write(type_category(lType) == TypeCategory::kSigned
709 ? ByteCodeInstruction::kShiftRightS
710 : ByteCodeInstruction::kShiftRightU);
711 }
712 this->write8(shift);
713 return false;
714 }
715
Ethan Nicholasd166d2e2019-09-23 11:43:45 -0400716 default:
717 break;
718 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400719 this->writeExpression(*b.fRight);
Brian Osman909231c2019-05-29 15:34:36 -0400720 if (lVecOrMtx && !rVecOrMtx) {
Brian Osman16e6fd52019-05-29 11:19:00 -0400721 for (int i = SlotCount(lType); i > 1; --i) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400722 this->write(ByteCodeInstruction::kDup);
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400723 this->write8(1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400724 }
725 }
Brian Osman909231c2019-05-29 15:34:36 -0400726 // Special case for M*V, V*M, M*M (but not V*V!)
727 if (op == Token::Kind::STAR && lVecOrMtx && rVecOrMtx &&
728 !(lType.kind() == Type::kVector_Kind && rType.kind() == Type::kVector_Kind)) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400729 this->write(ByteCodeInstruction::kMatrixMultiply,
730 SlotCount(b.fType) - (SlotCount(lType) + SlotCount(rType)));
Brian Osman909231c2019-05-29 15:34:36 -0400731 int rCols = rType.columns(),
732 rRows = rType.rows(),
733 lCols = lType.columns(),
734 lRows = lType.rows();
735 // M*V treats the vector as a column
736 if (rType.kind() == Type::kVector_Kind) {
737 std::swap(rCols, rRows);
738 }
739 SkASSERT(lCols == rRows);
740 SkASSERT(SlotCount(b.fType) == lRows * rCols);
741 this->write8(lCols);
742 this->write8(lRows);
743 this->write8(rCols);
744 } else {
Brian Osman909231c2019-05-29 15:34:36 -0400745 switch (op) {
746 case Token::Kind::EQEQ:
747 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareIEQ,
748 ByteCodeInstruction::kCompareIEQ,
749 ByteCodeInstruction::kCompareFEQ,
750 count);
751 // Collapse to a single bool
752 for (int i = count; i > 1; --i) {
753 this->write(ByteCodeInstruction::kAndB);
754 }
755 break;
756 case Token::Kind::GT:
757 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSGT,
758 ByteCodeInstruction::kCompareUGT,
759 ByteCodeInstruction::kCompareFGT,
760 count);
761 break;
762 case Token::Kind::GTEQ:
763 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSGTEQ,
764 ByteCodeInstruction::kCompareUGTEQ,
765 ByteCodeInstruction::kCompareFGTEQ,
766 count);
767 break;
768 case Token::Kind::LT:
769 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSLT,
770 ByteCodeInstruction::kCompareULT,
771 ByteCodeInstruction::kCompareFLT,
772 count);
773 break;
774 case Token::Kind::LTEQ:
775 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSLTEQ,
776 ByteCodeInstruction::kCompareULTEQ,
777 ByteCodeInstruction::kCompareFLTEQ,
778 count);
779 break;
780 case Token::Kind::MINUS:
781 this->writeTypedInstruction(lType, ByteCodeInstruction::kSubtractI,
782 ByteCodeInstruction::kSubtractI,
783 ByteCodeInstruction::kSubtractF,
784 count);
785 break;
786 case Token::Kind::NEQ:
787 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareINEQ,
788 ByteCodeInstruction::kCompareINEQ,
789 ByteCodeInstruction::kCompareFNEQ,
790 count);
791 // Collapse to a single bool
792 for (int i = count; i > 1; --i) {
793 this->write(ByteCodeInstruction::kOrB);
794 }
795 break;
796 case Token::Kind::PERCENT:
797 this->writeTypedInstruction(lType, ByteCodeInstruction::kRemainderS,
798 ByteCodeInstruction::kRemainderU,
799 ByteCodeInstruction::kRemainderF,
800 count);
801 break;
802 case Token::Kind::PLUS:
803 this->writeTypedInstruction(lType, ByteCodeInstruction::kAddI,
804 ByteCodeInstruction::kAddI,
805 ByteCodeInstruction::kAddF,
806 count);
807 break;
808 case Token::Kind::SLASH:
809 this->writeTypedInstruction(lType, ByteCodeInstruction::kDivideS,
810 ByteCodeInstruction::kDivideU,
811 ByteCodeInstruction::kDivideF,
812 count);
813 break;
814 case Token::Kind::STAR:
815 this->writeTypedInstruction(lType, ByteCodeInstruction::kMultiplyI,
816 ByteCodeInstruction::kMultiplyI,
817 ByteCodeInstruction::kMultiplyF,
818 count);
819 break;
Brian Osman569f12f2019-06-13 11:23:57 -0400820
Brian Osman569f12f2019-06-13 11:23:57 -0400821 case Token::Kind::LOGICALXOR:
Brian Osmane5bbce22019-09-23 12:38:40 -0400822 SkASSERT(tc == SkSL::TypeCategory::kBool && count == 1);
823 this->write(ByteCodeInstruction::kXorB);
824 break;
825
826 case Token::Kind::BITWISEAND:
827 SkASSERT(count == 1 && (tc == SkSL::TypeCategory::kSigned ||
828 tc == SkSL::TypeCategory::kUnsigned));
829 this->write(ByteCodeInstruction::kAndB);
830 break;
831 case Token::Kind::BITWISEOR:
832 SkASSERT(count == 1 && (tc == SkSL::TypeCategory::kSigned ||
833 tc == SkSL::TypeCategory::kUnsigned));
834 this->write(ByteCodeInstruction::kOrB);
835 break;
836 case Token::Kind::BITWISEXOR:
837 SkASSERT(count == 1 && (tc == SkSL::TypeCategory::kSigned ||
838 tc == SkSL::TypeCategory::kUnsigned));
Brian Osman569f12f2019-06-13 11:23:57 -0400839 this->write(ByteCodeInstruction::kXorB);
840 break;
841
Brian Osman909231c2019-05-29 15:34:36 -0400842 default:
Brian Osmandb3dad22019-07-26 15:44:29 -0400843 fErrors.error(b.fOffset, SkSL::String::printf("Unsupported binary operator '%s'",
844 Compiler::OperatorName(op)));
845 break;
Brian Osman909231c2019-05-29 15:34:36 -0400846 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400847 }
848 if (lvalue) {
Brian Osman3e29f1d2019-05-28 09:35:05 -0400849 lvalue->store(discard);
850 discard = false;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400851 }
Brian Osman3e29f1d2019-05-28 09:35:05 -0400852 return discard;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400853}
854
855void ByteCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
856 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osman569f12f2019-06-13 11:23:57 -0400857 this->write32(b.fValue ? ~0 : 0);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400858}
859
860void ByteCodeGenerator::writeConstructor(const Constructor& c) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400861 for (const auto& arg : c.fArguments) {
862 this->writeExpression(*arg);
863 }
864 if (c.fArguments.size() == 1) {
Brian Osman29e013d2019-05-28 17:16:03 -0400865 const Type& inType = c.fArguments[0]->fType;
866 const Type& outType = c.fType;
867 TypeCategory inCategory = type_category(inType);
868 TypeCategory outCategory = type_category(outType);
869 int inCount = SlotCount(inType);
870 int outCount = SlotCount(outType);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400871 if (inCategory != outCategory) {
Brian Osmanc51d7912019-05-22 15:16:16 -0700872 SkASSERT(inCount == outCount);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400873 if (inCategory == TypeCategory::kFloat) {
874 SkASSERT(outCategory == TypeCategory::kSigned ||
875 outCategory == TypeCategory::kUnsigned);
Brian Osmanc51d7912019-05-22 15:16:16 -0700876 this->write(vector_instruction(ByteCodeInstruction::kConvertFtoI, outCount));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400877 } else if (outCategory == TypeCategory::kFloat) {
878 if (inCategory == TypeCategory::kSigned) {
Brian Osmanc51d7912019-05-22 15:16:16 -0700879 this->write(vector_instruction(ByteCodeInstruction::kConvertStoF, outCount));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400880 } else {
881 SkASSERT(inCategory == TypeCategory::kUnsigned);
Brian Osmanc51d7912019-05-22 15:16:16 -0700882 this->write(vector_instruction(ByteCodeInstruction::kConvertUtoF, outCount));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400883 }
884 } else {
885 SkASSERT(false);
886 }
887 }
Brian Osman29e013d2019-05-28 17:16:03 -0400888 if (inType.kind() == Type::kMatrix_Kind && outType.kind() == Type::kMatrix_Kind) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400889 this->write(ByteCodeInstruction::kMatrixToMatrix,
890 SlotCount(outType) - SlotCount(inType));
Brian Osman29e013d2019-05-28 17:16:03 -0400891 this->write8(inType.columns());
892 this->write8(inType.rows());
893 this->write8(outType.columns());
894 this->write8(outType.rows());
895 } else if (inCount != outCount) {
Brian Osmanc51d7912019-05-22 15:16:16 -0700896 SkASSERT(inCount == 1);
Brian Osman29e013d2019-05-28 17:16:03 -0400897 if (outType.kind() == Type::kMatrix_Kind) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400898 this->write(ByteCodeInstruction::kScalarToMatrix, SlotCount(outType) - 1);
Brian Osman29e013d2019-05-28 17:16:03 -0400899 this->write8(outType.columns());
900 this->write8(outType.rows());
901 } else {
902 SkASSERT(outType.kind() == Type::kVector_Kind);
903 for (; inCount != outCount; ++inCount) {
904 this->write(ByteCodeInstruction::kDup);
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400905 this->write8(1);
Brian Osman29e013d2019-05-28 17:16:03 -0400906 }
Brian Osmanc51d7912019-05-22 15:16:16 -0700907 }
908 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400909 }
910}
911
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400912void ByteCodeGenerator::writeExternalFunctionCall(const ExternalFunctionCall& f) {
913 int argumentCount = 0;
914 for (const auto& arg : f.fArguments) {
915 this->writeExpression(*arg);
Brian Osman07c117b2019-05-23 12:51:06 -0700916 argumentCount += SlotCount(arg->fType);
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400917 }
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400918 this->write(ByteCodeInstruction::kCallExternal, SlotCount(f.fType) - argumentCount);
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400919 SkASSERT(argumentCount <= 255);
920 this->write8(argumentCount);
Brian Osman07c117b2019-05-23 12:51:06 -0700921 this->write8(SlotCount(f.fType));
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400922 int index = fOutput->fExternalValues.size();
923 fOutput->fExternalValues.push_back(f.fFunction);
924 SkASSERT(index <= 255);
925 this->write8(index);
926}
927
Ethan Nicholas91164d12019-05-15 15:29:54 -0400928void ByteCodeGenerator::writeExternalValue(const ExternalValueReference& e) {
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400929 int count = SlotCount(e.fValue->type());
930 this->write(vector_instruction(ByteCodeInstruction::kReadExternal, count));
931 this->write8(count);
Ethan Nicholas91164d12019-05-15 15:29:54 -0400932 int index = fOutput->fExternalValues.size();
933 fOutput->fExternalValues.push_back(e.fValue);
934 SkASSERT(index <= 255);
935 this->write8(index);
936}
937
Brian Osman07c117b2019-05-23 12:51:06 -0700938void ByteCodeGenerator::writeVariableExpression(const Expression& expr) {
Brian Osman1c110a02019-10-01 14:53:32 -0400939 Location location = this->getLocation(expr);
Brian Osman07c117b2019-05-23 12:51:06 -0700940 int count = SlotCount(expr.fType);
Brian Osman1c110a02019-10-01 14:53:32 -0400941 if (location.isOnStack() || count > 4) {
942 if (!location.isOnStack()) {
Brian Osman07c117b2019-05-23 12:51:06 -0700943 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osman1c110a02019-10-01 14:53:32 -0400944 this->write32(location.fSlot);
Brian Osman07c117b2019-05-23 12:51:06 -0700945 }
Brian Osman1c110a02019-10-01 14:53:32 -0400946 this->write(location.selectLoad(ByteCodeInstruction::kLoadExtended,
947 ByteCodeInstruction::kLoadExtendedGlobal,
948 ByteCodeInstruction::kLoadExtendedUniform),
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400949 count);
Brian Osman07c117b2019-05-23 12:51:06 -0700950 this->write8(count);
951 } else {
Brian Osman1c110a02019-10-01 14:53:32 -0400952 this->write(vector_instruction(location.selectLoad(ByteCodeInstruction::kLoad,
953 ByteCodeInstruction::kLoadGlobal,
954 ByteCodeInstruction::kLoadUniform),
Brian Osman07c117b2019-05-23 12:51:06 -0700955 count));
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400956 this->write8(count);
Brian Osman1c110a02019-10-01 14:53:32 -0400957 this->write8(location.fSlot);
Brian Osman07c117b2019-05-23 12:51:06 -0700958 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400959}
960
Brian Osmand30e0392019-06-14 14:05:14 -0400961static inline uint32_t float_to_bits(float x) {
962 uint32_t u;
963 memcpy(&u, &x, sizeof(uint32_t));
964 return u;
965}
966
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400967void ByteCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
968 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osmand30e0392019-06-14 14:05:14 -0400969 this->write32(float_to_bits(f.fValue));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400970}
971
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400972void ByteCodeGenerator::writeIntrinsicCall(const FunctionCall& c) {
973 auto found = fIntrinsics.find(c.fFunction.fName);
974 if (found == fIntrinsics.end()) {
975 fErrors.error(c.fOffset, "unsupported intrinsic function");
976 return;
977 }
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400978 int count = SlotCount(c.fArguments[0]->fType);
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400979 if (found->second.fIsSpecial) {
Brian Osmanb380e712019-07-24 17:02:39 -0400980 SpecialIntrinsic special = found->second.fValue.fSpecial;
981 switch (special) {
982 case SpecialIntrinsic::kDot: {
983 SkASSERT(c.fArguments.size() == 2);
984 SkASSERT(count == SlotCount(c.fArguments[1]->fType));
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400985 this->write(vector_instruction(ByteCodeInstruction::kMultiplyF, count));
986 this->write8(count);
Brian Osmanb380e712019-07-24 17:02:39 -0400987 for (int i = count; i > 1; --i) {
988 this->write(ByteCodeInstruction::kAddF);
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400989 this->write8(1);
Brian Osmanb380e712019-07-24 17:02:39 -0400990 }
991 break;
992 }
Brian Osmanb380e712019-07-24 17:02:39 -0400993 default:
994 SkASSERT(false);
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400995 }
996 } else {
997 switch (found->second.fValue.fInstruction) {
998 case ByteCodeInstruction::kCos:
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400999 case ByteCodeInstruction::kSin:
Ethan Nicholasae9633b2019-05-24 12:46:34 -04001000 case ByteCodeInstruction::kTan:
1001 SkASSERT(c.fArguments.size() > 0);
Ethan Nicholasc70027b2019-09-05 16:50:52 -04001002 this->write(vector_instruction(found->second.fValue.fInstruction, count));
1003 this->write8(count);
1004 break;
1005 case ByteCodeInstruction::kSqrt:
1006 SkASSERT(c.fArguments.size() > 0);
1007 this->write(vector_instruction(found->second.fValue.fInstruction, count));
Ethan Nicholasae9633b2019-05-24 12:46:34 -04001008 break;
Mike Reed634c9412019-07-18 13:20:04 -04001009 case ByteCodeInstruction::kInverse2x2: {
1010 SkASSERT(c.fArguments.size() > 0);
1011 auto op = ByteCodeInstruction::kInverse2x2;
1012 switch (count) {
1013 case 4: break; // float2x2
1014 case 9: op = ByteCodeInstruction::kInverse3x3; break;
1015 case 16: op = ByteCodeInstruction::kInverse4x4; break;
1016 default: SkASSERT(false);
1017 }
1018 this->write(op);
Brian Osmanb380e712019-07-24 17:02:39 -04001019 break;
1020 }
Ethan Nicholasae9633b2019-05-24 12:46:34 -04001021 default:
1022 SkASSERT(false);
1023 }
Ethan Nicholas82162ee2019-05-21 16:05:08 -04001024 }
1025}
1026
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001027void ByteCodeGenerator::writeFunctionCall(const FunctionCall& f) {
Ethan Nicholasdb80f692019-11-22 14:06:12 -05001028 // Find the index of the function we're calling. We explicitly do not allow calls to functions
1029 // before they're defined. This is an easy-to-understand rule that prevents recursion.
1030 int idx = -1;
1031 for (size_t i = 0; i < fFunctions.size(); ++i) {
1032 if (f.fFunction.matches(fFunctions[i]->fDeclaration)) {
1033 idx = i;
1034 break;
1035 }
1036 }
1037 if (idx == -1) {
Brian Osmand3494ed2019-06-20 15:41:34 -04001038 for (const auto& arg : f.fArguments) {
1039 this->writeExpression(*arg);
1040 }
Ethan Nicholas82162ee2019-05-21 16:05:08 -04001041 this->writeIntrinsicCall(f);
1042 return;
1043 }
Brian Osmand3494ed2019-06-20 15:41:34 -04001044
Ethan Nicholasdb80f692019-11-22 14:06:12 -05001045
Brian Osman6f5358f2019-07-09 14:17:23 -04001046 if (idx > 255) {
1047 fErrors.error(f.fOffset, "Function count limit exceeded");
1048 return;
Ethan Nicholasdb80f692019-11-22 14:06:12 -05001049 } else if (idx >= (int) fFunctions.size()) {
Brian Osman6f5358f2019-07-09 14:17:23 -04001050 fErrors.error(f.fOffset, "Call to undefined function");
1051 return;
1052 }
1053
1054 // We may need to deal with out parameters, so the sequence is tricky
Brian Osmand3494ed2019-06-20 15:41:34 -04001055 if (int returnCount = SlotCount(f.fType)) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001056 this->write(ByteCodeInstruction::kReserve, returnCount);
Brian Osmand3494ed2019-06-20 15:41:34 -04001057 this->write8(returnCount);
1058 }
1059
1060 int argCount = f.fArguments.size();
1061 std::vector<std::unique_ptr<LValue>> lvalues;
1062 for (int i = 0; i < argCount; ++i) {
1063 const auto& param = f.fFunction.fParameters[i];
1064 const auto& arg = f.fArguments[i];
1065 if (param->fModifiers.fFlags & Modifiers::kOut_Flag) {
1066 lvalues.emplace_back(this->getLValue(*arg));
1067 lvalues.back()->load();
1068 } else {
1069 this->writeExpression(*arg);
1070 }
1071 }
1072
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001073 // The space used by the call is based on the callee, but it also unwinds all of that before
1074 // we continue execution. We adjust our max stack depths below.
Brian Osman226668a2019-05-14 16:47:30 -04001075 this->write(ByteCodeInstruction::kCall);
Brian Osman6f5358f2019-07-09 14:17:23 -04001076 this->write8(idx);
Brian Osmand3494ed2019-06-20 15:41:34 -04001077
Brian Osman4a47da72019-07-12 11:30:32 -04001078 const ByteCodeFunction* callee = fOutput->fFunctions[idx].get();
1079 fMaxLoopCount = std::max(fMaxLoopCount, fLoopCount + callee->fLoopCount);
1080 fMaxConditionCount = std::max(fMaxConditionCount, fConditionCount + callee->fConditionCount);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001081 fMaxStackCount = std::max(fMaxStackCount, fStackCount + callee->fLocalCount
1082 + callee->fStackCount);
Brian Osman4a47da72019-07-12 11:30:32 -04001083
Brian Osmand3494ed2019-06-20 15:41:34 -04001084 // After the called function returns, the stack will still contain our arguments. We have to
1085 // pop them (storing any out parameters back to their lvalues as we go). We glob together slot
1086 // counts for all parameters that aren't out-params, so we can pop them in one big chunk.
1087 int popCount = 0;
1088 auto pop = [&]() {
1089 if (popCount > 4) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001090 this->write(ByteCodeInstruction::kPopN, popCount);
Brian Osmand3494ed2019-06-20 15:41:34 -04001091 this->write8(popCount);
1092 } else if (popCount > 0) {
1093 this->write(vector_instruction(ByteCodeInstruction::kPop, popCount));
1094 }
1095 popCount = 0;
1096 };
1097
1098 for (int i = argCount - 1; i >= 0; --i) {
1099 const auto& param = f.fFunction.fParameters[i];
1100 const auto& arg = f.fArguments[i];
1101 if (param->fModifiers.fFlags & Modifiers::kOut_Flag) {
1102 pop();
1103 lvalues.back()->store(true);
1104 lvalues.pop_back();
1105 } else {
1106 popCount += SlotCount(arg->fType);
1107 }
1108 }
1109 pop();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001110}
1111
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001112void ByteCodeGenerator::writeIntLiteral(const IntLiteral& i) {
1113 this->write(ByteCodeInstruction::kPushImmediate);
1114 this->write32(i.fValue);
1115}
1116
1117void ByteCodeGenerator::writeNullLiteral(const NullLiteral& n) {
1118 // not yet implemented
1119 abort();
1120}
1121
Brian Osman3e29f1d2019-05-28 09:35:05 -04001122bool ByteCodeGenerator::writePrefixExpression(const PrefixExpression& p, bool discard) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001123 switch (p.fOperator) {
1124 case Token::Kind::PLUSPLUS: // fall through
1125 case Token::Kind::MINUSMINUS: {
Brian Osman07c117b2019-05-23 12:51:06 -07001126 SkASSERT(SlotCount(p.fOperand->fType) == 1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001127 std::unique_ptr<LValue> lvalue = this->getLValue(*p.fOperand);
1128 lvalue->load();
1129 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osmand30e0392019-06-14 14:05:14 -04001130 this->write32(type_category(p.fType) == TypeCategory::kFloat ? float_to_bits(1.0f) : 1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001131 if (p.fOperator == Token::Kind::PLUSPLUS) {
1132 this->writeTypedInstruction(p.fType,
1133 ByteCodeInstruction::kAddI,
1134 ByteCodeInstruction::kAddI,
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001135 ByteCodeInstruction::kAddF,
1136 1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001137 } else {
1138 this->writeTypedInstruction(p.fType,
1139 ByteCodeInstruction::kSubtractI,
1140 ByteCodeInstruction::kSubtractI,
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001141 ByteCodeInstruction::kSubtractF,
1142 1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001143 }
Brian Osman3e29f1d2019-05-28 09:35:05 -04001144 lvalue->store(discard);
1145 discard = false;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001146 break;
1147 }
Ethan Nicholas354ecf32019-05-07 16:13:02 -04001148 case Token::Kind::MINUS: {
1149 this->writeExpression(*p.fOperand);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001150 this->writeTypedInstruction(p.fType,
Mike Klein12710912019-05-21 11:04:59 -05001151 ByteCodeInstruction::kNegateI,
1152 ByteCodeInstruction::kNegateI,
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001153 ByteCodeInstruction::kNegateF,
Ethan Nicholasc70027b2019-09-05 16:50:52 -04001154 SlotCount(p.fOperand->fType),
1155 false);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001156 break;
Ethan Nicholas354ecf32019-05-07 16:13:02 -04001157 }
Brian Osmane5bbce22019-09-23 12:38:40 -04001158 case Token::Kind::LOGICALNOT:
1159 case Token::Kind::BITWISENOT: {
1160 SkASSERT(SlotCount(p.fOperand->fType) == 1);
1161 SkDEBUGCODE(TypeCategory tc = type_category(p.fOperand->fType));
1162 SkASSERT((p.fOperator == Token::Kind::LOGICALNOT && tc == TypeCategory::kBool) ||
1163 (p.fOperator == Token::Kind::BITWISENOT && (tc == TypeCategory::kSigned ||
1164 tc == TypeCategory::kUnsigned)));
1165 this->writeExpression(*p.fOperand);
1166 this->write(ByteCodeInstruction::kNotB);
1167 break;
1168 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001169 default:
1170 SkASSERT(false);
1171 }
Brian Osman3e29f1d2019-05-28 09:35:05 -04001172 return discard;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001173}
1174
Brian Osman3e29f1d2019-05-28 09:35:05 -04001175bool ByteCodeGenerator::writePostfixExpression(const PostfixExpression& p, bool discard) {
Brian Osmanf3fa6002019-05-17 14:26:53 -04001176 switch (p.fOperator) {
1177 case Token::Kind::PLUSPLUS: // fall through
1178 case Token::Kind::MINUSMINUS: {
Brian Osman07c117b2019-05-23 12:51:06 -07001179 SkASSERT(SlotCount(p.fOperand->fType) == 1);
Brian Osmanf3fa6002019-05-17 14:26:53 -04001180 std::unique_ptr<LValue> lvalue = this->getLValue(*p.fOperand);
1181 lvalue->load();
Brian Osman52c1bf12019-07-18 13:12:19 -04001182 // If we're not supposed to discard the result, then make a copy *before* the +/-
Brian Osman3e29f1d2019-05-28 09:35:05 -04001183 if (!discard) {
1184 this->write(ByteCodeInstruction::kDup);
Ethan Nicholasc70027b2019-09-05 16:50:52 -04001185 this->write8(1);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001186 }
Brian Osmanf3fa6002019-05-17 14:26:53 -04001187 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osmand30e0392019-06-14 14:05:14 -04001188 this->write32(type_category(p.fType) == TypeCategory::kFloat ? float_to_bits(1.0f) : 1);
Brian Osmanf3fa6002019-05-17 14:26:53 -04001189 if (p.fOperator == Token::Kind::PLUSPLUS) {
1190 this->writeTypedInstruction(p.fType,
1191 ByteCodeInstruction::kAddI,
1192 ByteCodeInstruction::kAddI,
1193 ByteCodeInstruction::kAddF,
1194 1);
1195 } else {
1196 this->writeTypedInstruction(p.fType,
1197 ByteCodeInstruction::kSubtractI,
1198 ByteCodeInstruction::kSubtractI,
1199 ByteCodeInstruction::kSubtractF,
1200 1);
1201 }
Brian Osman52c1bf12019-07-18 13:12:19 -04001202 // Always consume the result as part of the store
1203 lvalue->store(true);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001204 discard = false;
Brian Osmanf3fa6002019-05-17 14:26:53 -04001205 break;
1206 }
1207 default:
1208 SkASSERT(false);
1209 }
Brian Osman3e29f1d2019-05-28 09:35:05 -04001210 return discard;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001211}
1212
1213void ByteCodeGenerator::writeSwizzle(const Swizzle& s) {
Brian Osman0785db02019-05-24 14:19:11 -04001214 if (swizzle_is_simple(s)) {
1215 this->writeVariableExpression(s);
1216 return;
1217 }
1218
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001219 switch (s.fBase->fKind) {
1220 case Expression::kVariableReference_Kind: {
Brian Osman1c110a02019-10-01 14:53:32 -04001221 Location location = this->getLocation(*s.fBase);
1222 this->write(location.selectLoad(ByteCodeInstruction::kLoadSwizzle,
1223 ByteCodeInstruction::kLoadSwizzleGlobal,
1224 ByteCodeInstruction::kLoadSwizzleUniform),
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001225 s.fComponents.size());
Brian Osman1c110a02019-10-01 14:53:32 -04001226 this->write8(location.fSlot);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001227 this->write8(s.fComponents.size());
1228 for (int c : s.fComponents) {
1229 this->write8(c);
1230 }
1231 break;
1232 }
1233 default:
1234 this->writeExpression(*s.fBase);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001235 this->write(ByteCodeInstruction::kSwizzle,
1236 s.fComponents.size() - s.fBase->fType.columns());
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001237 this->write8(s.fBase->fType.columns());
1238 this->write8(s.fComponents.size());
1239 for (int c : s.fComponents) {
1240 this->write8(c);
1241 }
1242 }
1243}
1244
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001245void ByteCodeGenerator::writeTernaryExpression(const TernaryExpression& t) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001246 int count = SlotCount(t.fType);
1247 SkASSERT(count == SlotCount(t.fIfTrue->fType));
1248 SkASSERT(count == SlotCount(t.fIfFalse->fType));
1249
Brian Osman4e93feb2019-05-16 15:38:00 -04001250 this->writeExpression(*t.fTest);
Brian Osman569f12f2019-06-13 11:23:57 -04001251 this->write(ByteCodeInstruction::kMaskPush);
Brian Osman4e93feb2019-05-16 15:38:00 -04001252 this->writeExpression(*t.fIfTrue);
Brian Osman569f12f2019-06-13 11:23:57 -04001253 this->write(ByteCodeInstruction::kMaskNegate);
1254 this->writeExpression(*t.fIfFalse);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001255 this->write(ByteCodeInstruction::kMaskBlend, count);
1256 this->write8(count);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001257}
1258
Brian Osman3e29f1d2019-05-28 09:35:05 -04001259void ByteCodeGenerator::writeExpression(const Expression& e, bool discard) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001260 switch (e.fKind) {
1261 case Expression::kBinary_Kind:
Brian Osman3e29f1d2019-05-28 09:35:05 -04001262 discard = this->writeBinaryExpression((BinaryExpression&) e, discard);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001263 break;
1264 case Expression::kBoolLiteral_Kind:
1265 this->writeBoolLiteral((BoolLiteral&) e);
1266 break;
1267 case Expression::kConstructor_Kind:
1268 this->writeConstructor((Constructor&) e);
1269 break;
Ethan Nicholas9e6a3932019-05-17 16:31:21 -04001270 case Expression::kExternalFunctionCall_Kind:
1271 this->writeExternalFunctionCall((ExternalFunctionCall&) e);
1272 break;
Ethan Nicholas91164d12019-05-15 15:29:54 -04001273 case Expression::kExternalValue_Kind:
1274 this->writeExternalValue((ExternalValueReference&) e);
1275 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001276 case Expression::kFieldAccess_Kind:
Brian Osman07c117b2019-05-23 12:51:06 -07001277 case Expression::kIndex_Kind:
1278 case Expression::kVariableReference_Kind:
1279 this->writeVariableExpression(e);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001280 break;
1281 case Expression::kFloatLiteral_Kind:
1282 this->writeFloatLiteral((FloatLiteral&) e);
1283 break;
1284 case Expression::kFunctionCall_Kind:
1285 this->writeFunctionCall((FunctionCall&) e);
1286 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001287 case Expression::kIntLiteral_Kind:
1288 this->writeIntLiteral((IntLiteral&) e);
1289 break;
1290 case Expression::kNullLiteral_Kind:
1291 this->writeNullLiteral((NullLiteral&) e);
1292 break;
1293 case Expression::kPrefix_Kind:
Brian Osman3e29f1d2019-05-28 09:35:05 -04001294 discard = this->writePrefixExpression((PrefixExpression&) e, discard);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001295 break;
1296 case Expression::kPostfix_Kind:
Brian Osman3e29f1d2019-05-28 09:35:05 -04001297 discard = this->writePostfixExpression((PostfixExpression&) e, discard);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001298 break;
1299 case Expression::kSwizzle_Kind:
1300 this->writeSwizzle((Swizzle&) e);
1301 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001302 case Expression::kTernary_Kind:
1303 this->writeTernaryExpression((TernaryExpression&) e);
1304 break;
1305 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -05001306#ifdef SK_DEBUG
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001307 printf("unsupported expression %s\n", e.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05001308#endif
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001309 SkASSERT(false);
1310 }
Brian Osman3e29f1d2019-05-28 09:35:05 -04001311 if (discard) {
1312 int count = SlotCount(e.fType);
1313 if (count > 4) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001314 this->write(ByteCodeInstruction::kPopN, count);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001315 this->write8(count);
Brian Osmanfba386b2019-06-20 14:54:15 -04001316 } else if (count != 0) {
Brian Osman3e29f1d2019-05-28 09:35:05 -04001317 this->write(vector_instruction(ByteCodeInstruction::kPop, count));
1318 }
1319 discard = false;
1320 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001321}
1322
Ethan Nicholas91164d12019-05-15 15:29:54 -04001323class ByteCodeExternalValueLValue : public ByteCodeGenerator::LValue {
1324public:
1325 ByteCodeExternalValueLValue(ByteCodeGenerator* generator, ExternalValue& value, int index)
1326 : INHERITED(*generator)
Brian Osman07c117b2019-05-23 12:51:06 -07001327 , fCount(ByteCodeGenerator::SlotCount(value.type()))
Ethan Nicholas91164d12019-05-15 15:29:54 -04001328 , fIndex(index) {}
1329
1330 void load() override {
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001331 fGenerator.write(vector_instruction(ByteCodeInstruction::kReadExternal, fCount));
Ethan Nicholasc70027b2019-09-05 16:50:52 -04001332 fGenerator.write8(fCount);
Ethan Nicholas91164d12019-05-15 15:29:54 -04001333 fGenerator.write8(fIndex);
1334 }
1335
Brian Osman3e29f1d2019-05-28 09:35:05 -04001336 void store(bool discard) override {
1337 if (!discard) {
1338 fGenerator.write(vector_instruction(ByteCodeInstruction::kDup, fCount));
Ethan Nicholasc70027b2019-09-05 16:50:52 -04001339 fGenerator.write8(fCount);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001340 }
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001341 fGenerator.write(vector_instruction(ByteCodeInstruction::kWriteExternal, fCount));
Ethan Nicholasc70027b2019-09-05 16:50:52 -04001342 fGenerator.write8(fCount);
Ethan Nicholas91164d12019-05-15 15:29:54 -04001343 fGenerator.write8(fIndex);
1344 }
1345
1346private:
1347 typedef LValue INHERITED;
1348
1349 int fCount;
1350
1351 int fIndex;
1352};
1353
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001354class ByteCodeSwizzleLValue : public ByteCodeGenerator::LValue {
1355public:
1356 ByteCodeSwizzleLValue(ByteCodeGenerator* generator, const Swizzle& swizzle)
1357 : INHERITED(*generator)
Brian Osman07c117b2019-05-23 12:51:06 -07001358 , fSwizzle(swizzle) {}
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001359
1360 void load() override {
Brian Osman1091f022019-05-16 09:42:16 -04001361 fGenerator.writeSwizzle(fSwizzle);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001362 }
1363
Brian Osman3e29f1d2019-05-28 09:35:05 -04001364 void store(bool discard) override {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001365 int count = fSwizzle.fComponents.size();
Brian Osman3e29f1d2019-05-28 09:35:05 -04001366 if (!discard) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001367 fGenerator.write(vector_instruction(ByteCodeInstruction::kDup, count));
Ethan Nicholasc70027b2019-09-05 16:50:52 -04001368 fGenerator.write8(count);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001369 }
Brian Osman1c110a02019-10-01 14:53:32 -04001370 ByteCodeGenerator::Location location = fGenerator.getLocation(*fSwizzle.fBase);
1371 if (location.isOnStack()) {
1372 fGenerator.write(location.selectStore(ByteCodeInstruction::kStoreSwizzleIndirect,
1373 ByteCodeInstruction::kStoreSwizzleIndirectGlobal),
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001374 count);
Brian Osman07c117b2019-05-23 12:51:06 -07001375 } else {
Brian Osman1c110a02019-10-01 14:53:32 -04001376 fGenerator.write(location.selectStore(ByteCodeInstruction::kStoreSwizzle,
1377 ByteCodeInstruction::kStoreSwizzleGlobal),
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001378 count);
Brian Osman1c110a02019-10-01 14:53:32 -04001379 fGenerator.write8(location.fSlot);
Brian Osman07c117b2019-05-23 12:51:06 -07001380 }
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001381 fGenerator.write8(count);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001382 for (int c : fSwizzle.fComponents) {
1383 fGenerator.write8(c);
1384 }
1385 }
1386
1387private:
1388 const Swizzle& fSwizzle;
1389
1390 typedef LValue INHERITED;
1391};
1392
Brian Osman07c117b2019-05-23 12:51:06 -07001393class ByteCodeExpressionLValue : public ByteCodeGenerator::LValue {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001394public:
Brian Osman07c117b2019-05-23 12:51:06 -07001395 ByteCodeExpressionLValue(ByteCodeGenerator* generator, const Expression& expr)
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001396 : INHERITED(*generator)
Brian Osman07c117b2019-05-23 12:51:06 -07001397 , fExpression(expr) {}
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001398
1399 void load() override {
Brian Osman07c117b2019-05-23 12:51:06 -07001400 fGenerator.writeVariableExpression(fExpression);
Brian Osman1091f022019-05-16 09:42:16 -04001401 }
1402
Brian Osman3e29f1d2019-05-28 09:35:05 -04001403 void store(bool discard) override {
Brian Osman07c117b2019-05-23 12:51:06 -07001404 int count = ByteCodeGenerator::SlotCount(fExpression.fType);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001405 if (!discard) {
1406 if (count > 4) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001407 fGenerator.write(ByteCodeInstruction::kDupN, count);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001408 fGenerator.write8(count);
1409 } else {
1410 fGenerator.write(vector_instruction(ByteCodeInstruction::kDup, count));
Ethan Nicholasc70027b2019-09-05 16:50:52 -04001411 fGenerator.write8(count);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001412 }
Brian Osman07c117b2019-05-23 12:51:06 -07001413 }
Brian Osman1c110a02019-10-01 14:53:32 -04001414 ByteCodeGenerator::Location location = fGenerator.getLocation(fExpression);
1415 if (location.isOnStack() || count > 4) {
1416 if (!location.isOnStack()) {
Brian Osman07c117b2019-05-23 12:51:06 -07001417 fGenerator.write(ByteCodeInstruction::kPushImmediate);
Brian Osman1c110a02019-10-01 14:53:32 -04001418 fGenerator.write32(location.fSlot);
Brian Osman07c117b2019-05-23 12:51:06 -07001419 }
Brian Osman1c110a02019-10-01 14:53:32 -04001420 fGenerator.write(location.selectStore(ByteCodeInstruction::kStoreExtended,
1421 ByteCodeInstruction::kStoreExtendedGlobal),
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001422 count);
Brian Osman07c117b2019-05-23 12:51:06 -07001423 fGenerator.write8(count);
1424 } else {
Brian Osman1c110a02019-10-01 14:53:32 -04001425 fGenerator.write(
1426 vector_instruction(location.selectStore(ByteCodeInstruction::kStore,
1427 ByteCodeInstruction::kStoreGlobal),
1428 count));
1429 fGenerator.write8(location.fSlot);
Brian Osman07c117b2019-05-23 12:51:06 -07001430 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001431 }
1432
1433private:
1434 typedef LValue INHERITED;
1435
Brian Osman07c117b2019-05-23 12:51:06 -07001436 const Expression& fExpression;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001437};
1438
1439std::unique_ptr<ByteCodeGenerator::LValue> ByteCodeGenerator::getLValue(const Expression& e) {
1440 switch (e.fKind) {
Ethan Nicholas91164d12019-05-15 15:29:54 -04001441 case Expression::kExternalValue_Kind: {
1442 ExternalValue* value = ((ExternalValueReference&) e).fValue;
1443 int index = fOutput->fExternalValues.size();
1444 fOutput->fExternalValues.push_back(value);
1445 SkASSERT(index <= 255);
1446 return std::unique_ptr<LValue>(new ByteCodeExternalValueLValue(this, *value, index));
1447 }
Brian Osman07c117b2019-05-23 12:51:06 -07001448 case Expression::kFieldAccess_Kind:
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001449 case Expression::kIndex_Kind:
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001450 case Expression::kVariableReference_Kind:
Brian Osman07c117b2019-05-23 12:51:06 -07001451 return std::unique_ptr<LValue>(new ByteCodeExpressionLValue(this, e));
Brian Osman0785db02019-05-24 14:19:11 -04001452 case Expression::kSwizzle_Kind: {
1453 const Swizzle& s = (const Swizzle&) e;
1454 return swizzle_is_simple(s)
1455 ? std::unique_ptr<LValue>(new ByteCodeExpressionLValue(this, e))
1456 : std::unique_ptr<LValue>(new ByteCodeSwizzleLValue(this, s));
1457 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001458 case Expression::kTernary_Kind:
1459 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -05001460#ifdef SK_DEBUG
1461 ABORT("unsupported lvalue %s\n", e.description().c_str());
1462#endif
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001463 return nullptr;
1464 }
1465}
1466
1467void ByteCodeGenerator::writeBlock(const Block& b) {
1468 for (const auto& s : b.fStatements) {
1469 this->writeStatement(*s);
1470 }
1471}
1472
1473void ByteCodeGenerator::setBreakTargets() {
1474 std::vector<DeferredLocation>& breaks = fBreakTargets.top();
1475 for (DeferredLocation& b : breaks) {
1476 b.set();
1477 }
1478 fBreakTargets.pop();
1479}
1480
1481void ByteCodeGenerator::setContinueTargets() {
1482 std::vector<DeferredLocation>& continues = fContinueTargets.top();
1483 for (DeferredLocation& c : continues) {
1484 c.set();
1485 }
1486 fContinueTargets.pop();
1487}
1488
1489void ByteCodeGenerator::writeBreakStatement(const BreakStatement& b) {
Brian Osman569f12f2019-06-13 11:23:57 -04001490 // TODO: Include BranchIfAllFalse to top-most LoopNext
1491 this->write(ByteCodeInstruction::kLoopBreak);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001492}
1493
1494void ByteCodeGenerator::writeContinueStatement(const ContinueStatement& c) {
Brian Osman569f12f2019-06-13 11:23:57 -04001495 // TODO: Include BranchIfAllFalse to top-most LoopNext
1496 this->write(ByteCodeInstruction::kLoopContinue);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001497}
1498
1499void ByteCodeGenerator::writeDoStatement(const DoStatement& d) {
Brian Osman569f12f2019-06-13 11:23:57 -04001500 this->write(ByteCodeInstruction::kLoopBegin);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001501 size_t start = fCode->size();
1502 this->writeStatement(*d.fStatement);
Brian Osman569f12f2019-06-13 11:23:57 -04001503 this->write(ByteCodeInstruction::kLoopNext);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001504 this->writeExpression(*d.fTest);
Brian Osman569f12f2019-06-13 11:23:57 -04001505 this->write(ByteCodeInstruction::kLoopMask);
1506 // TODO: Could shorten this with kBranchIfAnyTrue
1507 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1508 DeferredLocation endLocation(this);
1509 this->write(ByteCodeInstruction::kBranch);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001510 this->write16(start);
Brian Osman569f12f2019-06-13 11:23:57 -04001511 endLocation.set();
1512 this->write(ByteCodeInstruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001513}
1514
1515void ByteCodeGenerator::writeForStatement(const ForStatement& f) {
1516 fContinueTargets.emplace();
1517 fBreakTargets.emplace();
1518 if (f.fInitializer) {
1519 this->writeStatement(*f.fInitializer);
1520 }
Brian Osman569f12f2019-06-13 11:23:57 -04001521 this->write(ByteCodeInstruction::kLoopBegin);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001522 size_t start = fCode->size();
1523 if (f.fTest) {
1524 this->writeExpression(*f.fTest);
Brian Osman569f12f2019-06-13 11:23:57 -04001525 this->write(ByteCodeInstruction::kLoopMask);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001526 }
Brian Osman569f12f2019-06-13 11:23:57 -04001527 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1528 DeferredLocation endLocation(this);
1529 this->writeStatement(*f.fStatement);
1530 this->write(ByteCodeInstruction::kLoopNext);
1531 if (f.fNext) {
1532 this->writeExpression(*f.fNext, true);
1533 }
1534 this->write(ByteCodeInstruction::kBranch);
1535 this->write16(start);
1536 endLocation.set();
1537 this->write(ByteCodeInstruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001538}
1539
1540void ByteCodeGenerator::writeIfStatement(const IfStatement& i) {
Brian Osman569f12f2019-06-13 11:23:57 -04001541 this->writeExpression(*i.fTest);
1542 this->write(ByteCodeInstruction::kMaskPush);
1543 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1544 DeferredLocation falseLocation(this);
1545 this->writeStatement(*i.fIfTrue);
1546 falseLocation.set();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001547 if (i.fIfFalse) {
Brian Osman569f12f2019-06-13 11:23:57 -04001548 this->write(ByteCodeInstruction::kMaskNegate);
1549 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1550 DeferredLocation endLocation(this);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001551 this->writeStatement(*i.fIfFalse);
Mike Kleinb45ee832019-05-17 11:11:11 -05001552 endLocation.set();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001553 }
Brian Osman569f12f2019-06-13 11:23:57 -04001554 this->write(ByteCodeInstruction::kMaskPop);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001555}
1556
1557void ByteCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
Brian Osman4a47da72019-07-12 11:30:32 -04001558 if (fLoopCount || fConditionCount) {
1559 fErrors.error(r.fOffset, "return not allowed inside conditional or loop");
1560 return;
1561 }
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001562 int count = SlotCount(r.fExpression->fType);
Ethan Nicholas746035a2019-04-23 13:31:09 -04001563 this->writeExpression(*r.fExpression);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001564
1565 // Technically, the kReturn also pops fOutput->fLocalCount values from the stack, too, but we
1566 // haven't counted pushing those (they're outside the scope of our stack tracking). Instead,
1567 // we account for those in writeFunction().
1568
1569 // This is all fine because we don't allow conditional returns, so we only return once anyway.
1570 this->write(ByteCodeInstruction::kReturn, -count);
1571 this->write8(count);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001572}
1573
1574void ByteCodeGenerator::writeSwitchStatement(const SwitchStatement& r) {
1575 // not yet implemented
1576 abort();
1577}
1578
1579void ByteCodeGenerator::writeVarDeclarations(const VarDeclarations& v) {
1580 for (const auto& declStatement : v.fVars) {
1581 const VarDeclaration& decl = (VarDeclaration&) *declStatement;
Brian Osman1c110a02019-10-01 14:53:32 -04001582 // we need to grab the location even if we don't use it, to ensure it has been allocated
1583 Location location = this->getLocation(*decl.fVar);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001584 if (decl.fValue) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001585 this->writeExpression(*decl.fValue);
Brian Osman07c117b2019-05-23 12:51:06 -07001586 int count = SlotCount(decl.fValue->fType);
1587 if (count > 4) {
1588 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osman1c110a02019-10-01 14:53:32 -04001589 this->write32(location.fSlot);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001590 this->write(ByteCodeInstruction::kStoreExtended, count);
Brian Osman07c117b2019-05-23 12:51:06 -07001591 this->write8(count);
1592 } else {
1593 this->write(vector_instruction(ByteCodeInstruction::kStore, count));
Brian Osman1c110a02019-10-01 14:53:32 -04001594 this->write8(location.fSlot);
Brian Osman07c117b2019-05-23 12:51:06 -07001595 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001596 }
1597 }
1598}
1599
1600void ByteCodeGenerator::writeWhileStatement(const WhileStatement& w) {
Brian Osman569f12f2019-06-13 11:23:57 -04001601 this->write(ByteCodeInstruction::kLoopBegin);
1602 size_t cond = fCode->size();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001603 this->writeExpression(*w.fTest);
Brian Osman569f12f2019-06-13 11:23:57 -04001604 this->write(ByteCodeInstruction::kLoopMask);
1605 this->write(ByteCodeInstruction::kBranchIfAllFalse);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001606 DeferredLocation endLocation(this);
1607 this->writeStatement(*w.fStatement);
Brian Osman569f12f2019-06-13 11:23:57 -04001608 this->write(ByteCodeInstruction::kLoopNext);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001609 this->write(ByteCodeInstruction::kBranch);
Brian Osman569f12f2019-06-13 11:23:57 -04001610 this->write16(cond);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001611 endLocation.set();
Brian Osman569f12f2019-06-13 11:23:57 -04001612 this->write(ByteCodeInstruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001613}
1614
1615void ByteCodeGenerator::writeStatement(const Statement& s) {
1616 switch (s.fKind) {
1617 case Statement::kBlock_Kind:
1618 this->writeBlock((Block&) s);
1619 break;
1620 case Statement::kBreak_Kind:
1621 this->writeBreakStatement((BreakStatement&) s);
1622 break;
1623 case Statement::kContinue_Kind:
1624 this->writeContinueStatement((ContinueStatement&) s);
1625 break;
1626 case Statement::kDiscard_Kind:
1627 // not yet implemented
1628 abort();
1629 case Statement::kDo_Kind:
1630 this->writeDoStatement((DoStatement&) s);
1631 break;
Brian Osman3e29f1d2019-05-28 09:35:05 -04001632 case Statement::kExpression_Kind:
1633 this->writeExpression(*((ExpressionStatement&) s).fExpression, true);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001634 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001635 case Statement::kFor_Kind:
1636 this->writeForStatement((ForStatement&) s);
1637 break;
1638 case Statement::kIf_Kind:
1639 this->writeIfStatement((IfStatement&) s);
1640 break;
1641 case Statement::kNop_Kind:
1642 break;
1643 case Statement::kReturn_Kind:
1644 this->writeReturnStatement((ReturnStatement&) s);
1645 break;
1646 case Statement::kSwitch_Kind:
1647 this->writeSwitchStatement((SwitchStatement&) s);
1648 break;
1649 case Statement::kVarDeclarations_Kind:
1650 this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration);
1651 break;
1652 case Statement::kWhile_Kind:
1653 this->writeWhileStatement((WhileStatement&) s);
1654 break;
1655 default:
1656 SkASSERT(false);
1657 }
1658}
1659
Brian Osman80164412019-06-07 13:00:23 -04001660ByteCodeFunction::ByteCodeFunction(const FunctionDeclaration* declaration)
1661 : fName(declaration->fName) {
1662 fParameterCount = 0;
1663 for (const auto& p : declaration->fParameters) {
1664 int slots = ByteCodeGenerator::SlotCount(p->fType);
1665 fParameters.push_back({ slots, (bool)(p->fModifiers.fFlags & Modifiers::kOut_Flag) });
1666 fParameterCount += slots;
1667 }
1668}
1669
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001670}