• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2018 Google Inc.
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 
8 #include "src/sksl/codegen/SkSLPipelineStageCodeGenerator.h"
9 
10 #include "include/private/SkSLProgramElement.h"
11 #include "include/private/SkSLStatement.h"
12 #include "src/sksl/SkSLCompiler.h"
13 #include "src/sksl/SkSLOperators.h"
14 #include "src/sksl/SkSLStringStream.h"
15 #include "src/sksl/ir/SkSLBinaryExpression.h"
16 #include "src/sksl/ir/SkSLChildCall.h"
17 #include "src/sksl/ir/SkSLConstructor.h"
18 #include "src/sksl/ir/SkSLConstructorArrayCast.h"
19 #include "src/sksl/ir/SkSLDoStatement.h"
20 #include "src/sksl/ir/SkSLExpressionStatement.h"
21 #include "src/sksl/ir/SkSLFieldAccess.h"
22 #include "src/sksl/ir/SkSLForStatement.h"
23 #include "src/sksl/ir/SkSLFunctionCall.h"
24 #include "src/sksl/ir/SkSLFunctionDeclaration.h"
25 #include "src/sksl/ir/SkSLFunctionDefinition.h"
26 #include "src/sksl/ir/SkSLFunctionPrototype.h"
27 #include "src/sksl/ir/SkSLIfStatement.h"
28 #include "src/sksl/ir/SkSLIndexExpression.h"
29 #include "src/sksl/ir/SkSLPostfixExpression.h"
30 #include "src/sksl/ir/SkSLPrefixExpression.h"
31 #include "src/sksl/ir/SkSLReturnStatement.h"
32 #include "src/sksl/ir/SkSLStructDefinition.h"
33 #include "src/sksl/ir/SkSLSwitchStatement.h"
34 #include "src/sksl/ir/SkSLSwizzle.h"
35 #include "src/sksl/ir/SkSLTernaryExpression.h"
36 #include "src/sksl/ir/SkSLVarDeclarations.h"
37 #include "src/sksl/ir/SkSLVariableReference.h"
38 
39 #include <unordered_map>
40 
41 #if defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
42 
43 namespace SkSL {
44 namespace PipelineStage {
45 
46 class PipelineStageCodeGenerator {
47 public:
PipelineStageCodeGenerator(const Program & program,const char * sampleCoords,const char * inputColor,const char * destColor,Callbacks * callbacks)48     PipelineStageCodeGenerator(const Program& program,
49                                const char* sampleCoords,
50                                const char* inputColor,
51                                const char* destColor,
52                                Callbacks* callbacks)
53             : fProgram(program)
54             , fSampleCoords(sampleCoords)
55             , fInputColor(inputColor)
56             , fDestColor(destColor)
57             , fCallbacks(callbacks) {}
58 
59     void generateCode();
60 
61 private:
62     using Precedence = Operator::Precedence;
63 
64     void write(skstd::string_view s);
65     void writeLine(skstd::string_view s = skstd::string_view());
66 
67     String typeName(const Type& type);
68     void writeType(const Type& type);
69 
70     String functionName(const FunctionDeclaration& decl);
71     void writeFunction(const FunctionDefinition& f);
72     void writeFunctionDeclaration(const FunctionDeclaration& decl);
73 
74     String modifierString(const Modifiers& modifiers);
75     String functionDeclaration(const FunctionDeclaration& decl);
76 
77     // Handles arrays correctly, eg: `float x[2]`
78     String typedVariable(const Type& type, skstd::string_view name);
79 
80     void writeVarDeclaration(const VarDeclaration& var);
81     void writeGlobalVarDeclaration(const GlobalVarDeclaration& g);
82     void writeStructDefinition(const StructDefinition& s);
83 
84     void writeExpression(const Expression& expr, Precedence parentPrecedence);
85     void writeChildCall(const ChildCall& c);
86     void writeFunctionCall(const FunctionCall& c);
87     void writeAnyConstructor(const AnyConstructor& c, Precedence parentPrecedence);
88     void writeFieldAccess(const FieldAccess& f);
89     void writeSwizzle(const Swizzle& swizzle);
90     void writeBinaryExpression(const BinaryExpression& b, Precedence parentPrecedence);
91     void writeTernaryExpression(const TernaryExpression& t, Precedence parentPrecedence);
92     void writeIndexExpression(const IndexExpression& expr);
93     void writePrefixExpression(const PrefixExpression& p, Precedence parentPrecedence);
94     void writePostfixExpression(const PostfixExpression& p, Precedence parentPrecedence);
95     void writeVariableReference(const VariableReference& ref);
96 
97     void writeStatement(const Statement& s);
98     void writeBlock(const Block& b);
99     void writeIfStatement(const IfStatement& stmt);
100     void writeDoStatement(const DoStatement& d);
101     void writeForStatement(const ForStatement& f);
102     void writeReturnStatement(const ReturnStatement& r);
103     void writeSwitchStatement(const SwitchStatement& s);
104 
105     void writeProgramElementFirstPass(const ProgramElement& e);
106     void writeProgramElementSecondPass(const ProgramElement& e);
107 
108     struct AutoOutputBuffer {
AutoOutputBufferSkSL::PipelineStage::PipelineStageCodeGenerator::AutoOutputBuffer109         AutoOutputBuffer(PipelineStageCodeGenerator* generator) : fGenerator(generator) {
110             fOldBuffer = fGenerator->fBuffer;
111             fGenerator->fBuffer = &fBuffer;
112         }
113 
~AutoOutputBufferSkSL::PipelineStage::PipelineStageCodeGenerator::AutoOutputBuffer114         ~AutoOutputBuffer() {
115             fGenerator->fBuffer = fOldBuffer;
116         }
117 
118         PipelineStageCodeGenerator* fGenerator;
119         StringStream*               fOldBuffer;
120         StringStream                fBuffer;
121     };
122 
123     const Program& fProgram;
124     const char*    fSampleCoords;
125     const char*    fInputColor;
126     const char*    fDestColor;
127     Callbacks*     fCallbacks;
128 
129     std::unordered_map<const Variable*, String>            fVariableNames;
130     std::unordered_map<const FunctionDeclaration*, String> fFunctionNames;
131     std::unordered_map<const Type*, String>                fStructNames;
132 
133     StringStream* fBuffer = nullptr;
134     bool          fCastReturnsToHalf = false;
135 };
136 
137 
write(skstd::string_view s)138 void PipelineStageCodeGenerator::write(skstd::string_view s) {
139     fBuffer->write(s.data(), s.length());
140 }
141 
writeLine(skstd::string_view s)142 void PipelineStageCodeGenerator::writeLine(skstd::string_view s) {
143     fBuffer->write(s.data(), s.length());
144     fBuffer->writeText("\n");
145 }
146 
writeChildCall(const ChildCall & c)147 void PipelineStageCodeGenerator::writeChildCall(const ChildCall& c) {
148     const ExpressionArray& arguments = c.arguments();
149     SkASSERT(arguments.size() >= 1);
150     int index = 0;
151     bool found = false;
152     for (const ProgramElement* p : fProgram.elements()) {
153         if (p->is<GlobalVarDeclaration>()) {
154             const GlobalVarDeclaration& global = p->as<GlobalVarDeclaration>();
155             const VarDeclaration& decl = global.declaration()->as<VarDeclaration>();
156             if (&decl.var() == &c.child()) {
157                 found = true;
158             } else if (decl.var().type().isEffectChild()) {
159                 ++index;
160             }
161         }
162         if (found) {
163             break;
164         }
165     }
166     SkASSERT(found);
167 
168     // Shaders require a coordinate argument. Color filters require a color argument.
169     // Blenders require two color arguments.
170     String sampleOutput;
171     {
172         AutoOutputBuffer exprBuffer(this);
173         this->writeExpression(*arguments[0], Precedence::kSequence);
174 
175         switch (c.child().type().typeKind()) {
176             case Type::TypeKind::kShader: {
177                 SkASSERT(arguments.size() == 1);
178                 SkASSERT(arguments[0]->type() == *fProgram.fContext->fTypes.fFloat2);
179                 sampleOutput = fCallbacks->sampleShader(index, exprBuffer.fBuffer.str());
180                 break;
181             }
182             case Type::TypeKind::kColorFilter: {
183                 SkASSERT(arguments.size() == 1);
184                 SkASSERT(arguments[0]->type() == *fProgram.fContext->fTypes.fHalf4 ||
185                          arguments[0]->type() == *fProgram.fContext->fTypes.fFloat4);
186                 sampleOutput = fCallbacks->sampleColorFilter(index, exprBuffer.fBuffer.str());
187                 break;
188             }
189             case Type::TypeKind::kBlender: {
190                 SkASSERT(arguments.size() == 2);
191                 SkASSERT(arguments[0]->type() == *fProgram.fContext->fTypes.fHalf4 ||
192                          arguments[0]->type() == *fProgram.fContext->fTypes.fFloat4);
193                 SkASSERT(arguments[1]->type() == *fProgram.fContext->fTypes.fHalf4 ||
194                          arguments[1]->type() == *fProgram.fContext->fTypes.fFloat4);
195 
196                 AutoOutputBuffer exprBuffer2(this);
197                 this->writeExpression(*arguments[1], Precedence::kSequence);
198 
199                 sampleOutput = fCallbacks->sampleBlender(index, exprBuffer.fBuffer.str(),
200                                                                 exprBuffer2.fBuffer.str());
201                 break;
202             }
203             default: {
204                 SkDEBUGFAILF("cannot sample from type '%s'",
205                              c.child().type().description().c_str());
206             }
207         }
208     }
209     this->write(sampleOutput);
210     return;
211 }
212 
writeFunctionCall(const FunctionCall & c)213 void PipelineStageCodeGenerator::writeFunctionCall(const FunctionCall& c) {
214     const FunctionDeclaration& function = c.function();
215 
216     if (function.isBuiltin()) {
217         this->write(function.name());
218     } else {
219         this->write(this->functionName(function));
220     }
221 
222     this->write("(");
223     const char* separator = "";
224     for (const auto& arg : c.arguments()) {
225         this->write(separator);
226         separator = ", ";
227         this->writeExpression(*arg, Precedence::kSequence);
228     }
229     this->write(")");
230 }
231 
writeVariableReference(const VariableReference & ref)232 void PipelineStageCodeGenerator::writeVariableReference(const VariableReference& ref) {
233     const Variable* var = ref.variable();
234     const Modifiers& modifiers = var->modifiers();
235 
236     if (modifiers.fLayout.fBuiltin == SK_MAIN_COORDS_BUILTIN) {
237         this->write(fSampleCoords);
238         return;
239     } else if (modifiers.fLayout.fBuiltin == SK_INPUT_COLOR_BUILTIN) {
240         this->write(fInputColor);
241         return;
242     } else if (modifiers.fLayout.fBuiltin == SK_DEST_COLOR_BUILTIN) {
243         this->write(fDestColor);
244         return;
245     }
246 
247     auto it = fVariableNames.find(var);
248     if (it != fVariableNames.end()) {
249         this->write(it->second);
250     } else {
251         this->write(var->name());
252     }
253 }
254 
writeIfStatement(const IfStatement & stmt)255 void PipelineStageCodeGenerator::writeIfStatement(const IfStatement& stmt) {
256     if (stmt.isStatic()) {
257         this->write("@");
258     }
259     this->write("if (");
260     this->writeExpression(*stmt.test(), Precedence::kTopLevel);
261     this->write(") ");
262     this->writeStatement(*stmt.ifTrue());
263     if (stmt.ifFalse()) {
264         this->write(" else ");
265         this->writeStatement(*stmt.ifFalse());
266     }
267 }
268 
writeReturnStatement(const ReturnStatement & r)269 void PipelineStageCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
270     this->write("return");
271     if (r.expression()) {
272         this->write(" ");
273         if (fCastReturnsToHalf) {
274             this->write("half4(");
275         }
276         this->writeExpression(*r.expression(), Precedence::kTopLevel);
277         if (fCastReturnsToHalf) {
278             this->write(")");
279         }
280     }
281     this->write(";");
282 }
283 
writeSwitchStatement(const SwitchStatement & s)284 void PipelineStageCodeGenerator::writeSwitchStatement(const SwitchStatement& s) {
285     this->write("switch (");
286     this->writeExpression(*s.value(), Precedence::kTopLevel);
287     this->writeLine(") {");
288     for (const std::unique_ptr<Statement>& stmt : s.cases()) {
289         const SwitchCase& c = stmt->as<SwitchCase>();
290         if (c.value()) {
291             this->write("case ");
292             this->writeExpression(*c.value(), Precedence::kTopLevel);
293             this->writeLine(":");
294         } else {
295             this->writeLine("default:");
296         }
297         if (!c.statement()->isEmpty()) {
298             this->writeStatement(*c.statement());
299             this->writeLine();
300         }
301     }
302     this->writeLine();
303     this->write("}");
304 }
305 
functionName(const FunctionDeclaration & decl)306 String PipelineStageCodeGenerator::functionName(const FunctionDeclaration& decl) {
307     if (decl.isMain()) {
308         return String(decl.name());
309     }
310 
311     auto it = fFunctionNames.find(&decl);
312     if (it != fFunctionNames.end()) {
313         return it->second;
314     }
315 
316     String mangledName = fCallbacks->getMangledName(String(decl.name()).c_str());
317     fFunctionNames.insert({&decl, mangledName});
318     return mangledName;
319 }
320 
writeFunction(const FunctionDefinition & f)321 void PipelineStageCodeGenerator::writeFunction(const FunctionDefinition& f) {
322     AutoOutputBuffer body(this);
323 
324     // We allow public SkSL's main() to return half4 -or- float4 (ie vec4). When we emit
325     // our code in the processor, the surrounding code is going to expect half4, so we
326     // explicitly cast any returns (from main) to half4. This is only strictly necessary
327     // if the return type is float4 - injecting it unconditionally reduces the risk of an
328     // obscure bug.
329     const FunctionDeclaration& decl = f.declaration();
330     if (decl.isMain()) {
331         fCastReturnsToHalf = true;
332     }
333 
334     for (const std::unique_ptr<Statement>& stmt : f.body()->as<Block>().children()) {
335         this->writeStatement(*stmt);
336         this->writeLine();
337     }
338 
339     if (decl.isMain()) {
340         fCastReturnsToHalf = false;
341     }
342 
343     fCallbacks->defineFunction(this->functionDeclaration(decl).c_str(),
344                                body.fBuffer.str().c_str(),
345                                decl.isMain());
346 }
347 
functionDeclaration(const FunctionDeclaration & decl)348 String PipelineStageCodeGenerator::functionDeclaration(const FunctionDeclaration& decl) {
349     // This is similar to decl.description(), but substitutes a mangled name, and handles modifiers
350     // on the function (e.g. `inline`) and its parameters (e.g. `inout`).
351     String declString =
352             String::printf("%s%s%s %s(",
353                            (decl.modifiers().fFlags & Modifiers::kInline_Flag) ? "inline " : "",
354                            (decl.modifiers().fFlags & Modifiers::kNoInline_Flag) ? "noinline " : "",
355                            this->typeName(decl.returnType()).c_str(),
356                            this->functionName(decl).c_str());
357     const char* separator = "";
358     for (const Variable* p : decl.parameters()) {
359         declString.append(separator);
360         declString.append(this->modifierString(p->modifiers()));
361         declString.append(this->typedVariable(p->type(), p->name()).c_str());
362         separator = ", ";
363     }
364 
365     return declString + ")";
366 }
367 
writeFunctionDeclaration(const FunctionDeclaration & decl)368 void PipelineStageCodeGenerator::writeFunctionDeclaration(const FunctionDeclaration& decl) {
369     if (!decl.isMain()) {
370         fCallbacks->declareFunction(this->functionDeclaration(decl).c_str());
371     }
372 }
373 
writeGlobalVarDeclaration(const GlobalVarDeclaration & g)374 void PipelineStageCodeGenerator::writeGlobalVarDeclaration(const GlobalVarDeclaration& g) {
375     const VarDeclaration& decl = g.declaration()->as<VarDeclaration>();
376     const Variable& var = decl.var();
377 
378     if (var.isBuiltin() || var.type().isOpaque()) {
379         // Don't re-declare these. (eg, sk_FragCoord, or fragmentProcessor children)
380     } else if (var.modifiers().fFlags & Modifiers::kUniform_Flag) {
381         String uniformName = fCallbacks->declareUniform(&decl);
382         fVariableNames.insert({&var, std::move(uniformName)});
383     } else {
384         String mangledName = fCallbacks->getMangledName(String(var.name()).c_str());
385         String declaration = this->modifierString(var.modifiers()) +
386                              this->typedVariable(var.type(),
387                                                  skstd::string_view(mangledName.c_str()));
388         if (decl.value()) {
389             AutoOutputBuffer outputToBuffer(this);
390             this->writeExpression(*decl.value(), Precedence::kTopLevel);
391             declaration += " = ";
392             declaration += outputToBuffer.fBuffer.str();
393         }
394         declaration += ";\n";
395         fCallbacks->declareGlobal(declaration.c_str());
396         fVariableNames.insert({&var, std::move(mangledName)});
397     }
398 }
399 
writeStructDefinition(const StructDefinition & s)400 void PipelineStageCodeGenerator::writeStructDefinition(const StructDefinition& s) {
401     const Type& type = s.type();
402     String mangledName = fCallbacks->getMangledName(String(type.name()).c_str());
403     String definition = "struct " + mangledName + " {\n";
404     for (const auto& f : type.fields()) {
405         definition += this->typedVariable(*f.fType, f.fName) + ";\n";
406     }
407     definition += "};\n";
408     fStructNames.insert({&type, std::move(mangledName)});
409     fCallbacks->defineStruct(definition.c_str());
410 }
411 
writeProgramElementFirstPass(const ProgramElement & e)412 void PipelineStageCodeGenerator::writeProgramElementFirstPass(const ProgramElement& e) {
413     switch (e.kind()) {
414         case ProgramElement::Kind::kGlobalVar:
415             this->writeGlobalVarDeclaration(e.as<GlobalVarDeclaration>());
416             break;
417         case ProgramElement::Kind::kFunction:
418             this->writeFunctionDeclaration(e.as<FunctionDefinition>().declaration());
419             break;
420         case ProgramElement::Kind::kFunctionPrototype:
421             // Skip this; we're already emitting prototypes for every FunctionDefinition.
422             // (See case kFunction, directly above.)
423             break;
424         case ProgramElement::Kind::kStructDefinition:
425             this->writeStructDefinition(e.as<StructDefinition>());
426             break;
427 
428         case ProgramElement::Kind::kExtension:
429         case ProgramElement::Kind::kInterfaceBlock:
430         case ProgramElement::Kind::kModifiers:
431         default:
432             SkDEBUGFAILF("unsupported program element %s\n", e.description().c_str());
433             break;
434     }
435 }
436 
writeProgramElementSecondPass(const ProgramElement & e)437 void PipelineStageCodeGenerator::writeProgramElementSecondPass(const ProgramElement& e) {
438     if (e.is<FunctionDefinition>()) {
439         this->writeFunction(e.as<FunctionDefinition>());
440     }
441 }
442 
typeName(const Type & type)443 String PipelineStageCodeGenerator::typeName(const Type& type) {
444     if (type.isArray()) {
445         // This is necessary so that name mangling on arrays-of-structs works properly.
446         String arrayName = this->typeName(type.componentType());
447         arrayName.push_back('[');
448         arrayName += to_string(type.columns());
449         arrayName.push_back(']');
450         return arrayName;
451     }
452 
453     auto it = fStructNames.find(&type);
454     return it != fStructNames.end() ? it->second : String(type.name());
455 }
456 
writeType(const Type & type)457 void PipelineStageCodeGenerator::writeType(const Type& type) {
458     this->write(this->typeName(type));
459 }
460 
writeExpression(const Expression & expr,Precedence parentPrecedence)461 void PipelineStageCodeGenerator::writeExpression(const Expression& expr,
462                                                  Precedence parentPrecedence) {
463     switch (expr.kind()) {
464         case Expression::Kind::kBinary:
465             this->writeBinaryExpression(expr.as<BinaryExpression>(), parentPrecedence);
466             break;
467         case Expression::Kind::kLiteral:
468             this->write(expr.description());
469             break;
470         case Expression::Kind::kChildCall:
471             this->writeChildCall(expr.as<ChildCall>());
472             break;
473         case Expression::Kind::kConstructorArray:
474         case Expression::Kind::kConstructorArrayCast:
475         case Expression::Kind::kConstructorCompound:
476         case Expression::Kind::kConstructorCompoundCast:
477         case Expression::Kind::kConstructorDiagonalMatrix:
478         case Expression::Kind::kConstructorMatrixResize:
479         case Expression::Kind::kConstructorScalarCast:
480         case Expression::Kind::kConstructorSplat:
481         case Expression::Kind::kConstructorStruct:
482             this->writeAnyConstructor(expr.asAnyConstructor(), parentPrecedence);
483             break;
484         case Expression::Kind::kFieldAccess:
485             this->writeFieldAccess(expr.as<FieldAccess>());
486             break;
487         case Expression::Kind::kFunctionCall:
488             this->writeFunctionCall(expr.as<FunctionCall>());
489             break;
490         case Expression::Kind::kPrefix:
491             this->writePrefixExpression(expr.as<PrefixExpression>(), parentPrecedence);
492             break;
493         case Expression::Kind::kPostfix:
494             this->writePostfixExpression(expr.as<PostfixExpression>(), parentPrecedence);
495             break;
496         case Expression::Kind::kSwizzle:
497             this->writeSwizzle(expr.as<Swizzle>());
498             break;
499         case Expression::Kind::kVariableReference:
500             this->writeVariableReference(expr.as<VariableReference>());
501             break;
502         case Expression::Kind::kTernary:
503             this->writeTernaryExpression(expr.as<TernaryExpression>(), parentPrecedence);
504             break;
505         case Expression::Kind::kIndex:
506             this->writeIndexExpression(expr.as<IndexExpression>());
507             break;
508         case Expression::Kind::kSetting:
509         default:
510             SkDEBUGFAILF("unsupported expression: %s", expr.description().c_str());
511             break;
512     }
513 }
514 
writeAnyConstructor(const AnyConstructor & c,Precedence parentPrecedence)515 void PipelineStageCodeGenerator::writeAnyConstructor(const AnyConstructor& c,
516                                                      Precedence parentPrecedence) {
517     this->writeType(c.type());
518     this->write("(");
519     const char* separator = "";
520     for (const auto& arg : c.argumentSpan()) {
521         this->write(separator);
522         separator = ", ";
523         this->writeExpression(*arg, Precedence::kSequence);
524     }
525     this->write(")");
526 }
527 
writeIndexExpression(const IndexExpression & expr)528 void PipelineStageCodeGenerator::writeIndexExpression(const IndexExpression& expr) {
529     this->writeExpression(*expr.base(), Precedence::kPostfix);
530     this->write("[");
531     this->writeExpression(*expr.index(), Precedence::kTopLevel);
532     this->write("]");
533 }
534 
writeFieldAccess(const FieldAccess & f)535 void PipelineStageCodeGenerator::writeFieldAccess(const FieldAccess& f) {
536     if (f.ownerKind() == FieldAccess::OwnerKind::kDefault) {
537         this->writeExpression(*f.base(), Precedence::kPostfix);
538         this->write(".");
539     }
540     const Type& baseType = f.base()->type();
541     this->write(baseType.fields()[f.fieldIndex()].fName);
542 }
543 
writeSwizzle(const Swizzle & swizzle)544 void PipelineStageCodeGenerator::writeSwizzle(const Swizzle& swizzle) {
545     this->writeExpression(*swizzle.base(), Precedence::kPostfix);
546     this->write(".");
547     for (int c : swizzle.components()) {
548         SkASSERT(c >= 0 && c <= 3);
549         this->write(&("x\0y\0z\0w\0"[c * 2]));
550     }
551 }
552 
writeBinaryExpression(const BinaryExpression & b,Precedence parentPrecedence)553 void PipelineStageCodeGenerator::writeBinaryExpression(const BinaryExpression& b,
554                                                        Precedence parentPrecedence) {
555     const Expression& left = *b.left();
556     const Expression& right = *b.right();
557     Operator op = b.getOperator();
558 
559     Precedence precedence = op.getBinaryPrecedence();
560     if (precedence >= parentPrecedence) {
561         this->write("(");
562     }
563     this->writeExpression(left, precedence);
564     this->write(" ");
565     this->write(op.operatorName());
566     this->write(" ");
567     this->writeExpression(right, precedence);
568     if (precedence >= parentPrecedence) {
569         this->write(")");
570     }
571 }
572 
writeTernaryExpression(const TernaryExpression & t,Precedence parentPrecedence)573 void PipelineStageCodeGenerator::writeTernaryExpression(const TernaryExpression& t,
574                                                         Precedence parentPrecedence) {
575     if (Precedence::kTernary >= parentPrecedence) {
576         this->write("(");
577     }
578     this->writeExpression(*t.test(), Precedence::kTernary);
579     this->write(" ? ");
580     this->writeExpression(*t.ifTrue(), Precedence::kTernary);
581     this->write(" : ");
582     this->writeExpression(*t.ifFalse(), Precedence::kTernary);
583     if (Precedence::kTernary >= parentPrecedence) {
584         this->write(")");
585     }
586 }
587 
writePrefixExpression(const PrefixExpression & p,Precedence parentPrecedence)588 void PipelineStageCodeGenerator::writePrefixExpression(const PrefixExpression& p,
589                                                        Precedence parentPrecedence) {
590     if (Precedence::kPrefix >= parentPrecedence) {
591         this->write("(");
592     }
593     this->write(p.getOperator().operatorName());
594     this->writeExpression(*p.operand(), Precedence::kPrefix);
595     if (Precedence::kPrefix >= parentPrecedence) {
596         this->write(")");
597     }
598 }
599 
writePostfixExpression(const PostfixExpression & p,Precedence parentPrecedence)600 void PipelineStageCodeGenerator::writePostfixExpression(const PostfixExpression& p,
601                                                         Precedence parentPrecedence) {
602     if (Precedence::kPostfix >= parentPrecedence) {
603         this->write("(");
604     }
605     this->writeExpression(*p.operand(), Precedence::kPostfix);
606     this->write(p.getOperator().operatorName());
607     if (Precedence::kPostfix >= parentPrecedence) {
608         this->write(")");
609     }
610 }
611 
modifierString(const Modifiers & modifiers)612 String PipelineStageCodeGenerator::modifierString(const Modifiers& modifiers) {
613     String result;
614     if (modifiers.fFlags & Modifiers::kConst_Flag) {
615         result.append("const ");
616     }
617 
618     if ((modifiers.fFlags & Modifiers::kIn_Flag) && (modifiers.fFlags & Modifiers::kOut_Flag)) {
619         result.append("inout ");
620     } else if (modifiers.fFlags & Modifiers::kIn_Flag) {
621         result.append("in ");
622     } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
623         result.append("out ");
624     }
625 
626     return result;
627 }
628 
typedVariable(const Type & type,skstd::string_view name)629 String PipelineStageCodeGenerator::typedVariable(const Type& type, skstd::string_view name) {
630     const Type& baseType = type.isArray() ? type.componentType() : type;
631 
632     String decl = this->typeName(baseType) + " " + name;
633     if (type.isArray()) {
634         decl += "[" + to_string(type.columns()) + "]";
635     }
636     return decl;
637 }
638 
writeVarDeclaration(const VarDeclaration & var)639 void PipelineStageCodeGenerator::writeVarDeclaration(const VarDeclaration& var) {
640     this->write(this->modifierString(var.var().modifiers()));
641     this->write(this->typedVariable(var.var().type(), var.var().name()));
642     if (var.value()) {
643         this->write(" = ");
644         this->writeExpression(*var.value(), Precedence::kTopLevel);
645     }
646     this->write(";");
647 }
648 
writeStatement(const Statement & s)649 void PipelineStageCodeGenerator::writeStatement(const Statement& s) {
650     switch (s.kind()) {
651         case Statement::Kind::kBlock:
652             this->writeBlock(s.as<Block>());
653             break;
654         case Statement::Kind::kBreak:
655             this->write("break;");
656             break;
657         case Statement::Kind::kContinue:
658             this->write("continue;");
659             break;
660         case Statement::Kind::kExpression:
661             this->writeExpression(*s.as<ExpressionStatement>().expression(), Precedence::kTopLevel);
662             this->write(";");
663             break;
664         case Statement::Kind::kDo:
665             this->writeDoStatement(s.as<DoStatement>());
666             break;
667         case Statement::Kind::kFor:
668             this->writeForStatement(s.as<ForStatement>());
669             break;
670         case Statement::Kind::kIf:
671             this->writeIfStatement(s.as<IfStatement>());
672             break;
673         case Statement::Kind::kReturn:
674             this->writeReturnStatement(s.as<ReturnStatement>());
675             break;
676         case Statement::Kind::kSwitch:
677             this->writeSwitchStatement(s.as<SwitchStatement>());
678             break;
679         case Statement::Kind::kVarDeclaration:
680             this->writeVarDeclaration(s.as<VarDeclaration>());
681             break;
682         case Statement::Kind::kDiscard:
683             SkDEBUGFAIL("Unsupported control flow");
684             break;
685         case Statement::Kind::kInlineMarker:
686         case Statement::Kind::kNop:
687             this->write(";");
688             break;
689         default:
690             SkDEBUGFAILF("unsupported statement: %s", s.description().c_str());
691             break;
692     }
693 }
694 
writeBlock(const Block & b)695 void PipelineStageCodeGenerator::writeBlock(const Block& b) {
696     // Write scope markers if this block is a scope, or if the block is empty (since we need to emit
697     // something here to make the code valid).
698     bool isScope = b.isScope() || b.isEmpty();
699     if (isScope) {
700         this->writeLine("{");
701     }
702     for (const std::unique_ptr<Statement>& stmt : b.children()) {
703         if (!stmt->isEmpty()) {
704             this->writeStatement(*stmt);
705             this->writeLine();
706         }
707     }
708     if (isScope) {
709         this->write("}");
710     }
711 }
712 
writeDoStatement(const DoStatement & d)713 void PipelineStageCodeGenerator::writeDoStatement(const DoStatement& d) {
714     this->write("do ");
715     this->writeStatement(*d.statement());
716     this->write(" while (");
717     this->writeExpression(*d.test(), Precedence::kTopLevel);
718     this->write(");");
719     return;
720 }
721 
writeForStatement(const ForStatement & f)722 void PipelineStageCodeGenerator::writeForStatement(const ForStatement& f) {
723     // Emit loops of the form 'for(;test;)' as 'while(test)', which is probably how they started
724     if (!f.initializer() && f.test() && !f.next()) {
725         this->write("while (");
726         this->writeExpression(*f.test(), Precedence::kTopLevel);
727         this->write(") ");
728         this->writeStatement(*f.statement());
729         return;
730     }
731 
732     this->write("for (");
733     if (f.initializer() && !f.initializer()->isEmpty()) {
734         this->writeStatement(*f.initializer());
735     } else {
736         this->write("; ");
737     }
738     if (f.test()) {
739         this->writeExpression(*f.test(), Precedence::kTopLevel);
740     }
741     this->write("; ");
742     if (f.next()) {
743         this->writeExpression(*f.next(), Precedence::kTopLevel);
744     }
745     this->write(") ");
746     this->writeStatement(*f.statement());
747 }
748 
generateCode()749 void PipelineStageCodeGenerator::generateCode() {
750     // Write all the program elements except for functions; prototype all the functions.
751     for (const ProgramElement* e : fProgram.elements()) {
752         this->writeProgramElementFirstPass(*e);
753     }
754 
755     // We always place FunctionDefinition elements last, because the inliner likes to move function
756     // bodies around. After inlining, code can inadvertently move upwards, above ProgramElements
757     // that the code relies on.
758     for (const ProgramElement* e : fProgram.elements()) {
759         this->writeProgramElementSecondPass(*e);
760     }
761 }
762 
ConvertProgram(const Program & program,const char * sampleCoords,const char * inputColor,const char * destColor,Callbacks * callbacks)763 void ConvertProgram(const Program& program,
764                     const char* sampleCoords,
765                     const char* inputColor,
766                     const char* destColor,
767                     Callbacks* callbacks) {
768     PipelineStageCodeGenerator generator(program, sampleCoords, inputColor, destColor, callbacks);
769     generator.generateCode();
770 }
771 
772 }  // namespace PipelineStage
773 }  // namespace SkSL
774 
775 #endif
776