blob: 1e9dab07ff3e91815596c1f1e8468515ece7f261 [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) {
Ethan Nicholase6592142020-09-08 10:22:09 -040015 switch (type.typeKind()) {
16 case Type::TypeKind::kVector:
17 case Type::TypeKind::kMatrix:
Brian Osmanb08cc022020-04-02 11:38:40 -040018 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 Osman2a4871b2020-06-19 11:29:58 -040049 { "atan", ByteCodeInstruction::kATan },
50 { "ceil", ByteCodeInstruction::kCeil },
51 { "clamp", SpecialIntrinsic::kClamp },
52 { "cos", ByteCodeInstruction::kCos },
53 { "dot", SpecialIntrinsic::kDot },
54 { "floor", ByteCodeInstruction::kFloor },
55 { "fract", ByteCodeInstruction::kFract },
56 { "inverse", ByteCodeInstruction::kInverse2x2 },
57 { "length", SpecialIntrinsic::kLength },
58 { "max", SpecialIntrinsic::kMax },
59 { "min", SpecialIntrinsic::kMin },
60 { "mix", SpecialIntrinsic::kMix },
61 { "normalize", SpecialIntrinsic::kNormalize },
62 { "pow", ByteCodeInstruction::kPow },
63 { "sample", SpecialIntrinsic::kSample },
64 { "saturate", SpecialIntrinsic::kSaturate },
65 { "sin", ByteCodeInstruction::kSin },
66 { "sqrt", ByteCodeInstruction::kSqrt },
67 { "tan", ByteCodeInstruction::kTan },
Brian Osman8842b372020-05-01 15:07:49 -040068
69 { "lessThan", { ByteCodeInstruction::kCompareFLT,
70 ByteCodeInstruction::kCompareSLT,
71 ByteCodeInstruction::kCompareULT } },
72 { "lessThanEqual", { ByteCodeInstruction::kCompareFLTEQ,
73 ByteCodeInstruction::kCompareSLTEQ,
74 ByteCodeInstruction::kCompareULTEQ } },
75 { "greaterThan", { ByteCodeInstruction::kCompareFGT,
76 ByteCodeInstruction::kCompareSGT,
77 ByteCodeInstruction::kCompareUGT } },
78 { "greaterThanEqual", { ByteCodeInstruction::kCompareFGTEQ,
79 ByteCodeInstruction::kCompareSGTEQ,
80 ByteCodeInstruction::kCompareUGTEQ } },
81 { "equal", { ByteCodeInstruction::kCompareFEQ,
82 ByteCodeInstruction::kCompareIEQ,
83 ByteCodeInstruction::kCompareIEQ } },
84 { "notEqual", { ByteCodeInstruction::kCompareFNEQ,
85 ByteCodeInstruction::kCompareINEQ,
86 ByteCodeInstruction::kCompareINEQ } },
87
88 { "any", SpecialIntrinsic::kAny },
89 { "all", SpecialIntrinsic::kAll },
90 { "not", ByteCodeInstruction::kNotB },
91 } {}
Brian Osmanb08cc022020-04-02 11:38:40 -040092
Ethan Nicholas82162ee2019-05-21 16:05:08 -040093
Brian Osman07c117b2019-05-23 12:51:06 -070094int ByteCodeGenerator::SlotCount(const Type& type) {
Ethan Nicholase6592142020-09-08 10:22:09 -040095 switch (type.typeKind()) {
96 case Type::TypeKind::kOther:
97 return 0;
98 case Type::TypeKind::kStruct: {
99 int slots = 0;
100 for (const auto& f : type.fields()) {
101 slots += SlotCount(*f.fType);
102 }
103 SkASSERT(slots <= 255);
104 return slots;
Brian Osman07c117b2019-05-23 12:51:06 -0700105 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400106 case Type::TypeKind::kArray: {
107 int columns = type.columns();
108 SkASSERT(columns >= 0);
109 int slots = columns * SlotCount(type.componentType());
110 SkASSERT(slots <= 255);
111 return slots;
112 }
113 default:
114 return type.columns() * type.rows();
Brian Osman07c117b2019-05-23 12:51:06 -0700115 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400116}
117
Brian Osman1c110a02019-10-01 14:53:32 -0400118static inline bool is_uniform(const SkSL::Variable& var) {
119 return var.fModifiers.fFlags & Modifiers::kUniform_Flag;
120}
121
Brian Osmaneadfeb92020-01-09 12:43:03 -0500122static inline bool is_in(const SkSL::Variable& var) {
123 return var.fModifiers.fFlags & Modifiers::kIn_Flag;
124}
Brian Osmanb08cc022020-04-02 11:38:40 -0400125
126void ByteCodeGenerator::gatherUniforms(const Type& type, const String& name) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400127 switch (type.typeKind()) {
128 case Type::TypeKind::kOther:
129 break;
130 case Type::TypeKind::kStruct:
131 for (const auto& f : type.fields()) {
132 this->gatherUniforms(*f.fType, name + "." + f.fName);
133 }
134 break;
135 case Type::TypeKind::kArray:
136 for (int i = 0; i < type.columns(); ++i) {
137 this->gatherUniforms(type.componentType(), String::printf("%s[%d]", name.c_str(),
138 i));
139 }
140 break;
141 default:
142 fOutput->fUniforms.push_back({ name, type_category(type), type.rows(), type.columns(),
143 fOutput->fUniformSlotCount });
144 fOutput->fUniformSlotCount += type.columns() * type.rows();
Brian Osmanb08cc022020-04-02 11:38:40 -0400145 }
146}
147
148bool ByteCodeGenerator::generateCode() {
149 for (const auto& e : fProgram) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400150 switch (e.kind()) {
151 case ProgramElement::Kind::kFunction: {
John Stiles3dc0da62020-08-19 17:48:31 -0400152 std::unique_ptr<ByteCodeFunction> f =
153 this->writeFunction(e.as<FunctionDefinition>());
Brian Osmanb08cc022020-04-02 11:38:40 -0400154 if (!f) {
155 return false;
156 }
157 fOutput->fFunctions.push_back(std::move(f));
John Stiles3dc0da62020-08-19 17:48:31 -0400158 fFunctions.push_back(&e.as<FunctionDefinition>());
Brian Osmanb08cc022020-04-02 11:38:40 -0400159 break;
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500160 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400161 case ProgramElement::Kind::kVar: {
John Stiles3dc0da62020-08-19 17:48:31 -0400162 const VarDeclarations& decl = e.as<VarDeclarations>();
Brian Osmanb08cc022020-04-02 11:38:40 -0400163 for (const auto& v : decl.fVars) {
John Stiles3dc0da62020-08-19 17:48:31 -0400164 const Variable* declVar = v->as<VarDeclaration>().fVar;
Ethan Nicholas30d30222020-09-11 12:27:26 -0400165 if (declVar->type() == *fContext.fFragmentProcessor_Type) {
Brian Osmana43d8202020-06-17 16:50:39 -0400166 fOutput->fChildFPCount++;
167 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400168 if (declVar->fModifiers.fLayout.fBuiltin >= 0 || is_in(*declVar)) {
169 continue;
170 }
171 if (is_uniform(*declVar)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400172 this->gatherUniforms(declVar->type(), declVar->fName);
Brian Osmanb08cc022020-04-02 11:38:40 -0400173 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400174 fOutput->fGlobalSlotCount += SlotCount(declVar->type());
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400175 }
176 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400177 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400178 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400179 default:
180 ; // ignore
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400181 }
182 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400183 return 0 == fErrors.errorCount();
184}
185
186std::unique_ptr<ByteCodeFunction> ByteCodeGenerator::writeFunction(const FunctionDefinition& f) {
187 fFunction = &f;
188 std::unique_ptr<ByteCodeFunction> result(new ByteCodeFunction(&f.fDeclaration));
189 fParameterCount = result->fParameterCount;
190 fLoopCount = fMaxLoopCount = 0;
191 fConditionCount = fMaxConditionCount = 0;
192 fStackCount = fMaxStackCount = 0;
193 fCode = &result->fCode;
194
195 this->writeStatement(*f.fBody);
196 if (0 == fErrors.errorCount()) {
197 SkASSERT(fLoopCount == 0);
198 SkASSERT(fConditionCount == 0);
199 SkASSERT(fStackCount == 0);
200 }
201 this->write(ByteCodeInstruction::kReturn, 0);
Brian Osmanb08cc022020-04-02 11:38:40 -0400202
203 result->fLocalCount = fLocals.size();
204 result->fConditionCount = fMaxConditionCount;
205 result->fLoopCount = fMaxLoopCount;
206 result->fStackCount = fMaxStackCount;
207
208 const Type& returnType = f.fDeclaration.fReturnType;
209 if (returnType != *fContext.fVoid_Type) {
210 result->fReturnCount = SlotCount(returnType);
211 }
212 fLocals.clear();
213 fFunction = nullptr;
214 return result;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400215}
216
Brian Osman5aaaeea2020-06-22 14:26:03 -0400217// If the expression is a reference to a builtin global variable, return the builtin ID.
218// Otherwise, return -1.
219static int expression_as_builtin(const Expression& e) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400220 if (e.kind() == Expression::Kind::kVariableReference) {
John Stiles403a3632020-08-20 12:11:48 -0400221 const Variable& var(e.as<VariableReference>().fVariable);
Brian Osman5aaaeea2020-06-22 14:26:03 -0400222 if (var.fStorage == Variable::kGlobal_Storage) {
223 return var.fModifiers.fLayout.fBuiltin;
224 }
225 }
226 return -1;
227}
228
Brian Osman0785db02019-05-24 14:19:11 -0400229// A "simple" Swizzle is based on a variable (or a compound variable like a struct or array), and
230// that references consecutive values, such that it can be implemented using normal load/store ops
231// with an offset. Note that all single-component swizzles (of suitable base types) are simple.
232static bool swizzle_is_simple(const Swizzle& s) {
Brian Osman5aaaeea2020-06-22 14:26:03 -0400233 // Builtin variables use dedicated instructions that don't allow subset loads
234 if (expression_as_builtin(*s.fBase) >= 0) {
235 return false;
236 }
237
Ethan Nicholase6592142020-09-08 10:22:09 -0400238 switch (s.fBase->kind()) {
239 case Expression::Kind::kFieldAccess:
240 case Expression::Kind::kIndex:
241 case Expression::Kind::kVariableReference:
Brian Osman0785db02019-05-24 14:19:11 -0400242 break;
243 default:
244 return false;
245 }
246
247 for (size_t i = 1; i < s.fComponents.size(); ++i) {
248 if (s.fComponents[i] != s.fComponents[i - 1] + 1) {
249 return false;
250 }
251 }
252 return true;
253}
254
Brian Osmanb08cc022020-04-02 11:38:40 -0400255int ByteCodeGenerator::StackUsage(ByteCodeInstruction inst, int count_) {
256 // Ensures that we use count iff we're passed a non-default value. Most instructions have an
257 // implicit count, so the caller shouldn't need to worry about it (or count makes no sense).
258 // The asserts avoids callers thinking they're supplying useful information in that scenario,
259 // or failing to supply necessary information for the ops that need a count.
260 struct CountValue {
261 operator int() {
262 SkASSERT(val != ByteCodeGenerator::kUnusedStackCount);
263 SkDEBUGCODE(used = true);
264 return val;
265 }
266 ~CountValue() {
267 SkASSERT(used || val == ByteCodeGenerator::kUnusedStackCount);
268 }
269 int val;
270 SkDEBUGCODE(bool used = false;)
271 } count = { count_ };
272
273 switch (inst) {
274 // Unary functions/operators that don't change stack depth at all:
Brian Osmanb08cc022020-04-02 11:38:40 -0400275
Brian Osman49b30f42020-06-26 17:22:27 -0400276#define VEC_UNARY(inst) case ByteCodeInstruction::inst: return count - count;
Brian Osmanb08cc022020-04-02 11:38:40 -0400277
Brian Osman49b30f42020-06-26 17:22:27 -0400278 VEC_UNARY(kConvertFtoI)
279 VEC_UNARY(kConvertStoF)
280 VEC_UNARY(kConvertUtoF)
Brian Osmanb08cc022020-04-02 11:38:40 -0400281
Brian Osman49b30f42020-06-26 17:22:27 -0400282 VEC_UNARY(kATan)
283 VEC_UNARY(kCeil)
284 VEC_UNARY(kCos)
285 VEC_UNARY(kFloor)
286 VEC_UNARY(kFract)
287 VEC_UNARY(kSin)
288 VEC_UNARY(kSqrt)
289 VEC_UNARY(kTan)
290
291 VEC_UNARY(kNegateF)
292 VEC_UNARY(kNegateI)
293 VEC_UNARY(kNotB)
294
295#undef VEC_UNARY
Brian Osmanb08cc022020-04-02 11:38:40 -0400296
297 case ByteCodeInstruction::kInverse2x2:
298 case ByteCodeInstruction::kInverse3x3:
299 case ByteCodeInstruction::kInverse4x4: return 0;
300
Brian Osman49b30f42020-06-26 17:22:27 -0400301 case ByteCodeInstruction::kClampIndex: return 0;
302 case ByteCodeInstruction::kShiftLeft: return 0;
Brian Osmanb08cc022020-04-02 11:38:40 -0400303 case ByteCodeInstruction::kShiftRightS: return 0;
304 case ByteCodeInstruction::kShiftRightU: return 0;
305
Brian Osman49b30f42020-06-26 17:22:27 -0400306 // Binary functions/operators that do a 2 -> 1 reduction, N times
307 case ByteCodeInstruction::kAndB: return -count;
308 case ByteCodeInstruction::kOrB: return -count;
309 case ByteCodeInstruction::kXorB: return -count;
Brian Osmanb08cc022020-04-02 11:38:40 -0400310
Brian Osman49b30f42020-06-26 17:22:27 -0400311 case ByteCodeInstruction::kAddI: return -count;
312 case ByteCodeInstruction::kAddF: return -count;
Brian Osmanb08cc022020-04-02 11:38:40 -0400313
Brian Osman49b30f42020-06-26 17:22:27 -0400314 case ByteCodeInstruction::kCompareIEQ: return -count;
315 case ByteCodeInstruction::kCompareFEQ: return -count;
316 case ByteCodeInstruction::kCompareINEQ: return -count;
317 case ByteCodeInstruction::kCompareFNEQ: return -count;
318 case ByteCodeInstruction::kCompareSGT: return -count;
319 case ByteCodeInstruction::kCompareUGT: return -count;
320 case ByteCodeInstruction::kCompareFGT: return -count;
321 case ByteCodeInstruction::kCompareSGTEQ: return -count;
322 case ByteCodeInstruction::kCompareUGTEQ: return -count;
323 case ByteCodeInstruction::kCompareFGTEQ: return -count;
324 case ByteCodeInstruction::kCompareSLT: return -count;
325 case ByteCodeInstruction::kCompareULT: return -count;
326 case ByteCodeInstruction::kCompareFLT: return -count;
327 case ByteCodeInstruction::kCompareSLTEQ: return -count;
328 case ByteCodeInstruction::kCompareULTEQ: return -count;
329 case ByteCodeInstruction::kCompareFLTEQ: return -count;
Brian Osmanb08cc022020-04-02 11:38:40 -0400330
Brian Osman49b30f42020-06-26 17:22:27 -0400331 case ByteCodeInstruction::kDivideS: return -count;
332 case ByteCodeInstruction::kDivideU: return -count;
333 case ByteCodeInstruction::kDivideF: return -count;
334 case ByteCodeInstruction::kMaxF: return -count;
335 case ByteCodeInstruction::kMaxS: return -count;
336 case ByteCodeInstruction::kMinF: return -count;
337 case ByteCodeInstruction::kMinS: return -count;
338 case ByteCodeInstruction::kMultiplyI: return -count;
339 case ByteCodeInstruction::kMultiplyF: return -count;
340 case ByteCodeInstruction::kPow: return -count;
341 case ByteCodeInstruction::kRemainderF: return -count;
342 case ByteCodeInstruction::kRemainderS: return -count;
343 case ByteCodeInstruction::kRemainderU: return -count;
344 case ByteCodeInstruction::kSubtractI: return -count;
345 case ByteCodeInstruction::kSubtractF: return -count;
Brian Osmanb08cc022020-04-02 11:38:40 -0400346
347 // Ops that push or load data to grow the stack:
Brian Osman49b30f42020-06-26 17:22:27 -0400348 case ByteCodeInstruction::kPushImmediate:
349 return 1;
350 case ByteCodeInstruction::kLoadFragCoord:
351 return 4;
352
Brian Osmanb08cc022020-04-02 11:38:40 -0400353 case ByteCodeInstruction::kDup:
354 case ByteCodeInstruction::kLoad:
355 case ByteCodeInstruction::kLoadGlobal:
356 case ByteCodeInstruction::kLoadUniform:
357 case ByteCodeInstruction::kReadExternal:
Brian Osman49b30f42020-06-26 17:22:27 -0400358 case ByteCodeInstruction::kReserve:
Brian Osmanb08cc022020-04-02 11:38:40 -0400359 return count;
360
361 // Pushes 'count' values, minus one for the 'address' that's consumed first
362 case ByteCodeInstruction::kLoadExtended:
363 case ByteCodeInstruction::kLoadExtendedGlobal:
364 case ByteCodeInstruction::kLoadExtendedUniform:
365 return count - 1;
366
367 // Ops that pop or store data to shrink the stack:
368 case ByteCodeInstruction::kPop:
Brian Osman49b30f42020-06-26 17:22:27 -0400369 case ByteCodeInstruction::kReturn:
Brian Osmanb08cc022020-04-02 11:38:40 -0400370 case ByteCodeInstruction::kStore:
371 case ByteCodeInstruction::kStoreGlobal:
372 case ByteCodeInstruction::kWriteExternal:
Brian Osmanb08cc022020-04-02 11:38:40 -0400373 return -count;
374
375 // Consumes 'count' values, plus one for the 'address'
376 case ByteCodeInstruction::kStoreExtended:
377 case ByteCodeInstruction::kStoreExtendedGlobal:
Brian Osmanb08cc022020-04-02 11:38:40 -0400378 return -count - 1;
379
380 // Strange ops where the caller computes the delta for us:
381 case ByteCodeInstruction::kCallExternal:
382 case ByteCodeInstruction::kMatrixToMatrix:
383 case ByteCodeInstruction::kMatrixMultiply:
Brian Osmanb08cc022020-04-02 11:38:40 -0400384 case ByteCodeInstruction::kScalarToMatrix:
385 case ByteCodeInstruction::kSwizzle:
386 return count;
387
388 // Miscellaneous
389
Brian Osman795efd22020-07-01 13:18:36 -0400390 // () -> (R, G, B, A)
391 case ByteCodeInstruction::kSample: return 4;
Brian Osmana43d8202020-06-17 16:50:39 -0400392 // (X, Y) -> (R, G, B, A)
393 case ByteCodeInstruction::kSampleExplicit: return 4 - 2;
394 // (float3x3) -> (R, G, B, A)
395 case ByteCodeInstruction::kSampleMatrix: return 4 - 9;
396
Brian Osman8842b372020-05-01 15:07:49 -0400397 // kMix does a 3 -> 1 reduction (A, B, M -> A -or- B) for each component
Brian Osman49b30f42020-06-26 17:22:27 -0400398 case ByteCodeInstruction::kMix: return -(2 * count);
Brian Osman8842b372020-05-01 15:07:49 -0400399
400 // kLerp works the same way (producing lerp(A, B, T) for each component)
Brian Osman49b30f42020-06-26 17:22:27 -0400401 case ByteCodeInstruction::kLerp: return -(2 * count);
Brian Osman8842b372020-05-01 15:07:49 -0400402
Brian Osmanb08cc022020-04-02 11:38:40 -0400403 // kCall is net-zero. Max stack depth is adjusted in writeFunctionCall.
404 case ByteCodeInstruction::kCall: return 0;
405 case ByteCodeInstruction::kBranch: return 0;
406 case ByteCodeInstruction::kBranchIfAllFalse: return 0;
407
408 case ByteCodeInstruction::kMaskPush: return -1;
409 case ByteCodeInstruction::kMaskPop: return 0;
410 case ByteCodeInstruction::kMaskNegate: return 0;
411 case ByteCodeInstruction::kMaskBlend: return -count;
412
413 case ByteCodeInstruction::kLoopBegin: return 0;
414 case ByteCodeInstruction::kLoopNext: return 0;
415 case ByteCodeInstruction::kLoopMask: return -1;
416 case ByteCodeInstruction::kLoopEnd: return 0;
417 case ByteCodeInstruction::kLoopBreak: return 0;
418 case ByteCodeInstruction::kLoopContinue: return 0;
Brian Osmanb08cc022020-04-02 11:38:40 -0400419 }
Brian Osmand5f937b2020-05-04 12:07:29 -0400420
421 SkUNREACHABLE;
Brian Osmanb08cc022020-04-02 11:38:40 -0400422}
423
424ByteCodeGenerator::Location ByteCodeGenerator::getLocation(const Variable& var) {
425 // given that we seldom have more than a couple of variables, linear search is probably the most
426 // efficient way to handle lookups
427 switch (var.fStorage) {
428 case Variable::kLocal_Storage: {
429 for (int i = fLocals.size() - 1; i >= 0; --i) {
430 if (fLocals[i] == &var) {
431 SkASSERT(fParameterCount + i <= 255);
432 return { fParameterCount + i, Storage::kLocal };
433 }
434 }
435 int result = fParameterCount + fLocals.size();
436 fLocals.push_back(&var);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400437 for (int i = 0; i < SlotCount(var.type()) - 1; ++i) {
Brian Osmanb08cc022020-04-02 11:38:40 -0400438 fLocals.push_back(nullptr);
439 }
440 SkASSERT(result <= 255);
441 return { result, Storage::kLocal };
442 }
443 case Variable::kParameter_Storage: {
444 int offset = 0;
445 for (const auto& p : fFunction->fDeclaration.fParameters) {
446 if (p == &var) {
447 SkASSERT(offset <= 255);
448 return { offset, Storage::kLocal };
449 }
Ethan Nicholas30d30222020-09-11 12:27:26 -0400450 offset += SlotCount(p->type());
Brian Osmanb08cc022020-04-02 11:38:40 -0400451 }
452 SkASSERT(false);
453 return Location::MakeInvalid();
454 }
455 case Variable::kGlobal_Storage: {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400456 if (var.type() == *fContext.fFragmentProcessor_Type) {
Brian Osmana43d8202020-06-17 16:50:39 -0400457 int offset = 0;
458 for (const auto& e : fProgram) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400459 if (e.kind() == ProgramElement::Kind::kVar) {
John Stiles403a3632020-08-20 12:11:48 -0400460 const VarDeclarations& decl = e.as<VarDeclarations>();
Brian Osmana43d8202020-06-17 16:50:39 -0400461 for (const auto& v : decl.fVars) {
John Stiles403a3632020-08-20 12:11:48 -0400462 const Variable* declVar = v->as<VarDeclaration>().fVar;
Ethan Nicholas30d30222020-09-11 12:27:26 -0400463 if (declVar->type() != *fContext.fFragmentProcessor_Type) {
Brian Osmana43d8202020-06-17 16:50:39 -0400464 continue;
465 }
466 if (declVar == &var) {
467 SkASSERT(offset <= 255);
468 return { offset, Storage::kChildFP };
469 }
470 offset++;
471 }
472 }
473 }
474 SkASSERT(false);
475 return Location::MakeInvalid();
476 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400477 if (is_in(var)) {
478 // If you see this error, it means the program is using raw 'in' variables. You
479 // should either specialize the program (Compiler::specialize) to bake in the final
480 // values of the 'in' variables, or not use 'in' variables (maybe you meant to use
481 // 'uniform' instead?).
482 fErrors.error(var.fOffset,
483 "'in' variable is not specialized or has unsupported type");
484 return Location::MakeInvalid();
485 }
486 int offset = 0;
487 bool isUniform = is_uniform(var);
488 for (const auto& e : fProgram) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400489 if (e.kind() == ProgramElement::Kind::kVar) {
John Stiles403a3632020-08-20 12:11:48 -0400490 const VarDeclarations& decl = e.as<VarDeclarations>();
Brian Osmanb08cc022020-04-02 11:38:40 -0400491 for (const auto& v : decl.fVars) {
John Stiles403a3632020-08-20 12:11:48 -0400492 const Variable* declVar = v->as<VarDeclaration>().fVar;
Brian Osmanb08cc022020-04-02 11:38:40 -0400493 if (declVar->fModifiers.fLayout.fBuiltin >= 0 || is_in(*declVar)) {
494 continue;
495 }
496 if (isUniform != is_uniform(*declVar)) {
497 continue;
498 }
499 if (declVar == &var) {
500 SkASSERT(offset <= 255);
501 return { offset, isUniform ? Storage::kUniform : Storage::kGlobal };
502 }
Ethan Nicholas30d30222020-09-11 12:27:26 -0400503 offset += SlotCount(declVar->type());
Brian Osmanb08cc022020-04-02 11:38:40 -0400504 }
505 }
506 }
507 SkASSERT(false);
508 return Location::MakeInvalid();
509 }
510 default:
511 SkASSERT(false);
512 return Location::MakeInvalid();
513 }
514}
515
Brian Osman1c110a02019-10-01 14:53:32 -0400516ByteCodeGenerator::Location ByteCodeGenerator::getLocation(const Expression& expr) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400517 switch (expr.kind()) {
518 case Expression::Kind::kFieldAccess: {
John Stiles403a3632020-08-20 12:11:48 -0400519 const FieldAccess& f = expr.as<FieldAccess>();
Brian Osmanb08cc022020-04-02 11:38:40 -0400520 Location baseLoc = this->getLocation(*f.fBase);
Brian Osman07c117b2019-05-23 12:51:06 -0700521 int offset = 0;
522 for (int i = 0; i < f.fFieldIndex; ++i) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400523 offset += SlotCount(*f.fBase->type().fields()[i].fType);
Brian Osman07c117b2019-05-23 12:51:06 -0700524 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400525 if (baseLoc.isOnStack()) {
526 if (offset != 0) {
527 this->write(ByteCodeInstruction::kPushImmediate);
528 this->write32(offset);
Brian Osman49b30f42020-06-26 17:22:27 -0400529 this->write(ByteCodeInstruction::kAddI, 1);
Ben Wagner470e0ac2020-01-22 16:59:21 -0500530 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400531 return baseLoc;
Ben Wagner470e0ac2020-01-22 16:59:21 -0500532 } else {
Brian Osmanb08cc022020-04-02 11:38:40 -0400533 return baseLoc + offset;
Ben Wagner470e0ac2020-01-22 16:59:21 -0500534 }
Ben Wagner470e0ac2020-01-22 16:59:21 -0500535 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400536 case Expression::Kind::kIndex: {
John Stiles403a3632020-08-20 12:11:48 -0400537 const IndexExpression& i = expr.as<IndexExpression>();
Ethan Nicholas30d30222020-09-11 12:27:26 -0400538 int stride = SlotCount(i.type());
539 int length = i.fBase->type().columns();
Brian Osmanb08cc022020-04-02 11:38:40 -0400540 SkASSERT(length <= 255);
541 int offset = -1;
Brian Osmanb6b95732020-06-30 11:44:27 -0400542 if (i.fIndex->isCompileTimeConstant()) {
Brian Osmanb08cc022020-04-02 11:38:40 -0400543 int64_t index = i.fIndex->getConstantInt();
544 if (index < 0 || index >= length) {
545 fErrors.error(i.fIndex->fOffset, "Array index out of bounds.");
546 return Location::MakeInvalid();
547 }
548 offset = index * stride;
549 } else {
550 if (i.fIndex->hasSideEffects()) {
551 // Having a side-effect in an indexer is technically safe for an rvalue,
552 // but with lvalues we have to evaluate the indexer twice, so make it an error.
553 fErrors.error(i.fIndex->fOffset,
554 "Index expressions with side-effects not supported in byte code.");
555 return Location::MakeInvalid();
556 }
557 this->writeExpression(*i.fIndex);
558 this->write(ByteCodeInstruction::kClampIndex);
559 this->write8(length);
560 if (stride != 1) {
561 this->write(ByteCodeInstruction::kPushImmediate);
562 this->write32(stride);
Brian Osman49b30f42020-06-26 17:22:27 -0400563 this->write(ByteCodeInstruction::kMultiplyI, 1);
Brian Osmanb08cc022020-04-02 11:38:40 -0400564 }
565 }
566 Location baseLoc = this->getLocation(*i.fBase);
567
568 // Are both components known statically?
569 if (!baseLoc.isOnStack() && offset >= 0) {
570 return baseLoc + offset;
571 }
572
573 // At least one component is dynamic (and on the stack).
574
575 // If the other component is zero, we're done
576 if (baseLoc.fSlot == 0 || offset == 0) {
577 return baseLoc.makeOnStack();
578 }
579
580 // Push the non-dynamic component (if any) to the stack, then add the two
581 if (!baseLoc.isOnStack()) {
582 this->write(ByteCodeInstruction::kPushImmediate);
583 this->write32(baseLoc.fSlot);
584 }
585 if (offset >= 0) {
586 this->write(ByteCodeInstruction::kPushImmediate);
587 this->write32(offset);
588 }
Brian Osman49b30f42020-06-26 17:22:27 -0400589 this->write(ByteCodeInstruction::kAddI, 1);
Brian Osmanb08cc022020-04-02 11:38:40 -0400590 return baseLoc.makeOnStack();
591 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400592 case Expression::Kind::kSwizzle: {
John Stiles403a3632020-08-20 12:11:48 -0400593 const Swizzle& s = expr.as<Swizzle>();
Brian Osman0785db02019-05-24 14:19:11 -0400594 SkASSERT(swizzle_is_simple(s));
Brian Osmanb08cc022020-04-02 11:38:40 -0400595 Location baseLoc = this->getLocation(*s.fBase);
596 int offset = s.fComponents[0];
597 if (baseLoc.isOnStack()) {
598 if (offset != 0) {
599 this->write(ByteCodeInstruction::kPushImmediate);
600 this->write32(offset);
Brian Osman49b30f42020-06-26 17:22:27 -0400601 this->write(ByteCodeInstruction::kAddI, 1);
Brian Osmanb08cc022020-04-02 11:38:40 -0400602 }
603 return baseLoc;
604 } else {
605 return baseLoc + offset;
606 }
Brian Osman0785db02019-05-24 14:19:11 -0400607 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400608 case Expression::Kind::kVariableReference: {
John Stiles403a3632020-08-20 12:11:48 -0400609 const Variable& var = expr.as<VariableReference>().fVariable;
Brian Osman07c117b2019-05-23 12:51:06 -0700610 return this->getLocation(var);
611 }
612 default:
613 SkASSERT(false);
Brian Osmanb08cc022020-04-02 11:38:40 -0400614 return Location::MakeInvalid();
Brian Osman07c117b2019-05-23 12:51:06 -0700615 }
616}
617
Brian Osmanb08cc022020-04-02 11:38:40 -0400618void ByteCodeGenerator::write8(uint8_t b) {
619 fCode->push_back(b);
Ethan Nicholas2cde3a12020-01-21 09:23:13 -0500620}
621
Brian Osmanb08cc022020-04-02 11:38:40 -0400622void ByteCodeGenerator::write16(uint16_t i) {
623 size_t n = fCode->size();
624 fCode->resize(n+2);
625 memcpy(fCode->data() + n, &i, 2);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500626}
Ben Wagner470e0ac2020-01-22 16:59:21 -0500627
Brian Osmanb08cc022020-04-02 11:38:40 -0400628void ByteCodeGenerator::write32(uint32_t i) {
629 size_t n = fCode->size();
630 fCode->resize(n+4);
631 memcpy(fCode->data() + n, &i, 4);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500632}
633
Brian Osmanb08cc022020-04-02 11:38:40 -0400634void ByteCodeGenerator::write(ByteCodeInstruction i, int count) {
635 switch (i) {
636 case ByteCodeInstruction::kLoopBegin: this->enterLoop(); break;
637 case ByteCodeInstruction::kLoopEnd: this->exitLoop(); break;
Ethan Nicholas2329da02020-01-24 15:49:33 -0500638
Brian Osmanb08cc022020-04-02 11:38:40 -0400639 case ByteCodeInstruction::kMaskPush: this->enterCondition(); break;
640 case ByteCodeInstruction::kMaskPop:
641 case ByteCodeInstruction::kMaskBlend: this->exitCondition(); break;
642 default: /* Do nothing */ break;
Ben Wagner470e0ac2020-01-22 16:59:21 -0500643 }
Mike Klein01d01612020-08-14 10:52:11 -0500644 this->write8((uint8_t)i);
Brian Osmanb08cc022020-04-02 11:38:40 -0400645 fStackCount += StackUsage(i, count);
646 fMaxStackCount = std::max(fMaxStackCount, fStackCount);
Brian Osman49b30f42020-06-26 17:22:27 -0400647
648 // Most ops have an explicit count byte after them (passed here as 'count')
649 // Ops that don't have a count byte pass the default (kUnusedStackCount)
650 // There are a handful of strange ops that pass in a computed stack delta as count, but where
651 // that value should *not* be written as a count byte (it may even be negative!)
652 if (count != kUnusedStackCount) {
653 switch (i) {
654 // Odd instructions that have a non-default count, but we shouldn't write it
655 case ByteCodeInstruction::kCallExternal:
656 case ByteCodeInstruction::kMatrixToMatrix:
657 case ByteCodeInstruction::kMatrixMultiply:
658 case ByteCodeInstruction::kScalarToMatrix:
659 case ByteCodeInstruction::kSwizzle:
660 break;
661 default:
662 this->write8(count);
663 break;
664 }
665 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500666}
667
Brian Osman49b30f42020-06-26 17:22:27 -0400668void ByteCodeGenerator::writeTypedInstruction(const Type& type,
669 ByteCodeInstruction s,
670 ByteCodeInstruction u,
671 ByteCodeInstruction f,
Brian Osmanab8f3842020-04-07 09:30:44 -0400672 int count) {
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500673 switch (type_category(type)) {
Brian Osman8842b372020-05-01 15:07:49 -0400674 case TypeCategory::kBool:
Brian Osman49b30f42020-06-26 17:22:27 -0400675 case TypeCategory::kSigned: this->write(s, count); break;
676 case TypeCategory::kUnsigned: this->write(u, count); break;
677 case TypeCategory::kFloat: this->write(f, count); break;
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500678 default:
679 SkASSERT(false);
680 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500681}
682
Brian Osmanb08cc022020-04-02 11:38:40 -0400683bool ByteCodeGenerator::writeBinaryExpression(const BinaryExpression& b, bool discard) {
Ethan Nicholas1d3e0e02020-09-16 15:19:24 -0400684 const Expression& left = b.left();
685 const Expression& right = b.right();
686 Token::Kind op = b.getOperator();
687 if (op == Token::Kind::TK_EQ) {
688 std::unique_ptr<LValue> lvalue = this->getLValue(left);
689 this->writeExpression(right);
Brian Osmanb08cc022020-04-02 11:38:40 -0400690 lvalue->store(discard);
691 discard = false;
692 return discard;
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500693 }
Ethan Nicholas1d3e0e02020-09-16 15:19:24 -0400694 const Type& lType = left.type();
695 const Type& rType = right.type();
Ethan Nicholase6592142020-09-08 10:22:09 -0400696 bool lVecOrMtx = (lType.typeKind() == Type::TypeKind::kVector ||
697 lType.typeKind() == Type::TypeKind::kMatrix);
698 bool rVecOrMtx = (rType.typeKind() == Type::TypeKind::kVector ||
699 rType.typeKind() == Type::TypeKind::kMatrix);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500700 std::unique_ptr<LValue> lvalue;
Ethan Nicholas1d3e0e02020-09-16 15:19:24 -0400701 if (Compiler::IsAssignment(op)) {
702 lvalue = this->getLValue(left);
Brian Osmanb08cc022020-04-02 11:38:40 -0400703 lvalue->load();
Ethan Nicholas1d3e0e02020-09-16 15:19:24 -0400704 op = Compiler::RemoveAssignment(op);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500705 } else {
Ethan Nicholas1d3e0e02020-09-16 15:19:24 -0400706 this->writeExpression(left);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500707 if (!lVecOrMtx && rVecOrMtx) {
Brian Osmanb08cc022020-04-02 11:38:40 -0400708 for (int i = SlotCount(rType); i > 1; --i) {
Brian Osman49b30f42020-06-26 17:22:27 -0400709 this->write(ByteCodeInstruction::kDup, 1);
Brian Osmanb08cc022020-04-02 11:38:40 -0400710 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500711 }
712 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500713 int count = std::max(SlotCount(lType), SlotCount(rType));
Brian Osmanb08cc022020-04-02 11:38:40 -0400714 SkDEBUGCODE(TypeCategory tc = type_category(lType));
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500715 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400716 case Token::Kind::TK_LOGICALAND: {
Brian Osmanb08cc022020-04-02 11:38:40 -0400717 SkASSERT(tc == SkSL::TypeCategory::kBool && count == 1);
Brian Osman49b30f42020-06-26 17:22:27 -0400718 this->write(ByteCodeInstruction::kDup, 1);
Brian Osmanb08cc022020-04-02 11:38:40 -0400719 this->write(ByteCodeInstruction::kMaskPush);
720 this->write(ByteCodeInstruction::kBranchIfAllFalse);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500721 DeferredLocation falseLocation(this);
Ethan Nicholas1d3e0e02020-09-16 15:19:24 -0400722 this->writeExpression(right);
Brian Osman49b30f42020-06-26 17:22:27 -0400723 this->write(ByteCodeInstruction::kAndB, 1);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500724 falseLocation.set();
Brian Osmanb08cc022020-04-02 11:38:40 -0400725 this->write(ByteCodeInstruction::kMaskPop);
726 return false;
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500727 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400728 case Token::Kind::TK_LOGICALOR: {
Brian Osmanb08cc022020-04-02 11:38:40 -0400729 SkASSERT(tc == SkSL::TypeCategory::kBool && count == 1);
Brian Osman49b30f42020-06-26 17:22:27 -0400730 this->write(ByteCodeInstruction::kDup, 1);
731 this->write(ByteCodeInstruction::kNotB, 1);
Brian Osmanb08cc022020-04-02 11:38:40 -0400732 this->write(ByteCodeInstruction::kMaskPush);
733 this->write(ByteCodeInstruction::kBranchIfAllFalse);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500734 DeferredLocation falseLocation(this);
Ethan Nicholas1d3e0e02020-09-16 15:19:24 -0400735 this->writeExpression(right);
Brian Osman49b30f42020-06-26 17:22:27 -0400736 this->write(ByteCodeInstruction::kOrB, 1);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500737 falseLocation.set();
Brian Osmanb08cc022020-04-02 11:38:40 -0400738 this->write(ByteCodeInstruction::kMaskPop);
739 return false;
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500740 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400741 case Token::Kind::TK_SHL:
742 case Token::Kind::TK_SHR: {
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500743 SkASSERT(count == 1 && (tc == SkSL::TypeCategory::kSigned ||
744 tc == SkSL::TypeCategory::kUnsigned));
Ethan Nicholas1d3e0e02020-09-16 15:19:24 -0400745 if (!right.isCompileTimeConstant()) {
746 fErrors.error(right.fOffset, "Shift amounts must be constant");
Brian Osmanb08cc022020-04-02 11:38:40 -0400747 return false;
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500748 }
Ethan Nicholas1d3e0e02020-09-16 15:19:24 -0400749 int64_t shift = right.getConstantInt();
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500750 if (shift < 0 || shift > 31) {
Ethan Nicholas1d3e0e02020-09-16 15:19:24 -0400751 fErrors.error(right.fOffset, "Shift amount out of range");
Brian Osmanb08cc022020-04-02 11:38:40 -0400752 return false;
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500753 }
754
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400755 if (op == Token::Kind::TK_SHL) {
Brian Osmanb08cc022020-04-02 11:38:40 -0400756 this->write(ByteCodeInstruction::kShiftLeft);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500757 } else {
758 this->write(type_category(lType) == TypeCategory::kSigned
Brian Osmanb08cc022020-04-02 11:38:40 -0400759 ? ByteCodeInstruction::kShiftRightS
760 : ByteCodeInstruction::kShiftRightU);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500761 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400762 this->write8(shift);
763 return false;
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500764 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500765
766 default:
767 break;
768 }
Ethan Nicholas1d3e0e02020-09-16 15:19:24 -0400769 this->writeExpression(right);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500770 if (lVecOrMtx && !rVecOrMtx) {
Brian Osmanb08cc022020-04-02 11:38:40 -0400771 for (int i = SlotCount(lType); i > 1; --i) {
Brian Osman49b30f42020-06-26 17:22:27 -0400772 this->write(ByteCodeInstruction::kDup, 1);
Brian Osmanb08cc022020-04-02 11:38:40 -0400773 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500774 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400775 // Special case for M*V, V*M, M*M (but not V*V!)
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400776 if (op == Token::Kind::TK_STAR && lVecOrMtx && rVecOrMtx &&
Ethan Nicholase6592142020-09-08 10:22:09 -0400777 !(lType.typeKind() == Type::TypeKind::kVector &&
778 rType.typeKind() == Type::TypeKind::kVector)) {
Brian Osmanb08cc022020-04-02 11:38:40 -0400779 this->write(ByteCodeInstruction::kMatrixMultiply,
Ethan Nicholas30d30222020-09-11 12:27:26 -0400780 SlotCount(b.type()) - (SlotCount(lType) + SlotCount(rType)));
Brian Osmanb08cc022020-04-02 11:38:40 -0400781 int rCols = rType.columns(),
782 rRows = rType.rows(),
783 lCols = lType.columns(),
784 lRows = lType.rows();
785 // M*V treats the vector as a column
Ethan Nicholase6592142020-09-08 10:22:09 -0400786 if (rType.typeKind() == Type::TypeKind::kVector) {
Brian Osmanb08cc022020-04-02 11:38:40 -0400787 std::swap(rCols, rRows);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500788 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400789 SkASSERT(lCols == rRows);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400790 SkASSERT(SlotCount(b.type()) == lRows * rCols);
Brian Osmanb08cc022020-04-02 11:38:40 -0400791 this->write8(lCols);
792 this->write8(lRows);
793 this->write8(rCols);
794 } else {
795 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400796 case Token::Kind::TK_EQEQ:
Brian Osmanb08cc022020-04-02 11:38:40 -0400797 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareIEQ,
798 ByteCodeInstruction::kCompareIEQ,
799 ByteCodeInstruction::kCompareFEQ,
800 count);
801 // Collapse to a single bool
802 for (int i = count; i > 1; --i) {
Brian Osman49b30f42020-06-26 17:22:27 -0400803 this->write(ByteCodeInstruction::kAndB, 1);
Brian Osmanb08cc022020-04-02 11:38:40 -0400804 }
805 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400806 case Token::Kind::TK_GT:
Brian Osmanb08cc022020-04-02 11:38:40 -0400807 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSGT,
808 ByteCodeInstruction::kCompareUGT,
809 ByteCodeInstruction::kCompareFGT,
810 count);
811 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400812 case Token::Kind::TK_GTEQ:
Brian Osmanb08cc022020-04-02 11:38:40 -0400813 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSGTEQ,
814 ByteCodeInstruction::kCompareUGTEQ,
815 ByteCodeInstruction::kCompareFGTEQ,
816 count);
817 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400818 case Token::Kind::TK_LT:
Brian Osmanb08cc022020-04-02 11:38:40 -0400819 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSLT,
820 ByteCodeInstruction::kCompareULT,
821 ByteCodeInstruction::kCompareFLT,
822 count);
823 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400824 case Token::Kind::TK_LTEQ:
Brian Osmanb08cc022020-04-02 11:38:40 -0400825 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareSLTEQ,
826 ByteCodeInstruction::kCompareULTEQ,
827 ByteCodeInstruction::kCompareFLTEQ,
828 count);
829 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400830 case Token::Kind::TK_MINUS:
Brian Osmanb08cc022020-04-02 11:38:40 -0400831 this->writeTypedInstruction(lType, ByteCodeInstruction::kSubtractI,
832 ByteCodeInstruction::kSubtractI,
833 ByteCodeInstruction::kSubtractF,
834 count);
835 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400836 case Token::Kind::TK_NEQ:
Brian Osmanb08cc022020-04-02 11:38:40 -0400837 this->writeTypedInstruction(lType, ByteCodeInstruction::kCompareINEQ,
838 ByteCodeInstruction::kCompareINEQ,
839 ByteCodeInstruction::kCompareFNEQ,
840 count);
841 // Collapse to a single bool
842 for (int i = count; i > 1; --i) {
Brian Osman49b30f42020-06-26 17:22:27 -0400843 this->write(ByteCodeInstruction::kOrB, 1);
Brian Osmanb08cc022020-04-02 11:38:40 -0400844 }
845 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400846 case Token::Kind::TK_PERCENT:
Brian Osmanb08cc022020-04-02 11:38:40 -0400847 this->writeTypedInstruction(lType, ByteCodeInstruction::kRemainderS,
848 ByteCodeInstruction::kRemainderU,
849 ByteCodeInstruction::kRemainderF,
850 count);
851 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400852 case Token::Kind::TK_PLUS:
Brian Osmanb08cc022020-04-02 11:38:40 -0400853 this->writeTypedInstruction(lType, ByteCodeInstruction::kAddI,
854 ByteCodeInstruction::kAddI,
855 ByteCodeInstruction::kAddF,
856 count);
857 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400858 case Token::Kind::TK_SLASH:
Brian Osmanb08cc022020-04-02 11:38:40 -0400859 this->writeTypedInstruction(lType, ByteCodeInstruction::kDivideS,
860 ByteCodeInstruction::kDivideU,
861 ByteCodeInstruction::kDivideF,
862 count);
863 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400864 case Token::Kind::TK_STAR:
Brian Osmanb08cc022020-04-02 11:38:40 -0400865 this->writeTypedInstruction(lType, ByteCodeInstruction::kMultiplyI,
866 ByteCodeInstruction::kMultiplyI,
867 ByteCodeInstruction::kMultiplyF,
868 count);
869 break;
870
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400871 case Token::Kind::TK_LOGICALXOR:
Brian Osman49b30f42020-06-26 17:22:27 -0400872 SkASSERT(tc == SkSL::TypeCategory::kBool);
873 this->write(ByteCodeInstruction::kXorB, count);
Brian Osmanb08cc022020-04-02 11:38:40 -0400874 break;
875
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400876 case Token::Kind::TK_BITWISEAND:
Brian Osman49b30f42020-06-26 17:22:27 -0400877 SkASSERT(tc == SkSL::TypeCategory::kSigned || tc == SkSL::TypeCategory::kUnsigned);
878 this->write(ByteCodeInstruction::kAndB, count);
Brian Osmanb08cc022020-04-02 11:38:40 -0400879 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400880 case Token::Kind::TK_BITWISEOR:
Brian Osman49b30f42020-06-26 17:22:27 -0400881 SkASSERT(tc == SkSL::TypeCategory::kSigned || tc == SkSL::TypeCategory::kUnsigned);
882 this->write(ByteCodeInstruction::kOrB, count);
Brian Osmanb08cc022020-04-02 11:38:40 -0400883 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400884 case Token::Kind::TK_BITWISEXOR:
Brian Osman49b30f42020-06-26 17:22:27 -0400885 SkASSERT(tc == SkSL::TypeCategory::kSigned || tc == SkSL::TypeCategory::kUnsigned);
886 this->write(ByteCodeInstruction::kXorB, count);
Brian Osmanb08cc022020-04-02 11:38:40 -0400887 break;
888
889 default:
890 fErrors.error(b.fOffset, SkSL::String::printf("Unsupported binary operator '%s'",
891 Compiler::OperatorName(op)));
892 break;
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500893 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500894 }
895 if (lvalue) {
Brian Osmanb08cc022020-04-02 11:38:40 -0400896 lvalue->store(discard);
897 discard = false;
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500898 }
Brian Osmanb08cc022020-04-02 11:38:40 -0400899 return discard;
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500900}
901
Brian Osmanb08cc022020-04-02 11:38:40 -0400902void ByteCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
903 this->write(ByteCodeInstruction::kPushImmediate);
904 this->write32(b.fValue ? ~0 : 0);
905}
906
907void ByteCodeGenerator::writeConstructor(const Constructor& c) {
908 for (const auto& arg : c.fArguments) {
909 this->writeExpression(*arg);
910 }
911 if (c.fArguments.size() == 1) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400912 const Type& inType = c.fArguments[0]->type();
913 const Type& outType = c.type();
Brian Osmanb08cc022020-04-02 11:38:40 -0400914 TypeCategory inCategory = type_category(inType);
915 TypeCategory outCategory = type_category(outType);
916 int inCount = SlotCount(inType);
917 int outCount = SlotCount(outType);
918 if (inCategory != outCategory) {
919 SkASSERT(inCount == outCount);
920 if (inCategory == TypeCategory::kFloat) {
921 SkASSERT(outCategory == TypeCategory::kSigned ||
922 outCategory == TypeCategory::kUnsigned);
Brian Osman49b30f42020-06-26 17:22:27 -0400923 this->write(ByteCodeInstruction::kConvertFtoI, outCount);
Brian Osmanb08cc022020-04-02 11:38:40 -0400924 } else if (outCategory == TypeCategory::kFloat) {
925 if (inCategory == TypeCategory::kSigned) {
Brian Osman49b30f42020-06-26 17:22:27 -0400926 this->write(ByteCodeInstruction::kConvertStoF, outCount);
Brian Osmanb08cc022020-04-02 11:38:40 -0400927 } else {
928 SkASSERT(inCategory == TypeCategory::kUnsigned);
Brian Osman49b30f42020-06-26 17:22:27 -0400929 this->write(ByteCodeInstruction::kConvertUtoF, outCount);
Brian Osmanb08cc022020-04-02 11:38:40 -0400930 }
931 } else {
932 SkASSERT(false);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500933 }
934 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400935 if (inType.typeKind() == Type::TypeKind::kMatrix &&
936 outType.typeKind() == Type::TypeKind::kMatrix) {
Brian Osmanb08cc022020-04-02 11:38:40 -0400937 this->write(ByteCodeInstruction::kMatrixToMatrix,
938 SlotCount(outType) - SlotCount(inType));
939 this->write8(inType.columns());
940 this->write8(inType.rows());
941 this->write8(outType.columns());
942 this->write8(outType.rows());
943 } else if (inCount != outCount) {
944 SkASSERT(inCount == 1);
Ethan Nicholase6592142020-09-08 10:22:09 -0400945 if (outType.typeKind() == Type::TypeKind::kMatrix) {
Brian Osmanb08cc022020-04-02 11:38:40 -0400946 this->write(ByteCodeInstruction::kScalarToMatrix, SlotCount(outType) - 1);
947 this->write8(outType.columns());
948 this->write8(outType.rows());
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500949 } else {
Ethan Nicholase6592142020-09-08 10:22:09 -0400950 SkASSERT(outType.typeKind() == Type::TypeKind::kVector);
Brian Osmanb08cc022020-04-02 11:38:40 -0400951 for (; inCount != outCount; ++inCount) {
Brian Osman49b30f42020-06-26 17:22:27 -0400952 this->write(ByteCodeInstruction::kDup, 1);
Brian Osmanb08cc022020-04-02 11:38:40 -0400953 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500954 }
955 }
956 }
957}
958
Brian Osmanb08cc022020-04-02 11:38:40 -0400959void ByteCodeGenerator::writeExternalFunctionCall(const ExternalFunctionCall& f) {
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500960 int argumentCount = 0;
961 for (const auto& arg : f.fArguments) {
Brian Osmanb08cc022020-04-02 11:38:40 -0400962 this->writeExpression(*arg);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400963 argumentCount += SlotCount(arg->type());
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500964 }
Ethan Nicholas30d30222020-09-11 12:27:26 -0400965 this->write(ByteCodeInstruction::kCallExternal, SlotCount(f.type()) - argumentCount);
Brian Osmanb08cc022020-04-02 11:38:40 -0400966 SkASSERT(argumentCount <= 255);
967 this->write8(argumentCount);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400968 this->write8(SlotCount(f.type()));
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500969 int index = fOutput->fExternalValues.size();
970 fOutput->fExternalValues.push_back(f.fFunction);
971 SkASSERT(index <= 255);
Brian Osmanb08cc022020-04-02 11:38:40 -0400972 this->write8(index);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500973}
974
Brian Osmanb08cc022020-04-02 11:38:40 -0400975void ByteCodeGenerator::writeExternalValue(const ExternalValueReference& e) {
976 int count = SlotCount(e.fValue->type());
Brian Osman49b30f42020-06-26 17:22:27 -0400977 this->write(ByteCodeInstruction::kReadExternal, count);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500978 int index = fOutput->fExternalValues.size();
979 fOutput->fExternalValues.push_back(e.fValue);
980 SkASSERT(index <= 255);
Brian Osmanb08cc022020-04-02 11:38:40 -0400981 this->write8(index);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500982}
983
Brian Osmanb08cc022020-04-02 11:38:40 -0400984void ByteCodeGenerator::writeVariableExpression(const Expression& expr) {
Brian Osman5aaaeea2020-06-22 14:26:03 -0400985 if (int builtin = expression_as_builtin(expr); builtin >= 0) {
986 switch (builtin) {
987 case SK_FRAGCOORD_BUILTIN:
988 this->write(ByteCodeInstruction::kLoadFragCoord);
989 fOutput->fUsesFragCoord = true;
990 break;
991 default:
992 fErrors.error(expr.fOffset, "Unsupported builtin");
993 break;
994 }
995 return;
996 }
997
Brian Osmanb08cc022020-04-02 11:38:40 -0400998 Location location = this->getLocation(expr);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400999 int count = SlotCount(expr.type());
Brian Osmanefb08402020-04-13 16:30:44 -04001000 if (count == 0) {
1001 return;
1002 }
Brian Osman02f8b072020-06-19 14:04:48 -04001003 if (location.isOnStack()) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001004 this->write(location.selectLoad(ByteCodeInstruction::kLoadExtended,
1005 ByteCodeInstruction::kLoadExtendedGlobal,
1006 ByteCodeInstruction::kLoadExtendedUniform),
1007 count);
Brian Osmanb08cc022020-04-02 11:38:40 -04001008 } else {
Brian Osman49b30f42020-06-26 17:22:27 -04001009 this->write(location.selectLoad(ByteCodeInstruction::kLoad,
1010 ByteCodeInstruction::kLoadGlobal,
1011 ByteCodeInstruction::kLoadUniform),
1012 count);
1013 this->write8(location.fSlot);
Brian Osmanb08cc022020-04-02 11:38:40 -04001014 }
1015}
1016
1017static inline uint32_t float_to_bits(float x) {
1018 uint32_t u;
1019 memcpy(&u, &x, sizeof(uint32_t));
1020 return u;
1021}
1022
1023void ByteCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
1024 this->write(ByteCodeInstruction::kPushImmediate);
1025 this->write32(float_to_bits(f.fValue));
1026}
1027
Brian Osman8842b372020-05-01 15:07:49 -04001028static bool is_generic_type(const Type* type, const Type* generic) {
1029 const std::vector<const Type*>& concrete(generic->coercibleTypes());
1030 return std::find(concrete.begin(), concrete.end(), type) != concrete.end();
1031}
1032
Brian Osmanb08cc022020-04-02 11:38:40 -04001033void ByteCodeGenerator::writeIntrinsicCall(const FunctionCall& c) {
1034 auto found = fIntrinsics.find(c.fFunction.fName);
1035 if (found == fIntrinsics.end()) {
1036 fErrors.error(c.fOffset, String::printf("Unsupported intrinsic: '%s'",
1037 String(c.fFunction.fName).c_str()));
1038 return;
1039 }
Mike Klein45be0772020-05-01 09:13:18 -05001040 Intrinsic intrin = found->second;
Brian Osman795efd22020-07-01 13:18:36 -04001041
1042 const auto& args = c.fArguments;
1043 const size_t nargs = args.size();
1044 SkASSERT(nargs >= 1);
1045
Ethan Nicholas30d30222020-09-11 12:27:26 -04001046 int count = SlotCount(args[0]->type());
Brian Osmand5f937b2020-05-04 12:07:29 -04001047
1048 // Several intrinsics have variants where one argument is either scalar, or the same size as
1049 // the first argument. Call dupSmallerType(SlotCount(argType)) to ensure equal component count.
1050 auto dupSmallerType = [count, this](int smallCount) {
1051 SkASSERT(smallCount == 1 || smallCount == count);
1052 for (int i = smallCount; i < count; ++i) {
Brian Osman49b30f42020-06-26 17:22:27 -04001053 this->write(ByteCodeInstruction::kDup, 1);
Brian Osmand5f937b2020-05-04 12:07:29 -04001054 }
1055 };
1056
Brian Osmana43d8202020-06-17 16:50:39 -04001057 if (intrin.is_special && intrin.special == SpecialIntrinsic::kSample) {
Brian Osman795efd22020-07-01 13:18:36 -04001058 // Sample is very special, the first argument is an FP, which can't be pushed to the stack.
Ethan Nicholas30d30222020-09-11 12:27:26 -04001059 if (nargs > 2 || args[0]->type() != *fContext.fFragmentProcessor_Type ||
1060 (nargs == 2 && (args[1]->type() != *fContext.fFloat2_Type &&
1061 args[1]->type() != *fContext.fFloat3x3_Type))) {
Brian Osmana43d8202020-06-17 16:50:39 -04001062 fErrors.error(c.fOffset, "Unsupported form of sample");
1063 return;
1064 }
1065
Brian Osman795efd22020-07-01 13:18:36 -04001066 if (nargs == 2) {
1067 // Write our coords or matrix
1068 this->writeExpression(*args[1]);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001069 this->write(args[1]->type() == *fContext.fFloat3x3_Type
Brian Osman795efd22020-07-01 13:18:36 -04001070 ? ByteCodeInstruction::kSampleMatrix
1071 : ByteCodeInstruction::kSampleExplicit);
1072 } else {
1073 this->write(ByteCodeInstruction::kSample);
1074 }
Brian Osmana43d8202020-06-17 16:50:39 -04001075
Brian Osman795efd22020-07-01 13:18:36 -04001076 Location childLoc = this->getLocation(*args[0]);
Brian Osmana43d8202020-06-17 16:50:39 -04001077 SkASSERT(childLoc.fStorage == Storage::kChildFP);
1078 this->write8(childLoc.fSlot);
1079 return;
1080 }
1081
Brian Osmand5f937b2020-05-04 12:07:29 -04001082 if (intrin.is_special && (intrin.special == SpecialIntrinsic::kClamp ||
1083 intrin.special == SpecialIntrinsic::kSaturate)) {
1084 // These intrinsics are extra-special, we need instructions interleaved with arguments
1085 bool saturate = (intrin.special == SpecialIntrinsic::kSaturate);
Brian Osman795efd22020-07-01 13:18:36 -04001086 SkASSERT(nargs == (saturate ? 1 : 3));
Ethan Nicholas30d30222020-09-11 12:27:26 -04001087 int limitCount = saturate ? 1 : SlotCount(args[1]->type());
Brian Osmand5f937b2020-05-04 12:07:29 -04001088
1089 // 'x'
Brian Osman795efd22020-07-01 13:18:36 -04001090 this->writeExpression(*args[0]);
Brian Osmand5f937b2020-05-04 12:07:29 -04001091
1092 // 'minVal'
1093 if (saturate) {
1094 this->write(ByteCodeInstruction::kPushImmediate);
1095 this->write32(float_to_bits(0.0f));
1096 } else {
Brian Osman795efd22020-07-01 13:18:36 -04001097 this->writeExpression(*args[1]);
Brian Osmand5f937b2020-05-04 12:07:29 -04001098 }
1099 dupSmallerType(limitCount);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001100 this->writeTypedInstruction(args[0]->type(),
Brian Osmand5f937b2020-05-04 12:07:29 -04001101 ByteCodeInstruction::kMaxS,
1102 ByteCodeInstruction::kMaxS,
1103 ByteCodeInstruction::kMaxF,
1104 count);
1105
1106 // 'maxVal'
1107 if (saturate) {
1108 this->write(ByteCodeInstruction::kPushImmediate);
1109 this->write32(float_to_bits(1.0f));
1110 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001111 SkASSERT(limitCount == SlotCount(args[2]->type()));
Brian Osman795efd22020-07-01 13:18:36 -04001112 this->writeExpression(*args[2]);
Brian Osmand5f937b2020-05-04 12:07:29 -04001113 }
1114 dupSmallerType(limitCount);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001115 this->writeTypedInstruction(args[0]->type(),
Brian Osmand5f937b2020-05-04 12:07:29 -04001116 ByteCodeInstruction::kMinS,
1117 ByteCodeInstruction::kMinS,
1118 ByteCodeInstruction::kMinF,
1119 count);
1120 return;
1121 }
1122
1123 // All other intrinsics can handle their arguments being on the stack in order
Brian Osman795efd22020-07-01 13:18:36 -04001124 for (const auto& arg : args) {
Brian Osmand5f937b2020-05-04 12:07:29 -04001125 this->writeExpression(*arg);
1126 }
1127
Mike Klein45be0772020-05-01 09:13:18 -05001128 if (intrin.is_special) {
1129 switch (intrin.special) {
Brian Osman8842b372020-05-01 15:07:49 -04001130 case SpecialIntrinsic::kAll: {
1131 for (int i = count-1; i --> 0;) {
Brian Osman49b30f42020-06-26 17:22:27 -04001132 this->write(ByteCodeInstruction::kAndB, 1);
Brian Osman8842b372020-05-01 15:07:49 -04001133 }
1134 } break;
1135
1136 case SpecialIntrinsic::kAny: {
1137 for (int i = count-1; i --> 0;) {
Brian Osman49b30f42020-06-26 17:22:27 -04001138 this->write(ByteCodeInstruction::kOrB, 1);
Brian Osman8842b372020-05-01 15:07:49 -04001139 }
1140 } break;
1141
Brian Osman15c98cb2020-02-27 18:36:57 +00001142 case SpecialIntrinsic::kDot: {
Brian Osman795efd22020-07-01 13:18:36 -04001143 SkASSERT(nargs == 2);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001144 SkASSERT(count == SlotCount(args[1]->type()));
Brian Osman49b30f42020-06-26 17:22:27 -04001145 this->write(ByteCodeInstruction::kMultiplyF, count);
Mike Klein45be0772020-05-01 09:13:18 -05001146 for (int i = count-1; i --> 0;) {
Brian Osman49b30f42020-06-26 17:22:27 -04001147 this->write(ByteCodeInstruction::kAddF, 1);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001148 }
Mike Klein45be0772020-05-01 09:13:18 -05001149 } break;
1150
1151 case SpecialIntrinsic::kLength: {
Brian Osman795efd22020-07-01 13:18:36 -04001152 SkASSERT(nargs == 1);
Brian Osman49b30f42020-06-26 17:22:27 -04001153 this->write(ByteCodeInstruction::kDup, count);
1154 this->write(ByteCodeInstruction::kMultiplyF, count);
Mike Klein45be0772020-05-01 09:13:18 -05001155 for (int i = count-1; i --> 0;) {
Brian Osman49b30f42020-06-26 17:22:27 -04001156 this->write(ByteCodeInstruction::kAddF, 1);
Mike Klein45be0772020-05-01 09:13:18 -05001157 }
Brian Osman49b30f42020-06-26 17:22:27 -04001158 this->write(ByteCodeInstruction::kSqrt, 1);
Mike Klein45be0772020-05-01 09:13:18 -05001159 } break;
1160
Brian Osmand5f937b2020-05-04 12:07:29 -04001161 case SpecialIntrinsic::kMax:
1162 case SpecialIntrinsic::kMin: {
Brian Osman795efd22020-07-01 13:18:36 -04001163 SkASSERT(nargs == 2);
Brian Osmand5f937b2020-05-04 12:07:29 -04001164 // There are variants where the second argument is scalar
Ethan Nicholas30d30222020-09-11 12:27:26 -04001165 dupSmallerType(SlotCount(args[1]->type()));
Brian Osmand5f937b2020-05-04 12:07:29 -04001166 if (intrin.special == SpecialIntrinsic::kMax) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001167 this->writeTypedInstruction(args[0]->type(),
Brian Osmand5f937b2020-05-04 12:07:29 -04001168 ByteCodeInstruction::kMaxS,
1169 ByteCodeInstruction::kMaxS,
1170 ByteCodeInstruction::kMaxF,
1171 count);
1172 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001173 this->writeTypedInstruction(args[0]->type(),
Brian Osmand5f937b2020-05-04 12:07:29 -04001174 ByteCodeInstruction::kMinS,
1175 ByteCodeInstruction::kMinS,
1176 ByteCodeInstruction::kMinF,
1177 count);
1178 }
1179 } break;
1180
Brian Osman8842b372020-05-01 15:07:49 -04001181 case SpecialIntrinsic::kMix: {
1182 // Two main variants of mix to handle
Brian Osman795efd22020-07-01 13:18:36 -04001183 SkASSERT(nargs == 3);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001184 SkASSERT(count == SlotCount(args[1]->type()));
1185 int selectorCount = SlotCount(args[2]->type());
Brian Osman8842b372020-05-01 15:07:49 -04001186
Ethan Nicholas30d30222020-09-11 12:27:26 -04001187 if (is_generic_type(&args[2]->type(), fContext.fGenBType_Type.get())) {
Brian Osman8842b372020-05-01 15:07:49 -04001188 // mix(genType, genType, genBoolType)
1189 SkASSERT(selectorCount == count);
Brian Osman49b30f42020-06-26 17:22:27 -04001190 this->write(ByteCodeInstruction::kMix, count);
Brian Osman8842b372020-05-01 15:07:49 -04001191 } else {
1192 // mix(genType, genType, genType) or mix(genType, genType, float)
Brian Osmand5f937b2020-05-04 12:07:29 -04001193 dupSmallerType(selectorCount);
Brian Osman49b30f42020-06-26 17:22:27 -04001194 this->write(ByteCodeInstruction::kLerp, count);
Brian Osman8842b372020-05-01 15:07:49 -04001195 }
1196 } break;
1197
Brian Osman2a4871b2020-06-19 11:29:58 -04001198 case SpecialIntrinsic::kNormalize: {
Brian Osman795efd22020-07-01 13:18:36 -04001199 SkASSERT(nargs == 1);
Brian Osman49b30f42020-06-26 17:22:27 -04001200 this->write(ByteCodeInstruction::kDup, count);
1201 this->write(ByteCodeInstruction::kDup, count);
1202 this->write(ByteCodeInstruction::kMultiplyF, count);
Brian Osman2a4871b2020-06-19 11:29:58 -04001203 for (int i = count-1; i --> 0;) {
Brian Osman49b30f42020-06-26 17:22:27 -04001204 this->write(ByteCodeInstruction::kAddF, 1);
Brian Osman2a4871b2020-06-19 11:29:58 -04001205 }
Brian Osman49b30f42020-06-26 17:22:27 -04001206 this->write(ByteCodeInstruction::kSqrt, 1);
Brian Osman2a4871b2020-06-19 11:29:58 -04001207 dupSmallerType(1);
Brian Osman49b30f42020-06-26 17:22:27 -04001208 this->write(ByteCodeInstruction::kDivideF, count);
Brian Osman2a4871b2020-06-19 11:29:58 -04001209 } 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: {
Brian Osmanb08cc022020-04-02 11:38:40 -04001217 auto op = ByteCodeInstruction::kInverse2x2;
1218 switch (count) {
1219 case 4: break; // float2x2
1220 case 9: op = ByteCodeInstruction::kInverse3x3; break;
1221 case 16: op = ByteCodeInstruction::kInverse4x4; break;
1222 default: SkASSERT(false);
1223 }
1224 this->write(op);
1225 break;
Brian Osman15c98cb2020-02-27 18:36:57 +00001226 }
Mike Klein45be0772020-05-01 09:13:18 -05001227
Brian Osmanb08cc022020-04-02 11:38:40 -04001228 default:
Ethan Nicholas30d30222020-09-11 12:27:26 -04001229 this->writeTypedInstruction(args[0]->type(),
Brian Osman49b30f42020-06-26 17:22:27 -04001230 intrin.inst_s,
1231 intrin.inst_u,
1232 intrin.inst_f,
1233 count);
Brian Osman8842b372020-05-01 15:07:49 -04001234 break;
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001235 }
1236 }
1237}
1238
Brian Osmanb08cc022020-04-02 11:38:40 -04001239void ByteCodeGenerator::writeFunctionCall(const FunctionCall& f) {
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001240 // Find the index of the function we're calling. We explicitly do not allow calls to functions
1241 // before they're defined. This is an easy-to-understand rule that prevents recursion.
Brian Osmanb08cc022020-04-02 11:38:40 -04001242 int idx = -1;
1243 for (size_t i = 0; i < fFunctions.size(); ++i) {
1244 if (f.fFunction.matches(fFunctions[i]->fDeclaration)) {
1245 idx = i;
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001246 break;
1247 }
1248 }
Brian Osmanb08cc022020-04-02 11:38:40 -04001249 if (idx == -1) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001250 this->writeIntrinsicCall(f);
1251 return;
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001252 }
Brian Osmanb08cc022020-04-02 11:38:40 -04001253
1254
1255 if (idx > 255) {
1256 fErrors.error(f.fOffset, "Function count limit exceeded");
1257 return;
1258 } else if (idx >= (int) fFunctions.size()) {
1259 fErrors.error(f.fOffset, "Call to undefined function");
1260 return;
1261 }
1262
1263 // We may need to deal with out parameters, so the sequence is tricky
Ethan Nicholas30d30222020-09-11 12:27:26 -04001264 if (int returnCount = SlotCount(f.type())) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001265 this->write(ByteCodeInstruction::kReserve, returnCount);
Brian Osmanb08cc022020-04-02 11:38:40 -04001266 }
1267
1268 int argCount = f.fArguments.size();
1269 std::vector<std::unique_ptr<LValue>> lvalues;
1270 for (int i = 0; i < argCount; ++i) {
1271 const auto& param = f.fFunction.fParameters[i];
1272 const auto& arg = f.fArguments[i];
1273 if (param->fModifiers.fFlags & Modifiers::kOut_Flag) {
1274 lvalues.emplace_back(this->getLValue(*arg));
1275 lvalues.back()->load();
1276 } else {
1277 this->writeExpression(*arg);
1278 }
1279 }
1280
1281 // The space used by the call is based on the callee, but it also unwinds all of that before
1282 // we continue execution. We adjust our max stack depths below.
1283 this->write(ByteCodeInstruction::kCall);
1284 this->write8(idx);
1285
1286 const ByteCodeFunction* callee = fOutput->fFunctions[idx].get();
1287 fMaxLoopCount = std::max(fMaxLoopCount, fLoopCount + callee->fLoopCount);
1288 fMaxConditionCount = std::max(fMaxConditionCount, fConditionCount + callee->fConditionCount);
1289 fMaxStackCount = std::max(fMaxStackCount, fStackCount + callee->fLocalCount
1290 + callee->fStackCount);
1291
1292 // After the called function returns, the stack will still contain our arguments. We have to
1293 // pop them (storing any out parameters back to their lvalues as we go). We glob together slot
1294 // counts for all parameters that aren't out-params, so we can pop them in one big chunk.
1295 int popCount = 0;
1296 auto pop = [&]() {
Brian Osman49b30f42020-06-26 17:22:27 -04001297 if (popCount > 0) {
1298 this->write(ByteCodeInstruction::kPop, popCount);
Brian Osmanb08cc022020-04-02 11:38:40 -04001299 }
1300 popCount = 0;
1301 };
1302
1303 for (int i = argCount - 1; i >= 0; --i) {
1304 const auto& param = f.fFunction.fParameters[i];
1305 const auto& arg = f.fArguments[i];
1306 if (param->fModifiers.fFlags & Modifiers::kOut_Flag) {
1307 pop();
1308 lvalues.back()->store(true);
1309 lvalues.pop_back();
1310 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001311 popCount += SlotCount(arg->type());
Brian Osmanb08cc022020-04-02 11:38:40 -04001312 }
1313 }
1314 pop();
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001315}
1316
Brian Osmanb08cc022020-04-02 11:38:40 -04001317void ByteCodeGenerator::writeIntLiteral(const IntLiteral& i) {
1318 this->write(ByteCodeInstruction::kPushImmediate);
1319 this->write32(i.fValue);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001320}
1321
Brian Osmanb08cc022020-04-02 11:38:40 -04001322void ByteCodeGenerator::writeNullLiteral(const NullLiteral& n) {
1323 // not yet implemented
1324 abort();
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001325}
1326
Brian Osmanb08cc022020-04-02 11:38:40 -04001327bool ByteCodeGenerator::writePrefixExpression(const PrefixExpression& p, bool discard) {
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001328 switch (p.fOperator) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001329 case Token::Kind::TK_PLUSPLUS: // fall through
1330 case Token::Kind::TK_MINUSMINUS: {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001331 SkASSERT(SlotCount(p.fOperand->type()) == 1);
Brian Osmanb08cc022020-04-02 11:38:40 -04001332 std::unique_ptr<LValue> lvalue = this->getLValue(*p.fOperand);
1333 lvalue->load();
1334 this->write(ByteCodeInstruction::kPushImmediate);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001335 this->write32(type_category(p.type()) == TypeCategory::kFloat ? float_to_bits(1.0f)
1336 : 1);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001337 if (p.fOperator == Token::Kind::TK_PLUSPLUS) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001338 this->writeTypedInstruction(p.type(),
Brian Osmanb08cc022020-04-02 11:38:40 -04001339 ByteCodeInstruction::kAddI,
1340 ByteCodeInstruction::kAddI,
1341 ByteCodeInstruction::kAddF,
1342 1);
1343 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001344 this->writeTypedInstruction(p.type(),
Brian Osmanb08cc022020-04-02 11:38:40 -04001345 ByteCodeInstruction::kSubtractI,
1346 ByteCodeInstruction::kSubtractI,
1347 ByteCodeInstruction::kSubtractF,
1348 1);
1349 }
1350 lvalue->store(discard);
1351 discard = false;
1352 break;
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001353 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001354 case Token::Kind::TK_MINUS: {
Brian Osmanb08cc022020-04-02 11:38:40 -04001355 this->writeExpression(*p.fOperand);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001356 this->writeTypedInstruction(p.type(),
Brian Osmanb08cc022020-04-02 11:38:40 -04001357 ByteCodeInstruction::kNegateI,
1358 ByteCodeInstruction::kNegateI,
1359 ByteCodeInstruction::kNegateF,
Ethan Nicholas30d30222020-09-11 12:27:26 -04001360 SlotCount(p.fOperand->type()));
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001361 break;
1362 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001363 case Token::Kind::TK_LOGICALNOT:
1364 case Token::Kind::TK_BITWISENOT: {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001365 SkASSERT(SlotCount(p.fOperand->type()) == 1);
1366 SkDEBUGCODE(TypeCategory tc = type_category(p.fOperand->type()));
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001367 SkASSERT((p.fOperator == Token::Kind::TK_LOGICALNOT && tc == TypeCategory::kBool) ||
1368 (p.fOperator == Token::Kind::TK_BITWISENOT && (tc == TypeCategory::kSigned ||
Brian Osmanb08cc022020-04-02 11:38:40 -04001369 tc == TypeCategory::kUnsigned)));
1370 this->writeExpression(*p.fOperand);
Brian Osman49b30f42020-06-26 17:22:27 -04001371 this->write(ByteCodeInstruction::kNotB, 1);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001372 break;
1373 }
1374 default:
1375 SkASSERT(false);
1376 }
Brian Osmanb08cc022020-04-02 11:38:40 -04001377 return discard;
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001378}
1379
Brian Osmanb08cc022020-04-02 11:38:40 -04001380bool ByteCodeGenerator::writePostfixExpression(const PostfixExpression& p, bool discard) {
1381 switch (p.fOperator) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001382 case Token::Kind::TK_PLUSPLUS: // fall through
1383 case Token::Kind::TK_MINUSMINUS: {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001384 SkASSERT(SlotCount(p.fOperand->type()) == 1);
Brian Osmanb08cc022020-04-02 11:38:40 -04001385 std::unique_ptr<LValue> lvalue = this->getLValue(*p.fOperand);
1386 lvalue->load();
1387 // If we're not supposed to discard the result, then make a copy *before* the +/-
1388 if (!discard) {
Brian Osman49b30f42020-06-26 17:22:27 -04001389 this->write(ByteCodeInstruction::kDup, 1);
Brian Osmanb08cc022020-04-02 11:38:40 -04001390 }
1391 this->write(ByteCodeInstruction::kPushImmediate);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001392 this->write32(type_category(p.type()) == TypeCategory::kFloat ? float_to_bits(1.0f)
1393 : 1);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001394 if (p.fOperator == Token::Kind::TK_PLUSPLUS) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001395 this->writeTypedInstruction(p.type(),
Brian Osmanb08cc022020-04-02 11:38:40 -04001396 ByteCodeInstruction::kAddI,
1397 ByteCodeInstruction::kAddI,
1398 ByteCodeInstruction::kAddF,
1399 1);
1400 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001401 this->writeTypedInstruction(p.type(),
Brian Osmanb08cc022020-04-02 11:38:40 -04001402 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);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001425 this->write(ByteCodeInstruction::kSwizzle, s.fComponents.size() - s.fBase->type().columns());
1426 this->write8(s.fBase->type().columns());
Brian Osman3711c662020-06-18 14:42:21 -04001427 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 Nicholas30d30222020-09-11 12:27:26 -04001434 int count = SlotCount(t.type());
1435 SkASSERT(count == SlotCount(t.fIfTrue->type()));
1436 SkASSERT(count == SlotCount(t.fIfFalse->type()));
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001437
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);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001444}
1445
Brian Osmanb08cc022020-04-02 11:38:40 -04001446void ByteCodeGenerator::writeExpression(const Expression& e, bool discard) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001447 switch (e.kind()) {
1448 case Expression::Kind::kBinary:
John Stiles81365af2020-08-18 09:24:00 -04001449 discard = this->writeBinaryExpression(e.as<BinaryExpression>(), discard);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001450 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001451 case Expression::Kind::kBoolLiteral:
John Stiles81365af2020-08-18 09:24:00 -04001452 this->writeBoolLiteral(e.as<BoolLiteral>());
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001453 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001454 case Expression::Kind::kConstructor:
John Stiles81365af2020-08-18 09:24:00 -04001455 this->writeConstructor(e.as<Constructor>());
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001456 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001457 case Expression::Kind::kExternalFunctionCall:
John Stiles81365af2020-08-18 09:24:00 -04001458 this->writeExternalFunctionCall(e.as<ExternalFunctionCall>());
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001459 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001460 case Expression::Kind::kExternalValue:
John Stiles81365af2020-08-18 09:24:00 -04001461 this->writeExternalValue(e.as<ExternalValueReference>());
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001462 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001463 case Expression::Kind::kFieldAccess:
1464 case Expression::Kind::kIndex:
1465 case Expression::Kind::kVariableReference:
Brian Osmanb08cc022020-04-02 11:38:40 -04001466 this->writeVariableExpression(e);
1467 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001468 case Expression::Kind::kFloatLiteral:
John Stiles81365af2020-08-18 09:24:00 -04001469 this->writeFloatLiteral(e.as<FloatLiteral>());
Brian Osmanb08cc022020-04-02 11:38:40 -04001470 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001471 case Expression::Kind::kFunctionCall:
John Stiles81365af2020-08-18 09:24:00 -04001472 this->writeFunctionCall(e.as<FunctionCall>());
Brian Osmanb08cc022020-04-02 11:38:40 -04001473 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001474 case Expression::Kind::kIntLiteral:
John Stiles81365af2020-08-18 09:24:00 -04001475 this->writeIntLiteral(e.as<IntLiteral>());
Brian Osmanb08cc022020-04-02 11:38:40 -04001476 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001477 case Expression::Kind::kNullLiteral:
John Stiles81365af2020-08-18 09:24:00 -04001478 this->writeNullLiteral(e.as<NullLiteral>());
Brian Osmanb08cc022020-04-02 11:38:40 -04001479 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001480 case Expression::Kind::kPrefix:
John Stiles81365af2020-08-18 09:24:00 -04001481 discard = this->writePrefixExpression(e.as<PrefixExpression>(), discard);
Brian Osmanb08cc022020-04-02 11:38:40 -04001482 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001483 case Expression::Kind::kPostfix:
John Stiles81365af2020-08-18 09:24:00 -04001484 discard = this->writePostfixExpression(e.as<PostfixExpression>(), discard);
Brian Osmanb08cc022020-04-02 11:38:40 -04001485 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001486 case Expression::Kind::kSwizzle:
John Stiles81365af2020-08-18 09:24:00 -04001487 this->writeSwizzle(e.as<Swizzle>());
Brian Osmanb08cc022020-04-02 11:38:40 -04001488 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001489 case Expression::Kind::kTernary:
John Stiles81365af2020-08-18 09:24:00 -04001490 this->writeTernaryExpression(e.as<TernaryExpression>());
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001491 break;
Ben Wagner470e0ac2020-01-22 16:59:21 -05001492 default:
1493#ifdef SK_DEBUG
Brian Osmanb08cc022020-04-02 11:38:40 -04001494 printf("unsupported expression %s\n", e.description().c_str());
Ben Wagner470e0ac2020-01-22 16:59:21 -05001495#endif
Brian Osmanb08cc022020-04-02 11:38:40 -04001496 SkASSERT(false);
1497 }
1498 if (discard) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001499 int count = SlotCount(e.type());
Brian Osman49b30f42020-06-26 17:22:27 -04001500 if (count > 0) {
1501 this->write(ByteCodeInstruction::kPop, count);
Brian Osmanb08cc022020-04-02 11:38:40 -04001502 }
1503 discard = false;
Ben Wagner470e0ac2020-01-22 16:59:21 -05001504 }
Ethan Nicholas7deb1c22020-01-22 10:31:55 -05001505}
1506
Brian Osmanb08cc022020-04-02 11:38:40 -04001507class ByteCodeExternalValueLValue : public ByteCodeGenerator::LValue {
1508public:
John Stiles534d7992020-08-18 00:06:01 -04001509 ByteCodeExternalValueLValue(ByteCodeGenerator* generator, const ExternalValue& value, int index)
Brian Osmanb08cc022020-04-02 11:38:40 -04001510 : INHERITED(*generator)
1511 , fCount(ByteCodeGenerator::SlotCount(value.type()))
1512 , fIndex(index) {}
1513
1514 void load() override {
Brian Osman49b30f42020-06-26 17:22:27 -04001515 fGenerator.write(ByteCodeInstruction::kReadExternal, fCount);
Brian Osmanb08cc022020-04-02 11:38:40 -04001516 fGenerator.write8(fIndex);
1517 }
1518
1519 void store(bool discard) override {
1520 if (!discard) {
Brian Osman49b30f42020-06-26 17:22:27 -04001521 fGenerator.write(ByteCodeInstruction::kDup, fCount);
Brian Osmanb08cc022020-04-02 11:38:40 -04001522 }
Brian Osman49b30f42020-06-26 17:22:27 -04001523 fGenerator.write(ByteCodeInstruction::kWriteExternal, fCount);
Brian Osmanb08cc022020-04-02 11:38:40 -04001524 fGenerator.write8(fIndex);
1525 }
1526
1527private:
John Stiles7571f9e2020-09-02 22:42:33 -04001528 using INHERITED = LValue;
Brian Osmanb08cc022020-04-02 11:38:40 -04001529
1530 int fCount;
Brian Osmanb08cc022020-04-02 11:38:40 -04001531 int fIndex;
1532};
1533
1534class ByteCodeSwizzleLValue : public ByteCodeGenerator::LValue {
1535public:
1536 ByteCodeSwizzleLValue(ByteCodeGenerator* generator, const Swizzle& swizzle)
1537 : INHERITED(*generator)
1538 , fSwizzle(swizzle) {}
1539
1540 void load() override {
1541 fGenerator.writeSwizzle(fSwizzle);
1542 }
1543
1544 void store(bool discard) override {
1545 int count = fSwizzle.fComponents.size();
1546 if (!discard) {
Brian Osman49b30f42020-06-26 17:22:27 -04001547 fGenerator.write(ByteCodeInstruction::kDup, count);
Brian Osmanb08cc022020-04-02 11:38:40 -04001548 }
Brian Osman304dfa32020-06-18 15:53:51 -04001549 // We already have the correct number of values on the stack, thanks to type checking.
1550 // The algorithm: Walk down the values on the stack, doing 'count' single-element stores.
1551 // For each value, use the corresponding swizzle component to offset the store location.
1552 //
1553 // Static locations: We (wastefully) call getLocation every time, but get good byte code.
1554 // Note that we could (but don't) store adjacent/sequential values with fewer instructions.
1555 //
1556 // Dynamic locations: ... are bad. We have to recompute the base address on each iteration,
1557 // because the stack doesn't let us retain that address between stores. Dynamic locations
1558 // are rare though, and swizzled writes to those are even rarer, so we just live with this.
1559 for (int i = count; i-- > 0;) {
1560 ByteCodeGenerator::Location location = fGenerator.getLocation(*fSwizzle.fBase);
1561 if (!location.isOnStack()) {
1562 fGenerator.write(location.selectStore(ByteCodeInstruction::kStore,
Brian Osman49b30f42020-06-26 17:22:27 -04001563 ByteCodeInstruction::kStoreGlobal),
1564 1);
Brian Osman304dfa32020-06-18 15:53:51 -04001565 fGenerator.write8(location.fSlot + fSwizzle.fComponents[i]);
1566 } else {
1567 fGenerator.write(ByteCodeInstruction::kPushImmediate);
1568 fGenerator.write32(fSwizzle.fComponents[i]);
Brian Osman49b30f42020-06-26 17:22:27 -04001569 fGenerator.write(ByteCodeInstruction::kAddI, 1);
Brian Osman304dfa32020-06-18 15:53:51 -04001570 fGenerator.write(location.selectStore(ByteCodeInstruction::kStoreExtended,
1571 ByteCodeInstruction::kStoreExtendedGlobal),
1572 1);
Brian Osman304dfa32020-06-18 15:53:51 -04001573 }
Brian Osmanb08cc022020-04-02 11:38:40 -04001574 }
1575 }
1576
1577private:
1578 const Swizzle& fSwizzle;
1579
John Stiles7571f9e2020-09-02 22:42:33 -04001580 using INHERITED = LValue;
Brian Osmanb08cc022020-04-02 11:38:40 -04001581};
1582
1583class ByteCodeExpressionLValue : public ByteCodeGenerator::LValue {
1584public:
1585 ByteCodeExpressionLValue(ByteCodeGenerator* generator, const Expression& expr)
1586 : INHERITED(*generator)
1587 , fExpression(expr) {}
1588
1589 void load() override {
1590 fGenerator.writeVariableExpression(fExpression);
1591 }
1592
1593 void store(bool discard) override {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001594 int count = ByteCodeGenerator::SlotCount(fExpression.type());
Brian Osmanb08cc022020-04-02 11:38:40 -04001595 if (!discard) {
Brian Osman49b30f42020-06-26 17:22:27 -04001596 fGenerator.write(ByteCodeInstruction::kDup, count);
Brian Osmanb08cc022020-04-02 11:38:40 -04001597 }
1598 ByteCodeGenerator::Location location = fGenerator.getLocation(fExpression);
Brian Osman49b30f42020-06-26 17:22:27 -04001599 if (location.isOnStack()) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001600 fGenerator.write(location.selectStore(ByteCodeInstruction::kStoreExtended,
1601 ByteCodeInstruction::kStoreExtendedGlobal),
1602 count);
Brian Osmanb08cc022020-04-02 11:38:40 -04001603 } else {
Brian Osman49b30f42020-06-26 17:22:27 -04001604 fGenerator.write(location.selectStore(ByteCodeInstruction::kStore,
1605 ByteCodeInstruction::kStoreGlobal),
1606 count);
Brian Osmanb08cc022020-04-02 11:38:40 -04001607 fGenerator.write8(location.fSlot);
1608 }
1609 }
1610
1611private:
John Stiles7571f9e2020-09-02 22:42:33 -04001612 using INHERITED = LValue;
Brian Osmanb08cc022020-04-02 11:38:40 -04001613
1614 const Expression& fExpression;
1615};
1616
1617std::unique_ptr<ByteCodeGenerator::LValue> ByteCodeGenerator::getLValue(const Expression& e) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001618 switch (e.kind()) {
1619 case Expression::Kind::kExternalValue: {
John Stiles17c5b702020-08-18 10:40:03 -04001620 const ExternalValue* value = e.as<ExternalValueReference>().fValue;
Brian Osmanb08cc022020-04-02 11:38:40 -04001621 int index = fOutput->fExternalValues.size();
1622 fOutput->fExternalValues.push_back(value);
1623 SkASSERT(index <= 255);
1624 return std::unique_ptr<LValue>(new ByteCodeExternalValueLValue(this, *value, index));
1625 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001626 case Expression::Kind::kFieldAccess:
1627 case Expression::Kind::kIndex:
1628 case Expression::Kind::kVariableReference:
Brian Osmanb08cc022020-04-02 11:38:40 -04001629 return std::unique_ptr<LValue>(new ByteCodeExpressionLValue(this, e));
Ethan Nicholase6592142020-09-08 10:22:09 -04001630 case Expression::Kind::kSwizzle: {
John Stiles17c5b702020-08-18 10:40:03 -04001631 const Swizzle& s = e.as<Swizzle>();
Brian Osmanb08cc022020-04-02 11:38:40 -04001632 return swizzle_is_simple(s)
1633 ? std::unique_ptr<LValue>(new ByteCodeExpressionLValue(this, e))
1634 : std::unique_ptr<LValue>(new ByteCodeSwizzleLValue(this, s));
1635 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001636 case Expression::Kind::kTernary:
Brian Osmanb08cc022020-04-02 11:38:40 -04001637 default:
1638#ifdef SK_DEBUG
1639 ABORT("unsupported lvalue %s\n", e.description().c_str());
1640#endif
1641 return nullptr;
1642 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001643}
1644
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001645void ByteCodeGenerator::writeBlock(const Block& b) {
1646 for (const auto& s : b.fStatements) {
1647 this->writeStatement(*s);
1648 }
1649}
1650
Brian Osmanb08cc022020-04-02 11:38:40 -04001651void ByteCodeGenerator::setBreakTargets() {
1652 std::vector<DeferredLocation>& breaks = fBreakTargets.top();
1653 for (DeferredLocation& b : breaks) {
1654 b.set();
1655 }
1656 fBreakTargets.pop();
1657}
1658
1659void ByteCodeGenerator::setContinueTargets() {
1660 std::vector<DeferredLocation>& continues = fContinueTargets.top();
1661 for (DeferredLocation& c : continues) {
1662 c.set();
1663 }
1664 fContinueTargets.pop();
1665}
1666
1667void ByteCodeGenerator::writeBreakStatement(const BreakStatement& b) {
1668 // TODO: Include BranchIfAllFalse to top-most LoopNext
1669 this->write(ByteCodeInstruction::kLoopBreak);
1670}
1671
1672void ByteCodeGenerator::writeContinueStatement(const ContinueStatement& c) {
1673 // TODO: Include BranchIfAllFalse to top-most LoopNext
1674 this->write(ByteCodeInstruction::kLoopContinue);
1675}
1676
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001677void ByteCodeGenerator::writeDoStatement(const DoStatement& d) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001678 this->write(ByteCodeInstruction::kLoopBegin);
1679 size_t start = fCode->size();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001680 this->writeStatement(*d.fStatement);
Brian Osmanb08cc022020-04-02 11:38:40 -04001681 this->write(ByteCodeInstruction::kLoopNext);
1682 this->writeExpression(*d.fTest);
1683 this->write(ByteCodeInstruction::kLoopMask);
1684 // TODO: Could shorten this with kBranchIfAnyTrue
1685 this->write(ByteCodeInstruction::kBranchIfAllFalse);
Brian Osman569f12f2019-06-13 11:23:57 -04001686 DeferredLocation endLocation(this);
Brian Osmanb08cc022020-04-02 11:38:40 -04001687 this->write(ByteCodeInstruction::kBranch);
1688 this->write16(start);
Brian Osman569f12f2019-06-13 11:23:57 -04001689 endLocation.set();
Brian Osmanb08cc022020-04-02 11:38:40 -04001690 this->write(ByteCodeInstruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001691}
1692
1693void ByteCodeGenerator::writeForStatement(const ForStatement& f) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001694 fContinueTargets.emplace();
1695 fBreakTargets.emplace();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001696 if (f.fInitializer) {
1697 this->writeStatement(*f.fInitializer);
1698 }
Brian Osmanb08cc022020-04-02 11:38:40 -04001699 this->write(ByteCodeInstruction::kLoopBegin);
1700 size_t start = fCode->size();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001701 if (f.fTest) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001702 this->writeExpression(*f.fTest);
1703 this->write(ByteCodeInstruction::kLoopMask);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001704 }
Brian Osmanb08cc022020-04-02 11:38:40 -04001705 this->write(ByteCodeInstruction::kBranchIfAllFalse);
Brian Osman569f12f2019-06-13 11:23:57 -04001706 DeferredLocation endLocation(this);
1707 this->writeStatement(*f.fStatement);
Brian Osmanb08cc022020-04-02 11:38:40 -04001708 this->write(ByteCodeInstruction::kLoopNext);
Brian Osman569f12f2019-06-13 11:23:57 -04001709 if (f.fNext) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001710 this->writeExpression(*f.fNext, true);
Brian Osman569f12f2019-06-13 11:23:57 -04001711 }
Brian Osmanb08cc022020-04-02 11:38:40 -04001712 this->write(ByteCodeInstruction::kBranch);
1713 this->write16(start);
Brian Osman569f12f2019-06-13 11:23:57 -04001714 endLocation.set();
Brian Osmanb08cc022020-04-02 11:38:40 -04001715 this->write(ByteCodeInstruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001716}
1717
1718void ByteCodeGenerator::writeIfStatement(const IfStatement& i) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001719 this->writeExpression(*i.fTest);
1720 this->write(ByteCodeInstruction::kMaskPush);
1721 this->write(ByteCodeInstruction::kBranchIfAllFalse);
Brian Osman569f12f2019-06-13 11:23:57 -04001722 DeferredLocation falseLocation(this);
1723 this->writeStatement(*i.fIfTrue);
1724 falseLocation.set();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001725 if (i.fIfFalse) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001726 this->write(ByteCodeInstruction::kMaskNegate);
1727 this->write(ByteCodeInstruction::kBranchIfAllFalse);
Brian Osman569f12f2019-06-13 11:23:57 -04001728 DeferredLocation endLocation(this);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001729 this->writeStatement(*i.fIfFalse);
Mike Kleinb45ee832019-05-17 11:11:11 -05001730 endLocation.set();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001731 }
Brian Osmanb08cc022020-04-02 11:38:40 -04001732 this->write(ByteCodeInstruction::kMaskPop);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001733}
1734
Brian Osmanb08cc022020-04-02 11:38:40 -04001735void ByteCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
1736 if (fLoopCount || fConditionCount) {
Brian Osman4a47da72019-07-12 11:30:32 -04001737 fErrors.error(r.fOffset, "return not allowed inside conditional or loop");
1738 return;
1739 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001740 int count = SlotCount(r.fExpression->type());
Brian Osmanb08cc022020-04-02 11:38:40 -04001741 this->writeExpression(*r.fExpression);
1742
1743 // Technically, the kReturn also pops fOutput->fLocalCount values from the stack, too, but we
1744 // haven't counted pushing those (they're outside the scope of our stack tracking). Instead,
1745 // we account for those in writeFunction().
1746
1747 // This is all fine because we don't allow conditional returns, so we only return once anyway.
Brian Osman49b30f42020-06-26 17:22:27 -04001748 this->write(ByteCodeInstruction::kReturn, count);
Brian Osmanb08cc022020-04-02 11:38:40 -04001749}
1750
1751void ByteCodeGenerator::writeSwitchStatement(const SwitchStatement& r) {
1752 // not yet implemented
1753 abort();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001754}
1755
1756void ByteCodeGenerator::writeVarDeclarations(const VarDeclarations& v) {
1757 for (const auto& declStatement : v.fVars) {
John Stiles403a3632020-08-20 12:11:48 -04001758 const VarDeclaration& decl = declStatement->as<VarDeclaration>();
Brian Osmanb08cc022020-04-02 11:38:40 -04001759 // we need to grab the location even if we don't use it, to ensure it has been allocated
1760 Location location = this->getLocation(*decl.fVar);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001761 if (decl.fValue) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001762 this->writeExpression(*decl.fValue);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001763 int count = SlotCount(decl.fValue->type());
Brian Osman49b30f42020-06-26 17:22:27 -04001764 this->write(ByteCodeInstruction::kStore, count);
1765 this->write8(location.fSlot);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001766 }
1767 }
1768}
1769
1770void ByteCodeGenerator::writeWhileStatement(const WhileStatement& w) {
Brian Osmanb08cc022020-04-02 11:38:40 -04001771 this->write(ByteCodeInstruction::kLoopBegin);
1772 size_t cond = fCode->size();
1773 this->writeExpression(*w.fTest);
1774 this->write(ByteCodeInstruction::kLoopMask);
1775 this->write(ByteCodeInstruction::kBranchIfAllFalse);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001776 DeferredLocation endLocation(this);
1777 this->writeStatement(*w.fStatement);
Brian Osmanb08cc022020-04-02 11:38:40 -04001778 this->write(ByteCodeInstruction::kLoopNext);
1779 this->write(ByteCodeInstruction::kBranch);
1780 this->write16(cond);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001781 endLocation.set();
Brian Osmanb08cc022020-04-02 11:38:40 -04001782 this->write(ByteCodeInstruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001783}
1784
1785void ByteCodeGenerator::writeStatement(const Statement& s) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001786 switch (s.kind()) {
1787 case Statement::Kind::kBlock:
John Stiles26f98502020-08-18 09:30:51 -04001788 this->writeBlock(s.as<Block>());
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001789 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001790 case Statement::Kind::kBreak:
John Stiles26f98502020-08-18 09:30:51 -04001791 this->writeBreakStatement(s.as<BreakStatement>());
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001792 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001793 case Statement::Kind::kContinue:
John Stiles26f98502020-08-18 09:30:51 -04001794 this->writeContinueStatement(s.as<ContinueStatement>());
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001795 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001796 case Statement::Kind::kDiscard:
Brian Osmanb08cc022020-04-02 11:38:40 -04001797 // not yet implemented
1798 abort();
Ethan Nicholase6592142020-09-08 10:22:09 -04001799 case Statement::Kind::kDo:
John Stiles26f98502020-08-18 09:30:51 -04001800 this->writeDoStatement(s.as<DoStatement>());
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001801 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001802 case Statement::Kind::kExpression:
John Stiles26f98502020-08-18 09:30:51 -04001803 this->writeExpression(*s.as<ExpressionStatement>().fExpression, true);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001804 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001805 case Statement::Kind::kFor:
John Stiles26f98502020-08-18 09:30:51 -04001806 this->writeForStatement(s.as<ForStatement>());
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001807 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001808 case Statement::Kind::kIf:
John Stiles26f98502020-08-18 09:30:51 -04001809 this->writeIfStatement(s.as<IfStatement>());
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001810 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001811 case Statement::Kind::kReturn:
John Stiles26f98502020-08-18 09:30:51 -04001812 this->writeReturnStatement(s.as<ReturnStatement>());
Brian Osmanb08cc022020-04-02 11:38:40 -04001813 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001814 case Statement::Kind::kSwitch:
John Stiles26f98502020-08-18 09:30:51 -04001815 this->writeSwitchStatement(s.as<SwitchStatement>());
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001816 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001817 case Statement::Kind::kVarDeclarations:
John Stiles26f98502020-08-18 09:30:51 -04001818 this->writeVarDeclarations(*s.as<VarDeclarationsStatement>().fDeclaration);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001819 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001820 case Statement::Kind::kWhile:
John Stiles26f98502020-08-18 09:30:51 -04001821 this->writeWhileStatement(s.as<WhileStatement>());
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001822 break;
John Stiles98c1f822020-09-09 14:18:53 -04001823 case Statement::Kind::kInlineMarker:
1824 case Statement::Kind::kNop:
1825 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001826 default:
Brian Osmanb08cc022020-04-02 11:38:40 -04001827 SkASSERT(false);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001828 }
1829}
1830
Brian Osmanb08cc022020-04-02 11:38:40 -04001831ByteCodeFunction::ByteCodeFunction(const FunctionDeclaration* declaration)
1832 : fName(declaration->fName) {
Brian Osman80164412019-06-07 13:00:23 -04001833 fParameterCount = 0;
Brian Osmanb08cc022020-04-02 11:38:40 -04001834 for (const auto& p : declaration->fParameters) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001835 int slots = ByteCodeGenerator::SlotCount(p->type());
Brian Osmanb08cc022020-04-02 11:38:40 -04001836 fParameters.push_back({ slots, (bool)(p->fModifiers.fFlags & Modifiers::kOut_Flag) });
1837 fParameterCount += slots;
Brian Osman80164412019-06-07 13:00:23 -04001838 }
1839}
1840
John Stilesa6841be2020-08-06 14:11:56 -04001841} // namespace SkSL