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