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