blob: 8ada9d5821cc65ce962697092a6a83e5ff59bbcf [file] [log] [blame]
Mike Reed8520e762020-04-30 12:06:23 -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 Osmanb08cc022020-04-02 11:38:40 -040010#include <algorithm>
11
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040012namespace SkSL {
13
Brian Osmanb08cc022020-04-02 11:38:40 -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" ||
23 type.fName == "short" ||
24 type.fName == "$intLiteral") {
25 return TypeCategory::kSigned;
26 } else if (type.fName == "uint" ||
27 type.fName == "ushort") {
28 return TypeCategory::kUnsigned;
29 } else {
30 SkASSERT(type.fName == "float" ||
31 type.fName == "half" ||
32 type.fName == "$floatLiteral");
33 return TypeCategory::kFloat;
34 }
35 ABORT("unsupported type: %s\n", type.displayName().c_str());
36 }
37}
38
39
40ByteCodeGenerator::ByteCodeGenerator(const Context* context, const Program* program, ErrorReporter* errors,
41 ByteCode* output)
Ethan Nicholas82162ee2019-05-21 16:05:08 -040042 : INHERITED(program, errors, nullptr)
Brian Osmanb08cc022020-04-02 11:38:40 -040043 , fContext(*context)
Ethan Nicholasae9633b2019-05-24 12:46:34 -040044 , fOutput(output)
Brian Osman3479a952020-05-04 10:22:53 -040045 // If you're adding new intrinsics here, ensure that they're declared in sksl_interp.inc, so
46 // they're available to "generic" interpreter programs (eg particles).
47 // You can probably copy the declarations from sksl_gpu.inc.
Ethan Nicholasae9633b2019-05-24 12:46:34 -040048 , fIntrinsics {
Brian Osmand5f937b2020-05-04 12:07:29 -040049 { "atan", ByteCodeInstruction::kATan },
50 { "clamp", SpecialIntrinsic::kClamp },
51 { "cos", ByteCodeInstruction::kCos },
52 { "dot", SpecialIntrinsic::kDot },
53 { "fract", ByteCodeInstruction::kFract },
54 { "inverse", ByteCodeInstruction::kInverse2x2 },
55 { "length", SpecialIntrinsic::kLength },
56 { "max", SpecialIntrinsic::kMax },
57 { "min", SpecialIntrinsic::kMin },
58 { "mix", SpecialIntrinsic::kMix },
59 { "pow", ByteCodeInstruction::kPow },
Brian Osmana43d8202020-06-17 16:50:39 -040060 { "sample", SpecialIntrinsic::kSample },
Brian Osmand5f937b2020-05-04 12:07:29 -040061 { "saturate", SpecialIntrinsic::kSaturate },
62 { "sin", ByteCodeInstruction::kSin },
63 { "sqrt", ByteCodeInstruction::kSqrt },
64 { "tan", ByteCodeInstruction::kTan },
Brian Osman8842b372020-05-01 15:07:49 -040065
66 { "lessThan", { ByteCodeInstruction::kCompareFLT,
67 ByteCodeInstruction::kCompareSLT,
68 ByteCodeInstruction::kCompareULT } },
69 { "lessThanEqual", { ByteCodeInstruction::kCompareFLTEQ,
70 ByteCodeInstruction::kCompareSLTEQ,
71 ByteCodeInstruction::kCompareULTEQ } },
72 { "greaterThan", { ByteCodeInstruction::kCompareFGT,
73 ByteCodeInstruction::kCompareSGT,
74 ByteCodeInstruction::kCompareUGT } },
75 { "greaterThanEqual", { ByteCodeInstruction::kCompareFGTEQ,
76 ByteCodeInstruction::kCompareSGTEQ,
77 ByteCodeInstruction::kCompareUGTEQ } },
78 { "equal", { ByteCodeInstruction::kCompareFEQ,
79 ByteCodeInstruction::kCompareIEQ,
80 ByteCodeInstruction::kCompareIEQ } },
81 { "notEqual", { ByteCodeInstruction::kCompareFNEQ,
82 ByteCodeInstruction::kCompareINEQ,
83 ByteCodeInstruction::kCompareINEQ } },
84
85 { "any", SpecialIntrinsic::kAny },
86 { "all", SpecialIntrinsic::kAll },
87 { "not", ByteCodeInstruction::kNotB },
88 } {}
Brian Osmanb08cc022020-04-02 11:38:40 -040089
Ethan Nicholas82162ee2019-05-21 16:05:08 -040090
Brian Osman07c117b2019-05-23 12:51:06 -070091int ByteCodeGenerator::SlotCount(const Type& type) {
Brian Osmanfba386b2019-06-20 14:54:15 -040092 if (type.kind() == Type::kOther_Kind) {
93 return 0;
94 } else if (type.kind() == Type::kStruct_Kind) {
Brian Osman07c117b2019-05-23 12:51:06 -070095 int slots = 0;
96 for (const auto& f : type.fields()) {
97 slots += SlotCount(*f.fType);
98 }
99 SkASSERT(slots <= 255);
100 return slots;
101 } else if (type.kind() == Type::kArray_Kind) {
102 int columns = type.columns();
103 SkASSERT(columns >= 0);
104 int slots = columns * SlotCount(type.componentType());
105 SkASSERT(slots <= 255);
106 return slots;
107 } else {
108 return type.columns() * type.rows();
109 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400110}
111
Brian Osman1c110a02019-10-01 14:53:32 -0400112static inline bool is_uniform(const SkSL::Variable& var) {
113 return var.fModifiers.fFlags & Modifiers::kUniform_Flag;
114}
115
Brian Osmaneadfeb92020-01-09 12:43:03 -0500116static inline bool is_in(const SkSL::Variable& var) {
117 return var.fModifiers.fFlags & Modifiers::kIn_Flag;
118}
Brian Osmanb08cc022020-04-02 11:38:40 -0400119
120void ByteCodeGenerator::gatherUniforms(const Type& type, const String& name) {
121 if (type.kind() == Type::kOther_Kind) {
122 return;
123 } else if (type.kind() == Type::kStruct_Kind) {
124 for (const auto& f : type.fields()) {
125 this->gatherUniforms(*f.fType, name + "." + f.fName);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500126 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400127 } else if (type.kind() == Type::kArray_Kind) {
128 for (int i = 0; i < type.columns(); ++i) {
129 this->gatherUniforms(type.componentType(), String::printf("%s[%d]", name.c_str(), i));
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500130 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400131 } else {
132 fOutput->fUniforms.push_back({ name, type_category(type), type.rows(), type.columns(),
133 fOutput->fUniformSlotCount });
134 fOutput->fUniformSlotCount += type.columns() * type.rows();
135 }
136}
137
138bool ByteCodeGenerator::generateCode() {
139 for (const auto& e : fProgram) {
140 switch (e.fKind) {
141 case ProgramElement::kFunction_Kind: {
142 std::unique_ptr<ByteCodeFunction> f = this->writeFunction((FunctionDefinition&) e);
143 if (!f) {
144 return false;
145 }
146 fOutput->fFunctions.push_back(std::move(f));
147 fFunctions.push_back(&(FunctionDefinition&)e);
148 break;
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500149 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400150 case ProgramElement::kVar_Kind: {
151 VarDeclarations& decl = (VarDeclarations&) e;
152 for (const auto& v : decl.fVars) {
153 const Variable* declVar = ((VarDeclaration&) *v).fVar;
Brian Osmana43d8202020-06-17 16:50:39 -0400154 if (declVar->fType == *fContext.fFragmentProcessor_Type) {
155 fOutput->fChildFPCount++;
156 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400157 if (declVar->fModifiers.fLayout.fBuiltin >= 0 || is_in(*declVar)) {
158 continue;
159 }
160 if (is_uniform(*declVar)) {
161 this->gatherUniforms(declVar->fType, declVar->fName);
162 } else {
163 fOutput->fGlobalSlotCount += SlotCount(declVar->fType);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400164 }
165 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400166 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400167 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400168 default:
169 ; // ignore
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400170 }
171 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400172 return 0 == fErrors.errorCount();
173}
174
175std::unique_ptr<ByteCodeFunction> ByteCodeGenerator::writeFunction(const FunctionDefinition& f) {
176 fFunction = &f;
177 std::unique_ptr<ByteCodeFunction> result(new ByteCodeFunction(&f.fDeclaration));
178 fParameterCount = result->fParameterCount;
179 fLoopCount = fMaxLoopCount = 0;
180 fConditionCount = fMaxConditionCount = 0;
181 fStackCount = fMaxStackCount = 0;
182 fCode = &result->fCode;
183
184 this->writeStatement(*f.fBody);
185 if (0 == fErrors.errorCount()) {
186 SkASSERT(fLoopCount == 0);
187 SkASSERT(fConditionCount == 0);
188 SkASSERT(fStackCount == 0);
189 }
190 this->write(ByteCodeInstruction::kReturn, 0);
191 this->write8(0);
192
193 result->fLocalCount = fLocals.size();
194 result->fConditionCount = fMaxConditionCount;
195 result->fLoopCount = fMaxLoopCount;
196 result->fStackCount = fMaxStackCount;
197
198 const Type& returnType = f.fDeclaration.fReturnType;
199 if (returnType != *fContext.fVoid_Type) {
200 result->fReturnCount = SlotCount(returnType);
201 }
202 fLocals.clear();
203 fFunction = nullptr;
204 return result;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400205}
206
Brian Osman0785db02019-05-24 14:19:11 -0400207// A "simple" Swizzle is based on a variable (or a compound variable like a struct or array), and
208// that references consecutive values, such that it can be implemented using normal load/store ops
209// with an offset. Note that all single-component swizzles (of suitable base types) are simple.
210static bool swizzle_is_simple(const Swizzle& s) {
211 switch (s.fBase->fKind) {
212 case Expression::kFieldAccess_Kind:
213 case Expression::kIndex_Kind:
214 case Expression::kVariableReference_Kind:
215 break;
216 default:
217 return false;
218 }
219
220 for (size_t i = 1; i < s.fComponents.size(); ++i) {
221 if (s.fComponents[i] != s.fComponents[i - 1] + 1) {
222 return false;
223 }
224 }
225 return true;
226}
227
Brian Osmanb08cc022020-04-02 11:38:40 -0400228int ByteCodeGenerator::StackUsage(ByteCodeInstruction inst, int count_) {
229 // Ensures that we use count iff we're passed a non-default value. Most instructions have an
230 // implicit count, so the caller shouldn't need to worry about it (or count makes no sense).
231 // The asserts avoids callers thinking they're supplying useful information in that scenario,
232 // or failing to supply necessary information for the ops that need a count.
233 struct CountValue {
234 operator int() {
235 SkASSERT(val != ByteCodeGenerator::kUnusedStackCount);
236 SkDEBUGCODE(used = true);
237 return val;
238 }
239 ~CountValue() {
240 SkASSERT(used || val == ByteCodeGenerator::kUnusedStackCount);
241 }
242 int val;
243 SkDEBUGCODE(bool used = false;)
244 } count = { count_ };
245
246 switch (inst) {
247 // Unary functions/operators that don't change stack depth at all:
248#define VECTOR_UNARY_OP(base) \
249 case ByteCodeInstruction::base: \
250 case ByteCodeInstruction::base ## 2: \
251 case ByteCodeInstruction::base ## 3: \
252 case ByteCodeInstruction::base ## 4: \
253 return 0;
254
255 VECTOR_UNARY_OP(kConvertFtoI)
256 VECTOR_UNARY_OP(kConvertStoF)
257 VECTOR_UNARY_OP(kConvertUtoF)
258
Mike Reed8520e762020-04-30 12:06:23 -0400259 VECTOR_UNARY_OP(kATan)
Brian Osmanb08cc022020-04-02 11:38:40 -0400260 VECTOR_UNARY_OP(kCos)
Mike Reed8520e762020-04-30 12:06:23 -0400261 VECTOR_UNARY_OP(kFract)
Brian Osmanb08cc022020-04-02 11:38:40 -0400262 VECTOR_UNARY_OP(kSin)
263 VECTOR_UNARY_OP(kSqrt)
264 VECTOR_UNARY_OP(kTan)
265
266 VECTOR_UNARY_OP(kNegateF)
267 VECTOR_UNARY_OP(kNegateI)
Brian Osman8842b372020-05-01 15:07:49 -0400268 VECTOR_UNARY_OP(kNotB)
Brian Osmanb08cc022020-04-02 11:38:40 -0400269
270 case ByteCodeInstruction::kInverse2x2:
271 case ByteCodeInstruction::kInverse3x3:
272 case ByteCodeInstruction::kInverse4x4: return 0;
273
274 case ByteCodeInstruction::kClampIndex: return 0;
Brian Osmanb08cc022020-04-02 11:38:40 -0400275 case ByteCodeInstruction::kNegateFN: return 0;
276 case ByteCodeInstruction::kShiftLeft: return 0;
277 case ByteCodeInstruction::kShiftRightS: return 0;
278 case ByteCodeInstruction::kShiftRightU: return 0;
279
280#undef VECTOR_UNARY_OP
281
282 // Binary functions/operators that do a 2 -> 1 reduction (possibly N times)
283#define VECTOR_BINARY_OP(base) \
284 case ByteCodeInstruction::base: return -1; \
285 case ByteCodeInstruction::base ## 2: return -2; \
286 case ByteCodeInstruction::base ## 3: return -3; \
287 case ByteCodeInstruction::base ## 4: return -4;
288
289#define VECTOR_MATRIX_BINARY_OP(base) \
290 VECTOR_BINARY_OP(base) \
291 case ByteCodeInstruction::base ## N: return -count;
292
293 case ByteCodeInstruction::kAndB: return -1;
294 case ByteCodeInstruction::kOrB: return -1;
295 case ByteCodeInstruction::kXorB: return -1;
296
297 VECTOR_BINARY_OP(kAddI)
298 VECTOR_MATRIX_BINARY_OP(kAddF)
299
300 VECTOR_BINARY_OP(kCompareIEQ)
301 VECTOR_MATRIX_BINARY_OP(kCompareFEQ)
302 VECTOR_BINARY_OP(kCompareINEQ)
303 VECTOR_MATRIX_BINARY_OP(kCompareFNEQ)
304 VECTOR_BINARY_OP(kCompareSGT)
305 VECTOR_BINARY_OP(kCompareUGT)
306 VECTOR_BINARY_OP(kCompareFGT)
307 VECTOR_BINARY_OP(kCompareSGTEQ)
308 VECTOR_BINARY_OP(kCompareUGTEQ)
309 VECTOR_BINARY_OP(kCompareFGTEQ)
310 VECTOR_BINARY_OP(kCompareSLT)
311 VECTOR_BINARY_OP(kCompareULT)
312 VECTOR_BINARY_OP(kCompareFLT)
313 VECTOR_BINARY_OP(kCompareSLTEQ)
314 VECTOR_BINARY_OP(kCompareULTEQ)
315 VECTOR_BINARY_OP(kCompareFLTEQ)
316
317 VECTOR_BINARY_OP(kDivideS)
318 VECTOR_BINARY_OP(kDivideU)
319 VECTOR_MATRIX_BINARY_OP(kDivideF)
Brian Osmand5f937b2020-05-04 12:07:29 -0400320 VECTOR_BINARY_OP(kMaxF)
321 VECTOR_BINARY_OP(kMaxS)
322 VECTOR_BINARY_OP(kMinF)
323 VECTOR_BINARY_OP(kMinS)
Brian Osmanb08cc022020-04-02 11:38:40 -0400324 VECTOR_BINARY_OP(kMultiplyI)
325 VECTOR_MATRIX_BINARY_OP(kMultiplyF)
Florin Malita3facc9c2020-05-04 09:26:15 -0400326 VECTOR_BINARY_OP(kPow)
Brian Osmanb08cc022020-04-02 11:38:40 -0400327 VECTOR_BINARY_OP(kRemainderF)
328 VECTOR_BINARY_OP(kRemainderS)
329 VECTOR_BINARY_OP(kRemainderU)
330 VECTOR_BINARY_OP(kSubtractI)
331 VECTOR_MATRIX_BINARY_OP(kSubtractF)
332
333#undef VECTOR_BINARY_OP
334#undef VECTOR_MATRIX_BINARY_OP
335
336 // Ops that push or load data to grow the stack:
337 case ByteCodeInstruction::kDup:
338 case ByteCodeInstruction::kLoad:
339 case ByteCodeInstruction::kLoadGlobal:
340 case ByteCodeInstruction::kLoadUniform:
341 case ByteCodeInstruction::kReadExternal:
342 case ByteCodeInstruction::kPushImmediate:
343 return 1;
344
345 case ByteCodeInstruction::kDup2:
346 case ByteCodeInstruction::kLoad2:
347 case ByteCodeInstruction::kLoadGlobal2:
348 case ByteCodeInstruction::kLoadUniform2:
349 case ByteCodeInstruction::kReadExternal2:
350 return 2;
351
352 case ByteCodeInstruction::kDup3:
353 case ByteCodeInstruction::kLoad3:
354 case ByteCodeInstruction::kLoadGlobal3:
355 case ByteCodeInstruction::kLoadUniform3:
356 case ByteCodeInstruction::kReadExternal3:
357 return 3;
358
359 case ByteCodeInstruction::kDup4:
360 case ByteCodeInstruction::kLoad4:
361 case ByteCodeInstruction::kLoadGlobal4:
362 case ByteCodeInstruction::kLoadUniform4:
363 case ByteCodeInstruction::kReadExternal4:
364 return 4;
365
366 case ByteCodeInstruction::kDupN:
Brian Osmanb08cc022020-04-02 11:38:40 -0400367 return count;
368
369 // Pushes 'count' values, minus one for the 'address' that's consumed first
370 case ByteCodeInstruction::kLoadExtended:
371 case ByteCodeInstruction::kLoadExtendedGlobal:
372 case ByteCodeInstruction::kLoadExtendedUniform:
373 return count - 1;
374
375 // Ops that pop or store data to shrink the stack:
376 case ByteCodeInstruction::kPop:
377 case ByteCodeInstruction::kStore:
378 case ByteCodeInstruction::kStoreGlobal:
379 case ByteCodeInstruction::kWriteExternal:
380 return -1;
381
382 case ByteCodeInstruction::kPop2:
383 case ByteCodeInstruction::kStore2:
384 case ByteCodeInstruction::kStoreGlobal2:
385 case ByteCodeInstruction::kWriteExternal2:
386 return -2;
387
388 case ByteCodeInstruction::kPop3:
389 case ByteCodeInstruction::kStore3:
390 case ByteCodeInstruction::kStoreGlobal3:
391 case ByteCodeInstruction::kWriteExternal3:
392 return -3;
393
394 case ByteCodeInstruction::kPop4:
395 case ByteCodeInstruction::kStore4:
396 case ByteCodeInstruction::kStoreGlobal4:
397 case ByteCodeInstruction::kWriteExternal4:
398 return -4;
399
400 case ByteCodeInstruction::kPopN:
Brian Osmanb08cc022020-04-02 11:38:40 -0400401 return -count;
402
403 // Consumes 'count' values, plus one for the 'address'
404 case ByteCodeInstruction::kStoreExtended:
405 case ByteCodeInstruction::kStoreExtendedGlobal:
Brian Osmanb08cc022020-04-02 11:38:40 -0400406 return -count - 1;
407
408 // Strange ops where the caller computes the delta for us:
409 case ByteCodeInstruction::kCallExternal:
410 case ByteCodeInstruction::kMatrixToMatrix:
411 case ByteCodeInstruction::kMatrixMultiply:
412 case ByteCodeInstruction::kReserve:
413 case ByteCodeInstruction::kReturn:
414 case ByteCodeInstruction::kScalarToMatrix:
415 case ByteCodeInstruction::kSwizzle:
416 return count;
417
418 // Miscellaneous
419
Brian Osmana43d8202020-06-17 16:50:39 -0400420 // (X, Y) -> (R, G, B, A)
421 case ByteCodeInstruction::kSampleExplicit: return 4 - 2;
422 // (float3x3) -> (R, G, B, A)
423 case ByteCodeInstruction::kSampleMatrix: return 4 - 9;
424
Brian Osman8842b372020-05-01 15:07:49 -0400425 // kMix does a 3 -> 1 reduction (A, B, M -> A -or- B) for each component
426 case ByteCodeInstruction::kMix: return -2;
427 case ByteCodeInstruction::kMix2: return -4;
428 case ByteCodeInstruction::kMix3: return -6;
429 case ByteCodeInstruction::kMix4: return -8;
430
431 // kLerp works the same way (producing lerp(A, B, T) for each component)
432 case ByteCodeInstruction::kLerp: return -2;
433 case ByteCodeInstruction::kLerp2: return -4;
434 case ByteCodeInstruction::kLerp3: return -6;
435 case ByteCodeInstruction::kLerp4: return -8;
436
Brian Osmanb08cc022020-04-02 11:38:40 -0400437 // kCall is net-zero. Max stack depth is adjusted in writeFunctionCall.
438 case ByteCodeInstruction::kCall: return 0;
439 case ByteCodeInstruction::kBranch: return 0;
440 case ByteCodeInstruction::kBranchIfAllFalse: return 0;
441
442 case ByteCodeInstruction::kMaskPush: return -1;
443 case ByteCodeInstruction::kMaskPop: return 0;
444 case ByteCodeInstruction::kMaskNegate: return 0;
445 case ByteCodeInstruction::kMaskBlend: return -count;
446
447 case ByteCodeInstruction::kLoopBegin: return 0;
448 case ByteCodeInstruction::kLoopNext: return 0;
449 case ByteCodeInstruction::kLoopMask: return -1;
450 case ByteCodeInstruction::kLoopEnd: return 0;
451 case ByteCodeInstruction::kLoopBreak: return 0;
452 case ByteCodeInstruction::kLoopContinue: return 0;
Brian Osmanb08cc022020-04-02 11:38:40 -0400453 }
Brian Osmand5f937b2020-05-04 12:07:29 -0400454
455 SkUNREACHABLE;
Brian Osmanb08cc022020-04-02 11:38:40 -0400456}
457
458ByteCodeGenerator::Location ByteCodeGenerator::getLocation(const Variable& var) {
459 // given that we seldom have more than a couple of variables, linear search is probably the most
460 // efficient way to handle lookups
461 switch (var.fStorage) {
462 case Variable::kLocal_Storage: {
463 for (int i = fLocals.size() - 1; i >= 0; --i) {
464 if (fLocals[i] == &var) {
465 SkASSERT(fParameterCount + i <= 255);
466 return { fParameterCount + i, Storage::kLocal };
467 }
468 }
469 int result = fParameterCount + fLocals.size();
470 fLocals.push_back(&var);
471 for (int i = 0; i < SlotCount(var.fType) - 1; ++i) {
472 fLocals.push_back(nullptr);
473 }
474 SkASSERT(result <= 255);
475 return { result, Storage::kLocal };
476 }
477 case Variable::kParameter_Storage: {
478 int offset = 0;
479 for (const auto& p : fFunction->fDeclaration.fParameters) {
480 if (p == &var) {
481 SkASSERT(offset <= 255);
482 return { offset, Storage::kLocal };
483 }
484 offset += SlotCount(p->fType);
485 }
486 SkASSERT(false);
487 return Location::MakeInvalid();
488 }
489 case Variable::kGlobal_Storage: {
Brian Osmana43d8202020-06-17 16:50:39 -0400490 if (var.fType == *fContext.fFragmentProcessor_Type) {
491 int offset = 0;
492 for (const auto& e : fProgram) {
493 if (e.fKind == ProgramElement::kVar_Kind) {
494 VarDeclarations& decl = (VarDeclarations&) e;
495 for (const auto& v : decl.fVars) {
496 const Variable* declVar = ((VarDeclaration&) *v).fVar;
497 if (declVar->fType != *fContext.fFragmentProcessor_Type) {
498 continue;
499 }
500 if (declVar == &var) {
501 SkASSERT(offset <= 255);
502 return { offset, Storage::kChildFP };
503 }
504 offset++;
505 }
506 }
507 }
508 SkASSERT(false);
509 return Location::MakeInvalid();
510 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400511 if (is_in(var)) {
512 // If you see this error, it means the program is using raw 'in' variables. You
513 // should either specialize the program (Compiler::specialize) to bake in the final
514 // values of the 'in' variables, or not use 'in' variables (maybe you meant to use
515 // 'uniform' instead?).
516 fErrors.error(var.fOffset,
517 "'in' variable is not specialized or has unsupported type");
518 return Location::MakeInvalid();
519 }
520 int offset = 0;
521 bool isUniform = is_uniform(var);
522 for (const auto& e : fProgram) {
523 if (e.fKind == ProgramElement::kVar_Kind) {
524 VarDeclarations& decl = (VarDeclarations&) e;
525 for (const auto& v : decl.fVars) {
526 const Variable* declVar = ((VarDeclaration&) *v).fVar;
527 if (declVar->fModifiers.fLayout.fBuiltin >= 0 || is_in(*declVar)) {
528 continue;
529 }
530 if (isUniform != is_uniform(*declVar)) {
531 continue;
532 }
533 if (declVar == &var) {
534 SkASSERT(offset <= 255);
535 return { offset, isUniform ? Storage::kUniform : Storage::kGlobal };
536 }
537 offset += SlotCount(declVar->fType);
538 }
539 }
540 }
541 SkASSERT(false);
542 return Location::MakeInvalid();
543 }
544 default:
545 SkASSERT(false);
546 return Location::MakeInvalid();
547 }
548}
549
Brian Osman1c110a02019-10-01 14:53:32 -0400550ByteCodeGenerator::Location ByteCodeGenerator::getLocation(const Expression& expr) {
Brian Osman07c117b2019-05-23 12:51:06 -0700551 switch (expr.fKind) {
552 case Expression::kFieldAccess_Kind: {
Brian Osmanb08cc022020-04-02 11:38:40 -0400553 const FieldAccess& f = (const FieldAccess&)expr;
554 Location baseLoc = this->getLocation(*f.fBase);
Brian Osman07c117b2019-05-23 12:51:06 -0700555 int offset = 0;
556 for (int i = 0; i < f.fFieldIndex; ++i) {
557 offset += SlotCount(*f.fBase->fType.fields()[i].fType);
558 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400559 if (baseLoc.isOnStack()) {
560 if (offset != 0) {
561 this->write(ByteCodeInstruction::kPushImmediate);
562 this->write32(offset);
563 this->write(ByteCodeInstruction::kAddI);
Ben Wagner470e0ac2020-01-22 16:59:21 -0500564 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400565 return baseLoc;
Ben Wagner470e0ac2020-01-22 16:59:21 -0500566 } else {
Brian Osmanb08cc022020-04-02 11:38:40 -0400567 return baseLoc + offset;
Ben Wagner470e0ac2020-01-22 16:59:21 -0500568 }
Ben Wagner470e0ac2020-01-22 16:59:21 -0500569 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400570 case Expression::kIndex_Kind: {
571 const IndexExpression& i = (const IndexExpression&)expr;
572 int stride = SlotCount(i.fType);
573 int length = i.fBase->fType.columns();
574 SkASSERT(length <= 255);
575 int offset = -1;
576 if (i.fIndex->isConstant()) {
577 int64_t index = i.fIndex->getConstantInt();
578 if (index < 0 || index >= length) {
579 fErrors.error(i.fIndex->fOffset, "Array index out of bounds.");
580 return Location::MakeInvalid();
581 }
582 offset = index * stride;
583 } else {
584 if (i.fIndex->hasSideEffects()) {
585 // Having a side-effect in an indexer is technically safe for an rvalue,
586 // but with lvalues we have to evaluate the indexer twice, so make it an error.
587 fErrors.error(i.fIndex->fOffset,
588 "Index expressions with side-effects not supported in byte code.");
589 return Location::MakeInvalid();
590 }
591 this->writeExpression(*i.fIndex);
592 this->write(ByteCodeInstruction::kClampIndex);
593 this->write8(length);
594 if (stride != 1) {
595 this->write(ByteCodeInstruction::kPushImmediate);
596 this->write32(stride);
597 this->write(ByteCodeInstruction::kMultiplyI);
Brian Osmanb08cc022020-04-02 11:38:40 -0400598 }
599 }
600 Location baseLoc = this->getLocation(*i.fBase);
601
602 // Are both components known statically?
603 if (!baseLoc.isOnStack() && offset >= 0) {
604 return baseLoc + offset;
605 }
606
607 // At least one component is dynamic (and on the stack).
608
609 // If the other component is zero, we're done
610 if (baseLoc.fSlot == 0 || offset == 0) {
611 return baseLoc.makeOnStack();
612 }
613
614 // Push the non-dynamic component (if any) to the stack, then add the two
615 if (!baseLoc.isOnStack()) {
616 this->write(ByteCodeInstruction::kPushImmediate);
617 this->write32(baseLoc.fSlot);
618 }
619 if (offset >= 0) {
620 this->write(ByteCodeInstruction::kPushImmediate);
621 this->write32(offset);
622 }
623 this->write(ByteCodeInstruction::kAddI);
Brian Osmanb08cc022020-04-02 11:38:40 -0400624 return baseLoc.makeOnStack();
625 }
Brian Osman0785db02019-05-24 14:19:11 -0400626 case Expression::kSwizzle_Kind: {
Brian Osmanb08cc022020-04-02 11:38:40 -0400627 const Swizzle& s = (const Swizzle&)expr;
Brian Osman0785db02019-05-24 14:19:11 -0400628 SkASSERT(swizzle_is_simple(s));
Brian Osmanb08cc022020-04-02 11:38:40 -0400629 Location baseLoc = this->getLocation(*s.fBase);
630 int offset = s.fComponents[0];
631 if (baseLoc.isOnStack()) {
632 if (offset != 0) {
633 this->write(ByteCodeInstruction::kPushImmediate);
634 this->write32(offset);
635 this->write(ByteCodeInstruction::kAddI);
Brian Osmanb08cc022020-04-02 11:38:40 -0400636 }
637 return baseLoc;
638 } else {
639 return baseLoc + offset;
640 }
Brian Osman0785db02019-05-24 14:19:11 -0400641 }
Brian Osman07c117b2019-05-23 12:51:06 -0700642 case Expression::kVariableReference_Kind: {
Brian Osmanb08cc022020-04-02 11:38:40 -0400643 const Variable& var = ((const VariableReference&)expr).fVariable;
Brian Osman07c117b2019-05-23 12:51:06 -0700644 return this->getLocation(var);
645 }
646 default:
647 SkASSERT(false);
Brian Osmanb08cc022020-04-02 11:38:40 -0400648 return Location::MakeInvalid();
Brian Osman07c117b2019-05-23 12:51:06 -0700649 }
650}
651
Brian Osmanb08cc022020-04-02 11:38:40 -0400652void ByteCodeGenerator::write8(uint8_t b) {
653 fCode->push_back(b);
Ethan Nicholas2cde3a12020-01-21 09:23:13 -0500654}
655
Brian Osmanb08cc022020-04-02 11:38:40 -0400656void ByteCodeGenerator::write16(uint16_t i) {
657 size_t n = fCode->size();
658 fCode->resize(n+2);
659 memcpy(fCode->data() + n, &i, 2);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500660}
Ben Wagner470e0ac2020-01-22 16:59:21 -0500661
Brian Osmanb08cc022020-04-02 11:38:40 -0400662void ByteCodeGenerator::write32(uint32_t i) {
663 size_t n = fCode->size();
664 fCode->resize(n+4);
665 memcpy(fCode->data() + n, &i, 4);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500666}
667
Brian Osmanb08cc022020-04-02 11:38:40 -0400668void ByteCodeGenerator::write(ByteCodeInstruction i, int count) {
669 switch (i) {
670 case ByteCodeInstruction::kLoopBegin: this->enterLoop(); break;
671 case ByteCodeInstruction::kLoopEnd: this->exitLoop(); break;
Ethan Nicholas2329da02020-01-24 15:49:33 -0500672
Brian Osmanb08cc022020-04-02 11:38:40 -0400673 case ByteCodeInstruction::kMaskPush: this->enterCondition(); break;
674 case ByteCodeInstruction::kMaskPop:
675 case ByteCodeInstruction::kMaskBlend: this->exitCondition(); break;
676 default: /* Do nothing */ break;
Ben Wagner470e0ac2020-01-22 16:59:21 -0500677 }
Brian Osmanab8f3842020-04-07 09:30:44 -0400678 this->write16((uint16_t)i);
Brian Osmanb08cc022020-04-02 11:38:40 -0400679 fStackCount += StackUsage(i, count);
680 fMaxStackCount = std::max(fMaxStackCount, fStackCount);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500681}
682
Brian Osmanb08cc022020-04-02 11:38:40 -0400683static ByteCodeInstruction vector_instruction(ByteCodeInstruction base, int count) {
684 SkASSERT(count >= 1 && count <= 4);
685 return ((ByteCodeInstruction) ((int) base + 1 - count));
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500686}
687
Brian Osmanb08cc022020-04-02 11:38:40 -0400688void ByteCodeGenerator::writeTypedInstruction(const Type& type, ByteCodeInstruction s,
689 ByteCodeInstruction u, ByteCodeInstruction f,
Brian Osmanab8f3842020-04-07 09:30:44 -0400690 int count) {
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500691 switch (type_category(type)) {
Brian Osman8842b372020-05-01 15:07:49 -0400692 case TypeCategory::kBool:
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500693 case TypeCategory::kSigned:
Brian Osmanb08cc022020-04-02 11:38:40 -0400694 this->write(vector_instruction(s, count));
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500695 break;
696 case TypeCategory::kUnsigned:
Brian Osmanb08cc022020-04-02 11:38:40 -0400697 this->write(vector_instruction(u, count));
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500698 break;
699 case TypeCategory::kFloat: {
Brian Osmanb08cc022020-04-02 11:38:40 -0400700 if (count > 4) {
701 this->write((ByteCodeInstruction)((int)f + 1), count);
Brian Osmanab8f3842020-04-07 09:30:44 -0400702 this->write8(count);
Brian Osmanb08cc022020-04-02 11:38:40 -0400703 } else {
704 this->write(vector_instruction(f, count));
705 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500706 break;
707 }
708 default:
709 SkASSERT(false);
710 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500711}
712
Brian Osmanb08cc022020-04-02 11:38:40 -0400713bool ByteCodeGenerator::writeBinaryExpression(const BinaryExpression& b, bool discard) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400714 if (b.fOperator == Token::Kind::TK_EQ) {
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500715 std::unique_ptr<LValue> lvalue = this->getLValue(*b.fLeft);
Brian Osmanb08cc022020-04-02 11:38:40 -0400716 this->writeExpression(*b.fRight);
717 lvalue->store(discard);
718 discard = false;
719 return discard;
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500720 }
721 const Type& lType = b.fLeft->fType;
722 const Type& rType = b.fRight->fType;
723 bool lVecOrMtx = (lType.kind() == Type::kVector_Kind || lType.kind() == Type::kMatrix_Kind);
724 bool rVecOrMtx = (rType.kind() == Type::kVector_Kind || rType.kind() == Type::kMatrix_Kind);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500725 Token::Kind op;
726 std::unique_ptr<LValue> lvalue;
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500727 if (is_assignment(b.fOperator)) {
728 lvalue = this->getLValue(*b.fLeft);
Brian Osmanb08cc022020-04-02 11:38:40 -0400729 lvalue->load();
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500730 op = remove_assignment(b.fOperator);
731 } else {
Brian Osmanb08cc022020-04-02 11:38:40 -0400732 this->writeExpression(*b.fLeft);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500733 op = b.fOperator;
734 if (!lVecOrMtx && rVecOrMtx) {
Brian Osmanb08cc022020-04-02 11:38:40 -0400735 for (int i = SlotCount(rType); i > 1; --i) {
736 this->write(ByteCodeInstruction::kDup);
Brian Osmanb08cc022020-04-02 11:38:40 -0400737 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500738 }
739 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500740 int count = std::max(SlotCount(lType), SlotCount(rType));
Brian Osmanb08cc022020-04-02 11:38:40 -0400741 SkDEBUGCODE(TypeCategory tc = type_category(lType));
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500742 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400743 case Token::Kind::TK_LOGICALAND: {
Brian Osmanb08cc022020-04-02 11:38:40 -0400744 SkASSERT(tc == SkSL::TypeCategory::kBool && count == 1);
745 this->write(ByteCodeInstruction::kDup);
Brian Osmanb08cc022020-04-02 11:38:40 -0400746 this->write(ByteCodeInstruction::kMaskPush);
747 this->write(ByteCodeInstruction::kBranchIfAllFalse);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500748 DeferredLocation falseLocation(this);
Brian Osmanb08cc022020-04-02 11:38:40 -0400749 this->writeExpression(*b.fRight);
750 this->write(ByteCodeInstruction::kAndB);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500751 falseLocation.set();
Brian Osmanb08cc022020-04-02 11:38:40 -0400752 this->write(ByteCodeInstruction::kMaskPop);
753 return false;
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500754 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400755 case Token::Kind::TK_LOGICALOR: {
Brian Osmanb08cc022020-04-02 11:38:40 -0400756 SkASSERT(tc == SkSL::TypeCategory::kBool && count == 1);
757 this->write(ByteCodeInstruction::kDup);
Brian Osmanb08cc022020-04-02 11:38:40 -0400758 this->write(ByteCodeInstruction::kNotB);
759 this->write(ByteCodeInstruction::kMaskPush);
760 this->write(ByteCodeInstruction::kBranchIfAllFalse);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500761 DeferredLocation falseLocation(this);
Brian Osmanb08cc022020-04-02 11:38:40 -0400762 this->writeExpression(*b.fRight);
763 this->write(ByteCodeInstruction::kOrB);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500764 falseLocation.set();
Brian Osmanb08cc022020-04-02 11:38:40 -0400765 this->write(ByteCodeInstruction::kMaskPop);
766 return false;
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500767 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400768 case Token::Kind::TK_SHL:
769 case Token::Kind::TK_SHR: {
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500770 SkASSERT(count == 1 && (tc == SkSL::TypeCategory::kSigned ||
771 tc == SkSL::TypeCategory::kUnsigned));
772 if (!b.fRight->isConstant()) {
773 fErrors.error(b.fRight->fOffset, "Shift amounts must be constant");
Brian Osmanb08cc022020-04-02 11:38:40 -0400774 return false;
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500775 }
776 int64_t shift = b.fRight->getConstantInt();
777 if (shift < 0 || shift > 31) {
778 fErrors.error(b.fRight->fOffset, "Shift amount out of range");
Brian Osmanb08cc022020-04-02 11:38:40 -0400779 return false;
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500780 }
781
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400782 if (op == Token::Kind::TK_SHL) {
Brian Osmanb08cc022020-04-02 11:38:40 -0400783 this->write(ByteCodeInstruction::kShiftLeft);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500784 } else {
785 this->write(type_category(lType) == TypeCategory::kSigned
Brian Osmanb08cc022020-04-02 11:38:40 -0400786 ? ByteCodeInstruction::kShiftRightS
787 : ByteCodeInstruction::kShiftRightU);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500788 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400789 this->write8(shift);
790 return false;
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500791 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500792
793 default:
794 break;
795 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400796 this->writeExpression(*b.fRight);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500797 if (lVecOrMtx && !rVecOrMtx) {
Brian Osmanb08cc022020-04-02 11:38:40 -0400798 for (int i = SlotCount(lType); i > 1; --i) {
799 this->write(ByteCodeInstruction::kDup);
Brian Osmanb08cc022020-04-02 11:38:40 -0400800 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500801 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400802 // Special case for M*V, V*M, M*M (but not V*V!)
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400803 if (op == Token::Kind::TK_STAR && lVecOrMtx && rVecOrMtx &&
Brian Osmanb08cc022020-04-02 11:38:40 -0400804 !(lType.kind() == Type::kVector_Kind && rType.kind() == Type::kVector_Kind)) {
805 this->write(ByteCodeInstruction::kMatrixMultiply,
806 SlotCount(b.fType) - (SlotCount(lType) + SlotCount(rType)));
807 int rCols = rType.columns(),
808 rRows = rType.rows(),
809 lCols = lType.columns(),
810 lRows = lType.rows();
811 // M*V treats the vector as a column
812 if (rType.kind() == Type::kVector_Kind) {
813 std::swap(rCols, rRows);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500814 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400815 SkASSERT(lCols == rRows);
816 SkASSERT(SlotCount(b.fType) == lRows * rCols);
817 this->write8(lCols);
818 this->write8(lRows);
819 this->write8(rCols);
820 } else {
821 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400822 case Token::Kind::TK_EQEQ:
Brian Osmanb08cc022020-04-02 11:38:40 -0400823 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareIEQ,
824 ByteCodeInstruction::kCompareIEQ,
825 ByteCodeInstruction::kCompareFEQ,
826 count);
827 // Collapse to a single bool
828 for (int i = count; i > 1; --i) {
829 this->write(ByteCodeInstruction::kAndB);
830 }
831 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400832 case Token::Kind::TK_GT:
Brian Osmanb08cc022020-04-02 11:38:40 -0400833 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSGT,
834 ByteCodeInstruction::kCompareUGT,
835 ByteCodeInstruction::kCompareFGT,
836 count);
837 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400838 case Token::Kind::TK_GTEQ:
Brian Osmanb08cc022020-04-02 11:38:40 -0400839 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSGTEQ,
840 ByteCodeInstruction::kCompareUGTEQ,
841 ByteCodeInstruction::kCompareFGTEQ,
842 count);
843 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400844 case Token::Kind::TK_LT:
Brian Osmanb08cc022020-04-02 11:38:40 -0400845 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSLT,
846 ByteCodeInstruction::kCompareULT,
847 ByteCodeInstruction::kCompareFLT,
848 count);
849 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400850 case Token::Kind::TK_LTEQ:
Brian Osmanb08cc022020-04-02 11:38:40 -0400851 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSLTEQ,
852 ByteCodeInstruction::kCompareULTEQ,
853 ByteCodeInstruction::kCompareFLTEQ,
854 count);
855 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400856 case Token::Kind::TK_MINUS:
Brian Osmanb08cc022020-04-02 11:38:40 -0400857 this->writeTypedInstruction(lType, ByteCodeInstruction::kSubtractI,
858 ByteCodeInstruction::kSubtractI,
859 ByteCodeInstruction::kSubtractF,
860 count);
861 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400862 case Token::Kind::TK_NEQ:
Brian Osmanb08cc022020-04-02 11:38:40 -0400863 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareINEQ,
864 ByteCodeInstruction::kCompareINEQ,
865 ByteCodeInstruction::kCompareFNEQ,
866 count);
867 // Collapse to a single bool
868 for (int i = count; i > 1; --i) {
869 this->write(ByteCodeInstruction::kOrB);
870 }
871 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400872 case Token::Kind::TK_PERCENT:
Brian Osmanb08cc022020-04-02 11:38:40 -0400873 this->writeTypedInstruction(lType, ByteCodeInstruction::kRemainderS,
874 ByteCodeInstruction::kRemainderU,
875 ByteCodeInstruction::kRemainderF,
876 count);
877 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400878 case Token::Kind::TK_PLUS:
Brian Osmanb08cc022020-04-02 11:38:40 -0400879 this->writeTypedInstruction(lType, ByteCodeInstruction::kAddI,
880 ByteCodeInstruction::kAddI,
881 ByteCodeInstruction::kAddF,
882 count);
883 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400884 case Token::Kind::TK_SLASH:
Brian Osmanb08cc022020-04-02 11:38:40 -0400885 this->writeTypedInstruction(lType, ByteCodeInstruction::kDivideS,
886 ByteCodeInstruction::kDivideU,
887 ByteCodeInstruction::kDivideF,
888 count);
889 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400890 case Token::Kind::TK_STAR:
Brian Osmanb08cc022020-04-02 11:38:40 -0400891 this->writeTypedInstruction(lType, ByteCodeInstruction::kMultiplyI,
892 ByteCodeInstruction::kMultiplyI,
893 ByteCodeInstruction::kMultiplyF,
894 count);
895 break;
896
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400897 case Token::Kind::TK_LOGICALXOR:
Brian Osmanb08cc022020-04-02 11:38:40 -0400898 SkASSERT(tc == SkSL::TypeCategory::kBool && count == 1);
899 this->write(ByteCodeInstruction::kXorB);
900 break;
901
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400902 case Token::Kind::TK_BITWISEAND:
Brian Osmanb08cc022020-04-02 11:38:40 -0400903 SkASSERT(count == 1 && (tc == SkSL::TypeCategory::kSigned ||
904 tc == SkSL::TypeCategory::kUnsigned));
905 this->write(ByteCodeInstruction::kAndB);
906 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400907 case Token::Kind::TK_BITWISEOR:
Brian Osmanb08cc022020-04-02 11:38:40 -0400908 SkASSERT(count == 1 && (tc == SkSL::TypeCategory::kSigned ||
909 tc == SkSL::TypeCategory::kUnsigned));
910 this->write(ByteCodeInstruction::kOrB);
911 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400912 case Token::Kind::TK_BITWISEXOR:
Brian Osmanb08cc022020-04-02 11:38:40 -0400913 SkASSERT(count == 1 && (tc == SkSL::TypeCategory::kSigned ||
914 tc == SkSL::TypeCategory::kUnsigned));
915 this->write(ByteCodeInstruction::kXorB);
916 break;
917
918 default:
919 fErrors.error(b.fOffset, SkSL::String::printf("Unsupported binary operator '%s'",
920 Compiler::OperatorName(op)));
921 break;
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500922 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500923 }
924 if (lvalue) {
Brian Osmanb08cc022020-04-02 11:38:40 -0400925 lvalue->store(discard);
926 discard = false;
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500927 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400928 return discard;
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500929}
930
Brian Osmanb08cc022020-04-02 11:38:40 -0400931void ByteCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
932 this->write(ByteCodeInstruction::kPushImmediate);
933 this->write32(b.fValue ? ~0 : 0);
934}
935
936void ByteCodeGenerator::writeConstructor(const Constructor& c) {
937 for (const auto& arg : c.fArguments) {
938 this->writeExpression(*arg);
939 }
940 if (c.fArguments.size() == 1) {
941 const Type& inType = c.fArguments[0]->fType;
942 const Type& outType = c.fType;
943 TypeCategory inCategory = type_category(inType);
944 TypeCategory outCategory = type_category(outType);
945 int inCount = SlotCount(inType);
946 int outCount = SlotCount(outType);
947 if (inCategory != outCategory) {
948 SkASSERT(inCount == outCount);
949 if (inCategory == TypeCategory::kFloat) {
950 SkASSERT(outCategory == TypeCategory::kSigned ||
951 outCategory == TypeCategory::kUnsigned);
952 this->write(vector_instruction(ByteCodeInstruction::kConvertFtoI, outCount));
953 } else if (outCategory == TypeCategory::kFloat) {
954 if (inCategory == TypeCategory::kSigned) {
955 this->write(vector_instruction(ByteCodeInstruction::kConvertStoF, outCount));
956 } else {
957 SkASSERT(inCategory == TypeCategory::kUnsigned);
958 this->write(vector_instruction(ByteCodeInstruction::kConvertUtoF, outCount));
959 }
960 } else {
961 SkASSERT(false);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500962 }
963 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400964 if (inType.kind() == Type::kMatrix_Kind && outType.kind() == Type::kMatrix_Kind) {
965 this->write(ByteCodeInstruction::kMatrixToMatrix,
966 SlotCount(outType) - SlotCount(inType));
967 this->write8(inType.columns());
968 this->write8(inType.rows());
969 this->write8(outType.columns());
970 this->write8(outType.rows());
971 } else if (inCount != outCount) {
972 SkASSERT(inCount == 1);
973 if (outType.kind() == Type::kMatrix_Kind) {
974 this->write(ByteCodeInstruction::kScalarToMatrix, SlotCount(outType) - 1);
975 this->write8(outType.columns());
976 this->write8(outType.rows());
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500977 } else {
Brian Osmanb08cc022020-04-02 11:38:40 -0400978 SkASSERT(outType.kind() == Type::kVector_Kind);
979 for (; inCount != outCount; ++inCount) {
980 this->write(ByteCodeInstruction::kDup);
Brian Osmanb08cc022020-04-02 11:38:40 -0400981 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500982 }
983 }
984 }
985}
986
Brian Osmanb08cc022020-04-02 11:38:40 -0400987void ByteCodeGenerator::writeExternalFunctionCall(const ExternalFunctionCall& f) {
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500988 int argumentCount = 0;
989 for (const auto& arg : f.fArguments) {
Brian Osmanb08cc022020-04-02 11:38:40 -0400990 this->writeExpression(*arg);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500991 argumentCount += SlotCount(arg->fType);
992 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400993 this->write(ByteCodeInstruction::kCallExternal, SlotCount(f.fType) - argumentCount);
994 SkASSERT(argumentCount <= 255);
995 this->write8(argumentCount);
996 this->write8(SlotCount(f.fType));
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500997 int index = fOutput->fExternalValues.size();
998 fOutput->fExternalValues.push_back(f.fFunction);
999 SkASSERT(index <= 255);
Brian Osmanb08cc022020-04-02 11:38:40 -04001000 this->write8(index);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001001}
1002
Brian Osmanb08cc022020-04-02 11:38:40 -04001003void ByteCodeGenerator::writeExternalValue(const ExternalValueReference& e) {
1004 int count = SlotCount(e.fValue->type());
1005 this->write(vector_instruction(ByteCodeInstruction::kReadExternal, count));
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001006 int index = fOutput->fExternalValues.size();
1007 fOutput->fExternalValues.push_back(e.fValue);
1008 SkASSERT(index <= 255);
Brian Osmanb08cc022020-04-02 11:38:40 -04001009 this->write8(index);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001010}
1011
Brian Osmanb08cc022020-04-02 11:38:40 -04001012void ByteCodeGenerator::writeVariableExpression(const Expression& expr) {
1013 Location location = this->getLocation(expr);
1014 int count = SlotCount(expr.fType);
Brian Osmanefb08402020-04-13 16:30:44 -04001015 if (count == 0) {
1016 return;
1017 }
Brian Osmanb08cc022020-04-02 11:38:40 -04001018 if (location.isOnStack() || count > 4) {
1019 if (!location.isOnStack()) {
1020 this->write(ByteCodeInstruction::kPushImmediate);
1021 this->write32(location.fSlot);
1022 }
1023 this->write(location.selectLoad(ByteCodeInstruction::kLoadExtended,
1024 ByteCodeInstruction::kLoadExtendedGlobal,
1025 ByteCodeInstruction::kLoadExtendedUniform),
1026 count);
1027 this->write8(count);
1028 } else {
1029 this->write(vector_instruction(location.selectLoad(ByteCodeInstruction::kLoad,
1030 ByteCodeInstruction::kLoadGlobal,
1031 ByteCodeInstruction::kLoadUniform),
1032 count));
Brian Osmanb08cc022020-04-02 11:38:40 -04001033 this->write8(location.fSlot);
1034 }
1035}
1036
1037static inline uint32_t float_to_bits(float x) {
1038 uint32_t u;
1039 memcpy(&u, &x, sizeof(uint32_t));
1040 return u;
1041}
1042
1043void ByteCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
1044 this->write(ByteCodeInstruction::kPushImmediate);
1045 this->write32(float_to_bits(f.fValue));
1046}
1047
Brian Osman8842b372020-05-01 15:07:49 -04001048static bool is_generic_type(const Type* type, const Type* generic) {
1049 const std::vector<const Type*>& concrete(generic->coercibleTypes());
1050 return std::find(concrete.begin(), concrete.end(), type) != concrete.end();
1051}
1052
Brian Osmanb08cc022020-04-02 11:38:40 -04001053void ByteCodeGenerator::writeIntrinsicCall(const FunctionCall& c) {
1054 auto found = fIntrinsics.find(c.fFunction.fName);
1055 if (found == fIntrinsics.end()) {
1056 fErrors.error(c.fOffset, String::printf("Unsupported intrinsic: '%s'",
1057 String(c.fFunction.fName).c_str()));
1058 return;
1059 }
Mike Klein45be0772020-05-01 09:13:18 -05001060 Intrinsic intrin = found->second;
Brian Osmanb08cc022020-04-02 11:38:40 -04001061 int count = SlotCount(c.fArguments[0]->fType);
Brian Osmand5f937b2020-05-04 12:07:29 -04001062
1063 // Several intrinsics have variants where one argument is either scalar, or the same size as
1064 // the first argument. Call dupSmallerType(SlotCount(argType)) to ensure equal component count.
1065 auto dupSmallerType = [count, this](int smallCount) {
1066 SkASSERT(smallCount == 1 || smallCount == count);
1067 for (int i = smallCount; i < count; ++i) {
1068 this->write(ByteCodeInstruction::kDup);
1069 }
1070 };
1071
Brian Osmana43d8202020-06-17 16:50:39 -04001072 if (intrin.is_special && intrin.special == SpecialIntrinsic::kSample) {
1073 // Sample is very special, the first argument is an FP, which can't be pushed to the stack
1074 if (c.fArguments.size() != 2 ||
1075 c.fArguments[0]->fType != *fContext.fFragmentProcessor_Type ||
1076 (c.fArguments[1]->fType != *fContext.fFloat2_Type &&
1077 c.fArguments[1]->fType != *fContext.fFloat3x3_Type)) {
1078 fErrors.error(c.fOffset, "Unsupported form of sample");
1079 return;
1080 }
1081
1082 // Write our coords or matrix
1083 this->writeExpression(*c.fArguments[1]);
1084
1085 this->write(c.fArguments[1]->fType == *fContext.fFloat3x3_Type
1086 ? ByteCodeInstruction::kSampleMatrix
1087 : ByteCodeInstruction::kSampleExplicit);
1088
1089 Location childLoc = this->getLocation(*c.fArguments[0]);
1090 SkASSERT(childLoc.fStorage == Storage::kChildFP);
1091 this->write8(childLoc.fSlot);
1092 return;
1093 }
1094
Brian Osmand5f937b2020-05-04 12:07:29 -04001095 if (intrin.is_special && (intrin.special == SpecialIntrinsic::kClamp ||
1096 intrin.special == SpecialIntrinsic::kSaturate)) {
1097 // These intrinsics are extra-special, we need instructions interleaved with arguments
1098 bool saturate = (intrin.special == SpecialIntrinsic::kSaturate);
1099 SkASSERT(c.fArguments.size() == (saturate ? 1 : 3));
1100 int limitCount = saturate ? 1 : SlotCount(c.fArguments[1]->fType);
1101
1102 // 'x'
1103 this->writeExpression(*c.fArguments[0]);
1104
1105 // 'minVal'
1106 if (saturate) {
1107 this->write(ByteCodeInstruction::kPushImmediate);
1108 this->write32(float_to_bits(0.0f));
1109 } else {
1110 this->writeExpression(*c.fArguments[1]);
1111 }
1112 dupSmallerType(limitCount);
1113 this->writeTypedInstruction(c.fArguments[0]->fType,
1114 ByteCodeInstruction::kMaxS,
1115 ByteCodeInstruction::kMaxS,
1116 ByteCodeInstruction::kMaxF,
1117 count);
1118
1119 // 'maxVal'
1120 if (saturate) {
1121 this->write(ByteCodeInstruction::kPushImmediate);
1122 this->write32(float_to_bits(1.0f));
1123 } else {
1124 SkASSERT(limitCount == SlotCount(c.fArguments[2]->fType));
1125 this->writeExpression(*c.fArguments[2]);
1126 }
1127 dupSmallerType(limitCount);
1128 this->writeTypedInstruction(c.fArguments[0]->fType,
1129 ByteCodeInstruction::kMinS,
1130 ByteCodeInstruction::kMinS,
1131 ByteCodeInstruction::kMinF,
1132 count);
1133 return;
1134 }
1135
1136 // All other intrinsics can handle their arguments being on the stack in order
1137 for (const auto& arg : c.fArguments) {
1138 this->writeExpression(*arg);
1139 }
1140
Mike Klein45be0772020-05-01 09:13:18 -05001141 if (intrin.is_special) {
1142 switch (intrin.special) {
Brian Osman8842b372020-05-01 15:07:49 -04001143 case SpecialIntrinsic::kAll: {
1144 for (int i = count-1; i --> 0;) {
1145 this->write(ByteCodeInstruction::kAndB);
1146 }
1147 } break;
1148
1149 case SpecialIntrinsic::kAny: {
1150 for (int i = count-1; i --> 0;) {
1151 this->write(ByteCodeInstruction::kOrB);
1152 }
1153 } break;
1154
Brian Osman15c98cb2020-02-27 18:36:57 +00001155 case SpecialIntrinsic::kDot: {
1156 SkASSERT(c.fArguments.size() == 2);
Brian Osmanb08cc022020-04-02 11:38:40 -04001157 SkASSERT(count == SlotCount(c.fArguments[1]->fType));
1158 this->write(vector_instruction(ByteCodeInstruction::kMultiplyF, count));
Mike Klein45be0772020-05-01 09:13:18 -05001159 for (int i = count-1; i --> 0;) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001160 this->write(ByteCodeInstruction::kAddF);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001161 }
Mike Klein45be0772020-05-01 09:13:18 -05001162 } break;
1163
1164 case SpecialIntrinsic::kLength: {
1165 SkASSERT(c.fArguments.size() == 1);
1166 this->write(vector_instruction(ByteCodeInstruction::kDup , count));
1167 this->write(vector_instruction(ByteCodeInstruction::kMultiplyF, count));
1168 for (int i = count-1; i --> 0;) {
1169 this->write(ByteCodeInstruction::kAddF);
1170 }
1171 this->write(ByteCodeInstruction::kSqrt);
1172 } break;
1173
Brian Osmand5f937b2020-05-04 12:07:29 -04001174 case SpecialIntrinsic::kMax:
1175 case SpecialIntrinsic::kMin: {
1176 SkASSERT(c.fArguments.size() == 2);
1177 // There are variants where the second argument is scalar
1178 dupSmallerType(SlotCount(c.fArguments[1]->fType));
1179 if (intrin.special == SpecialIntrinsic::kMax) {
1180 this->writeTypedInstruction(c.fArguments[0]->fType,
1181 ByteCodeInstruction::kMaxS,
1182 ByteCodeInstruction::kMaxS,
1183 ByteCodeInstruction::kMaxF,
1184 count);
1185 } else {
1186 this->writeTypedInstruction(c.fArguments[0]->fType,
1187 ByteCodeInstruction::kMinS,
1188 ByteCodeInstruction::kMinS,
1189 ByteCodeInstruction::kMinF,
1190 count);
1191 }
1192 } break;
1193
Brian Osman8842b372020-05-01 15:07:49 -04001194 case SpecialIntrinsic::kMix: {
1195 // Two main variants of mix to handle
1196 SkASSERT(c.fArguments.size() == 3);
1197 SkASSERT(count == SlotCount(c.fArguments[1]->fType));
1198 int selectorCount = SlotCount(c.fArguments[2]->fType);
1199
1200 if (is_generic_type(&c.fArguments[2]->fType, fContext.fGenBType_Type.get())) {
1201 // mix(genType, genType, genBoolType)
1202 SkASSERT(selectorCount == count);
1203 this->write(vector_instruction(ByteCodeInstruction::kMix, count));
1204 } else {
1205 // mix(genType, genType, genType) or mix(genType, genType, float)
Brian Osmand5f937b2020-05-04 12:07:29 -04001206 dupSmallerType(selectorCount);
Brian Osman8842b372020-05-01 15:07:49 -04001207 this->write(vector_instruction(ByteCodeInstruction::kLerp, count));
1208 }
1209 } break;
1210
Brian Osmanb08cc022020-04-02 11:38:40 -04001211 default:
1212 SkASSERT(false);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001213 }
1214 } else {
Brian Osman8842b372020-05-01 15:07:49 -04001215 switch (intrin.inst_f) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001216 case ByteCodeInstruction::kInverse2x2: {
1217 SkASSERT(c.fArguments.size() > 0);
1218 auto op = ByteCodeInstruction::kInverse2x2;
1219 switch (count) {
1220 case 4: break; // float2x2
1221 case 9: op = ByteCodeInstruction::kInverse3x3; break;
1222 case 16: op = ByteCodeInstruction::kInverse4x4; break;
1223 default: SkASSERT(false);
1224 }
1225 this->write(op);
1226 break;
Brian Osman15c98cb2020-02-27 18:36:57 +00001227 }
Mike Klein45be0772020-05-01 09:13:18 -05001228
Brian Osmanb08cc022020-04-02 11:38:40 -04001229 default:
Brian Osman8842b372020-05-01 15:07:49 -04001230 this->writeTypedInstruction(c.fArguments[0]->fType, intrin.inst_s, intrin.inst_u,
1231 intrin.inst_f, count);
1232 break;
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001233 }
1234 }
1235}
1236
Brian Osmanb08cc022020-04-02 11:38:40 -04001237void ByteCodeGenerator::writeFunctionCall(const FunctionCall& f) {
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001238 // Find the index of the function we're calling. We explicitly do not allow calls to functions
1239 // before they're defined. This is an easy-to-understand rule that prevents recursion.
Brian Osmanb08cc022020-04-02 11:38:40 -04001240 int idx = -1;
1241 for (size_t i = 0; i < fFunctions.size(); ++i) {
1242 if (f.fFunction.matches(fFunctions[i]->fDeclaration)) {
1243 idx = i;
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001244 break;
1245 }
1246 }
Brian Osmanb08cc022020-04-02 11:38:40 -04001247 if (idx == -1) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001248 this->writeIntrinsicCall(f);
1249 return;
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001250 }
Brian Osmanb08cc022020-04-02 11:38:40 -04001251
1252
1253 if (idx > 255) {
1254 fErrors.error(f.fOffset, "Function count limit exceeded");
1255 return;
1256 } else if (idx >= (int) fFunctions.size()) {
1257 fErrors.error(f.fOffset, "Call to undefined function");
1258 return;
1259 }
1260
1261 // We may need to deal with out parameters, so the sequence is tricky
1262 if (int returnCount = SlotCount(f.fType)) {
1263 this->write(ByteCodeInstruction::kReserve, returnCount);
1264 this->write8(returnCount);
1265 }
1266
1267 int argCount = f.fArguments.size();
1268 std::vector<std::unique_ptr<LValue>> lvalues;
1269 for (int i = 0; i < argCount; ++i) {
1270 const auto& param = f.fFunction.fParameters[i];
1271 const auto& arg = f.fArguments[i];
1272 if (param->fModifiers.fFlags & Modifiers::kOut_Flag) {
1273 lvalues.emplace_back(this->getLValue(*arg));
1274 lvalues.back()->load();
1275 } else {
1276 this->writeExpression(*arg);
1277 }
1278 }
1279
1280 // The space used by the call is based on the callee, but it also unwinds all of that before
1281 // we continue execution. We adjust our max stack depths below.
1282 this->write(ByteCodeInstruction::kCall);
1283 this->write8(idx);
1284
1285 const ByteCodeFunction* callee = fOutput->fFunctions[idx].get();
1286 fMaxLoopCount = std::max(fMaxLoopCount, fLoopCount + callee->fLoopCount);
1287 fMaxConditionCount = std::max(fMaxConditionCount, fConditionCount + callee->fConditionCount);
1288 fMaxStackCount = std::max(fMaxStackCount, fStackCount + callee->fLocalCount
1289 + callee->fStackCount);
1290
1291 // After the called function returns, the stack will still contain our arguments. We have to
1292 // pop them (storing any out parameters back to their lvalues as we go). We glob together slot
1293 // counts for all parameters that aren't out-params, so we can pop them in one big chunk.
1294 int popCount = 0;
1295 auto pop = [&]() {
1296 if (popCount > 4) {
1297 this->write(ByteCodeInstruction::kPopN, popCount);
1298 this->write8(popCount);
1299 } else if (popCount > 0) {
1300 this->write(vector_instruction(ByteCodeInstruction::kPop, popCount));
1301 }
1302 popCount = 0;
1303 };
1304
1305 for (int i = argCount - 1; i >= 0; --i) {
1306 const auto& param = f.fFunction.fParameters[i];
1307 const auto& arg = f.fArguments[i];
1308 if (param->fModifiers.fFlags & Modifiers::kOut_Flag) {
1309 pop();
1310 lvalues.back()->store(true);
1311 lvalues.pop_back();
1312 } else {
1313 popCount += SlotCount(arg->fType);
1314 }
1315 }
1316 pop();
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001317}
1318
Brian Osmanb08cc022020-04-02 11:38:40 -04001319void ByteCodeGenerator::writeIntLiteral(const IntLiteral& i) {
1320 this->write(ByteCodeInstruction::kPushImmediate);
1321 this->write32(i.fValue);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001322}
1323
Brian Osmanb08cc022020-04-02 11:38:40 -04001324void ByteCodeGenerator::writeNullLiteral(const NullLiteral& n) {
1325 // not yet implemented
1326 abort();
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001327}
1328
Brian Osmanb08cc022020-04-02 11:38:40 -04001329bool ByteCodeGenerator::writePrefixExpression(const PrefixExpression& p, bool discard) {
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001330 switch (p.fOperator) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001331 case Token::Kind::TK_PLUSPLUS: // fall through
1332 case Token::Kind::TK_MINUSMINUS: {
Brian Osmanb08cc022020-04-02 11:38:40 -04001333 SkASSERT(SlotCount(p.fOperand->fType) == 1);
1334 std::unique_ptr<LValue> lvalue = this->getLValue(*p.fOperand);
1335 lvalue->load();
1336 this->write(ByteCodeInstruction::kPushImmediate);
1337 this->write32(type_category(p.fType) == TypeCategory::kFloat ? float_to_bits(1.0f) : 1);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001338 if (p.fOperator == Token::Kind::TK_PLUSPLUS) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001339 this->writeTypedInstruction(p.fType,
1340 ByteCodeInstruction::kAddI,
1341 ByteCodeInstruction::kAddI,
1342 ByteCodeInstruction::kAddF,
1343 1);
1344 } else {
1345 this->writeTypedInstruction(p.fType,
1346 ByteCodeInstruction::kSubtractI,
1347 ByteCodeInstruction::kSubtractI,
1348 ByteCodeInstruction::kSubtractF,
1349 1);
1350 }
1351 lvalue->store(discard);
1352 discard = false;
1353 break;
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001354 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001355 case Token::Kind::TK_MINUS: {
Brian Osmanb08cc022020-04-02 11:38:40 -04001356 this->writeExpression(*p.fOperand);
1357 this->writeTypedInstruction(p.fType,
1358 ByteCodeInstruction::kNegateI,
1359 ByteCodeInstruction::kNegateI,
1360 ByteCodeInstruction::kNegateF,
Brian Osmanab8f3842020-04-07 09:30:44 -04001361 SlotCount(p.fOperand->fType));
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001362 break;
1363 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001364 case Token::Kind::TK_LOGICALNOT:
1365 case Token::Kind::TK_BITWISENOT: {
Brian Osmanb08cc022020-04-02 11:38:40 -04001366 SkASSERT(SlotCount(p.fOperand->fType) == 1);
1367 SkDEBUGCODE(TypeCategory tc = type_category(p.fOperand->fType));
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001368 SkASSERT((p.fOperator == Token::Kind::TK_LOGICALNOT && tc == TypeCategory::kBool) ||
1369 (p.fOperator == Token::Kind::TK_BITWISENOT && (tc == TypeCategory::kSigned ||
Brian Osmanb08cc022020-04-02 11:38:40 -04001370 tc == TypeCategory::kUnsigned)));
1371 this->writeExpression(*p.fOperand);
1372 this->write(ByteCodeInstruction::kNotB);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001373 break;
1374 }
1375 default:
1376 SkASSERT(false);
1377 }
Brian Osmanb08cc022020-04-02 11:38:40 -04001378 return discard;
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001379}
1380
Brian Osmanb08cc022020-04-02 11:38:40 -04001381bool ByteCodeGenerator::writePostfixExpression(const PostfixExpression& p, bool discard) {
1382 switch (p.fOperator) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001383 case Token::Kind::TK_PLUSPLUS: // fall through
1384 case Token::Kind::TK_MINUSMINUS: {
Brian Osmanb08cc022020-04-02 11:38:40 -04001385 SkASSERT(SlotCount(p.fOperand->fType) == 1);
1386 std::unique_ptr<LValue> lvalue = this->getLValue(*p.fOperand);
1387 lvalue->load();
1388 // If we're not supposed to discard the result, then make a copy *before* the +/-
1389 if (!discard) {
1390 this->write(ByteCodeInstruction::kDup);
Brian Osmanb08cc022020-04-02 11:38:40 -04001391 }
1392 this->write(ByteCodeInstruction::kPushImmediate);
1393 this->write32(type_category(p.fType) == TypeCategory::kFloat ? float_to_bits(1.0f) : 1);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001394 if (p.fOperator == Token::Kind::TK_PLUSPLUS) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001395 this->writeTypedInstruction(p.fType,
1396 ByteCodeInstruction::kAddI,
1397 ByteCodeInstruction::kAddI,
1398 ByteCodeInstruction::kAddF,
1399 1);
1400 } else {
1401 this->writeTypedInstruction(p.fType,
1402 ByteCodeInstruction::kSubtractI,
1403 ByteCodeInstruction::kSubtractI,
1404 ByteCodeInstruction::kSubtractF,
1405 1);
1406 }
1407 // Always consume the result as part of the store
1408 lvalue->store(true);
1409 discard = false;
1410 break;
1411 }
1412 default:
1413 SkASSERT(false);
1414 }
1415 return discard;
1416}
1417
1418void ByteCodeGenerator::writeSwizzle(const Swizzle& s) {
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001419 if (swizzle_is_simple(s)) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001420 this->writeVariableExpression(s);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001421 return;
1422 }
Brian Osmanb08cc022020-04-02 11:38:40 -04001423
Brian Osman3711c662020-06-18 14:42:21 -04001424 this->writeExpression(*s.fBase);
1425 this->write(ByteCodeInstruction::kSwizzle, s.fComponents.size() - s.fBase->fType.columns());
1426 this->write8(s.fBase->fType.columns());
1427 this->write8(s.fComponents.size());
1428 for (int c : s.fComponents) {
1429 this->write8(c);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001430 }
1431}
1432
Brian Osmanb08cc022020-04-02 11:38:40 -04001433void ByteCodeGenerator::writeTernaryExpression(const TernaryExpression& t) {
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001434 int count = SlotCount(t.fType);
1435 SkASSERT(count == SlotCount(t.fIfTrue->fType));
1436 SkASSERT(count == SlotCount(t.fIfFalse->fType));
1437
Brian Osmanb08cc022020-04-02 11:38:40 -04001438 this->writeExpression(*t.fTest);
1439 this->write(ByteCodeInstruction::kMaskPush);
1440 this->writeExpression(*t.fIfTrue);
1441 this->write(ByteCodeInstruction::kMaskNegate);
1442 this->writeExpression(*t.fIfFalse);
1443 this->write(ByteCodeInstruction::kMaskBlend, count);
1444 this->write8(count);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001445}
1446
Brian Osmanb08cc022020-04-02 11:38:40 -04001447void ByteCodeGenerator::writeExpression(const Expression& e, bool discard) {
1448 switch (e.fKind) {
1449 case Expression::kBinary_Kind:
1450 discard = this->writeBinaryExpression((BinaryExpression&) e, discard);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001451 break;
Brian Osmanb08cc022020-04-02 11:38:40 -04001452 case Expression::kBoolLiteral_Kind:
1453 this->writeBoolLiteral((BoolLiteral&) e);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001454 break;
Brian Osmanb08cc022020-04-02 11:38:40 -04001455 case Expression::kConstructor_Kind:
1456 this->writeConstructor((Constructor&) e);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001457 break;
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001458 case Expression::kExternalFunctionCall_Kind:
Brian Osmanb08cc022020-04-02 11:38:40 -04001459 this->writeExternalFunctionCall((ExternalFunctionCall&) e);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001460 break;
1461 case Expression::kExternalValue_Kind:
Brian Osmanb08cc022020-04-02 11:38:40 -04001462 this->writeExternalValue((ExternalValueReference&) e);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001463 break;
1464 case Expression::kFieldAccess_Kind:
1465 case Expression::kIndex_Kind:
1466 case Expression::kVariableReference_Kind:
Brian Osmanb08cc022020-04-02 11:38:40 -04001467 this->writeVariableExpression(e);
1468 break;
1469 case Expression::kFloatLiteral_Kind:
1470 this->writeFloatLiteral((FloatLiteral&) e);
1471 break;
1472 case Expression::kFunctionCall_Kind:
1473 this->writeFunctionCall((FunctionCall&) e);
1474 break;
1475 case Expression::kIntLiteral_Kind:
1476 this->writeIntLiteral((IntLiteral&) e);
1477 break;
1478 case Expression::kNullLiteral_Kind:
1479 this->writeNullLiteral((NullLiteral&) e);
1480 break;
1481 case Expression::kPrefix_Kind:
1482 discard = this->writePrefixExpression((PrefixExpression&) e, discard);
1483 break;
1484 case Expression::kPostfix_Kind:
1485 discard = this->writePostfixExpression((PostfixExpression&) e, discard);
1486 break;
1487 case Expression::kSwizzle_Kind:
1488 this->writeSwizzle((Swizzle&) e);
1489 break;
1490 case Expression::kTernary_Kind:
1491 this->writeTernaryExpression((TernaryExpression&) e);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001492 break;
Ben Wagner470e0ac2020-01-22 16:59:21 -05001493 default:
1494#ifdef SK_DEBUG
Brian Osmanb08cc022020-04-02 11:38:40 -04001495 printf("unsupported expression %s\n", e.description().c_str());
Ben Wagner470e0ac2020-01-22 16:59:21 -05001496#endif
Brian Osmanb08cc022020-04-02 11:38:40 -04001497 SkASSERT(false);
1498 }
1499 if (discard) {
1500 int count = SlotCount(e.fType);
1501 if (count > 4) {
1502 this->write(ByteCodeInstruction::kPopN, count);
1503 this->write8(count);
1504 } else if (count != 0) {
1505 this->write(vector_instruction(ByteCodeInstruction::kPop, count));
1506 }
1507 discard = false;
Ben Wagner470e0ac2020-01-22 16:59:21 -05001508 }
Ethan Nicholas7deb1c22020-01-22 10:31:55 -05001509}
1510
Brian Osmanb08cc022020-04-02 11:38:40 -04001511class ByteCodeExternalValueLValue : public ByteCodeGenerator::LValue {
1512public:
1513 ByteCodeExternalValueLValue(ByteCodeGenerator* generator, ExternalValue& value, int index)
1514 : INHERITED(*generator)
1515 , fCount(ByteCodeGenerator::SlotCount(value.type()))
1516 , fIndex(index) {}
1517
1518 void load() override {
1519 fGenerator.write(vector_instruction(ByteCodeInstruction::kReadExternal, fCount));
Brian Osmanb08cc022020-04-02 11:38:40 -04001520 fGenerator.write8(fIndex);
1521 }
1522
1523 void store(bool discard) override {
1524 if (!discard) {
1525 fGenerator.write(vector_instruction(ByteCodeInstruction::kDup, fCount));
Brian Osmanb08cc022020-04-02 11:38:40 -04001526 }
1527 fGenerator.write(vector_instruction(ByteCodeInstruction::kWriteExternal, fCount));
Brian Osmanb08cc022020-04-02 11:38:40 -04001528 fGenerator.write8(fIndex);
1529 }
1530
1531private:
1532 typedef LValue INHERITED;
1533
1534 int fCount;
1535
1536 int fIndex;
1537};
1538
1539class ByteCodeSwizzleLValue : public ByteCodeGenerator::LValue {
1540public:
1541 ByteCodeSwizzleLValue(ByteCodeGenerator* generator, const Swizzle& swizzle)
1542 : INHERITED(*generator)
1543 , fSwizzle(swizzle) {}
1544
1545 void load() override {
1546 fGenerator.writeSwizzle(fSwizzle);
1547 }
1548
1549 void store(bool discard) override {
1550 int count = fSwizzle.fComponents.size();
1551 if (!discard) {
1552 fGenerator.write(vector_instruction(ByteCodeInstruction::kDup, count));
Brian Osmanb08cc022020-04-02 11:38:40 -04001553 }
Brian Osman304dfa32020-06-18 15:53:51 -04001554 // We already have the correct number of values on the stack, thanks to type checking.
1555 // The algorithm: Walk down the values on the stack, doing 'count' single-element stores.
1556 // For each value, use the corresponding swizzle component to offset the store location.
1557 //
1558 // Static locations: We (wastefully) call getLocation every time, but get good byte code.
1559 // Note that we could (but don't) store adjacent/sequential values with fewer instructions.
1560 //
1561 // Dynamic locations: ... are bad. We have to recompute the base address on each iteration,
1562 // because the stack doesn't let us retain that address between stores. Dynamic locations
1563 // are rare though, and swizzled writes to those are even rarer, so we just live with this.
1564 for (int i = count; i-- > 0;) {
1565 ByteCodeGenerator::Location location = fGenerator.getLocation(*fSwizzle.fBase);
1566 if (!location.isOnStack()) {
1567 fGenerator.write(location.selectStore(ByteCodeInstruction::kStore,
1568 ByteCodeInstruction::kStoreGlobal));
1569 fGenerator.write8(location.fSlot + fSwizzle.fComponents[i]);
1570 } else {
1571 fGenerator.write(ByteCodeInstruction::kPushImmediate);
1572 fGenerator.write32(fSwizzle.fComponents[i]);
1573 fGenerator.write(ByteCodeInstruction::kAddI);
1574 fGenerator.write(location.selectStore(ByteCodeInstruction::kStoreExtended,
1575 ByteCodeInstruction::kStoreExtendedGlobal),
1576 1);
1577 fGenerator.write8(1);
1578 }
Brian Osmanb08cc022020-04-02 11:38:40 -04001579 }
1580 }
1581
1582private:
1583 const Swizzle& fSwizzle;
1584
1585 typedef LValue INHERITED;
1586};
1587
1588class ByteCodeExpressionLValue : public ByteCodeGenerator::LValue {
1589public:
1590 ByteCodeExpressionLValue(ByteCodeGenerator* generator, const Expression& expr)
1591 : INHERITED(*generator)
1592 , fExpression(expr) {}
1593
1594 void load() override {
1595 fGenerator.writeVariableExpression(fExpression);
1596 }
1597
1598 void store(bool discard) override {
1599 int count = ByteCodeGenerator::SlotCount(fExpression.fType);
1600 if (!discard) {
1601 if (count > 4) {
1602 fGenerator.write(ByteCodeInstruction::kDupN, count);
1603 fGenerator.write8(count);
1604 } else {
1605 fGenerator.write(vector_instruction(ByteCodeInstruction::kDup, count));
Brian Osmanb08cc022020-04-02 11:38:40 -04001606 }
1607 }
1608 ByteCodeGenerator::Location location = fGenerator.getLocation(fExpression);
1609 if (location.isOnStack() || count > 4) {
1610 if (!location.isOnStack()) {
1611 fGenerator.write(ByteCodeInstruction::kPushImmediate);
1612 fGenerator.write32(location.fSlot);
1613 }
1614 fGenerator.write(location.selectStore(ByteCodeInstruction::kStoreExtended,
1615 ByteCodeInstruction::kStoreExtendedGlobal),
1616 count);
1617 fGenerator.write8(count);
1618 } else {
1619 fGenerator.write(
1620 vector_instruction(location.selectStore(ByteCodeInstruction::kStore,
1621 ByteCodeInstruction::kStoreGlobal),
1622 count));
1623 fGenerator.write8(location.fSlot);
1624 }
1625 }
1626
1627private:
1628 typedef LValue INHERITED;
1629
1630 const Expression& fExpression;
1631};
1632
1633std::unique_ptr<ByteCodeGenerator::LValue> ByteCodeGenerator::getLValue(const Expression& e) {
1634 switch (e.fKind) {
1635 case Expression::kExternalValue_Kind: {
1636 ExternalValue* value = ((ExternalValueReference&) e).fValue;
1637 int index = fOutput->fExternalValues.size();
1638 fOutput->fExternalValues.push_back(value);
1639 SkASSERT(index <= 255);
1640 return std::unique_ptr<LValue>(new ByteCodeExternalValueLValue(this, *value, index));
1641 }
1642 case Expression::kFieldAccess_Kind:
1643 case Expression::kIndex_Kind:
1644 case Expression::kVariableReference_Kind:
1645 return std::unique_ptr<LValue>(new ByteCodeExpressionLValue(this, e));
1646 case Expression::kSwizzle_Kind: {
1647 const Swizzle& s = (const Swizzle&) e;
1648 return swizzle_is_simple(s)
1649 ? std::unique_ptr<LValue>(new ByteCodeExpressionLValue(this, e))
1650 : std::unique_ptr<LValue>(new ByteCodeSwizzleLValue(this, s));
1651 }
1652 case Expression::kTernary_Kind:
1653 default:
1654#ifdef SK_DEBUG
1655 ABORT("unsupported lvalue %s\n", e.description().c_str());
1656#endif
1657 return nullptr;
1658 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001659}
1660
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001661void ByteCodeGenerator::writeBlock(const Block& b) {
1662 for (const auto& s : b.fStatements) {
1663 this->writeStatement(*s);
1664 }
1665}
1666
Brian Osmanb08cc022020-04-02 11:38:40 -04001667void ByteCodeGenerator::setBreakTargets() {
1668 std::vector<DeferredLocation>& breaks = fBreakTargets.top();
1669 for (DeferredLocation& b : breaks) {
1670 b.set();
1671 }
1672 fBreakTargets.pop();
1673}
1674
1675void ByteCodeGenerator::setContinueTargets() {
1676 std::vector<DeferredLocation>& continues = fContinueTargets.top();
1677 for (DeferredLocation& c : continues) {
1678 c.set();
1679 }
1680 fContinueTargets.pop();
1681}
1682
1683void ByteCodeGenerator::writeBreakStatement(const BreakStatement& b) {
1684 // TODO: Include BranchIfAllFalse to top-most LoopNext
1685 this->write(ByteCodeInstruction::kLoopBreak);
1686}
1687
1688void ByteCodeGenerator::writeContinueStatement(const ContinueStatement& c) {
1689 // TODO: Include BranchIfAllFalse to top-most LoopNext
1690 this->write(ByteCodeInstruction::kLoopContinue);
1691}
1692
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001693void ByteCodeGenerator::writeDoStatement(const DoStatement& d) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001694 this->write(ByteCodeInstruction::kLoopBegin);
1695 size_t start = fCode->size();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001696 this->writeStatement(*d.fStatement);
Brian Osmanb08cc022020-04-02 11:38:40 -04001697 this->write(ByteCodeInstruction::kLoopNext);
1698 this->writeExpression(*d.fTest);
1699 this->write(ByteCodeInstruction::kLoopMask);
1700 // TODO: Could shorten this with kBranchIfAnyTrue
1701 this->write(ByteCodeInstruction::kBranchIfAllFalse);
Brian Osman569f12f2019-06-13 11:23:57 -04001702 DeferredLocation endLocation(this);
Brian Osmanb08cc022020-04-02 11:38:40 -04001703 this->write(ByteCodeInstruction::kBranch);
1704 this->write16(start);
Brian Osman569f12f2019-06-13 11:23:57 -04001705 endLocation.set();
Brian Osmanb08cc022020-04-02 11:38:40 -04001706 this->write(ByteCodeInstruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001707}
1708
1709void ByteCodeGenerator::writeForStatement(const ForStatement& f) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001710 fContinueTargets.emplace();
1711 fBreakTargets.emplace();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001712 if (f.fInitializer) {
1713 this->writeStatement(*f.fInitializer);
1714 }
Brian Osmanb08cc022020-04-02 11:38:40 -04001715 this->write(ByteCodeInstruction::kLoopBegin);
1716 size_t start = fCode->size();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001717 if (f.fTest) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001718 this->writeExpression(*f.fTest);
1719 this->write(ByteCodeInstruction::kLoopMask);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001720 }
Brian Osmanb08cc022020-04-02 11:38:40 -04001721 this->write(ByteCodeInstruction::kBranchIfAllFalse);
Brian Osman569f12f2019-06-13 11:23:57 -04001722 DeferredLocation endLocation(this);
1723 this->writeStatement(*f.fStatement);
Brian Osmanb08cc022020-04-02 11:38:40 -04001724 this->write(ByteCodeInstruction::kLoopNext);
Brian Osman569f12f2019-06-13 11:23:57 -04001725 if (f.fNext) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001726 this->writeExpression(*f.fNext, true);
Brian Osman569f12f2019-06-13 11:23:57 -04001727 }
Brian Osmanb08cc022020-04-02 11:38:40 -04001728 this->write(ByteCodeInstruction::kBranch);
1729 this->write16(start);
Brian Osman569f12f2019-06-13 11:23:57 -04001730 endLocation.set();
Brian Osmanb08cc022020-04-02 11:38:40 -04001731 this->write(ByteCodeInstruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001732}
1733
1734void ByteCodeGenerator::writeIfStatement(const IfStatement& i) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001735 this->writeExpression(*i.fTest);
1736 this->write(ByteCodeInstruction::kMaskPush);
1737 this->write(ByteCodeInstruction::kBranchIfAllFalse);
Brian Osman569f12f2019-06-13 11:23:57 -04001738 DeferredLocation falseLocation(this);
1739 this->writeStatement(*i.fIfTrue);
1740 falseLocation.set();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001741 if (i.fIfFalse) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001742 this->write(ByteCodeInstruction::kMaskNegate);
1743 this->write(ByteCodeInstruction::kBranchIfAllFalse);
Brian Osman569f12f2019-06-13 11:23:57 -04001744 DeferredLocation endLocation(this);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001745 this->writeStatement(*i.fIfFalse);
Mike Kleinb45ee832019-05-17 11:11:11 -05001746 endLocation.set();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001747 }
Brian Osmanb08cc022020-04-02 11:38:40 -04001748 this->write(ByteCodeInstruction::kMaskPop);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001749}
1750
Brian Osmanb08cc022020-04-02 11:38:40 -04001751void ByteCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
1752 if (fLoopCount || fConditionCount) {
Brian Osman4a47da72019-07-12 11:30:32 -04001753 fErrors.error(r.fOffset, "return not allowed inside conditional or loop");
1754 return;
1755 }
Brian Osmanb08cc022020-04-02 11:38:40 -04001756 int count = SlotCount(r.fExpression->fType);
1757 this->writeExpression(*r.fExpression);
1758
1759 // Technically, the kReturn also pops fOutput->fLocalCount values from the stack, too, but we
1760 // haven't counted pushing those (they're outside the scope of our stack tracking). Instead,
1761 // we account for those in writeFunction().
1762
1763 // This is all fine because we don't allow conditional returns, so we only return once anyway.
1764 this->write(ByteCodeInstruction::kReturn, -count);
1765 this->write8(count);
1766}
1767
1768void ByteCodeGenerator::writeSwitchStatement(const SwitchStatement& r) {
1769 // not yet implemented
1770 abort();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001771}
1772
1773void ByteCodeGenerator::writeVarDeclarations(const VarDeclarations& v) {
1774 for (const auto& declStatement : v.fVars) {
1775 const VarDeclaration& decl = (VarDeclaration&) *declStatement;
Brian Osmanb08cc022020-04-02 11:38:40 -04001776 // we need to grab the location even if we don't use it, to ensure it has been allocated
1777 Location location = this->getLocation(*decl.fVar);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001778 if (decl.fValue) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001779 this->writeExpression(*decl.fValue);
1780 int count = SlotCount(decl.fValue->fType);
1781 if (count > 4) {
1782 this->write(ByteCodeInstruction::kPushImmediate);
1783 this->write32(location.fSlot);
1784 this->write(ByteCodeInstruction::kStoreExtended, count);
1785 this->write8(count);
1786 } else {
1787 this->write(vector_instruction(ByteCodeInstruction::kStore, count));
1788 this->write8(location.fSlot);
1789 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001790 }
1791 }
1792}
1793
1794void ByteCodeGenerator::writeWhileStatement(const WhileStatement& w) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001795 this->write(ByteCodeInstruction::kLoopBegin);
1796 size_t cond = fCode->size();
1797 this->writeExpression(*w.fTest);
1798 this->write(ByteCodeInstruction::kLoopMask);
1799 this->write(ByteCodeInstruction::kBranchIfAllFalse);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001800 DeferredLocation endLocation(this);
1801 this->writeStatement(*w.fStatement);
Brian Osmanb08cc022020-04-02 11:38:40 -04001802 this->write(ByteCodeInstruction::kLoopNext);
1803 this->write(ByteCodeInstruction::kBranch);
1804 this->write16(cond);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001805 endLocation.set();
Brian Osmanb08cc022020-04-02 11:38:40 -04001806 this->write(ByteCodeInstruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001807}
1808
1809void ByteCodeGenerator::writeStatement(const Statement& s) {
1810 switch (s.fKind) {
1811 case Statement::kBlock_Kind:
1812 this->writeBlock((Block&) s);
1813 break;
1814 case Statement::kBreak_Kind:
Brian Osmanb08cc022020-04-02 11:38:40 -04001815 this->writeBreakStatement((BreakStatement&) s);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001816 break;
1817 case Statement::kContinue_Kind:
Brian Osmanb08cc022020-04-02 11:38:40 -04001818 this->writeContinueStatement((ContinueStatement&) s);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001819 break;
Brian Osmanb08cc022020-04-02 11:38:40 -04001820 case Statement::kDiscard_Kind:
1821 // not yet implemented
1822 abort();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001823 case Statement::kDo_Kind:
1824 this->writeDoStatement((DoStatement&) s);
1825 break;
Brian Osman3e29f1d2019-05-28 09:35:05 -04001826 case Statement::kExpression_Kind:
Brian Osmanb08cc022020-04-02 11:38:40 -04001827 this->writeExpression(*((ExpressionStatement&) s).fExpression, true);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001828 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001829 case Statement::kFor_Kind:
1830 this->writeForStatement((ForStatement&) s);
1831 break;
1832 case Statement::kIf_Kind:
1833 this->writeIfStatement((IfStatement&) s);
1834 break;
1835 case Statement::kNop_Kind:
1836 break;
1837 case Statement::kReturn_Kind:
Brian Osmanb08cc022020-04-02 11:38:40 -04001838 this->writeReturnStatement((ReturnStatement&) s);
1839 break;
1840 case Statement::kSwitch_Kind:
1841 this->writeSwitchStatement((SwitchStatement&) s);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001842 break;
1843 case Statement::kVarDeclarations_Kind:
1844 this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration);
1845 break;
1846 case Statement::kWhile_Kind:
1847 this->writeWhileStatement((WhileStatement&) s);
1848 break;
1849 default:
Brian Osmanb08cc022020-04-02 11:38:40 -04001850 SkASSERT(false);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001851 }
1852}
1853
Brian Osmanb08cc022020-04-02 11:38:40 -04001854ByteCodeFunction::ByteCodeFunction(const FunctionDeclaration* declaration)
1855 : fName(declaration->fName) {
Brian Osman80164412019-06-07 13:00:23 -04001856 fParameterCount = 0;
Brian Osmanb08cc022020-04-02 11:38:40 -04001857 for (const auto& p : declaration->fParameters) {
1858 int slots = ByteCodeGenerator::SlotCount(p->fType);
1859 fParameters.push_back({ slots, (bool)(p->fModifiers.fFlags & Modifiers::kOut_Flag) });
1860 fParameterCount += slots;
Brian Osman80164412019-06-07 13:00:23 -04001861 }
1862}
1863
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001864}