blob: 3a65d8c40e13c52910f97eaa82d9d1902a7562e0 [file] [log] [blame]
Brian Osmanb380e712019-07-24 17:02:39 -04001/*
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04002 * Copyright 2019 Google LLC
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "src/sksl/SkSLByteCodeGenerator.h"
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04009
10namespace SkSL {
11
Ethan Nicholasb962eff2020-01-23 16:49:41 -050012ByteCodeGenerator::ByteCodeGenerator(const Program* program, ErrorReporter* errors,
13 ByteCode* output)
Ethan Nicholas82162ee2019-05-21 16:05:08 -040014 : INHERITED(program, errors, nullptr)
Ethan Nicholasae9633b2019-05-24 12:46:34 -040015 , fOutput(output)
16 , fIntrinsics {
Brian Osmandc2a9772020-02-21 17:00:43 -050017 // "Normal" intrinsics are all $genType f($genType), mapped to a single instruction
Ethan Nicholasb962eff2020-01-23 16:49:41 -050018 { "cos", ByteCode::Instruction::kCos },
Ethan Nicholasb962eff2020-01-23 16:49:41 -050019 { "sin", ByteCode::Instruction::kSin },
20 { "sqrt", ByteCode::Instruction::kSqrt },
21 { "tan", ByteCode::Instruction::kTan },
Brian Osmandc2a9772020-02-21 17:00:43 -050022
23 // Special intrinsics have other signatures, or non-standard code-gen
24 { "dot", SpecialIntrinsic::kDot },
25 { "inverse", SpecialIntrinsic::kInverse },
26 { "print", SpecialIntrinsic::kPrint },
Ethan Nicholasb962eff2020-01-23 16:49:41 -050027 } {}
Ethan Nicholas82162ee2019-05-21 16:05:08 -040028
Brian Osman07c117b2019-05-23 12:51:06 -070029int ByteCodeGenerator::SlotCount(const Type& type) {
Brian Osmanfba386b2019-06-20 14:54:15 -040030 if (type.kind() == Type::kOther_Kind) {
31 return 0;
32 } else if (type.kind() == Type::kStruct_Kind) {
Brian Osman07c117b2019-05-23 12:51:06 -070033 int slots = 0;
34 for (const auto& f : type.fields()) {
35 slots += SlotCount(*f.fType);
36 }
37 SkASSERT(slots <= 255);
38 return slots;
39 } else if (type.kind() == Type::kArray_Kind) {
40 int columns = type.columns();
41 SkASSERT(columns >= 0);
42 int slots = columns * SlotCount(type.componentType());
43 SkASSERT(slots <= 255);
44 return slots;
45 } else {
46 return type.columns() * type.rows();
47 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -040048}
49
Brian Osman1c110a02019-10-01 14:53:32 -040050static inline bool is_uniform(const SkSL::Variable& var) {
51 return var.fModifiers.fFlags & Modifiers::kUniform_Flag;
52}
53
Brian Osmaneadfeb92020-01-09 12:43:03 -050054static inline bool is_in(const SkSL::Variable& var) {
55 return var.fModifiers.fFlags & Modifiers::kIn_Flag;
56}
Ethan Nicholasb962eff2020-01-23 16:49:41 -050057ByteCodeGenerator::Location ByteCodeGenerator::getLocation(const Variable& var) {
58 // given that we seldom have more than a couple of variables, linear search is probably the most
59 // efficient way to handle lookups
60 switch (var.fStorage) {
61 case Variable::kLocal_Storage: {
62 for (int i = fLocals.size() - 1; i >= 0; --i) {
63 if (fLocals[i] == &var) {
64 return ByteCode::Pointer{(uint16_t) (i + fParameterCount)};
Ben Wagner470e0ac2020-01-22 16:59:21 -050065 }
Ethan Nicholas7deb1c22020-01-22 10:31:55 -050066 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -050067 int result = fLocals.size() + fParameterCount;
68 fLocals.push_back(&var);
69 for (int i = 0; i < SlotCount(var.fType) - 1; ++i) {
70 fLocals.push_back(nullptr);
71 }
72 SkASSERT(result <= ByteCode::kPointerMax);
73 return ByteCode::Pointer{(uint16_t) result};
74 }
75 case Variable::kParameter_Storage: {
76 int offset = 0;
77 for (const auto& p : fFunction->fDeclaration.fParameters) {
78 if (p == &var) {
79 SkASSERT(offset <= ByteCode::kPointerMax);
80 return ByteCode::Pointer{(uint16_t) offset};
81 }
82 offset += SlotCount(p->fType);
83 }
84 SkASSERT(false);
85 return ByteCode::Pointer{0};
86 }
87 case Variable::kGlobal_Storage: {
88 if (is_in(var)) {
Brian Osmana95f10c2020-02-21 13:27:06 -050089 // If you see this error, it means the program is using raw 'in' variables. You
Ethan Nicholasb962eff2020-01-23 16:49:41 -050090 // should either specialize the program (Compiler::specialize) to bake in the final
91 // values of the 'in' variables, or not use 'in' variables (maybe you meant to use
92 // 'uniform' instead?).
Brian Osmana95f10c2020-02-21 13:27:06 -050093 fErrors.error(var.fOffset,
94 "'in' variable is not specialized or has unsupported type");
Ethan Nicholasb962eff2020-01-23 16:49:41 -050095 return ByteCode::Pointer{0};
96 }
97 bool isUniform = is_uniform(var);
98 int offset = isUniform ? fOutput->getGlobalSlotCount() : 0;
99 for (const auto& e : fProgram) {
100 if (e.fKind == ProgramElement::kVar_Kind) {
101 VarDeclarations& decl = (VarDeclarations&) e;
102 for (const auto& v : decl.fVars) {
103 const Variable* declVar = ((VarDeclaration&) *v).fVar;
104 if (declVar->fModifiers.fLayout.fBuiltin >= 0 || is_in(*declVar)) {
105 continue;
106 }
107 if (isUniform != is_uniform(*declVar)) {
108 continue;
109 }
110 if (declVar == &var) {
111 SkASSERT(offset <= ByteCode::kPointerMax);
112 return ByteCode::Pointer{(uint16_t) offset};
113 }
114 offset += SlotCount(declVar->fType);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400115 }
116 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400117 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500118 SkASSERT(false);
119 return ByteCode::Pointer{0};
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400120 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500121 default:
122 SkASSERT(false);
123 return ByteCode::Pointer{0};
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400124 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -0400125}
126
Brian Osman0785db02019-05-24 14:19:11 -0400127// A "simple" Swizzle is based on a variable (or a compound variable like a struct or array), and
128// that references consecutive values, such that it can be implemented using normal load/store ops
129// with an offset. Note that all single-component swizzles (of suitable base types) are simple.
130static bool swizzle_is_simple(const Swizzle& s) {
131 switch (s.fBase->fKind) {
132 case Expression::kFieldAccess_Kind:
133 case Expression::kIndex_Kind:
134 case Expression::kVariableReference_Kind:
135 break;
136 default:
137 return false;
138 }
139
140 for (size_t i = 1; i < s.fComponents.size(); ++i) {
141 if (s.fComponents[i] != s.fComponents[i - 1] + 1) {
142 return false;
143 }
144 }
145 return true;
146}
147
Brian Osman1c110a02019-10-01 14:53:32 -0400148ByteCodeGenerator::Location ByteCodeGenerator::getLocation(const Expression& expr) {
Brian Osman07c117b2019-05-23 12:51:06 -0700149 switch (expr.fKind) {
150 case Expression::kFieldAccess_Kind: {
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500151 const FieldAccess& f = (const FieldAccess&) expr;
152 Location result = this->getLocation(*f.fBase);
Brian Osman07c117b2019-05-23 12:51:06 -0700153 int offset = 0;
154 for (int i = 0; i < f.fFieldIndex; ++i) {
155 offset += SlotCount(*f.fBase->fType.fields()[i].fType);
156 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500157 return result.offset(*this, offset);
Ethan Nicholas99c54f02020-01-21 16:06:47 +0000158 }
Ben Wagner470e0ac2020-01-22 16:59:21 -0500159 case Expression::kIndex_Kind: {
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500160 const IndexExpression& idx = (const IndexExpression&) expr;
161 int stride = SlotCount(idx.fType);
162 int length = idx.fBase->fType.columns();
163 Location result = this->getLocation(*idx.fBase);
164 if (idx.fIndex->isConstant()) {
165 int64_t index = idx.fIndex->getConstantInt();
Ben Wagner470e0ac2020-01-22 16:59:21 -0500166 if (index < 0 || index >= length) {
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500167 fErrors.error(idx.fIndex->fOffset, "Array index out of bounds");
168 return result;
Ben Wagner470e0ac2020-01-22 16:59:21 -0500169 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500170 return result.offset(*this, index * stride);
Ben Wagner470e0ac2020-01-22 16:59:21 -0500171 } else {
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500172 ByteCode::Register index = this->next(1);
173 this->writeExpression(*idx.fIndex, index);
174 this->write(ByteCode::Instruction::kBoundsCheck);
175 this->write(index);
176 this->write(length);
177 ByteCode::Register imm = this->next(1);
178 this->write(ByteCode::Instruction::kImmediate);
179 this->write(imm);
180 this->write(ByteCode::Immediate{stride});
181 ByteCode::Register offset = this->next(1);
182 this->write(ByteCode::Instruction::kMultiplyI);
183 this->write(offset);
184 this->write(index);
185 this->write(imm);
186 return result.offset(*this, offset);
Ben Wagner470e0ac2020-01-22 16:59:21 -0500187 }
Ben Wagner470e0ac2020-01-22 16:59:21 -0500188 }
Brian Osman0785db02019-05-24 14:19:11 -0400189 case Expression::kSwizzle_Kind: {
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500190 const Swizzle& s = (const Swizzle&) expr;
Brian Osman0785db02019-05-24 14:19:11 -0400191 SkASSERT(swizzle_is_simple(s));
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500192 return this->getLocation(*s.fBase).offset(*this, s.fComponents[0]);
Brian Osman0785db02019-05-24 14:19:11 -0400193 }
Brian Osman07c117b2019-05-23 12:51:06 -0700194 case Expression::kVariableReference_Kind: {
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500195 const Variable& var = ((const VariableReference&) expr).fVariable;
Brian Osman07c117b2019-05-23 12:51:06 -0700196 return this->getLocation(var);
197 }
198 default:
199 SkASSERT(false);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500200 return ByteCode::Pointer{0};
Brian Osman07c117b2019-05-23 12:51:06 -0700201 }
202}
203
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500204Variable::Storage ByteCodeGenerator::getStorage(const Expression& expr) {
205 switch (expr.fKind) {
206 case Expression::kFieldAccess_Kind: {
207 const FieldAccess& f = (const FieldAccess&) expr;
208 return this->getStorage(*f.fBase);
Ethan Nicholas7deb1c22020-01-22 10:31:55 -0500209 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500210 case Expression::kIndex_Kind: {
211 const IndexExpression& idx = (const IndexExpression&) expr;
212 return this->getStorage(*idx.fBase);
Ethan Nicholas7deb1c22020-01-22 10:31:55 -0500213 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500214 case Expression::kSwizzle_Kind: {
215 const Swizzle& s = (const Swizzle&) expr;
216 return this->getStorage(*s.fBase);
Ethan Nicholas7deb1c22020-01-22 10:31:55 -0500217 }
Ben Wagner470e0ac2020-01-22 16:59:21 -0500218 case Expression::kVariableReference_Kind: {
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500219 const Variable& var = ((const VariableReference&) expr).fVariable;
220 return var.fStorage;
Ben Wagner470e0ac2020-01-22 16:59:21 -0500221 }
222 default:
Ben Wagner470e0ac2020-01-22 16:59:21 -0500223 SkASSERT(false);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500224 return Variable::kLocal_Storage;
Ethan Nicholas99c54f02020-01-21 16:06:47 +0000225 }
Ethan Nicholas2cde3a12020-01-21 09:23:13 -0500226}
227
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500228ByteCode::Instruction ByteCodeGenerator::getLoadInstruction(ByteCodeGenerator::Location location,
229 Variable::Storage storage) {
230 switch (storage) {
231 case Variable::kGlobal_Storage:
232 switch (location.fKind) {
233 case Location::kPointer_Kind: return ByteCode::Instruction::kLoadDirect;
234 case Location::kRegister_Kind: return ByteCode::Instruction::kLoad;
235 }
236 case Variable::kParameter_Storage:
237 switch (location.fKind) {
238 case Location::kPointer_Kind: return ByteCode::Instruction::kLoadParameterDirect;
239 case Location::kRegister_Kind: return ByteCode::Instruction::kLoadParameter;
240 }
241 case Variable::kLocal_Storage:
242 switch (location.fKind) {
243 case Location::kPointer_Kind: return ByteCode::Instruction::kLoadStackDirect;
244 case Location::kRegister_Kind: return ByteCode::Instruction::kLoadStack;
245 }
246 default:
247 break;
248 }
249 SkASSERT(false);
250 return ByteCode::Instruction::kNop;
251}
Ben Wagner470e0ac2020-01-22 16:59:21 -0500252
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500253ByteCode::Instruction ByteCodeGenerator::getStoreInstruction(ByteCodeGenerator::Location location,
254 Variable::Storage storage) {
255 switch (storage) {
256 case Variable::kGlobal_Storage:
257 switch (location.fKind) {
258 case Location::kPointer_Kind: return ByteCode::Instruction::kStoreDirect;
259 case Location::kRegister_Kind: return ByteCode::Instruction::kStore;
260 }
261 case Variable::kParameter_Storage:
262 switch (location.fKind) {
263 case Location::kPointer_Kind: return ByteCode::Instruction::kStoreParameterDirect;
264 case Location::kRegister_Kind: return ByteCode::Instruction::kStoreParameter;
265 }
266 case Variable::kLocal_Storage:
267 switch (location.fKind) {
268 case Location::kPointer_Kind: return ByteCode::Instruction::kStoreStackDirect;
269 case Location::kRegister_Kind: return ByteCode::Instruction::kStoreStack;
270 }
271 default:
272 break;
273 }
274 SkASSERT(false);
275 return ByteCode::Instruction::kNop;
276}
277
Ethan Nicholas2329da02020-01-24 15:49:33 -0500278#define VEC(inst) ((ByteCode::Instruction) ((uint16_t) inst + 1))
279
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500280class ByteCodeSimpleLValue : public ByteCodeGenerator::LValue {
281public:
282 ByteCodeSimpleLValue(ByteCodeGenerator* generator, ByteCodeGenerator::Location location,
283 int count, ByteCode::Instruction load, ByteCode::Instruction store)
284 : INHERITED(*generator)
285 , fLocation(location)
Ethan Nicholas2329da02020-01-24 15:49:33 -0500286 , fCount((uint8_t) count)
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500287 , fLoad(load)
288 , fStore(store) {}
289
290 void load(ByteCode::Register result) override {
Ethan Nicholas2329da02020-01-24 15:49:33 -0500291 fGenerator.write(fLoad, fCount);
292 fGenerator.write(result);
293 fGenerator.write(fLocation);
Ben Wagner470e0ac2020-01-22 16:59:21 -0500294 }
295
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500296 void store(ByteCode::Register src) override {
Ethan Nicholas2329da02020-01-24 15:49:33 -0500297 fGenerator.write(fStore, fCount);
298 fGenerator.write(fLocation);
299 fGenerator.write(src);
Ben Wagner470e0ac2020-01-22 16:59:21 -0500300 }
301
302private:
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500303 ByteCodeGenerator::Location fLocation;
Ben Wagner470e0ac2020-01-22 16:59:21 -0500304
Ethan Nicholas2329da02020-01-24 15:49:33 -0500305 uint8_t fCount;
Ben Wagner470e0ac2020-01-22 16:59:21 -0500306
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500307 ByteCode::Instruction fLoad;
308
309 ByteCode::Instruction fStore;
310
311 typedef ByteCodeGenerator::LValue INHERITED;
Ben Wagner470e0ac2020-01-22 16:59:21 -0500312};
313
314class ByteCodeSwizzleLValue : public ByteCodeGenerator::LValue {
315public:
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500316 ByteCodeSwizzleLValue(ByteCodeGenerator* generator, const Swizzle* swizzle)
Ben Wagner470e0ac2020-01-22 16:59:21 -0500317 : INHERITED(*generator)
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500318 , fSwizzle(*swizzle) {}
Ben Wagner470e0ac2020-01-22 16:59:21 -0500319
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500320 void load(ByteCode::Register result) override {
321 fGenerator.writeSwizzle(fSwizzle, result);
Ben Wagner470e0ac2020-01-22 16:59:21 -0500322 }
323
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500324 void store(ByteCode::Register src) override {
325 ByteCodeGenerator::Location target = fGenerator.getLocation(*fSwizzle.fBase);
326 ByteCode::Instruction inst = fGenerator.getStoreInstruction(
327 target,
328 fGenerator.getStorage(*fSwizzle.fBase));
329 for (size_t i = 0; i < fSwizzle.fComponents.size(); ++i) {
330 ByteCodeGenerator::Location final = target.offset(fGenerator, fSwizzle.fComponents[i]);
331 fGenerator.write(inst);
332 fGenerator.write(final);
333 fGenerator.write(src + i);
Ben Wagner470e0ac2020-01-22 16:59:21 -0500334 }
335 }
336
337private:
338 const Swizzle& fSwizzle;
339
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500340 typedef ByteCodeGenerator::LValue INHERITED;
Ben Wagner470e0ac2020-01-22 16:59:21 -0500341};
342
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500343class ByteCodeExternalValueLValue : public ByteCodeGenerator::LValue {
Ben Wagner470e0ac2020-01-22 16:59:21 -0500344public:
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500345 ByteCodeExternalValueLValue(ByteCodeGenerator* generator, ExternalValue& value, int index)
Ben Wagner470e0ac2020-01-22 16:59:21 -0500346 : INHERITED(*generator)
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500347 , fIndex(index)
348 , fSlotCount(ByteCodeGenerator::SlotCount(value.type())) {
349 SkASSERT(fSlotCount <= 4);
Ben Wagner470e0ac2020-01-22 16:59:21 -0500350 }
351
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500352 void load(ByteCode::Register result) override {
353 fGenerator.write(ByteCode::Instruction::kReadExternal);
354 fGenerator.write(result);
355 fGenerator.write((uint8_t) fSlotCount);
356 fGenerator.write((uint8_t) fIndex);
357 }
358
359 void store(ByteCode::Register src) override {
360 fGenerator.write(ByteCode::Instruction::kWriteExternal);
361 fGenerator.write((uint8_t) fIndex);
362 fGenerator.write((uint8_t) fSlotCount);
363 fGenerator.write(src);
Ben Wagner470e0ac2020-01-22 16:59:21 -0500364 }
365
366private:
367 typedef LValue INHERITED;
368
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500369 int fIndex;
370
371 int fSlotCount;
Ben Wagner470e0ac2020-01-22 16:59:21 -0500372};
373
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500374std::unique_ptr<ByteCodeGenerator::LValue> ByteCodeGenerator::getLValue(const Expression& expr) {
375 switch (expr.fKind) {
Ben Wagner470e0ac2020-01-22 16:59:21 -0500376 case Expression::kExternalValue_Kind: {
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500377 ExternalValue* value = ((ExternalValueReference&) expr).fValue;
Ben Wagner470e0ac2020-01-22 16:59:21 -0500378 int index = fOutput->fExternalValues.size();
379 fOutput->fExternalValues.push_back(value);
380 SkASSERT(index <= 255);
381 return std::unique_ptr<LValue>(new ByteCodeExternalValueLValue(this, *value, index));
382 }
383 case Expression::kFieldAccess_Kind:
384 case Expression::kIndex_Kind:
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500385 case Expression::kVariableReference_Kind: {
386 Location location = this->getLocation(expr);
387 Variable::Storage storage = this->getStorage(expr);
388 ByteCode::Instruction loadInst = this->getLoadInstruction(location, storage);
389 ByteCode::Instruction storeInst = this->getStoreInstruction(location, storage);
390 return std::unique_ptr<LValue>(new ByteCodeSimpleLValue(this, location,
391 SlotCount(expr.fType),
392 loadInst, storeInst));
Ben Wagner470e0ac2020-01-22 16:59:21 -0500393 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500394 case Expression::kSwizzle_Kind:
395 return std::unique_ptr<LValue>(new ByteCodeSwizzleLValue(this, &(Swizzle&) expr));
396 default:
397 ABORT("unsupported lvalue\n");
398 }
399}
400
401ByteCode::Register ByteCodeGenerator::next(int count) {
402 SkASSERT(fNextRegister + count <= ByteCode::kRegisterMax);
403 fNextRegister += count;
404 return ByteCode::Register{(uint16_t) (fNextRegister - count)};
405}
406
407static TypeCategory type_category(const Type& type) {
408 switch (type.kind()) {
409 case Type::Kind::kVector_Kind:
410 case Type::Kind::kMatrix_Kind:
411 return type_category(type.componentType());
412 default:
413 String name = type.displayName();
414 if (name == "bool") {
415 return TypeCategory::kBool;
416 } else if (name == "int" || name == "short") {
417 return TypeCategory::kSigned;
418 } else if (name == "uint" || name == "ushort") {
419 return TypeCategory::kUnsigned;
420 } else {
421 SkASSERT(name == "float" || name == "half");
422 return TypeCategory::kFloat;
423 }
424 ABORT("unsupported type: %s\n", name.c_str());
425 }
426}
427
Ethan Nicholas2329da02020-01-24 15:49:33 -0500428void ByteCodeGenerator::write(ByteCode::Instruction inst, int count) {
429 SkASSERT(count <= 255);
430 if (count > 1) {
431 this->write(VEC(inst));
432 this->write((uint8_t) count);
433 }
434 else {
435 this->write(inst);
436 }
437}
438
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500439void ByteCodeGenerator::writeTypedInstruction(const Type& type, ByteCode::Instruction s,
440 ByteCode::Instruction u, ByteCode::Instruction f) {
441 switch (type_category(type)) {
442 case TypeCategory::kSigned:
443 this->write(s);
444 break;
445 case TypeCategory::kUnsigned:
446 this->write(u);
447 break;
448 case TypeCategory::kFloat: {
449 this->write(f);
450 break;
451 }
452 default:
453 SkASSERT(false);
454 }
455}
456
Ethan Nicholas2329da02020-01-24 15:49:33 -0500457void ByteCodeGenerator::writeVectorBinaryInstruction(const Type& operandType,
458 ByteCode::Register left,
459 ByteCode::Register right,
460 ByteCode::Instruction s,
461 ByteCode::Instruction u,
462 ByteCode::Instruction f,
463 ByteCode::Register result) {
464 uint8_t count = (uint8_t) SlotCount(operandType);
465 if (count == 1) {
466 this->writeTypedInstruction(operandType, s, u, f);
467 }
468 else {
469 this->writeTypedInstruction(operandType, VEC(s), VEC(u), VEC(f));
470 this->write(count);
471 }
472 this->write(result);
473 this->write(left);
474 this->write(right);
475}
476
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500477void ByteCodeGenerator::writeBinaryInstruction(const Type& operandType,
478 ByteCode::Register left,
479 ByteCode::Register right,
480 ByteCode::Instruction s,
481 ByteCode::Instruction u,
482 ByteCode::Instruction f,
483 ByteCode::Register result) {
484 for (int i = 0; i < SlotCount(operandType); ++i) {
485 this->writeTypedInstruction(operandType, s, u, f);
486 this->write(result + i);
487 this->write(left + i);
488 this->write(right + i);
489 }
490}
491
492void ByteCodeGenerator::writeBinaryExpression(const BinaryExpression& b,
493 ByteCode::Register result) {
494 if (b.fOperator == Token::Kind::EQ) {
495 std::unique_ptr<LValue> lvalue = this->getLValue(*b.fLeft);
496 this->writeExpression(*b.fRight, result);
497 lvalue->store(result);
498 return;
499 }
500 const Type& lType = b.fLeft->fType;
501 const Type& rType = b.fRight->fType;
502 bool lVecOrMtx = (lType.kind() == Type::kVector_Kind || lType.kind() == Type::kMatrix_Kind);
503 bool rVecOrMtx = (rType.kind() == Type::kVector_Kind || rType.kind() == Type::kMatrix_Kind);
504 const Type* operandType;
505 if (!lVecOrMtx && rVecOrMtx) {
506 operandType = &rType;
507 } else {
508 operandType = &lType;
509 }
510 Token::Kind op;
511 std::unique_ptr<LValue> lvalue;
512 ByteCode::Register left;
513 switch (b.fOperator) {
514 case Token::Kind::LOGICALAND:
515 case Token::Kind::LOGICALANDEQ:
516 case Token::Kind::LOGICALOR:
517 case Token::Kind::LOGICALOREQ:
518 left = result;
519 break;
520 default:
521 left = this->next(SlotCount(*operandType));
522 }
523 if (is_assignment(b.fOperator)) {
524 lvalue = this->getLValue(*b.fLeft);
525 lvalue->load(left);
526 op = remove_assignment(b.fOperator);
527 } else {
528 this->writeExpression(*b.fLeft, left);
529 op = b.fOperator;
530 if (!lVecOrMtx && rVecOrMtx) {
Ethan Nicholas2329da02020-01-24 15:49:33 -0500531 this->write(ByteCode::Instruction::kSplat);
532 this->write((uint8_t) (SlotCount(rType) - 1));
533 this->write(left + 1);
534 this->write(left);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500535 }
536 }
537 SkDEBUGCODE(TypeCategory tc = type_category(lType));
538 int count = std::max(SlotCount(lType), SlotCount(rType));
539 switch (op) {
540 case Token::Kind::LOGICALAND: {
541 SkASSERT(left.fIndex == result.fIndex);
542 this->write(ByteCode::Instruction::kMaskPush);
543 ++fConditionCount;
544 this->write(left);
545 this->write(ByteCode::Instruction::kBranchIfAllFalse);
546 DeferredLocation falseLocation(this);
547 SkASSERT(SlotCount(b.fRight->fType) == 1);
548 ByteCode::Register right = this->next(1);
549 this->writeExpression(*b.fRight, right);
550 this->write(ByteCode::Instruction::kAnd);
551 this->write(result);
552 this->write(left);
553 this->write(right);
554 falseLocation.set();
555 --fConditionCount;
556 this->write(ByteCode::Instruction::kMaskPop);
557 return;
558 }
559 case Token::Kind::LOGICALOR: {
560 SkASSERT(left.fIndex == result.fIndex);
561 ByteCode::Register mask = this->next(1);
562 this->write(ByteCode::Instruction::kNot);
563 this->write(mask);
564 this->write(left);
565 this->write(ByteCode::Instruction::kMaskPush);
566 ++fConditionCount;
567 this->write(mask);
568 this->write(ByteCode::Instruction::kBranchIfAllFalse);
569 DeferredLocation falseLocation(this);
570 SkASSERT(SlotCount(b.fRight->fType) == 1);
571 ByteCode::Register right = this->next(1);
572 this->writeExpression(*b.fRight, right);
573 this->write(ByteCode::Instruction::kOr);
574 this->write(result);
575 this->write(left);
576 this->write(right);
577 falseLocation.set();
578 --fConditionCount;
579 this->write(ByteCode::Instruction::kMaskPop);
580 return;
581 }
582 case Token::Kind::SHL:
583 case Token::Kind::SHR: {
584 SkASSERT(count == 1 && (tc == SkSL::TypeCategory::kSigned ||
585 tc == SkSL::TypeCategory::kUnsigned));
586 if (!b.fRight->isConstant()) {
587 fErrors.error(b.fRight->fOffset, "Shift amounts must be constant");
588 return;
589 }
590 int64_t shift = b.fRight->getConstantInt();
591 if (shift < 0 || shift > 31) {
592 fErrors.error(b.fRight->fOffset, "Shift amount out of range");
593 return;
594 }
595
596 if (op == Token::Kind::SHL) {
597 this->write(ByteCode::Instruction::kShiftLeft);
598 } else {
599 this->write(type_category(lType) == TypeCategory::kSigned
600 ? ByteCode::Instruction::kShiftRightS
601 : ByteCode::Instruction::kShiftRightU);
602 }
603 this->write(result);
604 this->write(left);
605 this->write((uint8_t) shift);
606 return;
607 }
608 case Token::Kind::STAR:
609 // Special case for M*V, V*M, M*M (but not V*V!)
610 if (lType.columns() > 1 && rType.columns() > 1 &&
611 (lType.rows() > 1 || rType.rows() > 1)) {
612 ByteCode::Register right = this->next(SlotCount(rType));
613 this->writeExpression(*b.fRight, right);
614 int rCols = rType.columns(),
615 rRows = rType.rows(),
616 lCols = lType.columns(),
617 lRows = lType.rows();
618 // M*V treats the vector as a column
619 if (rType.kind() == Type::kVector_Kind) {
620 std::swap(rCols, rRows);
621 }
622 SkASSERT(lCols == rRows);
623 SkASSERT(SlotCount(b.fType) == lRows * rCols);
624 this->write(ByteCode::Instruction::kMatrixMultiply);
625 this->write(result);
626 this->write(left);
627 this->write(right);
628 this->write((uint8_t) lCols);
629 this->write((uint8_t) lRows);
630 this->write((uint8_t) rCols);
631 return;
632 }
633
634 default:
635 break;
636 }
637 ByteCode::Register right = this->next(SlotCount(*operandType));
638 this->writeExpression(*b.fRight, right);
639 if (lVecOrMtx && !rVecOrMtx) {
Ethan Nicholas2329da02020-01-24 15:49:33 -0500640 this->write(ByteCode::Instruction::kSplat);
641 this->write((uint8_t) (SlotCount(*operandType) - 1));
642 this->write(right + 1);
643 this->write(right);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500644 }
645 switch (op) {
646 case Token::Kind::EQEQ:
647 this->writeBinaryInstruction(*operandType, left, right,
648 ByteCode::Instruction::kCompareEQI,
649 ByteCode::Instruction::kCompareEQI,
650 ByteCode::Instruction::kCompareEQF,
651 result);
652 // Collapse to a single bool
653 for (int i = 1; i < count; ++i) {
654 this->write(ByteCode::Instruction::kAnd);
655 this->write(result);
656 this->write(result);
657 this->write(result + i);
658 }
659 break;
660 case Token::Kind::GT:
661 this->writeBinaryInstruction(*operandType, left, right,
662 ByteCode::Instruction::kCompareGTS,
663 ByteCode::Instruction::kCompareGTU,
664 ByteCode::Instruction::kCompareGTF,
665 result);
666 break;
667 case Token::Kind::GTEQ:
668 this->writeBinaryInstruction(*operandType, left, right,
669 ByteCode::Instruction::kCompareGTEQS,
670 ByteCode::Instruction::kCompareGTEQU,
671 ByteCode::Instruction::kCompareGTEQF,
672 result);
673 break;
674 case Token::Kind::LT:
675 this->writeBinaryInstruction(*operandType, left, right,
676 ByteCode::Instruction::kCompareLTS,
677 ByteCode::Instruction::kCompareLTU,
678 ByteCode::Instruction::kCompareLTF,
679 result);
680 break;
681 case Token::Kind::LTEQ:
682 this->writeBinaryInstruction(*operandType, left, right,
683 ByteCode::Instruction::kCompareLTEQS,
684 ByteCode::Instruction::kCompareLTEQU,
685 ByteCode::Instruction::kCompareLTEQF,
686 result);
687 break;
688 case Token::Kind::MINUS:
Ethan Nicholas2329da02020-01-24 15:49:33 -0500689 this->writeVectorBinaryInstruction(*operandType, left, right,
690 ByteCode::Instruction::kSubtractI,
691 ByteCode::Instruction::kSubtractI,
692 ByteCode::Instruction::kSubtractF,
693 result);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500694 break;
695 case Token::Kind::NEQ:
696 this->writeBinaryInstruction(*operandType, left, right,
697 ByteCode::Instruction::kCompareNEQI,
698 ByteCode::Instruction::kCompareNEQI,
699 ByteCode::Instruction::kCompareNEQF,
700 result);
701 // Collapse to a single bool
702 for (int i = 1; i < count; ++i) {
703 this->write(ByteCode::Instruction::kOr);
704 this->write(result);
705 this->write(result);
706 this->write(result + i);
707 }
708 break;
709 case Token::Kind::PERCENT:
Ethan Nicholas2329da02020-01-24 15:49:33 -0500710 this->writeVectorBinaryInstruction(*operandType, left, right,
711 ByteCode::Instruction::kRemainderS,
712 ByteCode::Instruction::kRemainderU,
713 ByteCode::Instruction::kRemainderF,
714 result);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500715 break;
716 case Token::Kind::PLUS:
Ethan Nicholas2329da02020-01-24 15:49:33 -0500717 this->writeVectorBinaryInstruction(*operandType, left, right,
718 ByteCode::Instruction::kAddI,
719 ByteCode::Instruction::kAddI,
720 ByteCode::Instruction::kAddF,
721 result);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500722 break;
723 case Token::Kind::SLASH:
Ethan Nicholas2329da02020-01-24 15:49:33 -0500724 this->writeVectorBinaryInstruction(*operandType, left, right,
725 ByteCode::Instruction::kDivideS,
726 ByteCode::Instruction::kDivideU,
727 ByteCode::Instruction::kDivideF,
728 result);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500729 break;
730 case Token::Kind::STAR:
Ethan Nicholas2329da02020-01-24 15:49:33 -0500731 this->writeVectorBinaryInstruction(*operandType, left, right,
732 ByteCode::Instruction::kMultiplyI,
733 ByteCode::Instruction::kMultiplyI,
734 ByteCode::Instruction::kMultiplyF,
735 result);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500736 break;
737 case Token::Kind::LOGICALXOR: {
738 SkASSERT(tc == SkSL::TypeCategory::kBool);
739 this->write(ByteCode::Instruction::kXor);
740 this->write(result);
741 this->write(left);
742 this->write(right);
743 break;
744 }
745 case Token::Kind::BITWISEAND: {
746 SkASSERT(tc == SkSL::TypeCategory::kSigned || tc == SkSL::TypeCategory::kUnsigned);
747 this->write(ByteCode::Instruction::kAnd);
748 this->write(result);
749 this->write(left);
750 this->write(right);
751 break;
752 }
753 case Token::Kind::BITWISEOR: {
754 SkASSERT(tc == SkSL::TypeCategory::kSigned || tc == SkSL::TypeCategory::kUnsigned);
755 this->write(ByteCode::Instruction::kOr);
756 this->write(result);
757 this->write(left);
758 this->write(right);
759 break;
760 }
761 case Token::Kind::BITWISEXOR: {
762 SkASSERT(tc == SkSL::TypeCategory::kSigned || tc == SkSL::TypeCategory::kUnsigned);
763 this->write(ByteCode::Instruction::kXor);
764 this->write(result);
765 this->write(left);
766 this->write(right);
767 break;
768 }
769 default:
770 fErrors.error(b.fOffset, SkSL::String::printf("Unsupported binary operator '%s'",
771 Compiler::OperatorName(op)));
772 break;
773 }
774 if (lvalue) {
775 lvalue->store(result);
776 }
777}
778
779void ByteCodeGenerator::writeConstructor(const Constructor& c, ByteCode::Register result) {
780 if (c.fType.rows() > 1) {
781 if (c.fArguments.size() == 1) {
782 if (SlotCount(c.fArguments[0]->fType) == 1) {
783 ByteCode::Register v = this->next(1);
784 this->writeExpression(*c.fArguments[0], v);
785 this->write(ByteCode::Instruction::kScalarToMatrix);
786 this->write(result);
787 this->write(v);
788 this->write((uint8_t) c.fType.columns());
789 this->write((uint8_t) c.fType.rows());
790 return;
791 } else if (c.fArguments[0]->fType.rows() > 1) {
792 ByteCode::Register v = this->next(SlotCount(c.fArguments[0]->fType));
793 this->writeExpression(*c.fArguments[0], v);
794 this->write(ByteCode::Instruction::kMatrixToMatrix);
795 this->write(result);
796 this->write(v);
797 this->write((uint8_t) c.fArguments[0]->fType.columns());
798 this->write((uint8_t) c.fArguments[0]->fType.rows());
799 this->write((uint8_t) c.fType.columns());
800 this->write((uint8_t) c.fType.rows());
801 return;
802 }
803 }
804 int offset = 0;
805 for (const auto& arg : c.fArguments) {
806 this->writeExpression(*arg, ByteCode::Register{(uint16_t) (result.fIndex + offset)});
807 offset += SlotCount(arg->fType);
808 }
809 return;
810 }
811 if (c.fArguments.size() == 1 && c.fArguments[0]->fType.columns() == 1 &&
812 c.fType.columns() > 1) {
813 SkASSERT(SlotCount(c.fArguments[0]->fType) == 1);
814 ByteCode::Register v = result;
815 this->writeExpression(*c.fArguments[0], v);
Ethan Nicholas2329da02020-01-24 15:49:33 -0500816 this->write(ByteCode::Instruction::kSplat);
817 this->write((uint8_t) (c.fType.columns() - 1));
818 this->write(v + 1);
819 this->write(v);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500820 return;
821 }
822 ByteCode::Instruction inst;
823 switch (type_category(c.fArguments[0]->fType)) {
824 case TypeCategory::kSigned:
825 if (type_category(c.fType) == TypeCategory::kFloat) {
826 inst = ByteCode::Instruction::kSignedToFloat;
827 } else {
828 inst = ByteCode::Instruction::kNop;
829 }
830 break;
831 case TypeCategory::kUnsigned:
832 if (type_category(c.fType) == TypeCategory::kFloat) {
833 inst = ByteCode::Instruction::kUnsignedToFloat;
834 } else {
835 inst = ByteCode::Instruction::kNop;
836 }
837 break;
838 case TypeCategory::kFloat:
839 if (type_category(c.fType) == TypeCategory::kSigned) {
840 inst = ByteCode::Instruction::kFloatToSigned;
841 } else if (type_category(c.fType) == TypeCategory::kUnsigned) {
842 inst = ByteCode::Instruction::kFloatToUnsigned;
843 } else {
844 inst = ByteCode::Instruction::kNop;
845 }
846 break;
847 default:
848 SkASSERT(false);
849 return;
850 }
851 ByteCode::Register values;
852 if (inst == ByteCode::Instruction::kNop) {
853 values = result;
854 } else {
855 values = this->next(SlotCount(c.fType));
856 }
857 ByteCode::Register v = values;
858 for (size_t i = 0; i < c.fArguments.size(); ++i) {
859 this->writeExpression(*c.fArguments[i], v);
860 v.fIndex += SlotCount(c.fArguments[i]->fType);
861 }
862 if (inst != ByteCode::Instruction::kNop) {
863 v = values;
864 ByteCode::Register target = result;
865 for (size_t i = 0; i < c.fArguments.size(); ++i) {
866 int count = SlotCount(c.fArguments[i]->fType);
867 for (int j = 0; j < count; ++j) {
868 this->write(inst);
869 this->write(target);
870 ++target.fIndex;
871 this->write(v + j);
872 }
873 }
874 }
875}
876
877void ByteCodeGenerator::writeExternalFunctionCall(const ExternalFunctionCall& f,
878 ByteCode::Register result) {
879 int argumentCount = 0;
880 for (const auto& arg : f.fArguments) {
881 argumentCount += SlotCount(arg->fType);
882 }
883 ByteCode::Register args = this->next(argumentCount);
884 argumentCount = 0;
885 for (const auto& arg : f.fArguments) {
886 this->writeExpression(*arg, args + argumentCount);
887 argumentCount += SlotCount(arg->fType);
888 }
889 this->write(ByteCode::Instruction::kCallExternal);
890 this->write(result);
891 int index = fOutput->fExternalValues.size();
892 fOutput->fExternalValues.push_back(f.fFunction);
893 SkASSERT(index <= 255);
894 this->write((uint8_t) index);
895 SkASSERT(SlotCount(f.fType) <= 255);
896 this->write((uint8_t) SlotCount(f.fType));
897 this->write(args);
898 SkASSERT(argumentCount <= 255);
899 this->write((uint8_t) argumentCount);
900}
901
902void ByteCodeGenerator::writeExternalValue(const ExternalValueReference& e,
903 ByteCode::Register result) {
904 this->write(ByteCode::Instruction::kReadExternal);
905 this->write(result);
906 this->write((uint8_t) SlotCount(e.fValue->type()));
907 int index = fOutput->fExternalValues.size();
908 fOutput->fExternalValues.push_back(e.fValue);
909 SkASSERT(index <= 255);
910 this->write((uint8_t) index);
911}
912
913void ByteCodeGenerator::writeIntrinsicCall(const FunctionCall& c, Intrinsic intrinsic,
914 ByteCode::Register result) {
915 if (intrinsic.fIsSpecial) {
916 switch (intrinsic.fValue.fSpecial) {
917 case SpecialIntrinsic::kDot: {
918 SkASSERT(c.fArguments.size() == 2);
919 int count = SlotCount(c.fArguments[0]->fType);
920 ByteCode::Register left = this->next(count);
921 this->writeExpression(*c.fArguments[0], left);
922 ByteCode::Register right = this->next(count);
923 this->writeExpression(*c.fArguments[1], right);
924 ByteCode::Register product = this->next(count);
Ethan Nicholas2329da02020-01-24 15:49:33 -0500925 this->writeTypedInstruction(c.fType,
926 ByteCode::Instruction::kMultiplyIN,
927 ByteCode::Instruction::kMultiplyIN,
928 ByteCode::Instruction::kMultiplyFN);
929 this->write((uint8_t) count);
930 this->write(product);
931 this->write(left);
932 this->write(right);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500933 ByteCode::Register total = product;
934 for (int i = 1; i < count; ++i) {
935 this->writeTypedInstruction(c.fType,
936 ByteCode::Instruction::kAddI,
937 ByteCode::Instruction::kAddI,
938 ByteCode::Instruction::kAddF);
939 ByteCode::Register sum = i == count - 1 ? result : this->next(1);
940 this->write(sum);
941 this->write(total);
942 this->write(product + i);
943 total = sum;
944 }
945 break;
946 }
947 case SpecialIntrinsic::kInverse: {
948 SkASSERT(c.fArguments.size() == 1);
949 int count = SlotCount(c.fArguments[0]->fType);
950 ByteCode::Register arg = this->next(count);
951 this->writeExpression(*c.fArguments[0], arg);
952 switch (SlotCount(c.fArguments[0]->fType)) {
953 case 4: this->write(ByteCode::Instruction::kInverse2x2); break;
954 case 9: this->write(ByteCode::Instruction::kInverse3x3); break;
955 case 16: this->write(ByteCode::Instruction::kInverse4x4); break;
956 default: SkASSERT(false);
957 }
958 this->write(result);
959 this->write(arg);
960 break;
961 }
Brian Osmandc2a9772020-02-21 17:00:43 -0500962 case SpecialIntrinsic::kPrint: {
963 SkASSERT(c.fArguments.size() == 1);
964 SkASSERT(SlotCount(c.fArguments[0]->fType) == 1);
965 ByteCode::Register arg = this->next(1);
966 this->writeExpression(*c.fArguments[0], arg);
967 this->write(ByteCode::Instruction::kPrint);
968 this->write(arg);
969 break;
970 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500971 }
972 } else {
Brian Osmandc2a9772020-02-21 17:00:43 -0500973 int count = SlotCount(c.fType);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500974 std::vector<ByteCode::Register> argRegs;
975 for (const auto& expr : c.fArguments) {
Brian Osmandc2a9772020-02-21 17:00:43 -0500976 SkASSERT(SlotCount(expr->fType) == count);
977 ByteCode::Register reg = this->next(count);
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500978 this->writeExpression(*expr, reg);
979 argRegs.push_back(reg);
980 }
Brian Osmandc2a9772020-02-21 17:00:43 -0500981 for (int i = 0; i < count; ++i) {
982 this->write(intrinsic.fValue.fInstruction);
983 if (c.fType.fName != "void") {
984 this->write(result + i);
985 }
986 for (ByteCode::Register arg : argRegs) {
987 this->write(arg + i);
988 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -0500989 }
990 }
991}
992
993void ByteCodeGenerator::writeFunctionCall(const FunctionCall& c, ByteCode::Register result) {
994 auto found = fIntrinsics.find(c.fFunction.fName);
995 if (found != fIntrinsics.end()) {
996 return this->writeIntrinsicCall(c, found->second, result);
997 }
998 int argCount = c.fArguments.size();
999 std::vector<std::unique_ptr<LValue>> lvalues;
1000 int parameterSlotCount = 0;
1001 for (const auto& p : c.fFunction.fParameters) {
1002 parameterSlotCount += SlotCount(p->fType);
1003 }
1004 ByteCode::Register argStart = this->next(parameterSlotCount);
1005 ByteCode::Register nextArg = argStart;
1006 for (int i = 0; i < argCount; ++i) {
1007 const auto& param = c.fFunction.fParameters[i];
1008 const auto& arg = c.fArguments[i];
1009 if (param->fModifiers.fFlags & Modifiers::kOut_Flag) {
1010 lvalues.emplace_back(this->getLValue(*arg));
1011 lvalues.back()->load(nextArg);
1012 } else {
1013 this->writeExpression(*arg, nextArg);
1014 }
1015 nextArg.fIndex += SlotCount(arg->fType);
1016 }
1017 // Find the index of the function we're calling. We explicitly do not allow calls to functions
1018 // before they're defined. This is an easy-to-understand rule that prevents recursion.
1019 size_t idx;
1020 for (idx = 0; idx < fFunctions.size(); ++idx) {
1021 if (c.fFunction.matches(fFunctions[idx]->fDeclaration)) {
1022 break;
1023 }
1024 }
1025 if (idx > 255) {
1026 fErrors.error(c.fOffset, "Function count limit exceeded");
1027 return;
1028 } else if (idx >= fOutput->fFunctions.size()) {
1029 fErrors.error(c.fOffset, "Call to undefined function");
1030 return;
1031 }
1032
1033 this->write(ByteCode::Instruction::kCall);
1034 this->write(result);
1035 this->write((uint8_t) idx);
1036 this->write(argStart);
1037 nextArg = argStart;
1038 auto lvalue = lvalues.begin();
1039 for (int i = 0; i < argCount; ++i) {
1040 const auto& param = c.fFunction.fParameters[i];
1041 if (param->fModifiers.fFlags & Modifiers::kOut_Flag) {
1042 (*(lvalue++))->store(nextArg);
1043 }
1044 nextArg.fIndex += SlotCount(param->fType);
1045 }
1046}
1047
1048void ByteCodeGenerator::incOrDec(Token::Kind op, Expression& operand, bool prefix,
1049 ByteCode::Register result) {
1050 SkASSERT(op == Token::Kind::PLUSPLUS || op == Token::Kind::MINUSMINUS);
1051 std::unique_ptr<LValue> lvalue = this->getLValue(operand);
1052 SkASSERT(SlotCount(operand.fType) == 1);
1053 ByteCode::Register value;
1054 if (prefix) {
1055 value = this->next(1);
1056 } else {
1057 value = result;
1058 }
1059 lvalue->load(value);
1060 ByteCode::Register one = this->next(1);
1061 this->write(ByteCode::Instruction::kImmediate);
1062 this->write(one);
1063 if (type_category(operand.fType) == TypeCategory::kFloat) {
1064 this->write(ByteCode::Immediate(1.0f));
1065 } else {
1066 this->write(ByteCode::Immediate((int32_t) 1));
1067 }
1068 if (op == Token::Kind::PLUSPLUS) {
1069 this->writeTypedInstruction(operand.fType,
1070 ByteCode::Instruction::kAddI,
1071 ByteCode::Instruction::kAddI,
1072 ByteCode::Instruction::kAddF);
1073 } else {
1074 this->writeTypedInstruction(operand.fType,
1075 ByteCode::Instruction::kSubtractI,
1076 ByteCode::Instruction::kSubtractI,
1077 ByteCode::Instruction::kSubtractF);
1078 }
1079 if (prefix) {
1080 this->write(result);
1081 this->write(value);
1082 this->write(one);
1083 lvalue->store(result);
1084 } else {
1085 ByteCode::Register temp = this->next(1);
1086 this->write(temp);
1087 this->write(value);
1088 this->write(one);
1089 lvalue->store(temp);
1090 }
1091}
1092
1093void ByteCodeGenerator::writePostfixExpression(const PostfixExpression& p,
1094 ByteCode::Register result) {
1095 this->incOrDec(p.fOperator, *p.fOperand, false, result);
1096}
1097
1098void ByteCodeGenerator::writePrefixExpression(const PrefixExpression& p,
1099 ByteCode::Register result) {
1100 switch (p.fOperator) {
1101 case Token::Kind::PLUSPLUS:
1102 case Token::Kind::MINUSMINUS: {
1103 return this->incOrDec(p.fOperator, *p.fOperand, true, result);
1104 }
1105 case Token::Kind::MINUS: {
1106 ByteCode::Register src = this->next(SlotCount(p.fType));
1107 this->writeExpression(*p.fOperand, src);
1108 for (int i = 0; i < SlotCount(p.fType); ++i) {
1109 this->writeTypedInstruction(p.fType,
1110 ByteCode::Instruction::kNegateS,
1111 ByteCode::Instruction::kNegateS,
1112 ByteCode::Instruction::kNegateF);
1113 this->write(result + i);
1114 this->write(src + i);
1115 }
1116 break;
1117 }
1118 case Token::Kind::LOGICALNOT:
1119 case Token::Kind::BITWISENOT: {
1120 ByteCode::Register src = this->next(SlotCount(p.fType));
1121 this->writeExpression(*p.fOperand, src);
1122 for (int i = 0; i < SlotCount(p.fType); ++i) {
1123 this->write(ByteCode::Instruction::kNot);
1124 this->write(result + i);
1125 this->write(src + i);
1126 }
1127 break;
1128 }
1129 default:
1130 SkASSERT(false);
1131 }
1132}
1133
1134void ByteCodeGenerator::writeSwizzle(const Swizzle& s, ByteCode::Register result) {
1135 if (swizzle_is_simple(s)) {
1136 this->writeVariableExpression(s, result);
1137 return;
1138 }
1139 ByteCode::Register base = this->writeExpression(*s.fBase);
1140 for (int i = 0; i < (int) s.fComponents.size(); ++i) {
1141 this->write(ByteCode::Instruction::kCopy);
1142 this->write(result + i);
1143 this->write(base + s.fComponents[i]);
1144 }
1145}
1146
1147void ByteCodeGenerator::writeTernaryExpression(const TernaryExpression& t,
1148 ByteCode::Register result) {
1149 int count = SlotCount(t.fType);
1150 SkASSERT(count == SlotCount(t.fIfTrue->fType));
1151 SkASSERT(count == SlotCount(t.fIfFalse->fType));
1152
1153 ByteCode::Register test = this->writeExpression(*t.fTest);
1154 this->write(ByteCode::Instruction::kMaskPush);
1155 ++fConditionCount;
1156 this->write(test);
1157 ByteCode::Register ifTrue = this->writeExpression(*t.fIfTrue);
1158 this->write(ByteCode::Instruction::kMaskNegate);
1159 ByteCode::Register ifFalse = this->writeExpression(*t.fIfFalse);
1160 --fConditionCount;
1161 this->write(ByteCode::Instruction::kMaskPop);
1162 for (int i = 0; i < count; ++i) {
1163 this->write(ByteCode::Instruction::kSelect);
1164 this->write(result + i);
1165 this->write(test);
1166 this->write(ifTrue + i);
1167 this->write(ifFalse + i);
1168 }
1169}
1170
1171void ByteCodeGenerator::writeVariableExpression(const Expression& expr,
1172 ByteCode::Register result) {
1173 ByteCodeGenerator::Location location = this->getLocation(expr);
1174 int count = SlotCount(expr.fType);
Ethan Nicholas2329da02020-01-24 15:49:33 -05001175 ByteCode::Instruction load = this->getLoadInstruction(location, this->getStorage(expr));
1176 this->write(load, count);
1177 this->write(result);
1178 this->write(location);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001179}
1180
1181void ByteCodeGenerator::writeExpression(const Expression& expr, ByteCode::Register result) {
1182 switch (expr.fKind) {
1183 case Expression::kBoolLiteral_Kind: {
1184 this->write(ByteCode::Instruction::kImmediate);
1185 this->write(result);
1186 this->write(ByteCode::Immediate((int32_t) (((BoolLiteral&) expr).fValue ? -1 : 0)));
1187 break;
1188 }
1189 case Expression::kBinary_Kind: {
1190 this->writeBinaryExpression((BinaryExpression&) expr, result);
1191 break;
1192 }
1193 case Expression::kConstructor_Kind: {
1194 this->writeConstructor((Constructor&) expr, result);
1195 break;
1196 }
1197 case Expression::kExternalFunctionCall_Kind:
1198 this->writeExternalFunctionCall((ExternalFunctionCall&) expr, result);
1199 break;
1200 case Expression::kExternalValue_Kind:
1201 this->writeExternalValue((ExternalValueReference&) expr, result);
1202 break;
1203 case Expression::kFloatLiteral_Kind: {
1204 this->write(ByteCode::Instruction::kImmediate);
1205 this->write(result);
1206 this->write(ByteCode::Immediate((float) ((FloatLiteral&) expr).fValue));
1207 break;
1208 }
1209 case Expression::kFunctionCall_Kind: {
1210 this->writeFunctionCall((FunctionCall&) expr, result);
1211 break;
1212 }
1213 case Expression::kIntLiteral_Kind: {
1214 this->write(ByteCode::Instruction::kImmediate);
1215 this->write(result);
1216 this->write(ByteCode::Immediate((int32_t) ((IntLiteral&) expr).fValue));
1217 break;
1218 }
1219 case Expression::kPostfix_Kind:
1220 this->writePostfixExpression((PostfixExpression&) expr, result);
1221 break;
1222 case Expression::kPrefix_Kind:
1223 this->writePrefixExpression((PrefixExpression&) expr, result);
1224 break;
1225 case Expression::kSwizzle_Kind:
1226 this->writeSwizzle((Swizzle&) expr, result);
1227 break;
Ben Wagner470e0ac2020-01-22 16:59:21 -05001228 case Expression::kTernary_Kind:
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001229 this->writeTernaryExpression((TernaryExpression&) expr, result);
1230 break;
1231 case Expression::kFieldAccess_Kind:
1232 case Expression::kIndex_Kind:
1233 case Expression::kVariableReference_Kind:
1234 this->writeVariableExpression(expr, result);
1235 break;
Ben Wagner470e0ac2020-01-22 16:59:21 -05001236 default:
1237#ifdef SK_DEBUG
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001238 ABORT("unsupported lvalue %s\n", expr.description().c_str());
Ben Wagner470e0ac2020-01-22 16:59:21 -05001239#endif
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001240 break;
Ben Wagner470e0ac2020-01-22 16:59:21 -05001241 }
Ethan Nicholas7deb1c22020-01-22 10:31:55 -05001242}
1243
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001244ByteCode::Register ByteCodeGenerator::writeExpression(const Expression& expr) {
1245 ByteCode::Register result = this->next(SlotCount(expr.fType));
1246 this->writeExpression(expr, result);
1247 return result;
1248}
1249
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001250void ByteCodeGenerator::writeBlock(const Block& b) {
1251 for (const auto& s : b.fStatements) {
1252 this->writeStatement(*s);
1253 }
1254}
1255
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001256void ByteCodeGenerator::writeDoStatement(const DoStatement& d) {
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001257 this->write(ByteCode::Instruction::kLoopBegin);
1258 ++fConditionCount;
1259 SkASSERT(fCode->size() < ByteCode::kPointerMax);
1260 ByteCode::Pointer start{(uint16_t) fCode->size()};
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001261 this->writeStatement(*d.fStatement);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001262 ByteCode::Register test = this->writeExpression(*d.fTest);
1263 this->write(ByteCode::Instruction::kLoopNext);
1264 this->write(ByteCode::Instruction::kLoopMask);
1265 this->write(test);
1266 this->write(ByteCode::Instruction::kBranchIfAllFalse);
Brian Osman569f12f2019-06-13 11:23:57 -04001267 DeferredLocation endLocation(this);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001268 this->write(ByteCode::Instruction::kBranch);
1269 this->write(start);
Brian Osman569f12f2019-06-13 11:23:57 -04001270 endLocation.set();
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001271 --fConditionCount;
1272 this->write(ByteCode::Instruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001273}
1274
1275void ByteCodeGenerator::writeForStatement(const ForStatement& f) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001276 if (f.fInitializer) {
1277 this->writeStatement(*f.fInitializer);
1278 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001279 this->write(ByteCode::Instruction::kLoopBegin);
1280 ++fConditionCount;
1281 ByteCode::Pointer start{(uint16_t) fCode->size()};
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001282 if (f.fTest) {
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001283 ByteCode::Register test = this->writeExpression(*f.fTest);
1284 this->write(ByteCode::Instruction::kLoopMask);
1285 this->write(test);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001286 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001287 this->write(ByteCode::Instruction::kBranchIfAllFalse);
Brian Osman569f12f2019-06-13 11:23:57 -04001288 DeferredLocation endLocation(this);
1289 this->writeStatement(*f.fStatement);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001290 this->write(ByteCode::Instruction::kLoopNext);
Brian Osman569f12f2019-06-13 11:23:57 -04001291 if (f.fNext) {
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001292 this->writeExpression(*f.fNext);
Brian Osman569f12f2019-06-13 11:23:57 -04001293 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001294 this->write(ByteCode::Instruction::kBranch);
1295 this->write(start);
Brian Osman569f12f2019-06-13 11:23:57 -04001296 endLocation.set();
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001297 --fConditionCount;
1298 this->write(ByteCode::Instruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001299}
1300
1301void ByteCodeGenerator::writeIfStatement(const IfStatement& i) {
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001302 ByteCode::Register test = this->writeExpression(*i.fTest);
1303 this->write(ByteCode::Instruction::kMaskPush);
1304 ++fConditionCount;
1305 this->write(test);
1306 this->write(ByteCode::Instruction::kBranchIfAllFalse);
Brian Osman569f12f2019-06-13 11:23:57 -04001307 DeferredLocation falseLocation(this);
1308 this->writeStatement(*i.fIfTrue);
1309 falseLocation.set();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001310 if (i.fIfFalse) {
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001311 this->write(ByteCode::Instruction::kMaskNegate);
1312 this->write(ByteCode::Instruction::kBranchIfAllFalse);
Brian Osman569f12f2019-06-13 11:23:57 -04001313 DeferredLocation endLocation(this);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001314 this->writeStatement(*i.fIfFalse);
Mike Kleinb45ee832019-05-17 11:11:11 -05001315 endLocation.set();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001316 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001317 --fConditionCount;
1318 this->write(ByteCode::Instruction::kMaskPop);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001319}
1320
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001321void ByteCodeGenerator::writeReturn(const ReturnStatement& r) {
1322 if (fConditionCount) {
Brian Osman4a47da72019-07-12 11:30:32 -04001323 fErrors.error(r.fOffset, "return not allowed inside conditional or loop");
1324 return;
1325 }
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001326 if (r.fExpression) {
1327 ByteCode::Register value = this->writeExpression(*r.fExpression);
1328 this->write(ByteCode::Instruction::kReturnValue);
1329 this->write(value);
1330 }
1331 else {
1332 this->write(ByteCode::Instruction::kReturn);
1333 }
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001334}
1335
1336void ByteCodeGenerator::writeVarDeclarations(const VarDeclarations& v) {
1337 for (const auto& declStatement : v.fVars) {
1338 const VarDeclaration& decl = (VarDeclaration&) *declStatement;
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001339 // we need to grab the location even if we don't use it, to ensure it
1340 // has been allocated
1341 ByteCodeGenerator::Location location = this->getLocation(*decl.fVar);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001342 if (decl.fValue) {
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001343 ByteCode::Register src = this->writeExpression(*decl.fValue);
Ethan Nicholas2329da02020-01-24 15:49:33 -05001344 uint8_t count = (uint8_t) SlotCount(decl.fVar->fType);
1345 this->write(ByteCode::Instruction::kStoreStackDirect, count);
1346 this->write(location);
1347 this->write(src);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001348 }
1349 }
1350}
1351
1352void ByteCodeGenerator::writeWhileStatement(const WhileStatement& w) {
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001353 this->write(ByteCode::Instruction::kLoopBegin);
1354 ++fConditionCount;
1355 SkASSERT(fCode->size() < ByteCode::kPointerMax);
1356 ByteCode::Pointer start{(uint16_t) fCode->size()};
1357 ByteCode::Register test = this->writeExpression(*w.fTest);
1358 this->write(ByteCode::Instruction::kLoopMask);
1359 this->write(test);
1360 this->write(ByteCode::Instruction::kBranchIfAllFalse);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001361 DeferredLocation endLocation(this);
1362 this->writeStatement(*w.fStatement);
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001363 this->write(ByteCode::Instruction::kLoopNext);
1364 this->write(ByteCode::Instruction::kBranch);
1365 this->write(start);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001366 endLocation.set();
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001367 --fConditionCount;
1368 this->write(ByteCode::Instruction::kLoopEnd);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001369}
1370
1371void ByteCodeGenerator::writeStatement(const Statement& s) {
1372 switch (s.fKind) {
1373 case Statement::kBlock_Kind:
1374 this->writeBlock((Block&) s);
1375 break;
1376 case Statement::kBreak_Kind:
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001377 this->write(ByteCode::Instruction::kBreak);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001378 break;
1379 case Statement::kContinue_Kind:
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001380 this->write(ByteCode::Instruction::kContinue);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001381 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001382 case Statement::kDo_Kind:
1383 this->writeDoStatement((DoStatement&) s);
1384 break;
Brian Osman3e29f1d2019-05-28 09:35:05 -04001385 case Statement::kExpression_Kind:
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001386 this->writeExpression(*((ExpressionStatement&) s).fExpression);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001387 break;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001388 case Statement::kFor_Kind:
1389 this->writeForStatement((ForStatement&) s);
1390 break;
1391 case Statement::kIf_Kind:
1392 this->writeIfStatement((IfStatement&) s);
1393 break;
1394 case Statement::kNop_Kind:
1395 break;
1396 case Statement::kReturn_Kind:
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001397 this->writeReturn((ReturnStatement&) s);
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001398 break;
1399 case Statement::kVarDeclarations_Kind:
1400 this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration);
1401 break;
1402 case Statement::kWhile_Kind:
1403 this->writeWhileStatement((WhileStatement&) s);
1404 break;
1405 default:
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001406 ABORT("unsupported statement\n");
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001407 }
1408}
1409
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001410void ByteCodeGenerator::writeFunction(const FunctionDefinition& f) {
1411 fFunction = &f;
1412 std::unique_ptr<ByteCodeFunction> result(new ByteCodeFunction(&f.fDeclaration));
1413 result->fReturnSlotCount = SlotCount(f.fDeclaration.fReturnType);
Brian Osman80164412019-06-07 13:00:23 -04001414 fParameterCount = 0;
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001415 fConditionCount = 0;
1416 for (const auto& p : f.fDeclaration.fParameters) {
1417 int count = SlotCount(p->fType);
1418 bool isOut = ((p->fModifiers.fFlags & Modifiers::kOut_Flag) != 0);
1419 result->fParameters.push_back(ByteCodeFunction::Parameter{count, isOut});
1420 fParameterCount += count;
1421 }
1422 result->fParameterSlotCount = fParameterCount;
1423 fCode = &result->fCode;
1424 this->writeStatement(*f.fBody);
1425 result->fStackSlotCount = fLocals.size();
1426 if (f.fDeclaration.fReturnType.fName == "void") {
1427 this->write(ByteCode::Instruction::kReturn);
1428 } else {
1429 this->write(ByteCode::Instruction::kAbort);
1430 }
1431 fOutput->fFunctions.push_back(std::move(result));
1432 SkASSERT(fConditionCount == 0);
1433}
1434
1435void ByteCodeGenerator::gatherUniforms(const Type& type, const String& name) {
1436 if (type.kind() == Type::kOther_Kind) {
1437 return;
1438 } else if (type.kind() == Type::kStruct_Kind) {
1439 for (const auto& f : type.fields()) {
1440 this->gatherUniforms(*f.fType, name + "." + f.fName);
1441 }
1442 } else if (type.kind() == Type::kArray_Kind) {
1443 for (int i = 0; i < type.columns(); ++i) {
1444 this->gatherUniforms(type.componentType(), String::printf("%s[%d]", name.c_str(), i));
1445 }
1446 } else {
1447 fOutput->fUniforms.push_back({ name, type_category(type), type.rows(), type.columns(),
1448 fOutput->fUniformSlotCount });
1449 fOutput->fUniformSlotCount += type.columns() * type.rows();
Brian Osman80164412019-06-07 13:00:23 -04001450 }
1451}
1452
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001453bool ByteCodeGenerator::generateCode() {
1454 fOutput->fGlobalSlotCount = 0;
1455 fOutput->fUniformSlotCount = 0;
1456 for (const auto& pe : fProgram) {
1457 if (pe.fKind == ProgramElement::kVar_Kind) {
1458 VarDeclarations& decl = (VarDeclarations&) pe;
1459 for (const auto& v : decl.fVars) {
1460 const Variable* declVar = ((VarDeclaration&) *v).fVar;
1461 if (declVar->fModifiers.fLayout.fBuiltin >= 0 || is_in(*declVar)) {
1462 continue;
1463 }
1464 if (is_uniform(*declVar)) {
1465 this->gatherUniforms(declVar->fType, declVar->fName);
1466 } else {
1467 fOutput->fGlobalSlotCount += SlotCount(declVar->fType);
1468 }
1469 }
1470 }
1471 }
1472 for (const auto& pe : fProgram) {
1473 if (pe.fKind == ProgramElement::kFunction_Kind) {
1474 FunctionDefinition& f = (FunctionDefinition&) pe;
1475 fFunctions.push_back(&f);
1476 this->writeFunction(f);
1477 }
1478 }
1479 return fErrors.errorCount() == 0;
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001480}
Ethan Nicholasb962eff2020-01-23 16:49:41 -05001481
1482} // namespace