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