1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2016 Google Inc.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#ifndef SKSL_SPIRVCODEGENERATOR
9cb93a386Sopenharmony_ci#define SKSL_SPIRVCODEGENERATOR
10cb93a386Sopenharmony_ci
11cb93a386Sopenharmony_ci#include <stack>
12cb93a386Sopenharmony_ci#include <tuple>
13cb93a386Sopenharmony_ci#include <unordered_map>
14cb93a386Sopenharmony_ci#include <unordered_set>
15cb93a386Sopenharmony_ci
16cb93a386Sopenharmony_ci#include "src/core/SkOpts.h"
17cb93a386Sopenharmony_ci#include "src/sksl/SkSLMemoryLayout.h"
18cb93a386Sopenharmony_ci#include "src/sksl/SkSLStringStream.h"
19cb93a386Sopenharmony_ci#include "src/sksl/codegen/SkSLCodeGenerator.h"
20cb93a386Sopenharmony_ci
21cb93a386Sopenharmony_cinamespace SkSL {
22cb93a386Sopenharmony_ci
23cb93a386Sopenharmony_ciclass BinaryExpression;
24cb93a386Sopenharmony_ciclass Block;
25cb93a386Sopenharmony_ciclass ConstructorCompound;
26cb93a386Sopenharmony_ciclass ConstructorCompoundCast;
27cb93a386Sopenharmony_ciclass ConstructorDiagonalMatrix;
28cb93a386Sopenharmony_ciclass ConstructorMatrixResize;
29cb93a386Sopenharmony_ciclass ConstructorScalarCast;
30cb93a386Sopenharmony_ciclass ConstructorSplat;
31cb93a386Sopenharmony_ciclass DoStatement;
32cb93a386Sopenharmony_ciclass FieldAccess;
33cb93a386Sopenharmony_ciclass ForStatement;
34cb93a386Sopenharmony_ciclass FunctionCall;
35cb93a386Sopenharmony_ciclass FunctionDeclaration;
36cb93a386Sopenharmony_ciclass FunctionDefinition;
37cb93a386Sopenharmony_ciclass FunctionPrototype;
38cb93a386Sopenharmony_ciclass IfStatement;
39cb93a386Sopenharmony_cistruct IndexExpression;
40cb93a386Sopenharmony_ciclass InterfaceBlock;
41cb93a386Sopenharmony_cienum IntrinsicKind : int8_t;
42cb93a386Sopenharmony_ciclass Literal;
43cb93a386Sopenharmony_ciclass Operator;
44cb93a386Sopenharmony_ciclass PostfixExpression;
45cb93a386Sopenharmony_ciclass PrefixExpression;
46cb93a386Sopenharmony_ciclass ReturnStatement;
47cb93a386Sopenharmony_ciclass Setting;
48cb93a386Sopenharmony_ciclass StructDefinition;
49cb93a386Sopenharmony_ciclass SwitchStatement;
50cb93a386Sopenharmony_cistruct Swizzle;
51cb93a386Sopenharmony_ciclass TernaryExpression;
52cb93a386Sopenharmony_ciclass VarDeclaration;
53cb93a386Sopenharmony_ciclass VariableReference;
54cb93a386Sopenharmony_ci
55cb93a386Sopenharmony_cistruct SPIRVNumberConstant {
56cb93a386Sopenharmony_ci    bool operator==(const SPIRVNumberConstant& that) const {
57cb93a386Sopenharmony_ci        return fValueBits == that.fValueBits &&
58cb93a386Sopenharmony_ci               fKind      == that.fKind;
59cb93a386Sopenharmony_ci    }
60cb93a386Sopenharmony_ci    int32_t                fValueBits;
61cb93a386Sopenharmony_ci    SkSL::Type::NumberKind fKind;
62cb93a386Sopenharmony_ci};
63cb93a386Sopenharmony_ci
64cb93a386Sopenharmony_cistruct SPIRVVectorConstant {
65cb93a386Sopenharmony_ci    bool operator==(const SPIRVVectorConstant& that) const {
66cb93a386Sopenharmony_ci        return fTypeId     == that.fTypeId &&
67cb93a386Sopenharmony_ci               fValueId[0] == that.fValueId[0] &&
68cb93a386Sopenharmony_ci               fValueId[1] == that.fValueId[1] &&
69cb93a386Sopenharmony_ci               fValueId[2] == that.fValueId[2] &&
70cb93a386Sopenharmony_ci               fValueId[3] == that.fValueId[3];
71cb93a386Sopenharmony_ci    }
72cb93a386Sopenharmony_ci    SpvId fTypeId;
73cb93a386Sopenharmony_ci    SpvId fValueId[4];
74cb93a386Sopenharmony_ci};
75cb93a386Sopenharmony_ci
76cb93a386Sopenharmony_ci}  // namespace SkSL
77cb93a386Sopenharmony_ci
78cb93a386Sopenharmony_cinamespace std {
79cb93a386Sopenharmony_ci
80cb93a386Sopenharmony_citemplate <>
81cb93a386Sopenharmony_cistruct hash<SkSL::SPIRVNumberConstant> {
82cb93a386Sopenharmony_ci    size_t operator()(const SkSL::SPIRVNumberConstant& key) const {
83cb93a386Sopenharmony_ci        return key.fValueBits ^ (int)key.fKind;
84cb93a386Sopenharmony_ci    }
85cb93a386Sopenharmony_ci};
86cb93a386Sopenharmony_ci
87cb93a386Sopenharmony_citemplate <>
88cb93a386Sopenharmony_cistruct hash<SkSL::SPIRVVectorConstant> {
89cb93a386Sopenharmony_ci    size_t operator()(const SkSL::SPIRVVectorConstant& key) const {
90cb93a386Sopenharmony_ci        return SkOpts::hash(&key, sizeof(key));
91cb93a386Sopenharmony_ci    }
92cb93a386Sopenharmony_ci};
93cb93a386Sopenharmony_ci
94cb93a386Sopenharmony_ci}  // namespace std
95cb93a386Sopenharmony_ci
96cb93a386Sopenharmony_cinamespace SkSL {
97cb93a386Sopenharmony_ci
98cb93a386Sopenharmony_ci/**
99cb93a386Sopenharmony_ci * Converts a Program into a SPIR-V binary.
100cb93a386Sopenharmony_ci */
101cb93a386Sopenharmony_ciclass SPIRVCodeGenerator : public CodeGenerator {
102cb93a386Sopenharmony_cipublic:
103cb93a386Sopenharmony_ci    class LValue {
104cb93a386Sopenharmony_ci    public:
105cb93a386Sopenharmony_ci        virtual ~LValue() {}
106cb93a386Sopenharmony_ci
107cb93a386Sopenharmony_ci        // returns a pointer to the lvalue, if possible. If the lvalue cannot be directly referenced
108cb93a386Sopenharmony_ci        // by a pointer (e.g. vector swizzles), returns -1.
109cb93a386Sopenharmony_ci        virtual SpvId getPointer() { return -1; }
110cb93a386Sopenharmony_ci
111cb93a386Sopenharmony_ci        // Returns true if a valid pointer returned by getPointer represents a memory object
112cb93a386Sopenharmony_ci        // (see https://github.com/KhronosGroup/SPIRV-Tools/issues/2892). Has no meaning if
113cb93a386Sopenharmony_ci        // getPointer() returns -1.
114cb93a386Sopenharmony_ci        virtual bool isMemoryObjectPointer() const { return true; }
115cb93a386Sopenharmony_ci
116cb93a386Sopenharmony_ci        // Applies a swizzle to the components of the LValue, if possible. This is used to create
117cb93a386Sopenharmony_ci        // LValues that are swizzes-of-swizzles. Non-swizzle LValues can just return false.
118cb93a386Sopenharmony_ci        virtual bool applySwizzle(const ComponentArray& components, const Type& newType) {
119cb93a386Sopenharmony_ci            return false;
120cb93a386Sopenharmony_ci        }
121cb93a386Sopenharmony_ci
122cb93a386Sopenharmony_ci        virtual SpvId load(OutputStream& out) = 0;
123cb93a386Sopenharmony_ci
124cb93a386Sopenharmony_ci        virtual void store(SpvId value, OutputStream& out) = 0;
125cb93a386Sopenharmony_ci    };
126cb93a386Sopenharmony_ci
127cb93a386Sopenharmony_ci    SPIRVCodeGenerator(const Context* context,
128cb93a386Sopenharmony_ci                       const Program* program,
129cb93a386Sopenharmony_ci                       OutputStream* out)
130cb93a386Sopenharmony_ci            : INHERITED(context, program, out)
131cb93a386Sopenharmony_ci            , fDefaultLayout(MemoryLayout::k140_Standard)
132cb93a386Sopenharmony_ci            , fCapabilities(0)
133cb93a386Sopenharmony_ci            , fIdCount(1)
134cb93a386Sopenharmony_ci            , fSetupFragPosition(false)
135cb93a386Sopenharmony_ci            , fCurrentBlock(0)
136cb93a386Sopenharmony_ci            , fSynthetics(fContext, /*builtin=*/true) {
137cb93a386Sopenharmony_ci        this->setupIntrinsics();
138cb93a386Sopenharmony_ci    }
139cb93a386Sopenharmony_ci
140cb93a386Sopenharmony_ci    bool generateCode() override;
141cb93a386Sopenharmony_ci
142cb93a386Sopenharmony_ciprivate:
143cb93a386Sopenharmony_ci    enum IntrinsicOpcodeKind {
144cb93a386Sopenharmony_ci        kGLSL_STD_450_IntrinsicOpcodeKind,
145cb93a386Sopenharmony_ci        kSPIRV_IntrinsicOpcodeKind,
146cb93a386Sopenharmony_ci        kSpecial_IntrinsicOpcodeKind
147cb93a386Sopenharmony_ci    };
148cb93a386Sopenharmony_ci
149cb93a386Sopenharmony_ci    enum SpecialIntrinsic {
150cb93a386Sopenharmony_ci        kAtan_SpecialIntrinsic,
151cb93a386Sopenharmony_ci        kClamp_SpecialIntrinsic,
152cb93a386Sopenharmony_ci        kMatrixCompMult_SpecialIntrinsic,
153cb93a386Sopenharmony_ci        kMax_SpecialIntrinsic,
154cb93a386Sopenharmony_ci        kMin_SpecialIntrinsic,
155cb93a386Sopenharmony_ci        kMix_SpecialIntrinsic,
156cb93a386Sopenharmony_ci        kMod_SpecialIntrinsic,
157cb93a386Sopenharmony_ci        kDFdy_SpecialIntrinsic,
158cb93a386Sopenharmony_ci        kSaturate_SpecialIntrinsic,
159cb93a386Sopenharmony_ci        kSampledImage_SpecialIntrinsic,
160cb93a386Sopenharmony_ci        kSmoothStep_SpecialIntrinsic,
161cb93a386Sopenharmony_ci        kStep_SpecialIntrinsic,
162cb93a386Sopenharmony_ci        kSubpassLoad_SpecialIntrinsic,
163cb93a386Sopenharmony_ci        kTexture_SpecialIntrinsic,
164cb93a386Sopenharmony_ci    };
165cb93a386Sopenharmony_ci
166cb93a386Sopenharmony_ci    enum class Precision {
167cb93a386Sopenharmony_ci        kDefault,
168cb93a386Sopenharmony_ci        kRelaxed,
169cb93a386Sopenharmony_ci    };
170cb93a386Sopenharmony_ci
171cb93a386Sopenharmony_ci    struct TempVar {
172cb93a386Sopenharmony_ci        SpvId spvId;
173cb93a386Sopenharmony_ci        const Type* type;
174cb93a386Sopenharmony_ci        std::unique_ptr<SPIRVCodeGenerator::LValue> lvalue;
175cb93a386Sopenharmony_ci    };
176cb93a386Sopenharmony_ci
177cb93a386Sopenharmony_ci    void setupIntrinsics();
178cb93a386Sopenharmony_ci
179cb93a386Sopenharmony_ci    /**
180cb93a386Sopenharmony_ci     * Pass in the type to automatically add a RelaxedPrecision decoration for the id when
181cb93a386Sopenharmony_ci     * appropriate, or null to never add one.
182cb93a386Sopenharmony_ci     */
183cb93a386Sopenharmony_ci    SpvId nextId(const Type* type);
184cb93a386Sopenharmony_ci
185cb93a386Sopenharmony_ci    SpvId nextId(Precision precision);
186cb93a386Sopenharmony_ci
187cb93a386Sopenharmony_ci    const Type& getActualType(const Type& type);
188cb93a386Sopenharmony_ci
189cb93a386Sopenharmony_ci    SpvId getType(const Type& type);
190cb93a386Sopenharmony_ci
191cb93a386Sopenharmony_ci    SpvId getType(const Type& type, const MemoryLayout& layout);
192cb93a386Sopenharmony_ci
193cb93a386Sopenharmony_ci    SpvId getImageType(const Type& type);
194cb93a386Sopenharmony_ci
195cb93a386Sopenharmony_ci    SpvId getFunctionType(const FunctionDeclaration& function);
196cb93a386Sopenharmony_ci
197cb93a386Sopenharmony_ci    SpvId getPointerType(const Type& type, SpvStorageClass_ storageClass);
198cb93a386Sopenharmony_ci
199cb93a386Sopenharmony_ci    SpvId getPointerType(const Type& type, const MemoryLayout& layout,
200cb93a386Sopenharmony_ci                         SpvStorageClass_ storageClass);
201cb93a386Sopenharmony_ci
202cb93a386Sopenharmony_ci    std::vector<SpvId> getAccessChain(const Expression& expr, OutputStream& out);
203cb93a386Sopenharmony_ci
204cb93a386Sopenharmony_ci    void writeLayout(const Layout& layout, SpvId target);
205cb93a386Sopenharmony_ci
206cb93a386Sopenharmony_ci    void writeLayout(const Layout& layout, SpvId target, int member);
207cb93a386Sopenharmony_ci
208cb93a386Sopenharmony_ci    void writeStruct(const Type& type, const MemoryLayout& layout, SpvId resultId);
209cb93a386Sopenharmony_ci
210cb93a386Sopenharmony_ci    void writeProgramElement(const ProgramElement& pe, OutputStream& out);
211cb93a386Sopenharmony_ci
212cb93a386Sopenharmony_ci    SpvId writeInterfaceBlock(const InterfaceBlock& intf, bool appendRTFlip = true);
213cb93a386Sopenharmony_ci
214cb93a386Sopenharmony_ci    SpvId writeFunctionStart(const FunctionDeclaration& f, OutputStream& out);
215cb93a386Sopenharmony_ci
216cb93a386Sopenharmony_ci    SpvId writeFunctionDeclaration(const FunctionDeclaration& f, OutputStream& out);
217cb93a386Sopenharmony_ci
218cb93a386Sopenharmony_ci    SpvId writeFunction(const FunctionDefinition& f, OutputStream& out);
219cb93a386Sopenharmony_ci
220cb93a386Sopenharmony_ci    void writeGlobalVar(ProgramKind kind, const VarDeclaration& v);
221cb93a386Sopenharmony_ci
222cb93a386Sopenharmony_ci    void writeVarDeclaration(const VarDeclaration& var, OutputStream& out);
223cb93a386Sopenharmony_ci
224cb93a386Sopenharmony_ci    SpvId writeVariableReference(const VariableReference& ref, OutputStream& out);
225cb93a386Sopenharmony_ci
226cb93a386Sopenharmony_ci    int findUniformFieldIndex(const Variable& var) const;
227cb93a386Sopenharmony_ci
228cb93a386Sopenharmony_ci    std::unique_ptr<LValue> getLValue(const Expression& value, OutputStream& out);
229cb93a386Sopenharmony_ci
230cb93a386Sopenharmony_ci    SpvId writeExpression(const Expression& expr, OutputStream& out);
231cb93a386Sopenharmony_ci
232cb93a386Sopenharmony_ci    SpvId writeIntrinsicCall(const FunctionCall& c, OutputStream& out);
233cb93a386Sopenharmony_ci
234cb93a386Sopenharmony_ci    SpvId writeFunctionCallArgument(const Expression& arg,
235cb93a386Sopenharmony_ci                                    const Modifiers& paramModifiers,
236cb93a386Sopenharmony_ci                                    std::vector<TempVar>* tempVars,
237cb93a386Sopenharmony_ci                                    OutputStream& out);
238cb93a386Sopenharmony_ci
239cb93a386Sopenharmony_ci    void copyBackTempVars(const std::vector<TempVar>& tempVars, OutputStream& out);
240cb93a386Sopenharmony_ci
241cb93a386Sopenharmony_ci    SpvId writeFunctionCall(const FunctionCall& c, OutputStream& out);
242cb93a386Sopenharmony_ci
243cb93a386Sopenharmony_ci
244cb93a386Sopenharmony_ci    void writeGLSLExtendedInstruction(const Type& type, SpvId id, SpvId floatInst,
245cb93a386Sopenharmony_ci                                      SpvId signedInst, SpvId unsignedInst,
246cb93a386Sopenharmony_ci                                      const std::vector<SpvId>& args, OutputStream& out);
247cb93a386Sopenharmony_ci
248cb93a386Sopenharmony_ci    /**
249cb93a386Sopenharmony_ci     * Promotes an expression to a vector. If the expression is already a vector with vectorSize
250cb93a386Sopenharmony_ci     * columns, returns it unmodified. If the expression is a scalar, either promotes it to a
251cb93a386Sopenharmony_ci     * vector (if vectorSize > 1) or returns it unmodified (if vectorSize == 1). Asserts if the
252cb93a386Sopenharmony_ci     * expression is already a vector and it does not have vectorSize columns.
253cb93a386Sopenharmony_ci     */
254cb93a386Sopenharmony_ci    SpvId vectorize(const Expression& expr, int vectorSize, OutputStream& out);
255cb93a386Sopenharmony_ci
256cb93a386Sopenharmony_ci    /**
257cb93a386Sopenharmony_ci     * Given a list of potentially mixed scalars and vectors, promotes the scalars to match the
258cb93a386Sopenharmony_ci     * size of the vectors and returns the ids of the written expressions. e.g. given (float, vec2),
259cb93a386Sopenharmony_ci     * returns (vec2(float), vec2). It is an error to use mismatched vector sizes, e.g. (float,
260cb93a386Sopenharmony_ci     * vec2, vec3).
261cb93a386Sopenharmony_ci     */
262cb93a386Sopenharmony_ci    std::vector<SpvId> vectorize(const ExpressionArray& args, OutputStream& out);
263cb93a386Sopenharmony_ci
264cb93a386Sopenharmony_ci    SpvId writeSpecialIntrinsic(const FunctionCall& c, SpecialIntrinsic kind, OutputStream& out);
265cb93a386Sopenharmony_ci
266cb93a386Sopenharmony_ci    SpvId writeConstantVector(const AnyConstructor& c);
267cb93a386Sopenharmony_ci
268cb93a386Sopenharmony_ci    SpvId writeScalarToMatrixSplat(const Type& matrixType, SpvId scalarId, OutputStream& out);
269cb93a386Sopenharmony_ci
270cb93a386Sopenharmony_ci    SpvId writeFloatConstructor(const AnyConstructor& c, OutputStream& out);
271cb93a386Sopenharmony_ci
272cb93a386Sopenharmony_ci    SpvId castScalarToFloat(SpvId inputId, const Type& inputType, const Type& outputType,
273cb93a386Sopenharmony_ci                            OutputStream& out);
274cb93a386Sopenharmony_ci
275cb93a386Sopenharmony_ci    SpvId writeIntConstructor(const AnyConstructor& c, OutputStream& out);
276cb93a386Sopenharmony_ci
277cb93a386Sopenharmony_ci    SpvId castScalarToSignedInt(SpvId inputId, const Type& inputType, const Type& outputType,
278cb93a386Sopenharmony_ci                                OutputStream& out);
279cb93a386Sopenharmony_ci
280cb93a386Sopenharmony_ci    SpvId writeUIntConstructor(const AnyConstructor& c, OutputStream& out);
281cb93a386Sopenharmony_ci
282cb93a386Sopenharmony_ci    SpvId castScalarToUnsignedInt(SpvId inputId, const Type& inputType, const Type& outputType,
283cb93a386Sopenharmony_ci                                  OutputStream& out);
284cb93a386Sopenharmony_ci
285cb93a386Sopenharmony_ci    SpvId writeBooleanConstructor(const AnyConstructor& c, OutputStream& out);
286cb93a386Sopenharmony_ci
287cb93a386Sopenharmony_ci    SpvId castScalarToBoolean(SpvId inputId, const Type& inputType, const Type& outputType,
288cb93a386Sopenharmony_ci                              OutputStream& out);
289cb93a386Sopenharmony_ci
290cb93a386Sopenharmony_ci    SpvId castScalarToType(SpvId inputExprId, const Type& inputType, const Type& outputType,
291cb93a386Sopenharmony_ci                           OutputStream& out);
292cb93a386Sopenharmony_ci
293cb93a386Sopenharmony_ci    /**
294cb93a386Sopenharmony_ci     * Writes a matrix with the diagonal entries all equal to the provided expression, and all other
295cb93a386Sopenharmony_ci     * entries equal to zero.
296cb93a386Sopenharmony_ci     */
297cb93a386Sopenharmony_ci    void writeUniformScaleMatrix(SpvId id, SpvId diagonal, const Type& type, OutputStream& out);
298cb93a386Sopenharmony_ci
299cb93a386Sopenharmony_ci    /**
300cb93a386Sopenharmony_ci     * Writes a potentially-different-sized copy of a matrix. Entries which do not exist in the
301cb93a386Sopenharmony_ci     * source matrix are filled with zero; entries which do not exist in the destination matrix are
302cb93a386Sopenharmony_ci     * ignored.
303cb93a386Sopenharmony_ci     */
304cb93a386Sopenharmony_ci    SpvId writeMatrixCopy(SpvId src, const Type& srcType, const Type& dstType, OutputStream& out);
305cb93a386Sopenharmony_ci
306cb93a386Sopenharmony_ci    void addColumnEntry(const Type& columnType, std::vector<SpvId>* currentColumn,
307cb93a386Sopenharmony_ci                        std::vector<SpvId>* columnIds, int rows, SpvId entry, OutputStream& out);
308cb93a386Sopenharmony_ci
309cb93a386Sopenharmony_ci    SpvId writeConstructorCompound(const ConstructorCompound& c, OutputStream& out);
310cb93a386Sopenharmony_ci
311cb93a386Sopenharmony_ci    SpvId writeMatrixConstructor(const ConstructorCompound& c, OutputStream& out);
312cb93a386Sopenharmony_ci
313cb93a386Sopenharmony_ci    SpvId writeVectorConstructor(const ConstructorCompound& c, OutputStream& out);
314cb93a386Sopenharmony_ci
315cb93a386Sopenharmony_ci    SpvId writeCompositeConstructor(const AnyConstructor& c, OutputStream& out);
316cb93a386Sopenharmony_ci
317cb93a386Sopenharmony_ci    SpvId writeConstructorDiagonalMatrix(const ConstructorDiagonalMatrix& c, OutputStream& out);
318cb93a386Sopenharmony_ci
319cb93a386Sopenharmony_ci    SpvId writeConstructorMatrixResize(const ConstructorMatrixResize& c, OutputStream& out);
320cb93a386Sopenharmony_ci
321cb93a386Sopenharmony_ci    SpvId writeConstructorScalarCast(const ConstructorScalarCast& c, OutputStream& out);
322cb93a386Sopenharmony_ci
323cb93a386Sopenharmony_ci    SpvId writeConstructorSplat(const ConstructorSplat& c, OutputStream& out);
324cb93a386Sopenharmony_ci
325cb93a386Sopenharmony_ci    SpvId writeConstructorCompoundCast(const ConstructorCompoundCast& c, OutputStream& out);
326cb93a386Sopenharmony_ci
327cb93a386Sopenharmony_ci    SpvId writeComposite(const std::vector<SpvId>& arguments, const Type& type, OutputStream& out);
328cb93a386Sopenharmony_ci
329cb93a386Sopenharmony_ci    SpvId writeFieldAccess(const FieldAccess& f, OutputStream& out);
330cb93a386Sopenharmony_ci
331cb93a386Sopenharmony_ci    SpvId writeSwizzle(const Swizzle& swizzle, OutputStream& out);
332cb93a386Sopenharmony_ci
333cb93a386Sopenharmony_ci    /**
334cb93a386Sopenharmony_ci     * Folds the potentially-vector result of a logical operation down to a single bool. If
335cb93a386Sopenharmony_ci     * operandType is a vector type, assumes that the intermediate result in id is a bvec of the
336cb93a386Sopenharmony_ci     * same dimensions, and applys all() to it to fold it down to a single bool value. Otherwise,
337cb93a386Sopenharmony_ci     * returns the original id value.
338cb93a386Sopenharmony_ci     */
339cb93a386Sopenharmony_ci    SpvId foldToBool(SpvId id, const Type& operandType, SpvOp op, OutputStream& out);
340cb93a386Sopenharmony_ci
341cb93a386Sopenharmony_ci    SpvId writeMatrixComparison(const Type& operandType, SpvId lhs, SpvId rhs, SpvOp_ floatOperator,
342cb93a386Sopenharmony_ci                                SpvOp_ intOperator, SpvOp_ vectorMergeOperator,
343cb93a386Sopenharmony_ci                                SpvOp_ mergeOperator, OutputStream& out);
344cb93a386Sopenharmony_ci
345cb93a386Sopenharmony_ci    SpvId writeStructComparison(const Type& structType, SpvId lhs, Operator op, SpvId rhs,
346cb93a386Sopenharmony_ci                                OutputStream& out);
347cb93a386Sopenharmony_ci
348cb93a386Sopenharmony_ci    SpvId writeArrayComparison(const Type& structType, SpvId lhs, Operator op, SpvId rhs,
349cb93a386Sopenharmony_ci                               OutputStream& out);
350cb93a386Sopenharmony_ci
351cb93a386Sopenharmony_ci    // Used by writeStructComparison and writeArrayComparison to logically combine field-by-field
352cb93a386Sopenharmony_ci    // comparisons into an overall comparison result.
353cb93a386Sopenharmony_ci    // - `a.x == b.x` merged with `a.y == b.y` generates `(a.x == b.x) && (a.y == b.y)`
354cb93a386Sopenharmony_ci    // - `a.x != b.x` merged with `a.y != b.y` generates `(a.x != b.x) || (a.y != b.y)`
355cb93a386Sopenharmony_ci    SpvId mergeComparisons(SpvId comparison, SpvId allComparisons, Operator op, OutputStream& out);
356cb93a386Sopenharmony_ci
357cb93a386Sopenharmony_ci    SpvId writeComponentwiseMatrixBinary(const Type& operandType, SpvId lhs, SpvId rhs,
358cb93a386Sopenharmony_ci                                         SpvOp_ op, OutputStream& out);
359cb93a386Sopenharmony_ci
360cb93a386Sopenharmony_ci    SpvId writeBinaryOperation(const Type& resultType, const Type& operandType, SpvId lhs,
361cb93a386Sopenharmony_ci                               SpvId rhs, SpvOp_ ifFloat, SpvOp_ ifInt, SpvOp_ ifUInt,
362cb93a386Sopenharmony_ci                               SpvOp_ ifBool, OutputStream& out);
363cb93a386Sopenharmony_ci
364cb93a386Sopenharmony_ci    SpvId writeBinaryOperation(const BinaryExpression& expr, SpvOp_ ifFloat, SpvOp_ ifInt,
365cb93a386Sopenharmony_ci                               SpvOp_ ifUInt, OutputStream& out);
366cb93a386Sopenharmony_ci
367cb93a386Sopenharmony_ci    SpvId writeReciprocal(const Type& type, SpvId value, OutputStream& out);
368cb93a386Sopenharmony_ci
369cb93a386Sopenharmony_ci    SpvId writeBinaryExpression(const Type& leftType, SpvId lhs, Operator op,
370cb93a386Sopenharmony_ci                                const Type& rightType, SpvId rhs, const Type& resultType,
371cb93a386Sopenharmony_ci                                OutputStream& out);
372cb93a386Sopenharmony_ci
373cb93a386Sopenharmony_ci    SpvId writeBinaryExpression(const BinaryExpression& b, OutputStream& out);
374cb93a386Sopenharmony_ci
375cb93a386Sopenharmony_ci    SpvId writeTernaryExpression(const TernaryExpression& t, OutputStream& out);
376cb93a386Sopenharmony_ci
377cb93a386Sopenharmony_ci    SpvId writeIndexExpression(const IndexExpression& expr, OutputStream& out);
378cb93a386Sopenharmony_ci
379cb93a386Sopenharmony_ci    SpvId writeLogicalAnd(const Expression& left, const Expression& right, OutputStream& out);
380cb93a386Sopenharmony_ci
381cb93a386Sopenharmony_ci    SpvId writeLogicalOr(const Expression& left, const Expression& right, OutputStream& out);
382cb93a386Sopenharmony_ci
383cb93a386Sopenharmony_ci    SpvId writePrefixExpression(const PrefixExpression& p, OutputStream& out);
384cb93a386Sopenharmony_ci
385cb93a386Sopenharmony_ci    SpvId writePostfixExpression(const PostfixExpression& p, OutputStream& out);
386cb93a386Sopenharmony_ci
387cb93a386Sopenharmony_ci    SpvId writeLiteral(const Literal& f);
388cb93a386Sopenharmony_ci
389cb93a386Sopenharmony_ci    SpvId writeLiteral(double value, const Type& type);
390cb93a386Sopenharmony_ci
391cb93a386Sopenharmony_ci    void writeStatement(const Statement& s, OutputStream& out);
392cb93a386Sopenharmony_ci
393cb93a386Sopenharmony_ci    void writeBlock(const Block& b, OutputStream& out);
394cb93a386Sopenharmony_ci
395cb93a386Sopenharmony_ci    void writeIfStatement(const IfStatement& stmt, OutputStream& out);
396cb93a386Sopenharmony_ci
397cb93a386Sopenharmony_ci    void writeForStatement(const ForStatement& f, OutputStream& out);
398cb93a386Sopenharmony_ci
399cb93a386Sopenharmony_ci    void writeDoStatement(const DoStatement& d, OutputStream& out);
400cb93a386Sopenharmony_ci
401cb93a386Sopenharmony_ci    void writeSwitchStatement(const SwitchStatement& s, OutputStream& out);
402cb93a386Sopenharmony_ci
403cb93a386Sopenharmony_ci    void writeReturnStatement(const ReturnStatement& r, OutputStream& out);
404cb93a386Sopenharmony_ci
405cb93a386Sopenharmony_ci    void writeCapabilities(OutputStream& out);
406cb93a386Sopenharmony_ci
407cb93a386Sopenharmony_ci    void writeInstructions(const Program& program, OutputStream& out);
408cb93a386Sopenharmony_ci
409cb93a386Sopenharmony_ci    void writeOpCode(SpvOp_ opCode, int length, OutputStream& out);
410cb93a386Sopenharmony_ci
411cb93a386Sopenharmony_ci    void writeWord(int32_t word, OutputStream& out);
412cb93a386Sopenharmony_ci
413cb93a386Sopenharmony_ci    void writeString(skstd::string_view s, OutputStream& out);
414cb93a386Sopenharmony_ci
415cb93a386Sopenharmony_ci    void writeLabel(SpvId id, OutputStream& out);
416cb93a386Sopenharmony_ci
417cb93a386Sopenharmony_ci    void writeInstruction(SpvOp_ opCode, OutputStream& out);
418cb93a386Sopenharmony_ci
419cb93a386Sopenharmony_ci    void writeInstruction(SpvOp_ opCode, skstd::string_view string, OutputStream& out);
420cb93a386Sopenharmony_ci
421cb93a386Sopenharmony_ci    void writeInstruction(SpvOp_ opCode, int32_t word1, OutputStream& out);
422cb93a386Sopenharmony_ci
423cb93a386Sopenharmony_ci    void writeInstruction(SpvOp_ opCode, int32_t word1, skstd::string_view string,
424cb93a386Sopenharmony_ci                          OutputStream& out);
425cb93a386Sopenharmony_ci
426cb93a386Sopenharmony_ci    void writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, skstd::string_view string,
427cb93a386Sopenharmony_ci                          OutputStream& out);
428cb93a386Sopenharmony_ci
429cb93a386Sopenharmony_ci    void writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, OutputStream& out);
430cb93a386Sopenharmony_ci
431cb93a386Sopenharmony_ci    void writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, int32_t word3,
432cb93a386Sopenharmony_ci                          OutputStream& out);
433cb93a386Sopenharmony_ci
434cb93a386Sopenharmony_ci    void writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, int32_t word3, int32_t word4,
435cb93a386Sopenharmony_ci                          OutputStream& out);
436cb93a386Sopenharmony_ci
437cb93a386Sopenharmony_ci    void writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, int32_t word3, int32_t word4,
438cb93a386Sopenharmony_ci                          int32_t word5, OutputStream& out);
439cb93a386Sopenharmony_ci
440cb93a386Sopenharmony_ci    void writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, int32_t word3, int32_t word4,
441cb93a386Sopenharmony_ci                          int32_t word5, int32_t word6, OutputStream& out);
442cb93a386Sopenharmony_ci
443cb93a386Sopenharmony_ci    void writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, int32_t word3, int32_t word4,
444cb93a386Sopenharmony_ci                          int32_t word5, int32_t word6, int32_t word7, OutputStream& out);
445cb93a386Sopenharmony_ci
446cb93a386Sopenharmony_ci    void writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, int32_t word3, int32_t word4,
447cb93a386Sopenharmony_ci                          int32_t word5, int32_t word6, int32_t word7, int32_t word8,
448cb93a386Sopenharmony_ci                          OutputStream& out);
449cb93a386Sopenharmony_ci
450cb93a386Sopenharmony_ci    bool isDead(const Variable& var) const;
451cb93a386Sopenharmony_ci
452cb93a386Sopenharmony_ci    MemoryLayout memoryLayoutForVariable(const Variable&) const;
453cb93a386Sopenharmony_ci
454cb93a386Sopenharmony_ci    struct EntrypointAdapter {
455cb93a386Sopenharmony_ci        std::unique_ptr<FunctionDefinition> entrypointDef;
456cb93a386Sopenharmony_ci        std::unique_ptr<FunctionDeclaration> entrypointDecl;
457cb93a386Sopenharmony_ci        Layout fLayout;
458cb93a386Sopenharmony_ci        Modifiers fModifiers;
459cb93a386Sopenharmony_ci    };
460cb93a386Sopenharmony_ci
461cb93a386Sopenharmony_ci    EntrypointAdapter writeEntrypointAdapter(const FunctionDeclaration& main);
462cb93a386Sopenharmony_ci
463cb93a386Sopenharmony_ci    struct UniformBuffer {
464cb93a386Sopenharmony_ci        std::unique_ptr<InterfaceBlock> fInterfaceBlock;
465cb93a386Sopenharmony_ci        std::unique_ptr<Variable> fInnerVariable;
466cb93a386Sopenharmony_ci        std::unique_ptr<Type> fStruct;
467cb93a386Sopenharmony_ci    };
468cb93a386Sopenharmony_ci
469cb93a386Sopenharmony_ci    void writeUniformBuffer(std::shared_ptr<SymbolTable> topLevelSymbolTable);
470cb93a386Sopenharmony_ci
471cb93a386Sopenharmony_ci    void addRTFlipUniform(int line);
472cb93a386Sopenharmony_ci
473cb93a386Sopenharmony_ci    const MemoryLayout fDefaultLayout;
474cb93a386Sopenharmony_ci
475cb93a386Sopenharmony_ci    uint64_t fCapabilities;
476cb93a386Sopenharmony_ci    SpvId fIdCount;
477cb93a386Sopenharmony_ci    SpvId fGLSLExtendedInstructions;
478cb93a386Sopenharmony_ci    typedef std::tuple<IntrinsicOpcodeKind, int32_t, int32_t, int32_t, int32_t> Intrinsic;
479cb93a386Sopenharmony_ci    std::unordered_map<IntrinsicKind, Intrinsic> fIntrinsicMap;
480cb93a386Sopenharmony_ci    std::unordered_map<const FunctionDeclaration*, SpvId> fFunctionMap;
481cb93a386Sopenharmony_ci    std::unordered_map<const Variable*, SpvId> fVariableMap;
482cb93a386Sopenharmony_ci    std::unordered_map<const Variable*, int32_t> fInterfaceBlockMap;
483cb93a386Sopenharmony_ci    std::unordered_map<String, SpvId> fImageTypeMap;
484cb93a386Sopenharmony_ci    std::unordered_map<String, SpvId> fTypeMap;
485cb93a386Sopenharmony_ci    StringStream fCapabilitiesBuffer;
486cb93a386Sopenharmony_ci    StringStream fGlobalInitializersBuffer;
487cb93a386Sopenharmony_ci    StringStream fConstantBuffer;
488cb93a386Sopenharmony_ci    StringStream fExtraGlobalsBuffer;
489cb93a386Sopenharmony_ci    StringStream fVariableBuffer;
490cb93a386Sopenharmony_ci    StringStream fNameBuffer;
491cb93a386Sopenharmony_ci    StringStream fDecorationBuffer;
492cb93a386Sopenharmony_ci
493cb93a386Sopenharmony_ci    std::unordered_map<SPIRVNumberConstant, SpvId> fNumberConstants;
494cb93a386Sopenharmony_ci    std::unordered_map<SPIRVVectorConstant, SpvId> fVectorConstants;
495cb93a386Sopenharmony_ci    bool fSetupFragPosition;
496cb93a386Sopenharmony_ci    // label of the current block, or 0 if we are not in a block
497cb93a386Sopenharmony_ci    SpvId fCurrentBlock;
498cb93a386Sopenharmony_ci    std::stack<SpvId> fBreakTarget;
499cb93a386Sopenharmony_ci    std::stack<SpvId> fContinueTarget;
500cb93a386Sopenharmony_ci    bool fWroteRTFlip = false;
501cb93a386Sopenharmony_ci    // holds variables synthesized during output, for lifetime purposes
502cb93a386Sopenharmony_ci    SymbolTable fSynthetics;
503cb93a386Sopenharmony_ci    int fSkInCount = 1;
504cb93a386Sopenharmony_ci    // Holds a list of uniforms that were declared as globals at the top-level instead of in an
505cb93a386Sopenharmony_ci    // interface block.
506cb93a386Sopenharmony_ci    UniformBuffer fUniformBuffer;
507cb93a386Sopenharmony_ci    std::vector<const VarDeclaration*> fTopLevelUniforms;
508cb93a386Sopenharmony_ci    std::unordered_map<const Variable*, int> fTopLevelUniformMap; //<var, UniformBuffer field index>
509cb93a386Sopenharmony_ci    std::unordered_set<const Variable*> fSPIRVBonusVariables;
510cb93a386Sopenharmony_ci    SpvId fUniformBufferId = -1;
511cb93a386Sopenharmony_ci
512cb93a386Sopenharmony_ci    friend class PointerLValue;
513cb93a386Sopenharmony_ci    friend class SwizzleLValue;
514cb93a386Sopenharmony_ci
515cb93a386Sopenharmony_ci    using INHERITED = CodeGenerator;
516cb93a386Sopenharmony_ci};
517cb93a386Sopenharmony_ci
518cb93a386Sopenharmony_ci}  // namespace SkSL
519cb93a386Sopenharmony_ci
520cb93a386Sopenharmony_ci#endif
521