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