xref: /aosp_15_r20/external/skia/src/sksl/ir/SkSLVariable.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2016 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 #ifndef SKSL_VARIABLE
9 #define SKSL_VARIABLE
10 
11 #include "include/core/SkTypes.h"
12 #include "src/sksl/SkSLPosition.h"
13 #include "src/sksl/ir/SkSLIRNode.h"
14 #include "src/sksl/ir/SkSLLayout.h"
15 #include "src/sksl/ir/SkSLModifierFlags.h"
16 #include "src/sksl/ir/SkSLStatement.h"
17 #include "src/sksl/ir/SkSLSymbol.h"
18 #include "src/sksl/ir/SkSLType.h"
19 
20 #include <cstdint>
21 #include <memory>
22 #include <string>
23 #include <string_view>
24 #include <utility>
25 
26 namespace SkSL {
27 
28 class Context;
29 class Expression;
30 class GlobalVarDeclaration;
31 class InterfaceBlock;
32 class Mangler;
33 class SymbolTable;
34 class VarDeclaration;
35 
36 enum class VariableStorage : int8_t {
37     kGlobal,
38     kInterfaceBlock,
39     kLocal,
40     kParameter,
41 };
42 
43 /**
44  * Represents a variable, whether local, global, or a function parameter. This represents the
45  * variable itself (the storage location), which is shared between all VariableReferences which
46  * read or write that storage location.
47  */
48 class Variable : public Symbol {
49 public:
50     using Storage = VariableStorage;
51 
52     inline static constexpr Kind kIRNodeKind = Kind::kVariable;
53 
Variable(Position pos,Position modifiersPosition,ModifierFlags modifierFlags,std::string_view name,const Type * type,bool builtin,Storage storage)54     Variable(Position pos, Position modifiersPosition, ModifierFlags modifierFlags,
55              std::string_view name, const Type* type, bool builtin, Storage storage)
56             : INHERITED(pos, kIRNodeKind, name, type)
57             , fModifierFlags(modifierFlags)
58             , fModifiersPosition(modifiersPosition)
59             , fStorage(storage)
60             , fBuiltin(builtin) {}
61 
62     ~Variable() override;
63 
64     static std::unique_ptr<Variable> Convert(const Context& context, Position pos,
65                                              Position modifiersPos, const Layout& layout,
66                                              ModifierFlags flags, const Type* type,
67                                              Position namePos, std::string_view name,
68                                              Storage storage);
69 
70     static std::unique_ptr<Variable> Make(Position pos, Position modifiersPosition,
71                                           const Layout& layout, ModifierFlags flags,
72                                           const Type* type, std::string_view name,
73                                           std::string mangledName, bool builtin, Storage storage);
74 
75     /**
76      * Creates a local scratch variable and the associated VarDeclaration statement.
77      * Useful when doing IR rewrites, e.g. inlining a function call.
78      */
79     struct ScratchVariable {
80         const Variable* fVarSymbol;
81         std::unique_ptr<Statement> fVarDecl;
82     };
83     static ScratchVariable MakeScratchVariable(const Context& context,
84                                                Mangler& mangler,
85                                                std::string_view baseName,
86                                                const Type* type,
87                                                SymbolTable* symbolTable,
88                                                std::unique_ptr<Expression> initialValue);
modifierFlags()89     ModifierFlags modifierFlags() const {
90         return fModifierFlags;
91     }
92 
93     virtual const Layout& layout() const;
94 
modifiersPosition()95     Position modifiersPosition() const {
96         return fModifiersPosition;
97     }
98 
isBuiltin()99     bool isBuiltin() const {
100         return fBuiltin;
101     }
102 
storage()103     Storage storage() const {
104         return fStorage;
105     }
106 
107     const Expression* initialValue() const;
108 
109     VarDeclaration* varDeclaration() const;
110 
111     void setVarDeclaration(VarDeclaration* declaration);
112 
113     GlobalVarDeclaration* globalVarDeclaration() const;
114 
115     void setGlobalVarDeclaration(GlobalVarDeclaration* global);
116 
detachDeadVarDeclaration()117     void detachDeadVarDeclaration() {
118         // The VarDeclaration is being deleted, so our reference to it has become stale.
119         fDeclaringElement = nullptr;
120     }
121 
122     // The interfaceBlock methods are no-op stubs here. They have proper implementations in
123     // ExtendedVariable, declared below this class, which dedicates extra space to store the pointer
124     // back to the InterfaceBlock.
interfaceBlock()125     virtual InterfaceBlock* interfaceBlock() const { return nullptr; }
126 
setInterfaceBlock(InterfaceBlock *)127     virtual void setInterfaceBlock(InterfaceBlock*) { SkUNREACHABLE; }
128 
detachDeadInterfaceBlock()129     virtual void detachDeadInterfaceBlock() {}
130 
131     // Only ExtendedVariables support mangled names.
mangledName()132     virtual std::string_view mangledName() const { return this->name(); }
133 
description()134     std::string description() const override {
135         return this->layout().paddedDescription() + this->modifierFlags().paddedDescription() +
136                this->type().displayName() + " " + std::string(this->name());
137     }
138 
139 private:
140     IRNode* fDeclaringElement = nullptr;
141     ModifierFlags fModifierFlags;
142     Position fModifiersPosition;
143     VariableStorage fStorage;
144     bool fBuiltin;
145 
146     using INHERITED = Symbol;
147 };
148 
149 /**
150  * ExtendedVariable is functionally equivalent to a regular Variable, but it also contains extra
151  * fields that most variables don't need:
152  * - The variable's associated InterfaceBlock
153  * - The variable's layout
154  * - The variable's mangled name
155  *
156  * Some of these fields can be null/empty.
157  */
158 class ExtendedVariable final : public Variable {
159 public:
ExtendedVariable(Position pos,Position modifiersPosition,const Layout & layout,ModifierFlags flags,std::string_view name,const Type * type,bool builtin,Storage storage,std::string mangledName)160     ExtendedVariable(Position pos, Position modifiersPosition, const Layout& layout,
161                      ModifierFlags flags, std::string_view name, const Type* type, bool builtin,
162                      Storage storage, std::string mangledName)
163             : INHERITED(pos, modifiersPosition, flags, name, type, builtin, storage)
164             , fLayout(layout)
165             , fMangledName(std::move(mangledName)) {}
166 
167     ~ExtendedVariable() override;
168 
interfaceBlock()169     InterfaceBlock* interfaceBlock() const override {
170         return fInterfaceBlockElement;
171     }
172 
layout()173     const Layout& layout() const override {
174         return fLayout;
175     }
176 
setInterfaceBlock(InterfaceBlock * elem)177     void setInterfaceBlock(InterfaceBlock* elem) override {
178         SkASSERT(!fInterfaceBlockElement);
179         fInterfaceBlockElement = elem;
180     }
181 
detachDeadInterfaceBlock()182     void detachDeadInterfaceBlock() override {
183         // The InterfaceBlock is being deleted, so our reference to it has become stale.
184         fInterfaceBlockElement = nullptr;
185     }
186 
187     std::string_view mangledName() const override;
188 
189 private:
190     InterfaceBlock* fInterfaceBlockElement = nullptr;
191     Layout fLayout;
192     std::string fMangledName;
193 
194     using INHERITED = Variable;
195 };
196 
197 } // namespace SkSL
198 
199 #endif
200