blob: d692daf8c99af71fced6fecbc42b550d518af7f6 [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 Osmaneadfeb92020-01-09 12:43:03 -050075static inline bool is_in(const SkSL::Variable& var) {
76 return var.fModifiers.fFlags & Modifiers::kIn_Flag;
77}
78
Brian Osman5b431132019-10-15 16:41:18 -040079void ByteCodeGenerator::gatherUniforms(const Type& type, const String& name) {
80 if (type.kind() == Type::kOther_Kind) {
81 return;
82 } else if (type.kind() == Type::kStruct_Kind) {
83 for (const auto& f : type.fields()) {
84 this->gatherUniforms(*f.fType, name + "." + f.fName);
85 }
86 } else if (type.kind() == Type::kArray_Kind) {
87 for (int i = 0; i < type.columns(); ++i) {
88 this->gatherUniforms(type.componentType(), String::printf("%s[%d]", name.c_str(), i));
89 }
90 } else {
91 fOutput->fUniforms.push_back({ name, type_category(type), type.rows(), type.columns(),
92 fOutput->fUniformSlotCount });
93 fOutput->fUniformSlotCount += type.columns() * type.rows();
94 }
95}
96
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040097bool ByteCodeGenerator::generateCode() {
98 for (const auto& e : fProgram) {
99 switch (e.fKind) {
100 case ProgramElement::kFunction_Kind: {
101 std::unique_ptr<ByteCodeFunction> f = this->writeFunction((FunctionDefinition&) e);
102 if (!f) {
103 return false;
104 }
105 fOutput->fFunctions.push_back(std::move(f));
Brian Osman80164412019-06-07 13:00:23 -0400106 fFunctions.push_back(&(FunctionDefinition&)e);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400107 break;
108 }
109 case ProgramElement::kVar_Kind: {
110 VarDeclarations& decl = (VarDeclarations&) e;
111 for (const auto& v : decl.fVars) {
112 const Variable* declVar = ((VarDeclaration&) *v).fVar;
Brian Osmaneadfeb92020-01-09 12:43:03 -0500113 if (declVar->fModifiers.fLayout.fBuiltin >= 0 || is_in(*declVar)) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400114 continue;
115 }
Brian Osman1c110a02019-10-01 14:53:32 -0400116 if (is_uniform(*declVar)) {
Brian Osman5b431132019-10-15 16:41:18 -0400117 this->gatherUniforms(declVar->fType, declVar->fName);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400118 } else {
Brian Osman1c110a02019-10-01 14:53:32 -0400119 fOutput->fGlobalSlotCount += SlotCount(declVar->fType);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400120 }
121 }
122 break;
123 }
124 default:
125 ; // ignore
126 }
127 }
Brian Osman6f5358f2019-07-09 14:17:23 -0400128 return 0 == fErrors.errorCount();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400129}
130
131std::unique_ptr<ByteCodeFunction> ByteCodeGenerator::writeFunction(const FunctionDefinition& f) {
132 fFunction = &f;
Brian Osman226668a2019-05-14 16:47:30 -0400133 std::unique_ptr<ByteCodeFunction> result(new ByteCodeFunction(&f.fDeclaration));
Brian Osman80164412019-06-07 13:00:23 -0400134 fParameterCount = result->fParameterCount;
Brian Osman4a47da72019-07-12 11:30:32 -0400135 fLoopCount = fMaxLoopCount = 0;
136 fConditionCount = fMaxConditionCount = 0;
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400137 fStackCount = fMaxStackCount = 0;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400138 fCode = &result->fCode;
Brian Osman4a47da72019-07-12 11:30:32 -0400139
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400140 this->writeStatement(*f.fBody);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400141 if (0 == fErrors.errorCount()) {
142 SkASSERT(fLoopCount == 0);
143 SkASSERT(fConditionCount == 0);
144 SkASSERT(fStackCount == 0);
145 }
146 this->write(ByteCodeInstruction::kReturn, 0);
Ethan Nicholas7e603db2019-05-03 12:57:47 -0400147 this->write8(0);
Brian Osman4a47da72019-07-12 11:30:32 -0400148
149 result->fLocalCount = fLocals.size();
150 result->fConditionCount = fMaxConditionCount;
151 result->fLoopCount = fMaxLoopCount;
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400152 result->fStackCount = fMaxStackCount;
Brian Osman4a47da72019-07-12 11:30:32 -0400153
Ethan Nicholasdfcad062019-05-07 12:53:34 -0400154 const Type& returnType = f.fDeclaration.fReturnType;
155 if (returnType != *fContext.fVoid_Type) {
Brian Osman07c117b2019-05-23 12:51:06 -0700156 result->fReturnCount = SlotCount(returnType);
Ethan Nicholasdfcad062019-05-07 12:53:34 -0400157 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400158 fLocals.clear();
159 fFunction = nullptr;
160 return result;
161}
162
Brian Osman0785db02019-05-24 14:19:11 -0400163// A "simple" Swizzle is based on a variable (or a compound variable like a struct or array), and
164// that references consecutive values, such that it can be implemented using normal load/store ops
165// with an offset. Note that all single-component swizzles (of suitable base types) are simple.
166static bool swizzle_is_simple(const Swizzle& s) {
167 switch (s.fBase->fKind) {
168 case Expression::kFieldAccess_Kind:
169 case Expression::kIndex_Kind:
170 case Expression::kVariableReference_Kind:
171 break;
172 default:
173 return false;
174 }
175
176 for (size_t i = 1; i < s.fComponents.size(); ++i) {
177 if (s.fComponents[i] != s.fComponents[i - 1] + 1) {
178 return false;
179 }
180 }
181 return true;
182}
183
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400184int ByteCodeGenerator::StackUsage(ByteCodeInstruction inst, int count_) {
185 // Ensures that we use count iff we're passed a non-default value. Most instructions have an
186 // implicit count, so the caller shouldn't need to worry about it (or count makes no sense).
187 // The asserts avoids callers thinking they're supplying useful information in that scenario,
188 // or failing to supply necessary information for the ops that need a count.
189 struct CountValue {
190 operator int() {
191 SkASSERT(val != ByteCodeGenerator::kUnusedStackCount);
192 SkDEBUGCODE(used = true);
193 return val;
194 }
195 ~CountValue() {
196 SkASSERT(used || val == ByteCodeGenerator::kUnusedStackCount);
197 }
198 int val;
199 SkDEBUGCODE(bool used = false;)
200 } count = { count_ };
201
202 switch (inst) {
203 // Unary functions/operators that don't change stack depth at all:
204#define VECTOR_UNARY_OP(base) \
205 case ByteCodeInstruction::base: \
206 case ByteCodeInstruction::base ## 2: \
207 case ByteCodeInstruction::base ## 3: \
208 case ByteCodeInstruction::base ## 4: \
209 return 0;
210
211 VECTOR_UNARY_OP(kConvertFtoI)
212 VECTOR_UNARY_OP(kConvertStoF)
213 VECTOR_UNARY_OP(kConvertUtoF)
214
215 VECTOR_UNARY_OP(kCos)
216 VECTOR_UNARY_OP(kSin)
217 VECTOR_UNARY_OP(kSqrt)
218 VECTOR_UNARY_OP(kTan)
219
220 VECTOR_UNARY_OP(kNegateF)
221 VECTOR_UNARY_OP(kNegateI)
222
Mike Reed634c9412019-07-18 13:20:04 -0400223 case ByteCodeInstruction::kInverse2x2:
224 case ByteCodeInstruction::kInverse3x3:
225 case ByteCodeInstruction::kInverse4x4: return 0;
226
Brian Osman869a3e82019-07-18 17:00:34 -0400227 case ByteCodeInstruction::kClampIndex: return 0;
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400228 case ByteCodeInstruction::kNotB: return 0;
229 case ByteCodeInstruction::kNegateFN: return 0;
Brian Osman4c2146f2019-09-24 09:39:38 -0400230 case ByteCodeInstruction::kShiftLeft: return 0;
231 case ByteCodeInstruction::kShiftRightS: return 0;
232 case ByteCodeInstruction::kShiftRightU: return 0;
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400233
234#undef VECTOR_UNARY_OP
235
236 // Binary functions/operators that do a 2 -> 1 reduction (possibly N times)
237#define VECTOR_BINARY_OP(base) \
238 case ByteCodeInstruction::base: return -1; \
239 case ByteCodeInstruction::base ## 2: return -2; \
240 case ByteCodeInstruction::base ## 3: return -3; \
241 case ByteCodeInstruction::base ## 4: return -4;
242
243#define VECTOR_MATRIX_BINARY_OP(base) \
244 VECTOR_BINARY_OP(base) \
245 case ByteCodeInstruction::base ## N: return -count;
246
247 case ByteCodeInstruction::kAndB: return -1;
248 case ByteCodeInstruction::kOrB: return -1;
249 case ByteCodeInstruction::kXorB: return -1;
250
251 VECTOR_BINARY_OP(kAddI)
252 VECTOR_MATRIX_BINARY_OP(kAddF)
253
254 VECTOR_BINARY_OP(kCompareIEQ)
255 VECTOR_MATRIX_BINARY_OP(kCompareFEQ)
256 VECTOR_BINARY_OP(kCompareINEQ)
257 VECTOR_MATRIX_BINARY_OP(kCompareFNEQ)
258 VECTOR_BINARY_OP(kCompareSGT)
259 VECTOR_BINARY_OP(kCompareUGT)
260 VECTOR_BINARY_OP(kCompareFGT)
261 VECTOR_BINARY_OP(kCompareSGTEQ)
262 VECTOR_BINARY_OP(kCompareUGTEQ)
263 VECTOR_BINARY_OP(kCompareFGTEQ)
264 VECTOR_BINARY_OP(kCompareSLT)
265 VECTOR_BINARY_OP(kCompareULT)
266 VECTOR_BINARY_OP(kCompareFLT)
267 VECTOR_BINARY_OP(kCompareSLTEQ)
268 VECTOR_BINARY_OP(kCompareULTEQ)
269 VECTOR_BINARY_OP(kCompareFLTEQ)
270
271 VECTOR_BINARY_OP(kDivideS)
272 VECTOR_BINARY_OP(kDivideU)
273 VECTOR_MATRIX_BINARY_OP(kDivideF)
274 VECTOR_BINARY_OP(kMultiplyI)
275 VECTOR_MATRIX_BINARY_OP(kMultiplyF)
276 VECTOR_BINARY_OP(kRemainderF)
277 VECTOR_BINARY_OP(kRemainderS)
278 VECTOR_BINARY_OP(kRemainderU)
279 VECTOR_BINARY_OP(kSubtractI)
280 VECTOR_MATRIX_BINARY_OP(kSubtractF)
281
282#undef VECTOR_BINARY_OP
283#undef VECTOR_MATRIX_BINARY_OP
284
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400285 // Ops that push or load data to grow the stack:
286 case ByteCodeInstruction::kDup:
287 case ByteCodeInstruction::kLoad:
288 case ByteCodeInstruction::kLoadGlobal:
Brian Osman1c110a02019-10-01 14:53:32 -0400289 case ByteCodeInstruction::kLoadUniform:
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400290 case ByteCodeInstruction::kReadExternal:
291 case ByteCodeInstruction::kPushImmediate:
292 return 1;
293
294 case ByteCodeInstruction::kDup2:
295 case ByteCodeInstruction::kLoad2:
296 case ByteCodeInstruction::kLoadGlobal2:
Brian Osman1c110a02019-10-01 14:53:32 -0400297 case ByteCodeInstruction::kLoadUniform2:
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400298 case ByteCodeInstruction::kReadExternal2:
299 return 2;
300
301 case ByteCodeInstruction::kDup3:
302 case ByteCodeInstruction::kLoad3:
303 case ByteCodeInstruction::kLoadGlobal3:
Brian Osman1c110a02019-10-01 14:53:32 -0400304 case ByteCodeInstruction::kLoadUniform3:
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400305 case ByteCodeInstruction::kReadExternal3:
306 return 3;
307
308 case ByteCodeInstruction::kDup4:
309 case ByteCodeInstruction::kLoad4:
310 case ByteCodeInstruction::kLoadGlobal4:
Brian Osman1c110a02019-10-01 14:53:32 -0400311 case ByteCodeInstruction::kLoadUniform4:
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400312 case ByteCodeInstruction::kReadExternal4:
313 return 4;
314
315 case ByteCodeInstruction::kDupN:
316 case ByteCodeInstruction::kLoadSwizzle:
317 case ByteCodeInstruction::kLoadSwizzleGlobal:
Brian Osman1c110a02019-10-01 14:53:32 -0400318 case ByteCodeInstruction::kLoadSwizzleUniform:
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400319 return count;
320
321 // Pushes 'count' values, minus one for the 'address' that's consumed first
322 case ByteCodeInstruction::kLoadExtended:
323 case ByteCodeInstruction::kLoadExtendedGlobal:
Brian Osman1c110a02019-10-01 14:53:32 -0400324 case ByteCodeInstruction::kLoadExtendedUniform:
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400325 return count - 1;
326
327 // Ops that pop or store data to shrink the stack:
328 case ByteCodeInstruction::kPop:
329 case ByteCodeInstruction::kStore:
330 case ByteCodeInstruction::kStoreGlobal:
331 case ByteCodeInstruction::kWriteExternal:
332 return -1;
333
334 case ByteCodeInstruction::kPop2:
335 case ByteCodeInstruction::kStore2:
336 case ByteCodeInstruction::kStoreGlobal2:
337 case ByteCodeInstruction::kWriteExternal2:
338 return -2;
339
340 case ByteCodeInstruction::kPop3:
341 case ByteCodeInstruction::kStore3:
342 case ByteCodeInstruction::kStoreGlobal3:
343 case ByteCodeInstruction::kWriteExternal3:
344 return -3;
345
346 case ByteCodeInstruction::kPop4:
347 case ByteCodeInstruction::kStore4:
348 case ByteCodeInstruction::kStoreGlobal4:
349 case ByteCodeInstruction::kWriteExternal4:
350 return -4;
351
352 case ByteCodeInstruction::kPopN:
353 case ByteCodeInstruction::kStoreSwizzle:
354 case ByteCodeInstruction::kStoreSwizzleGlobal:
355 return -count;
356
357 // Consumes 'count' values, plus one for the 'address'
358 case ByteCodeInstruction::kStoreExtended:
359 case ByteCodeInstruction::kStoreExtendedGlobal:
360 case ByteCodeInstruction::kStoreSwizzleIndirect:
361 case ByteCodeInstruction::kStoreSwizzleIndirectGlobal:
362 return -count - 1;
363
364 // Strange ops where the caller computes the delta for us:
365 case ByteCodeInstruction::kCallExternal:
366 case ByteCodeInstruction::kMatrixToMatrix:
367 case ByteCodeInstruction::kMatrixMultiply:
368 case ByteCodeInstruction::kReserve:
369 case ByteCodeInstruction::kReturn:
370 case ByteCodeInstruction::kScalarToMatrix:
371 case ByteCodeInstruction::kSwizzle:
372 return count;
373
374 // Miscellaneous
375
376 // kCall is net-zero. Max stack depth is adjusted in writeFunctionCall.
377 case ByteCodeInstruction::kCall: return 0;
378 case ByteCodeInstruction::kBranch: return 0;
379 case ByteCodeInstruction::kBranchIfAllFalse: return 0;
380
381 case ByteCodeInstruction::kMaskPush: return -1;
382 case ByteCodeInstruction::kMaskPop: return 0;
383 case ByteCodeInstruction::kMaskNegate: return 0;
384 case ByteCodeInstruction::kMaskBlend: return -count;
385
386 case ByteCodeInstruction::kLoopBegin: return 0;
387 case ByteCodeInstruction::kLoopNext: return 0;
388 case ByteCodeInstruction::kLoopMask: return -1;
389 case ByteCodeInstruction::kLoopEnd: return 0;
390 case ByteCodeInstruction::kLoopBreak: return 0;
391 case ByteCodeInstruction::kLoopContinue: return 0;
392
393 default:
Brian Osmanc7ec9e22019-07-16 08:49:11 -0400394 ABORT("unsupported instruction %d\n", (int)inst);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400395 return 0;
396 }
397}
398
Brian Osman1c110a02019-10-01 14:53:32 -0400399ByteCodeGenerator::Location ByteCodeGenerator::getLocation(const Variable& var) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400400 // given that we seldom have more than a couple of variables, linear search is probably the most
401 // efficient way to handle lookups
402 switch (var.fStorage) {
403 case Variable::kLocal_Storage: {
404 for (int i = fLocals.size() - 1; i >= 0; --i) {
405 if (fLocals[i] == &var) {
Brian Osman1091f022019-05-16 09:42:16 -0400406 SkASSERT(fParameterCount + i <= 255);
Brian Osman1c110a02019-10-01 14:53:32 -0400407 return { fParameterCount + i, Storage::kLocal };
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400408 }
409 }
410 int result = fParameterCount + fLocals.size();
411 fLocals.push_back(&var);
Brian Osman07c117b2019-05-23 12:51:06 -0700412 for (int i = 0; i < SlotCount(var.fType) - 1; ++i) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400413 fLocals.push_back(nullptr);
414 }
Brian Osman1091f022019-05-16 09:42:16 -0400415 SkASSERT(result <= 255);
Brian Osman1c110a02019-10-01 14:53:32 -0400416 return { result, Storage::kLocal };
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400417 }
418 case Variable::kParameter_Storage: {
419 int offset = 0;
420 for (const auto& p : fFunction->fDeclaration.fParameters) {
421 if (p == &var) {
Brian Osman1091f022019-05-16 09:42:16 -0400422 SkASSERT(offset <= 255);
Brian Osman1c110a02019-10-01 14:53:32 -0400423 return { offset, Storage::kLocal };
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400424 }
Brian Osman07c117b2019-05-23 12:51:06 -0700425 offset += SlotCount(p->fType);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400426 }
427 SkASSERT(false);
Brian Osman1c110a02019-10-01 14:53:32 -0400428 return Location::MakeInvalid();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400429 }
430 case Variable::kGlobal_Storage: {
Brian Osmaneadfeb92020-01-09 12:43:03 -0500431 if (is_in(var)) {
432 // If you trip this assert, it means the program is using raw 'in' variables. You
433 // should either specialize the program (Compiler::specialize) to bake in the final
434 // values of the 'in' variables, or not use 'in' variables (maybe you meant to use
435 // 'uniform' instead?).
436 SkASSERT(false);
437 return Location::MakeInvalid();
438 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400439 int offset = 0;
Brian Osman1c110a02019-10-01 14:53:32 -0400440 bool isUniform = is_uniform(var);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400441 for (const auto& e : fProgram) {
442 if (e.fKind == ProgramElement::kVar_Kind) {
443 VarDeclarations& decl = (VarDeclarations&) e;
444 for (const auto& v : decl.fVars) {
445 const Variable* declVar = ((VarDeclaration&) *v).fVar;
Brian Osmaneadfeb92020-01-09 12:43:03 -0500446 if (declVar->fModifiers.fLayout.fBuiltin >= 0 || is_in(*declVar)) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400447 continue;
448 }
Brian Osman1c110a02019-10-01 14:53:32 -0400449 if (isUniform != is_uniform(*declVar)) {
450 continue;
451 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400452 if (declVar == &var) {
Brian Osmanb7451292019-05-15 13:02:13 -0400453 SkASSERT(offset <= 255);
Brian Osman1c110a02019-10-01 14:53:32 -0400454 return { offset, isUniform ? Storage::kUniform : Storage::kGlobal };
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400455 }
Brian Osman07c117b2019-05-23 12:51:06 -0700456 offset += SlotCount(declVar->fType);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400457 }
458 }
459 }
460 SkASSERT(false);
Brian Osman1c110a02019-10-01 14:53:32 -0400461 return Location::MakeInvalid();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400462 }
463 default:
464 SkASSERT(false);
Brian Osman1c110a02019-10-01 14:53:32 -0400465 return Location::MakeInvalid();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400466 }
467}
468
Brian Osman1c110a02019-10-01 14:53:32 -0400469ByteCodeGenerator::Location ByteCodeGenerator::getLocation(const Expression& expr) {
Brian Osman07c117b2019-05-23 12:51:06 -0700470 switch (expr.fKind) {
471 case Expression::kFieldAccess_Kind: {
472 const FieldAccess& f = (const FieldAccess&)expr;
Brian Osman1c110a02019-10-01 14:53:32 -0400473 Location baseLoc = this->getLocation(*f.fBase);
Brian Osman07c117b2019-05-23 12:51:06 -0700474 int offset = 0;
475 for (int i = 0; i < f.fFieldIndex; ++i) {
476 offset += SlotCount(*f.fBase->fType.fields()[i].fType);
477 }
Brian Osman1c110a02019-10-01 14:53:32 -0400478 if (baseLoc.isOnStack()) {
Brian Osman86769292019-06-21 11:05:47 -0400479 if (offset != 0) {
480 this->write(ByteCodeInstruction::kPushImmediate);
481 this->write32(offset);
482 this->write(ByteCodeInstruction::kAddI);
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400483 this->write8(1);
Brian Osman86769292019-06-21 11:05:47 -0400484 }
Brian Osman1c110a02019-10-01 14:53:32 -0400485 return baseLoc;
Brian Osman07c117b2019-05-23 12:51:06 -0700486 } else {
Brian Osman1c110a02019-10-01 14:53:32 -0400487 return baseLoc + offset;
Brian Osman07c117b2019-05-23 12:51:06 -0700488 }
489 }
490 case Expression::kIndex_Kind: {
491 const IndexExpression& i = (const IndexExpression&)expr;
492 int stride = SlotCount(i.fType);
Brian Osman869a3e82019-07-18 17:00:34 -0400493 int length = i.fBase->fType.columns();
494 SkASSERT(length <= 255);
Brian Osman07c117b2019-05-23 12:51:06 -0700495 int offset = -1;
496 if (i.fIndex->isConstant()) {
Brian Osman869a3e82019-07-18 17:00:34 -0400497 int64_t index = i.fIndex->getConstantInt();
498 if (index < 0 || index >= length) {
499 fErrors.error(i.fIndex->fOffset, "Array index out of bounds.");
Brian Osman1c110a02019-10-01 14:53:32 -0400500 return Location::MakeInvalid();
Brian Osman869a3e82019-07-18 17:00:34 -0400501 }
502 offset = index * stride;
Brian Osman07c117b2019-05-23 12:51:06 -0700503 } else {
Brian Osman86769292019-06-21 11:05:47 -0400504 if (i.fIndex->hasSideEffects()) {
505 // Having a side-effect in an indexer is technically safe for an rvalue,
506 // but with lvalues we have to evaluate the indexer twice, so make it an error.
507 fErrors.error(i.fIndex->fOffset,
508 "Index expressions with side-effects not supported in byte code.");
Brian Osman1c110a02019-10-01 14:53:32 -0400509 return Location::MakeInvalid();
Brian Osman86769292019-06-21 11:05:47 -0400510 }
Brian Osman07c117b2019-05-23 12:51:06 -0700511 this->writeExpression(*i.fIndex);
Brian Osman869a3e82019-07-18 17:00:34 -0400512 this->write(ByteCodeInstruction::kClampIndex);
513 this->write8(length);
Brian Osman86769292019-06-21 11:05:47 -0400514 if (stride != 1) {
515 this->write(ByteCodeInstruction::kPushImmediate);
516 this->write32(stride);
517 this->write(ByteCodeInstruction::kMultiplyI);
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400518 this->write8(1);
Brian Osman86769292019-06-21 11:05:47 -0400519 }
Brian Osman07c117b2019-05-23 12:51:06 -0700520 }
Brian Osman1c110a02019-10-01 14:53:32 -0400521 Location baseLoc = this->getLocation(*i.fBase);
Brian Osman86769292019-06-21 11:05:47 -0400522
523 // Are both components known statically?
Brian Osman1c110a02019-10-01 14:53:32 -0400524 if (!baseLoc.isOnStack() && offset >= 0) {
525 return baseLoc + offset;
Brian Osman07c117b2019-05-23 12:51:06 -0700526 }
Brian Osman86769292019-06-21 11:05:47 -0400527
528 // At least one component is dynamic (and on the stack).
529
530 // If the other component is zero, we're done
Brian Osman1c110a02019-10-01 14:53:32 -0400531 if (baseLoc.fSlot == 0 || offset == 0) {
532 return baseLoc.makeOnStack();
Brian Osman86769292019-06-21 11:05:47 -0400533 }
534
535 // Push the non-dynamic component (if any) to the stack, then add the two
Brian Osman1c110a02019-10-01 14:53:32 -0400536 if (!baseLoc.isOnStack()) {
Brian Osman07c117b2019-05-23 12:51:06 -0700537 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osman1c110a02019-10-01 14:53:32 -0400538 this->write32(baseLoc.fSlot);
Brian Osman07c117b2019-05-23 12:51:06 -0700539 }
540 if (offset >= 0) {
541 this->write(ByteCodeInstruction::kPushImmediate);
542 this->write32(offset);
543 }
544 this->write(ByteCodeInstruction::kAddI);
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400545 this->write8(1);
Brian Osman1c110a02019-10-01 14:53:32 -0400546 return baseLoc.makeOnStack();
Brian Osman07c117b2019-05-23 12:51:06 -0700547 }
Brian Osman0785db02019-05-24 14:19:11 -0400548 case Expression::kSwizzle_Kind: {
549 const Swizzle& s = (const Swizzle&)expr;
550 SkASSERT(swizzle_is_simple(s));
Brian Osman1c110a02019-10-01 14:53:32 -0400551 Location baseLoc = this->getLocation(*s.fBase);
Brian Osman0785db02019-05-24 14:19:11 -0400552 int offset = s.fComponents[0];
Brian Osman1c110a02019-10-01 14:53:32 -0400553 if (baseLoc.isOnStack()) {
Brian Osman86769292019-06-21 11:05:47 -0400554 if (offset != 0) {
555 this->write(ByteCodeInstruction::kPushImmediate);
556 this->write32(offset);
557 this->write(ByteCodeInstruction::kAddI);
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400558 this->write8(1);
Brian Osman86769292019-06-21 11:05:47 -0400559 }
Brian Osman1c110a02019-10-01 14:53:32 -0400560 return baseLoc;
Brian Osman0785db02019-05-24 14:19:11 -0400561 } else {
Brian Osman1c110a02019-10-01 14:53:32 -0400562 return baseLoc + offset;
Brian Osman0785db02019-05-24 14:19:11 -0400563 }
564 }
Brian Osman07c117b2019-05-23 12:51:06 -0700565 case Expression::kVariableReference_Kind: {
566 const Variable& var = ((const VariableReference&)expr).fVariable;
Brian Osman07c117b2019-05-23 12:51:06 -0700567 return this->getLocation(var);
568 }
569 default:
570 SkASSERT(false);
Brian Osman1c110a02019-10-01 14:53:32 -0400571 return Location::MakeInvalid();
Brian Osman07c117b2019-05-23 12:51:06 -0700572 }
573}
574
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400575void ByteCodeGenerator::write8(uint8_t b) {
576 fCode->push_back(b);
577}
578
579void ByteCodeGenerator::write16(uint16_t i) {
Mike Klein76346ac2019-05-17 11:57:10 -0500580 size_t n = fCode->size();
581 fCode->resize(n+2);
582 memcpy(fCode->data() + n, &i, 2);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400583}
584
585void ByteCodeGenerator::write32(uint32_t i) {
Mike Klein76346ac2019-05-17 11:57:10 -0500586 size_t n = fCode->size();
587 fCode->resize(n+4);
588 memcpy(fCode->data() + n, &i, 4);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400589}
590
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400591void ByteCodeGenerator::write(ByteCodeInstruction i, int count) {
Brian Osman4a47da72019-07-12 11:30:32 -0400592 switch (i) {
593 case ByteCodeInstruction::kLoopBegin: this->enterLoop(); break;
594 case ByteCodeInstruction::kLoopEnd: this->exitLoop(); break;
595
596 case ByteCodeInstruction::kMaskPush: this->enterCondition(); break;
597 case ByteCodeInstruction::kMaskPop:
598 case ByteCodeInstruction::kMaskBlend: this->exitCondition(); break;
599 default: /* Do nothing */ break;
600 }
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400601 instruction val = (instruction) i;
602 size_t n = fCode->size();
603 fCode->resize(n + sizeof(val));
604 memcpy(fCode->data() + n, &val, sizeof(val));
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400605 fStackCount += StackUsage(i, count);
606 fMaxStackCount = std::max(fMaxStackCount, fStackCount);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400607}
608
Mike Klein76346ac2019-05-17 11:57:10 -0500609static ByteCodeInstruction vector_instruction(ByteCodeInstruction base, int count) {
Brian Osman07c117b2019-05-23 12:51:06 -0700610 SkASSERT(count >= 1 && count <= 4);
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400611 return ((ByteCodeInstruction) ((int) base + 1 - count));
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400612}
613
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400614void ByteCodeGenerator::writeTypedInstruction(const Type& type, ByteCodeInstruction s,
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400615 ByteCodeInstruction u, ByteCodeInstruction f,
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400616 int count, bool writeCount) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400617 switch (type_category(type)) {
618 case TypeCategory::kSigned:
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400619 this->write(vector_instruction(s, count));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400620 break;
621 case TypeCategory::kUnsigned:
Ethan Nicholas48a75aa2019-05-16 17:15:56 -0400622 this->write(vector_instruction(u, count));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400623 break;
Brian Osman1e855b22019-05-29 15:21:52 -0400624 case TypeCategory::kFloat: {
625 if (count > 4) {
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400626 this->write((ByteCodeInstruction)((int)f + 1), count);
Brian Osman1e855b22019-05-29 15:21:52 -0400627 } else {
628 this->write(vector_instruction(f, count));
629 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400630 break;
Brian Osman1e855b22019-05-29 15:21:52 -0400631 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400632 default:
633 SkASSERT(false);
634 }
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400635 if (writeCount) {
636 this->write8(count);
637 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400638}
639
Brian Osman3e29f1d2019-05-28 09:35:05 -0400640bool ByteCodeGenerator::writeBinaryExpression(const BinaryExpression& b, bool discard) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400641 if (b.fOperator == Token::Kind::EQ) {
642 std::unique_ptr<LValue> lvalue = this->getLValue(*b.fLeft);
643 this->writeExpression(*b.fRight);
Brian Osman3e29f1d2019-05-28 09:35:05 -0400644 lvalue->store(discard);
645 discard = false;
646 return discard;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400647 }
Brian Osman16e6fd52019-05-29 11:19:00 -0400648 const Type& lType = b.fLeft->fType;
649 const Type& rType = b.fRight->fType;
Brian Osman909231c2019-05-29 15:34:36 -0400650 bool lVecOrMtx = (lType.kind() == Type::kVector_Kind || lType.kind() == Type::kMatrix_Kind);
651 bool rVecOrMtx = (rType.kind() == Type::kVector_Kind || rType.kind() == Type::kMatrix_Kind);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400652 Token::Kind op;
653 std::unique_ptr<LValue> lvalue;
654 if (is_assignment(b.fOperator)) {
655 lvalue = this->getLValue(*b.fLeft);
656 lvalue->load();
657 op = remove_assignment(b.fOperator);
658 } else {
659 this->writeExpression(*b.fLeft);
660 op = b.fOperator;
Brian Osman909231c2019-05-29 15:34:36 -0400661 if (!lVecOrMtx && rVecOrMtx) {
Brian Osman16e6fd52019-05-29 11:19:00 -0400662 for (int i = SlotCount(rType); i > 1; --i) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400663 this->write(ByteCodeInstruction::kDup);
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400664 this->write8(1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400665 }
666 }
667 }
Ethan Nicholasd166d2e2019-09-23 11:43:45 -0400668 int count = std::max(SlotCount(lType), SlotCount(rType));
Brian Osmane5bbce22019-09-23 12:38:40 -0400669 SkDEBUGCODE(TypeCategory tc = type_category(lType));
Ethan Nicholasd166d2e2019-09-23 11:43:45 -0400670 switch (op) {
671 case Token::Kind::LOGICALAND: {
Brian Osmane5bbce22019-09-23 12:38:40 -0400672 SkASSERT(tc == SkSL::TypeCategory::kBool && count == 1);
Ethan Nicholasd166d2e2019-09-23 11:43:45 -0400673 this->write(ByteCodeInstruction::kDup);
674 this->write8(1);
675 this->write(ByteCodeInstruction::kMaskPush);
676 this->write(ByteCodeInstruction::kBranchIfAllFalse);
677 DeferredLocation falseLocation(this);
678 this->writeExpression(*b.fRight);
679 this->write(ByteCodeInstruction::kAndB);
680 falseLocation.set();
681 this->write(ByteCodeInstruction::kMaskPop);
682 return false;
683 }
684 case Token::Kind::LOGICALOR: {
Brian Osmane5bbce22019-09-23 12:38:40 -0400685 SkASSERT(tc == SkSL::TypeCategory::kBool && count == 1);
Ethan Nicholasd166d2e2019-09-23 11:43:45 -0400686 this->write(ByteCodeInstruction::kDup);
687 this->write8(1);
688 this->write(ByteCodeInstruction::kNotB);
689 this->write(ByteCodeInstruction::kMaskPush);
690 this->write(ByteCodeInstruction::kBranchIfAllFalse);
691 DeferredLocation falseLocation(this);
692 this->writeExpression(*b.fRight);
693 this->write(ByteCodeInstruction::kOrB);
694 falseLocation.set();
695 this->write(ByteCodeInstruction::kMaskPop);
696 return false;
697 }
Brian Osman4c2146f2019-09-24 09:39:38 -0400698 case Token::Kind::SHL:
699 case Token::Kind::SHR: {
700 SkASSERT(count == 1 && (tc == SkSL::TypeCategory::kSigned ||
701 tc == SkSL::TypeCategory::kUnsigned));
702 if (!b.fRight->isConstant()) {
703 fErrors.error(b.fRight->fOffset, "Shift amounts must be constant");
704 return false;
705 }
706 int64_t shift = b.fRight->getConstantInt();
707 if (shift < 0 || shift > 31) {
708 fErrors.error(b.fRight->fOffset, "Shift amount out of range");
709 return false;
710 }
711
712 if (op == Token::Kind::SHL) {
713 this->write(ByteCodeInstruction::kShiftLeft);
714 } else {
715 this->write(type_category(lType) == TypeCategory::kSigned
716 ? ByteCodeInstruction::kShiftRightS
717 : ByteCodeInstruction::kShiftRightU);
718 }
719 this->write8(shift);
720 return false;
721 }
722
Ethan Nicholasd166d2e2019-09-23 11:43:45 -0400723 default:
724 break;
725 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400726 this->writeExpression(*b.fRight);
Brian Osman909231c2019-05-29 15:34:36 -0400727 if (lVecOrMtx && !rVecOrMtx) {
Brian Osman16e6fd52019-05-29 11:19:00 -0400728 for (int i = SlotCount(lType); i > 1; --i) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400729 this->write(ByteCodeInstruction::kDup);
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400730 this->write8(1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400731 }
732 }
Brian Osman909231c2019-05-29 15:34:36 -0400733 // Special case for M*V, V*M, M*M (but not V*V!)
734 if (op == Token::Kind::STAR && lVecOrMtx && rVecOrMtx &&
735 !(lType.kind() == Type::kVector_Kind && rType.kind() == Type::kVector_Kind)) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400736 this->write(ByteCodeInstruction::kMatrixMultiply,
737 SlotCount(b.fType) - (SlotCount(lType) + SlotCount(rType)));
Brian Osman909231c2019-05-29 15:34:36 -0400738 int rCols = rType.columns(),
739 rRows = rType.rows(),
740 lCols = lType.columns(),
741 lRows = lType.rows();
742 // M*V treats the vector as a column
743 if (rType.kind() == Type::kVector_Kind) {
744 std::swap(rCols, rRows);
745 }
746 SkASSERT(lCols == rRows);
747 SkASSERT(SlotCount(b.fType) == lRows * rCols);
748 this->write8(lCols);
749 this->write8(lRows);
750 this->write8(rCols);
751 } else {
Brian Osman909231c2019-05-29 15:34:36 -0400752 switch (op) {
753 case Token::Kind::EQEQ:
754 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareIEQ,
755 ByteCodeInstruction::kCompareIEQ,
756 ByteCodeInstruction::kCompareFEQ,
757 count);
758 // Collapse to a single bool
759 for (int i = count; i > 1; --i) {
760 this->write(ByteCodeInstruction::kAndB);
761 }
762 break;
763 case Token::Kind::GT:
764 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSGT,
765 ByteCodeInstruction::kCompareUGT,
766 ByteCodeInstruction::kCompareFGT,
767 count);
768 break;
769 case Token::Kind::GTEQ:
770 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSGTEQ,
771 ByteCodeInstruction::kCompareUGTEQ,
772 ByteCodeInstruction::kCompareFGTEQ,
773 count);
774 break;
775 case Token::Kind::LT:
776 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSLT,
777 ByteCodeInstruction::kCompareULT,
778 ByteCodeInstruction::kCompareFLT,
779 count);
780 break;
781 case Token::Kind::LTEQ:
782 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSLTEQ,
783 ByteCodeInstruction::kCompareULTEQ,
784 ByteCodeInstruction::kCompareFLTEQ,
785 count);
786 break;
787 case Token::Kind::MINUS:
788 this->writeTypedInstruction(lType, ByteCodeInstruction::kSubtractI,
789 ByteCodeInstruction::kSubtractI,
790 ByteCodeInstruction::kSubtractF,
791 count);
792 break;
793 case Token::Kind::NEQ:
794 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareINEQ,
795 ByteCodeInstruction::kCompareINEQ,
796 ByteCodeInstruction::kCompareFNEQ,
797 count);
798 // Collapse to a single bool
799 for (int i = count; i > 1; --i) {
800 this->write(ByteCodeInstruction::kOrB);
801 }
802 break;
803 case Token::Kind::PERCENT:
804 this->writeTypedInstruction(lType, ByteCodeInstruction::kRemainderS,
805 ByteCodeInstruction::kRemainderU,
806 ByteCodeInstruction::kRemainderF,
807 count);
808 break;
809 case Token::Kind::PLUS:
810 this->writeTypedInstruction(lType, ByteCodeInstruction::kAddI,
811 ByteCodeInstruction::kAddI,
812 ByteCodeInstruction::kAddF,
813 count);
814 break;
815 case Token::Kind::SLASH:
816 this->writeTypedInstruction(lType, ByteCodeInstruction::kDivideS,
817 ByteCodeInstruction::kDivideU,
818 ByteCodeInstruction::kDivideF,
819 count);
820 break;
821 case Token::Kind::STAR:
822 this->writeTypedInstruction(lType, ByteCodeInstruction::kMultiplyI,
823 ByteCodeInstruction::kMultiplyI,
824 ByteCodeInstruction::kMultiplyF,
825 count);
826 break;
Brian Osman569f12f2019-06-13 11:23:57 -0400827
Brian Osman569f12f2019-06-13 11:23:57 -0400828 case Token::Kind::LOGICALXOR:
Brian Osmane5bbce22019-09-23 12:38:40 -0400829 SkASSERT(tc == SkSL::TypeCategory::kBool && count == 1);
830 this->write(ByteCodeInstruction::kXorB);
831 break;
832
833 case Token::Kind::BITWISEAND:
834 SkASSERT(count == 1 && (tc == SkSL::TypeCategory::kSigned ||
835 tc == SkSL::TypeCategory::kUnsigned));
836 this->write(ByteCodeInstruction::kAndB);
837 break;
838 case Token::Kind::BITWISEOR:
839 SkASSERT(count == 1 && (tc == SkSL::TypeCategory::kSigned ||
840 tc == SkSL::TypeCategory::kUnsigned));
841 this->write(ByteCodeInstruction::kOrB);
842 break;
843 case Token::Kind::BITWISEXOR:
844 SkASSERT(count == 1 && (tc == SkSL::TypeCategory::kSigned ||
845 tc == SkSL::TypeCategory::kUnsigned));
Brian Osman569f12f2019-06-13 11:23:57 -0400846 this->write(ByteCodeInstruction::kXorB);
847 break;
848
Brian Osman909231c2019-05-29 15:34:36 -0400849 default:
Brian Osmandb3dad22019-07-26 15:44:29 -0400850 fErrors.error(b.fOffset, SkSL::String::printf("Unsupported binary operator '%s'",
851 Compiler::OperatorName(op)));
852 break;
Brian Osman909231c2019-05-29 15:34:36 -0400853 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400854 }
855 if (lvalue) {
Brian Osman3e29f1d2019-05-28 09:35:05 -0400856 lvalue->store(discard);
857 discard = false;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400858 }
Brian Osman3e29f1d2019-05-28 09:35:05 -0400859 return discard;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400860}
861
862void ByteCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
863 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osman569f12f2019-06-13 11:23:57 -0400864 this->write32(b.fValue ? ~0 : 0);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400865}
866
867void ByteCodeGenerator::writeConstructor(const Constructor& c) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400868 for (const auto& arg : c.fArguments) {
869 this->writeExpression(*arg);
870 }
871 if (c.fArguments.size() == 1) {
Brian Osman29e013d2019-05-28 17:16:03 -0400872 const Type& inType = c.fArguments[0]->fType;
873 const Type& outType = c.fType;
874 TypeCategory inCategory = type_category(inType);
875 TypeCategory outCategory = type_category(outType);
876 int inCount = SlotCount(inType);
877 int outCount = SlotCount(outType);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400878 if (inCategory != outCategory) {
Brian Osmanc51d7912019-05-22 15:16:16 -0700879 SkASSERT(inCount == outCount);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400880 if (inCategory == TypeCategory::kFloat) {
881 SkASSERT(outCategory == TypeCategory::kSigned ||
882 outCategory == TypeCategory::kUnsigned);
Brian Osmanc51d7912019-05-22 15:16:16 -0700883 this->write(vector_instruction(ByteCodeInstruction::kConvertFtoI, outCount));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400884 } else if (outCategory == TypeCategory::kFloat) {
885 if (inCategory == TypeCategory::kSigned) {
Brian Osmanc51d7912019-05-22 15:16:16 -0700886 this->write(vector_instruction(ByteCodeInstruction::kConvertStoF, outCount));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400887 } else {
888 SkASSERT(inCategory == TypeCategory::kUnsigned);
Brian Osmanc51d7912019-05-22 15:16:16 -0700889 this->write(vector_instruction(ByteCodeInstruction::kConvertUtoF, outCount));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400890 }
891 } else {
892 SkASSERT(false);
893 }
894 }
Brian Osman29e013d2019-05-28 17:16:03 -0400895 if (inType.kind() == Type::kMatrix_Kind && outType.kind() == Type::kMatrix_Kind) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400896 this->write(ByteCodeInstruction::kMatrixToMatrix,
897 SlotCount(outType) - SlotCount(inType));
Brian Osman29e013d2019-05-28 17:16:03 -0400898 this->write8(inType.columns());
899 this->write8(inType.rows());
900 this->write8(outType.columns());
901 this->write8(outType.rows());
902 } else if (inCount != outCount) {
Brian Osmanc51d7912019-05-22 15:16:16 -0700903 SkASSERT(inCount == 1);
Brian Osman29e013d2019-05-28 17:16:03 -0400904 if (outType.kind() == Type::kMatrix_Kind) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400905 this->write(ByteCodeInstruction::kScalarToMatrix, SlotCount(outType) - 1);
Brian Osman29e013d2019-05-28 17:16:03 -0400906 this->write8(outType.columns());
907 this->write8(outType.rows());
908 } else {
909 SkASSERT(outType.kind() == Type::kVector_Kind);
910 for (; inCount != outCount; ++inCount) {
911 this->write(ByteCodeInstruction::kDup);
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400912 this->write8(1);
Brian Osman29e013d2019-05-28 17:16:03 -0400913 }
Brian Osmanc51d7912019-05-22 15:16:16 -0700914 }
915 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400916 }
917}
918
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400919void ByteCodeGenerator::writeExternalFunctionCall(const ExternalFunctionCall& f) {
920 int argumentCount = 0;
921 for (const auto& arg : f.fArguments) {
922 this->writeExpression(*arg);
Brian Osman07c117b2019-05-23 12:51:06 -0700923 argumentCount += SlotCount(arg->fType);
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400924 }
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400925 this->write(ByteCodeInstruction::kCallExternal, SlotCount(f.fType) - argumentCount);
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400926 SkASSERT(argumentCount <= 255);
927 this->write8(argumentCount);
Brian Osman07c117b2019-05-23 12:51:06 -0700928 this->write8(SlotCount(f.fType));
Ethan Nicholas9e6a3932019-05-17 16:31:21 -0400929 int index = fOutput->fExternalValues.size();
930 fOutput->fExternalValues.push_back(f.fFunction);
931 SkASSERT(index <= 255);
932 this->write8(index);
933}
934
Ethan Nicholas91164d12019-05-15 15:29:54 -0400935void ByteCodeGenerator::writeExternalValue(const ExternalValueReference& e) {
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400936 int count = SlotCount(e.fValue->type());
937 this->write(vector_instruction(ByteCodeInstruction::kReadExternal, count));
938 this->write8(count);
Ethan Nicholas91164d12019-05-15 15:29:54 -0400939 int index = fOutput->fExternalValues.size();
940 fOutput->fExternalValues.push_back(e.fValue);
941 SkASSERT(index <= 255);
942 this->write8(index);
943}
944
Brian Osman07c117b2019-05-23 12:51:06 -0700945void ByteCodeGenerator::writeVariableExpression(const Expression& expr) {
Brian Osman1c110a02019-10-01 14:53:32 -0400946 Location location = this->getLocation(expr);
Brian Osman07c117b2019-05-23 12:51:06 -0700947 int count = SlotCount(expr.fType);
Brian Osman1c110a02019-10-01 14:53:32 -0400948 if (location.isOnStack() || count > 4) {
949 if (!location.isOnStack()) {
Brian Osman07c117b2019-05-23 12:51:06 -0700950 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osman1c110a02019-10-01 14:53:32 -0400951 this->write32(location.fSlot);
Brian Osman07c117b2019-05-23 12:51:06 -0700952 }
Brian Osman1c110a02019-10-01 14:53:32 -0400953 this->write(location.selectLoad(ByteCodeInstruction::kLoadExtended,
954 ByteCodeInstruction::kLoadExtendedGlobal,
955 ByteCodeInstruction::kLoadExtendedUniform),
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400956 count);
Brian Osman07c117b2019-05-23 12:51:06 -0700957 this->write8(count);
958 } else {
Brian Osman1c110a02019-10-01 14:53:32 -0400959 this->write(vector_instruction(location.selectLoad(ByteCodeInstruction::kLoad,
960 ByteCodeInstruction::kLoadGlobal,
961 ByteCodeInstruction::kLoadUniform),
Brian Osman07c117b2019-05-23 12:51:06 -0700962 count));
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400963 this->write8(count);
Brian Osman1c110a02019-10-01 14:53:32 -0400964 this->write8(location.fSlot);
Brian Osman07c117b2019-05-23 12:51:06 -0700965 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400966}
967
Brian Osmand30e0392019-06-14 14:05:14 -0400968static inline uint32_t float_to_bits(float x) {
969 uint32_t u;
970 memcpy(&u, &x, sizeof(uint32_t));
971 return u;
972}
973
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400974void ByteCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
975 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osmand30e0392019-06-14 14:05:14 -0400976 this->write32(float_to_bits(f.fValue));
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400977}
978
Ethan Nicholas82162ee2019-05-21 16:05:08 -0400979void ByteCodeGenerator::writeIntrinsicCall(const FunctionCall& c) {
980 auto found = fIntrinsics.find(c.fFunction.fName);
981 if (found == fIntrinsics.end()) {
982 fErrors.error(c.fOffset, "unsupported intrinsic function");
983 return;
984 }
Brian Osmanaa2ca3f2019-07-15 13:24:48 -0400985 int count = SlotCount(c.fArguments[0]->fType);
Ethan Nicholasae9633b2019-05-24 12:46:34 -0400986 if (found->second.fIsSpecial) {
Brian Osmanb380e712019-07-24 17:02:39 -0400987 SpecialIntrinsic special = found->second.fValue.fSpecial;
988 switch (special) {
989 case SpecialIntrinsic::kDot: {
990 SkASSERT(c.fArguments.size() == 2);
991 SkASSERT(count == SlotCount(c.fArguments[1]->fType));
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400992 this->write(vector_instruction(ByteCodeInstruction::kMultiplyF, count));
993 this->write8(count);
Brian Osmanb380e712019-07-24 17:02:39 -0400994 for (int i = count; i > 1; --i) {
995 this->write(ByteCodeInstruction::kAddF);
Ethan Nicholasc70027b2019-09-05 16:50:52 -0400996 this->write8(1);
Brian Osmanb380e712019-07-24 17:02:39 -0400997 }
998 break;
999 }
Brian Osmanb380e712019-07-24 17:02:39 -04001000 default:
1001 SkASSERT(false);
Ethan Nicholasae9633b2019-05-24 12:46:34 -04001002 }
1003 } else {
1004 switch (found->second.fValue.fInstruction) {
1005 case ByteCodeInstruction::kCos:
Ethan Nicholasae9633b2019-05-24 12:46:34 -04001006 case ByteCodeInstruction::kSin:
Ethan Nicholasae9633b2019-05-24 12:46:34 -04001007 case ByteCodeInstruction::kTan:
1008 SkASSERT(c.fArguments.size() > 0);
Ethan Nicholasc70027b2019-09-05 16:50:52 -04001009 this->write(vector_instruction(found->second.fValue.fInstruction, count));
1010 this->write8(count);
1011 break;
1012 case ByteCodeInstruction::kSqrt:
1013 SkASSERT(c.fArguments.size() > 0);
1014 this->write(vector_instruction(found->second.fValue.fInstruction, count));
Ethan Nicholasae9633b2019-05-24 12:46:34 -04001015 break;
Mike Reed634c9412019-07-18 13:20:04 -04001016 case ByteCodeInstruction::kInverse2x2: {
1017 SkASSERT(c.fArguments.size() > 0);
1018 auto op = ByteCodeInstruction::kInverse2x2;
1019 switch (count) {
1020 case 4: break; // float2x2
1021 case 9: op = ByteCodeInstruction::kInverse3x3; break;
1022 case 16: op = ByteCodeInstruction::kInverse4x4; break;
1023 default: SkASSERT(false);
1024 }
1025 this->write(op);
Brian Osmanb380e712019-07-24 17:02:39 -04001026 break;
1027 }
Ethan Nicholasae9633b2019-05-24 12:46:34 -04001028 default:
1029 SkASSERT(false);
1030 }
Ethan Nicholas82162ee2019-05-21 16:05:08 -04001031 }
1032}
1033
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001034void ByteCodeGenerator::writeFunctionCall(const FunctionCall& f) {
Ethan Nicholasdb80f692019-11-22 14:06:12 -05001035 // Find the index of the function we're calling. We explicitly do not allow calls to functions
1036 // before they're defined. This is an easy-to-understand rule that prevents recursion.
1037 int idx = -1;
1038 for (size_t i = 0; i < fFunctions.size(); ++i) {
1039 if (f.fFunction.matches(fFunctions[i]->fDeclaration)) {
1040 idx = i;
1041 break;
1042 }
1043 }
1044 if (idx == -1) {
Brian Osmand3494ed2019-06-20 15:41:34 -04001045 for (const auto& arg : f.fArguments) {
1046 this->writeExpression(*arg);
1047 }
Ethan Nicholas82162ee2019-05-21 16:05:08 -04001048 this->writeIntrinsicCall(f);
1049 return;
1050 }
Brian Osmand3494ed2019-06-20 15:41:34 -04001051
Ethan Nicholasdb80f692019-11-22 14:06:12 -05001052
Brian Osman6f5358f2019-07-09 14:17:23 -04001053 if (idx > 255) {
1054 fErrors.error(f.fOffset, "Function count limit exceeded");
1055 return;
Ethan Nicholasdb80f692019-11-22 14:06:12 -05001056 } else if (idx >= (int) fFunctions.size()) {
Brian Osman6f5358f2019-07-09 14:17:23 -04001057 fErrors.error(f.fOffset, "Call to undefined function");
1058 return;
1059 }
1060
1061 // We may need to deal with out parameters, so the sequence is tricky
Brian Osmand3494ed2019-06-20 15:41:34 -04001062 if (int returnCount = SlotCount(f.fType)) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001063 this->write(ByteCodeInstruction::kReserve, returnCount);
Brian Osmand3494ed2019-06-20 15:41:34 -04001064 this->write8(returnCount);
1065 }
1066
1067 int argCount = f.fArguments.size();
1068 std::vector<std::unique_ptr<LValue>> lvalues;
1069 for (int i = 0; i < argCount; ++i) {
1070 const auto& param = f.fFunction.fParameters[i];
1071 const auto& arg = f.fArguments[i];
1072 if (param->fModifiers.fFlags & Modifiers::kOut_Flag) {
1073 lvalues.emplace_back(this->getLValue(*arg));
1074 lvalues.back()->load();
1075 } else {
1076 this->writeExpression(*arg);
1077 }
1078 }
1079
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001080 // The space used by the call is based on the callee, but it also unwinds all of that before
1081 // we continue execution. We adjust our max stack depths below.
Brian Osman226668a2019-05-14 16:47:30 -04001082 this->write(ByteCodeInstruction::kCall);
Brian Osman6f5358f2019-07-09 14:17:23 -04001083 this->write8(idx);
Brian Osmand3494ed2019-06-20 15:41:34 -04001084
Brian Osman4a47da72019-07-12 11:30:32 -04001085 const ByteCodeFunction* callee = fOutput->fFunctions[idx].get();
1086 fMaxLoopCount = std::max(fMaxLoopCount, fLoopCount + callee->fLoopCount);
1087 fMaxConditionCount = std::max(fMaxConditionCount, fConditionCount + callee->fConditionCount);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001088 fMaxStackCount = std::max(fMaxStackCount, fStackCount + callee->fLocalCount
1089 + callee->fStackCount);
Brian Osman4a47da72019-07-12 11:30:32 -04001090
Brian Osmand3494ed2019-06-20 15:41:34 -04001091 // After the called function returns, the stack will still contain our arguments. We have to
1092 // pop them (storing any out parameters back to their lvalues as we go). We glob together slot
1093 // counts for all parameters that aren't out-params, so we can pop them in one big chunk.
1094 int popCount = 0;
1095 auto pop = [&]() {
1096 if (popCount > 4) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001097 this->write(ByteCodeInstruction::kPopN, popCount);
Brian Osmand3494ed2019-06-20 15:41:34 -04001098 this->write8(popCount);
1099 } else if (popCount > 0) {
1100 this->write(vector_instruction(ByteCodeInstruction::kPop, popCount));
1101 }
1102 popCount = 0;
1103 };
1104
1105 for (int i = argCount - 1; i >= 0; --i) {
1106 const auto& param = f.fFunction.fParameters[i];
1107 const auto& arg = f.fArguments[i];
1108 if (param->fModifiers.fFlags & Modifiers::kOut_Flag) {
1109 pop();
1110 lvalues.back()->store(true);
1111 lvalues.pop_back();
1112 } else {
1113 popCount += SlotCount(arg->fType);
1114 }
1115 }
1116 pop();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001117}
1118
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001119void ByteCodeGenerator::writeIntLiteral(const IntLiteral& i) {
1120 this->write(ByteCodeInstruction::kPushImmediate);
1121 this->write32(i.fValue);
1122}
1123
1124void ByteCodeGenerator::writeNullLiteral(const NullLiteral& n) {
1125 // not yet implemented
1126 abort();
1127}
1128
Brian Osman3e29f1d2019-05-28 09:35:05 -04001129bool ByteCodeGenerator::writePrefixExpression(const PrefixExpression& p, bool discard) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001130 switch (p.fOperator) {
1131 case Token::Kind::PLUSPLUS: // fall through
1132 case Token::Kind::MINUSMINUS: {
Brian Osman07c117b2019-05-23 12:51:06 -07001133 SkASSERT(SlotCount(p.fOperand->fType) == 1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001134 std::unique_ptr<LValue> lvalue = this->getLValue(*p.fOperand);
1135 lvalue->load();
1136 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osmand30e0392019-06-14 14:05:14 -04001137 this->write32(type_category(p.fType) == TypeCategory::kFloat ? float_to_bits(1.0f) : 1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001138 if (p.fOperator == Token::Kind::PLUSPLUS) {
1139 this->writeTypedInstruction(p.fType,
1140 ByteCodeInstruction::kAddI,
1141 ByteCodeInstruction::kAddI,
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001142 ByteCodeInstruction::kAddF,
1143 1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001144 } else {
1145 this->writeTypedInstruction(p.fType,
1146 ByteCodeInstruction::kSubtractI,
1147 ByteCodeInstruction::kSubtractI,
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001148 ByteCodeInstruction::kSubtractF,
1149 1);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001150 }
Brian Osman3e29f1d2019-05-28 09:35:05 -04001151 lvalue->store(discard);
1152 discard = false;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001153 break;
1154 }
Ethan Nicholas354ecf32019-05-07 16:13:02 -04001155 case Token::Kind::MINUS: {
1156 this->writeExpression(*p.fOperand);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001157 this->writeTypedInstruction(p.fType,
Mike Klein12710912019-05-21 11:04:59 -05001158 ByteCodeInstruction::kNegateI,
1159 ByteCodeInstruction::kNegateI,
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001160 ByteCodeInstruction::kNegateF,
Ethan Nicholasc70027b2019-09-05 16:50:52 -04001161 SlotCount(p.fOperand->fType),
1162 false);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001163 break;
Ethan Nicholas354ecf32019-05-07 16:13:02 -04001164 }
Brian Osmane5bbce22019-09-23 12:38:40 -04001165 case Token::Kind::LOGICALNOT:
1166 case Token::Kind::BITWISENOT: {
1167 SkASSERT(SlotCount(p.fOperand->fType) == 1);
1168 SkDEBUGCODE(TypeCategory tc = type_category(p.fOperand->fType));
1169 SkASSERT((p.fOperator == Token::Kind::LOGICALNOT && tc == TypeCategory::kBool) ||
1170 (p.fOperator == Token::Kind::BITWISENOT && (tc == TypeCategory::kSigned ||
1171 tc == TypeCategory::kUnsigned)));
1172 this->writeExpression(*p.fOperand);
1173 this->write(ByteCodeInstruction::kNotB);
1174 break;
1175 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001176 default:
1177 SkASSERT(false);
1178 }
Brian Osman3e29f1d2019-05-28 09:35:05 -04001179 return discard;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001180}
1181
Brian Osman3e29f1d2019-05-28 09:35:05 -04001182bool ByteCodeGenerator::writePostfixExpression(const PostfixExpression& p, bool discard) {
Brian Osmanf3fa6002019-05-17 14:26:53 -04001183 switch (p.fOperator) {
1184 case Token::Kind::PLUSPLUS: // fall through
1185 case Token::Kind::MINUSMINUS: {
Brian Osman07c117b2019-05-23 12:51:06 -07001186 SkASSERT(SlotCount(p.fOperand->fType) == 1);
Brian Osmanf3fa6002019-05-17 14:26:53 -04001187 std::unique_ptr<LValue> lvalue = this->getLValue(*p.fOperand);
1188 lvalue->load();
Brian Osman52c1bf12019-07-18 13:12:19 -04001189 // If we're not supposed to discard the result, then make a copy *before* the +/-
Brian Osman3e29f1d2019-05-28 09:35:05 -04001190 if (!discard) {
1191 this->write(ByteCodeInstruction::kDup);
Ethan Nicholasc70027b2019-09-05 16:50:52 -04001192 this->write8(1);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001193 }
Brian Osmanf3fa6002019-05-17 14:26:53 -04001194 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osmand30e0392019-06-14 14:05:14 -04001195 this->write32(type_category(p.fType) == TypeCategory::kFloat ? float_to_bits(1.0f) : 1);
Brian Osmanf3fa6002019-05-17 14:26:53 -04001196 if (p.fOperator == Token::Kind::PLUSPLUS) {
1197 this->writeTypedInstruction(p.fType,
1198 ByteCodeInstruction::kAddI,
1199 ByteCodeInstruction::kAddI,
1200 ByteCodeInstruction::kAddF,
1201 1);
1202 } else {
1203 this->writeTypedInstruction(p.fType,
1204 ByteCodeInstruction::kSubtractI,
1205 ByteCodeInstruction::kSubtractI,
1206 ByteCodeInstruction::kSubtractF,
1207 1);
1208 }
Brian Osman52c1bf12019-07-18 13:12:19 -04001209 // Always consume the result as part of the store
1210 lvalue->store(true);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001211 discard = false;
Brian Osmanf3fa6002019-05-17 14:26:53 -04001212 break;
1213 }
1214 default:
1215 SkASSERT(false);
1216 }
Brian Osman3e29f1d2019-05-28 09:35:05 -04001217 return discard;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001218}
1219
1220void ByteCodeGenerator::writeSwizzle(const Swizzle& s) {
Brian Osman0785db02019-05-24 14:19:11 -04001221 if (swizzle_is_simple(s)) {
1222 this->writeVariableExpression(s);
1223 return;
1224 }
1225
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001226 switch (s.fBase->fKind) {
1227 case Expression::kVariableReference_Kind: {
Brian Osman1c110a02019-10-01 14:53:32 -04001228 Location location = this->getLocation(*s.fBase);
1229 this->write(location.selectLoad(ByteCodeInstruction::kLoadSwizzle,
1230 ByteCodeInstruction::kLoadSwizzleGlobal,
1231 ByteCodeInstruction::kLoadSwizzleUniform),
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001232 s.fComponents.size());
Brian Osman1c110a02019-10-01 14:53:32 -04001233 this->write8(location.fSlot);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001234 this->write8(s.fComponents.size());
1235 for (int c : s.fComponents) {
1236 this->write8(c);
1237 }
1238 break;
1239 }
1240 default:
1241 this->writeExpression(*s.fBase);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001242 this->write(ByteCodeInstruction::kSwizzle,
1243 s.fComponents.size() - s.fBase->fType.columns());
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001244 this->write8(s.fBase->fType.columns());
1245 this->write8(s.fComponents.size());
1246 for (int c : s.fComponents) {
1247 this->write8(c);
1248 }
1249 }
1250}
1251
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001252void ByteCodeGenerator::writeTernaryExpression(const TernaryExpression& t) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001253 int count = SlotCount(t.fType);
1254 SkASSERT(count == SlotCount(t.fIfTrue->fType));
1255 SkASSERT(count == SlotCount(t.fIfFalse->fType));
1256
Brian Osman4e93feb2019-05-16 15:38:00 -04001257 this->writeExpression(*t.fTest);
Brian Osman569f12f2019-06-13 11:23:57 -04001258 this->write(ByteCodeInstruction::kMaskPush);
Brian Osman4e93feb2019-05-16 15:38:00 -04001259 this->writeExpression(*t.fIfTrue);
Brian Osman569f12f2019-06-13 11:23:57 -04001260 this->write(ByteCodeInstruction::kMaskNegate);
1261 this->writeExpression(*t.fIfFalse);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001262 this->write(ByteCodeInstruction::kMaskBlend, count);
1263 this->write8(count);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001264}
1265
Brian Osman3e29f1d2019-05-28 09:35:05 -04001266void ByteCodeGenerator::writeExpression(const Expression& e, bool discard) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001267 switch (e.fKind) {
1268 case Expression::kBinary_Kind:
Brian Osman3e29f1d2019-05-28 09:35:05 -04001269 discard = this->writeBinaryExpression((BinaryExpression&) e, discard);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001270 break;
1271 case Expression::kBoolLiteral_Kind:
1272 this->writeBoolLiteral((BoolLiteral&) e);
1273 break;
1274 case Expression::kConstructor_Kind:
1275 this->writeConstructor((Constructor&) e);
1276 break;
Ethan Nicholas9e6a3932019-05-17 16:31:21 -04001277 case Expression::kExternalFunctionCall_Kind:
1278 this->writeExternalFunctionCall((ExternalFunctionCall&) e);
1279 break;
Ethan Nicholas91164d12019-05-15 15:29:54 -04001280 case Expression::kExternalValue_Kind:
1281 this->writeExternalValue((ExternalValueReference&) e);
1282 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001283 case Expression::kFieldAccess_Kind:
Brian Osman07c117b2019-05-23 12:51:06 -07001284 case Expression::kIndex_Kind:
1285 case Expression::kVariableReference_Kind:
1286 this->writeVariableExpression(e);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001287 break;
1288 case Expression::kFloatLiteral_Kind:
1289 this->writeFloatLiteral((FloatLiteral&) e);
1290 break;
1291 case Expression::kFunctionCall_Kind:
1292 this->writeFunctionCall((FunctionCall&) e);
1293 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001294 case Expression::kIntLiteral_Kind:
1295 this->writeIntLiteral((IntLiteral&) e);
1296 break;
1297 case Expression::kNullLiteral_Kind:
1298 this->writeNullLiteral((NullLiteral&) e);
1299 break;
1300 case Expression::kPrefix_Kind:
Brian Osman3e29f1d2019-05-28 09:35:05 -04001301 discard = this->writePrefixExpression((PrefixExpression&) e, discard);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001302 break;
1303 case Expression::kPostfix_Kind:
Brian Osman3e29f1d2019-05-28 09:35:05 -04001304 discard = this->writePostfixExpression((PostfixExpression&) e, discard);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001305 break;
1306 case Expression::kSwizzle_Kind:
1307 this->writeSwizzle((Swizzle&) e);
1308 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001309 case Expression::kTernary_Kind:
1310 this->writeTernaryExpression((TernaryExpression&) e);
1311 break;
1312 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -05001313#ifdef SK_DEBUG
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001314 printf("unsupported expression %s\n", e.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05001315#endif
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001316 SkASSERT(false);
1317 }
Brian Osman3e29f1d2019-05-28 09:35:05 -04001318 if (discard) {
1319 int count = SlotCount(e.fType);
1320 if (count > 4) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001321 this->write(ByteCodeInstruction::kPopN, count);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001322 this->write8(count);
Brian Osmanfba386b2019-06-20 14:54:15 -04001323 } else if (count != 0) {
Brian Osman3e29f1d2019-05-28 09:35:05 -04001324 this->write(vector_instruction(ByteCodeInstruction::kPop, count));
1325 }
1326 discard = false;
1327 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001328}
1329
Ethan Nicholas91164d12019-05-15 15:29:54 -04001330class ByteCodeExternalValueLValue : public ByteCodeGenerator::LValue {
1331public:
1332 ByteCodeExternalValueLValue(ByteCodeGenerator* generator, ExternalValue& value, int index)
1333 : INHERITED(*generator)
Brian Osman07c117b2019-05-23 12:51:06 -07001334 , fCount(ByteCodeGenerator::SlotCount(value.type()))
Ethan Nicholas91164d12019-05-15 15:29:54 -04001335 , fIndex(index) {}
1336
1337 void load() override {
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001338 fGenerator.write(vector_instruction(ByteCodeInstruction::kReadExternal, fCount));
Ethan Nicholasc70027b2019-09-05 16:50:52 -04001339 fGenerator.write8(fCount);
Ethan Nicholas91164d12019-05-15 15:29:54 -04001340 fGenerator.write8(fIndex);
1341 }
1342
Brian Osman3e29f1d2019-05-28 09:35:05 -04001343 void store(bool discard) override {
1344 if (!discard) {
1345 fGenerator.write(vector_instruction(ByteCodeInstruction::kDup, fCount));
Ethan Nicholasc70027b2019-09-05 16:50:52 -04001346 fGenerator.write8(fCount);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001347 }
Ethan Nicholas48a75aa2019-05-16 17:15:56 -04001348 fGenerator.write(vector_instruction(ByteCodeInstruction::kWriteExternal, fCount));
Ethan Nicholasc70027b2019-09-05 16:50:52 -04001349 fGenerator.write8(fCount);
Ethan Nicholas91164d12019-05-15 15:29:54 -04001350 fGenerator.write8(fIndex);
1351 }
1352
1353private:
1354 typedef LValue INHERITED;
1355
1356 int fCount;
1357
1358 int fIndex;
1359};
1360
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001361class ByteCodeSwizzleLValue : public ByteCodeGenerator::LValue {
1362public:
1363 ByteCodeSwizzleLValue(ByteCodeGenerator* generator, const Swizzle& swizzle)
1364 : INHERITED(*generator)
Brian Osman07c117b2019-05-23 12:51:06 -07001365 , fSwizzle(swizzle) {}
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001366
1367 void load() override {
Brian Osman1091f022019-05-16 09:42:16 -04001368 fGenerator.writeSwizzle(fSwizzle);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001369 }
1370
Brian Osman3e29f1d2019-05-28 09:35:05 -04001371 void store(bool discard) override {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001372 int count = fSwizzle.fComponents.size();
Brian Osman3e29f1d2019-05-28 09:35:05 -04001373 if (!discard) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001374 fGenerator.write(vector_instruction(ByteCodeInstruction::kDup, count));
Ethan Nicholasc70027b2019-09-05 16:50:52 -04001375 fGenerator.write8(count);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001376 }
Brian Osman1c110a02019-10-01 14:53:32 -04001377 ByteCodeGenerator::Location location = fGenerator.getLocation(*fSwizzle.fBase);
1378 if (location.isOnStack()) {
1379 fGenerator.write(location.selectStore(ByteCodeInstruction::kStoreSwizzleIndirect,
1380 ByteCodeInstruction::kStoreSwizzleIndirectGlobal),
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001381 count);
Brian Osman07c117b2019-05-23 12:51:06 -07001382 } else {
Brian Osman1c110a02019-10-01 14:53:32 -04001383 fGenerator.write(location.selectStore(ByteCodeInstruction::kStoreSwizzle,
1384 ByteCodeInstruction::kStoreSwizzleGlobal),
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001385 count);
Brian Osman1c110a02019-10-01 14:53:32 -04001386 fGenerator.write8(location.fSlot);
Brian Osman07c117b2019-05-23 12:51:06 -07001387 }
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001388 fGenerator.write8(count);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001389 for (int c : fSwizzle.fComponents) {
1390 fGenerator.write8(c);
1391 }
1392 }
1393
1394private:
1395 const Swizzle& fSwizzle;
1396
1397 typedef LValue INHERITED;
1398};
1399
Brian Osman07c117b2019-05-23 12:51:06 -07001400class ByteCodeExpressionLValue : public ByteCodeGenerator::LValue {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001401public:
Brian Osman07c117b2019-05-23 12:51:06 -07001402 ByteCodeExpressionLValue(ByteCodeGenerator* generator, const Expression& expr)
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001403 : INHERITED(*generator)
Brian Osman07c117b2019-05-23 12:51:06 -07001404 , fExpression(expr) {}
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001405
1406 void load() override {
Brian Osman07c117b2019-05-23 12:51:06 -07001407 fGenerator.writeVariableExpression(fExpression);
Brian Osman1091f022019-05-16 09:42:16 -04001408 }
1409
Brian Osman3e29f1d2019-05-28 09:35:05 -04001410 void store(bool discard) override {
Brian Osman07c117b2019-05-23 12:51:06 -07001411 int count = ByteCodeGenerator::SlotCount(fExpression.fType);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001412 if (!discard) {
1413 if (count > 4) {
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001414 fGenerator.write(ByteCodeInstruction::kDupN, count);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001415 fGenerator.write8(count);
1416 } else {
1417 fGenerator.write(vector_instruction(ByteCodeInstruction::kDup, count));
Ethan Nicholasc70027b2019-09-05 16:50:52 -04001418 fGenerator.write8(count);
Brian Osman3e29f1d2019-05-28 09:35:05 -04001419 }
Brian Osman07c117b2019-05-23 12:51:06 -07001420 }
Brian Osman1c110a02019-10-01 14:53:32 -04001421 ByteCodeGenerator::Location location = fGenerator.getLocation(fExpression);
1422 if (location.isOnStack() || count > 4) {
1423 if (!location.isOnStack()) {
Brian Osman07c117b2019-05-23 12:51:06 -07001424 fGenerator.write(ByteCodeInstruction::kPushImmediate);
Brian Osman1c110a02019-10-01 14:53:32 -04001425 fGenerator.write32(location.fSlot);
Brian Osman07c117b2019-05-23 12:51:06 -07001426 }
Brian Osman1c110a02019-10-01 14:53:32 -04001427 fGenerator.write(location.selectStore(ByteCodeInstruction::kStoreExtended,
1428 ByteCodeInstruction::kStoreExtendedGlobal),
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001429 count);
Brian Osman07c117b2019-05-23 12:51:06 -07001430 fGenerator.write8(count);
1431 } else {
Brian Osman1c110a02019-10-01 14:53:32 -04001432 fGenerator.write(
1433 vector_instruction(location.selectStore(ByteCodeInstruction::kStore,
1434 ByteCodeInstruction::kStoreGlobal),
1435 count));
1436 fGenerator.write8(location.fSlot);
Brian Osman07c117b2019-05-23 12:51:06 -07001437 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001438 }
1439
1440private:
1441 typedef LValue INHERITED;
1442
Brian Osman07c117b2019-05-23 12:51:06 -07001443 const Expression& fExpression;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001444};
1445
1446std::unique_ptr<ByteCodeGenerator::LValue> ByteCodeGenerator::getLValue(const Expression& e) {
1447 switch (e.fKind) {
Ethan Nicholas91164d12019-05-15 15:29:54 -04001448 case Expression::kExternalValue_Kind: {
1449 ExternalValue* value = ((ExternalValueReference&) e).fValue;
1450 int index = fOutput->fExternalValues.size();
1451 fOutput->fExternalValues.push_back(value);
1452 SkASSERT(index <= 255);
1453 return std::unique_ptr<LValue>(new ByteCodeExternalValueLValue(this, *value, index));
1454 }
Brian Osman07c117b2019-05-23 12:51:06 -07001455 case Expression::kFieldAccess_Kind:
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001456 case Expression::kIndex_Kind:
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001457 case Expression::kVariableReference_Kind:
Brian Osman07c117b2019-05-23 12:51:06 -07001458 return std::unique_ptr<LValue>(new ByteCodeExpressionLValue(this, e));
Brian Osman0785db02019-05-24 14:19:11 -04001459 case Expression::kSwizzle_Kind: {
1460 const Swizzle& s = (const Swizzle&) e;
1461 return swizzle_is_simple(s)
1462 ? std::unique_ptr<LValue>(new ByteCodeExpressionLValue(this, e))
1463 : std::unique_ptr<LValue>(new ByteCodeSwizzleLValue(this, s));
1464 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001465 case Expression::kTernary_Kind:
1466 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -05001467#ifdef SK_DEBUG
1468 ABORT("unsupported lvalue %s\n", e.description().c_str());
1469#endif
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001470 return nullptr;
1471 }
1472}
1473
1474void ByteCodeGenerator::writeBlock(const Block& b) {
1475 for (const auto& s : b.fStatements) {
1476 this->writeStatement(*s);
1477 }
1478}
1479
1480void ByteCodeGenerator::setBreakTargets() {
1481 std::vector<DeferredLocation>& breaks = fBreakTargets.top();
1482 for (DeferredLocation& b : breaks) {
1483 b.set();
1484 }
1485 fBreakTargets.pop();
1486}
1487
1488void ByteCodeGenerator::setContinueTargets() {
1489 std::vector<DeferredLocation>& continues = fContinueTargets.top();
1490 for (DeferredLocation& c : continues) {
1491 c.set();
1492 }
1493 fContinueTargets.pop();
1494}
1495
1496void ByteCodeGenerator::writeBreakStatement(const BreakStatement& b) {
Brian Osman569f12f2019-06-13 11:23:57 -04001497 // TODO: Include BranchIfAllFalse to top-most LoopNext
1498 this->write(ByteCodeInstruction::kLoopBreak);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001499}
1500
1501void ByteCodeGenerator::writeContinueStatement(const ContinueStatement& c) {
Brian Osman569f12f2019-06-13 11:23:57 -04001502 // TODO: Include BranchIfAllFalse to top-most LoopNext
1503 this->write(ByteCodeInstruction::kLoopContinue);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001504}
1505
1506void ByteCodeGenerator::writeDoStatement(const DoStatement& d) {
Brian Osman569f12f2019-06-13 11:23:57 -04001507 this->write(ByteCodeInstruction::kLoopBegin);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001508 size_t start = fCode->size();
1509 this->writeStatement(*d.fStatement);
Brian Osman569f12f2019-06-13 11:23:57 -04001510 this->write(ByteCodeInstruction::kLoopNext);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001511 this->writeExpression(*d.fTest);
Brian Osman569f12f2019-06-13 11:23:57 -04001512 this->write(ByteCodeInstruction::kLoopMask);
1513 // TODO: Could shorten this with kBranchIfAnyTrue
1514 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1515 DeferredLocation endLocation(this);
1516 this->write(ByteCodeInstruction::kBranch);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001517 this->write16(start);
Brian Osman569f12f2019-06-13 11:23:57 -04001518 endLocation.set();
1519 this->write(ByteCodeInstruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001520}
1521
1522void ByteCodeGenerator::writeForStatement(const ForStatement& f) {
1523 fContinueTargets.emplace();
1524 fBreakTargets.emplace();
1525 if (f.fInitializer) {
1526 this->writeStatement(*f.fInitializer);
1527 }
Brian Osman569f12f2019-06-13 11:23:57 -04001528 this->write(ByteCodeInstruction::kLoopBegin);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001529 size_t start = fCode->size();
1530 if (f.fTest) {
1531 this->writeExpression(*f.fTest);
Brian Osman569f12f2019-06-13 11:23:57 -04001532 this->write(ByteCodeInstruction::kLoopMask);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001533 }
Brian Osman569f12f2019-06-13 11:23:57 -04001534 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1535 DeferredLocation endLocation(this);
1536 this->writeStatement(*f.fStatement);
1537 this->write(ByteCodeInstruction::kLoopNext);
1538 if (f.fNext) {
1539 this->writeExpression(*f.fNext, true);
1540 }
1541 this->write(ByteCodeInstruction::kBranch);
1542 this->write16(start);
1543 endLocation.set();
1544 this->write(ByteCodeInstruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001545}
1546
1547void ByteCodeGenerator::writeIfStatement(const IfStatement& i) {
Brian Osman569f12f2019-06-13 11:23:57 -04001548 this->writeExpression(*i.fTest);
1549 this->write(ByteCodeInstruction::kMaskPush);
1550 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1551 DeferredLocation falseLocation(this);
1552 this->writeStatement(*i.fIfTrue);
1553 falseLocation.set();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001554 if (i.fIfFalse) {
Brian Osman569f12f2019-06-13 11:23:57 -04001555 this->write(ByteCodeInstruction::kMaskNegate);
1556 this->write(ByteCodeInstruction::kBranchIfAllFalse);
1557 DeferredLocation endLocation(this);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001558 this->writeStatement(*i.fIfFalse);
Mike Kleinb45ee832019-05-17 11:11:11 -05001559 endLocation.set();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001560 }
Brian Osman569f12f2019-06-13 11:23:57 -04001561 this->write(ByteCodeInstruction::kMaskPop);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001562}
1563
1564void ByteCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
Brian Osman4a47da72019-07-12 11:30:32 -04001565 if (fLoopCount || fConditionCount) {
1566 fErrors.error(r.fOffset, "return not allowed inside conditional or loop");
1567 return;
1568 }
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001569 int count = SlotCount(r.fExpression->fType);
Ethan Nicholas746035a2019-04-23 13:31:09 -04001570 this->writeExpression(*r.fExpression);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001571
1572 // Technically, the kReturn also pops fOutput->fLocalCount values from the stack, too, but we
1573 // haven't counted pushing those (they're outside the scope of our stack tracking). Instead,
1574 // we account for those in writeFunction().
1575
1576 // This is all fine because we don't allow conditional returns, so we only return once anyway.
1577 this->write(ByteCodeInstruction::kReturn, -count);
1578 this->write8(count);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001579}
1580
1581void ByteCodeGenerator::writeSwitchStatement(const SwitchStatement& r) {
1582 // not yet implemented
1583 abort();
1584}
1585
1586void ByteCodeGenerator::writeVarDeclarations(const VarDeclarations& v) {
1587 for (const auto& declStatement : v.fVars) {
1588 const VarDeclaration& decl = (VarDeclaration&) *declStatement;
Brian Osman1c110a02019-10-01 14:53:32 -04001589 // we need to grab the location even if we don't use it, to ensure it has been allocated
1590 Location location = this->getLocation(*decl.fVar);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001591 if (decl.fValue) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001592 this->writeExpression(*decl.fValue);
Brian Osman07c117b2019-05-23 12:51:06 -07001593 int count = SlotCount(decl.fValue->fType);
1594 if (count > 4) {
1595 this->write(ByteCodeInstruction::kPushImmediate);
Brian Osman1c110a02019-10-01 14:53:32 -04001596 this->write32(location.fSlot);
Brian Osmanaa2ca3f2019-07-15 13:24:48 -04001597 this->write(ByteCodeInstruction::kStoreExtended, count);
Brian Osman07c117b2019-05-23 12:51:06 -07001598 this->write8(count);
1599 } else {
1600 this->write(vector_instruction(ByteCodeInstruction::kStore, count));
Brian Osman1c110a02019-10-01 14:53:32 -04001601 this->write8(location.fSlot);
Brian Osman07c117b2019-05-23 12:51:06 -07001602 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001603 }
1604 }
1605}
1606
1607void ByteCodeGenerator::writeWhileStatement(const WhileStatement& w) {
Brian Osman569f12f2019-06-13 11:23:57 -04001608 this->write(ByteCodeInstruction::kLoopBegin);
1609 size_t cond = fCode->size();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001610 this->writeExpression(*w.fTest);
Brian Osman569f12f2019-06-13 11:23:57 -04001611 this->write(ByteCodeInstruction::kLoopMask);
1612 this->write(ByteCodeInstruction::kBranchIfAllFalse);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001613 DeferredLocation endLocation(this);
1614 this->writeStatement(*w.fStatement);
Brian Osman569f12f2019-06-13 11:23:57 -04001615 this->write(ByteCodeInstruction::kLoopNext);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001616 this->write(ByteCodeInstruction::kBranch);
Brian Osman569f12f2019-06-13 11:23:57 -04001617 this->write16(cond);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001618 endLocation.set();
Brian Osman569f12f2019-06-13 11:23:57 -04001619 this->write(ByteCodeInstruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001620}
1621
1622void ByteCodeGenerator::writeStatement(const Statement& s) {
1623 switch (s.fKind) {
1624 case Statement::kBlock_Kind:
1625 this->writeBlock((Block&) s);
1626 break;
1627 case Statement::kBreak_Kind:
1628 this->writeBreakStatement((BreakStatement&) s);
1629 break;
1630 case Statement::kContinue_Kind:
1631 this->writeContinueStatement((ContinueStatement&) s);
1632 break;
1633 case Statement::kDiscard_Kind:
1634 // not yet implemented
1635 abort();
1636 case Statement::kDo_Kind:
1637 this->writeDoStatement((DoStatement&) s);
1638 break;
Brian Osman3e29f1d2019-05-28 09:35:05 -04001639 case Statement::kExpression_Kind:
1640 this->writeExpression(*((ExpressionStatement&) s).fExpression, true);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001641 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001642 case Statement::kFor_Kind:
1643 this->writeForStatement((ForStatement&) s);
1644 break;
1645 case Statement::kIf_Kind:
1646 this->writeIfStatement((IfStatement&) s);
1647 break;
1648 case Statement::kNop_Kind:
1649 break;
1650 case Statement::kReturn_Kind:
1651 this->writeReturnStatement((ReturnStatement&) s);
1652 break;
1653 case Statement::kSwitch_Kind:
1654 this->writeSwitchStatement((SwitchStatement&) s);
1655 break;
1656 case Statement::kVarDeclarations_Kind:
1657 this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration);
1658 break;
1659 case Statement::kWhile_Kind:
1660 this->writeWhileStatement((WhileStatement&) s);
1661 break;
1662 default:
1663 SkASSERT(false);
1664 }
1665}
1666
Brian Osman80164412019-06-07 13:00:23 -04001667ByteCodeFunction::ByteCodeFunction(const FunctionDeclaration* declaration)
1668 : fName(declaration->fName) {
1669 fParameterCount = 0;
1670 for (const auto& p : declaration->fParameters) {
1671 int slots = ByteCodeGenerator::SlotCount(p->fType);
1672 fParameters.push_back({ slots, (bool)(p->fModifiers.fFlags & Modifiers::kOut_Flag) });
1673 fParameterCount += slots;
1674 }
1675}
1676
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001677}