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 "include/private/SkSLIRNode.h" 13 #include "include/private/SkSLModifiers.h" 14 #include "include/private/SkSLStatement.h" 15 #include "include/private/SkSLSymbol.h" 16 #include "include/sksl/SkSLPosition.h" 17 #include "src/sksl/ir/SkSLType.h" 18 19 #include <cstdint> 20 #include <memory> 21 #include <string> 22 #include <string_view> 23 24 namespace SkSL { 25 26 class Context; 27 class Expression; 28 class GlobalVarDeclaration; 29 class InterfaceBlock; 30 class Mangler; 31 class SymbolTable; 32 class VarDeclaration; 33 34 enum class VariableStorage : int8_t { 35 kGlobal, 36 kInterfaceBlock, 37 kLocal, 38 kParameter, 39 }; 40 41 /** 42 * Represents a variable, whether local, global, or a function parameter. This represents the 43 * variable itself (the storage location), which is shared between all VariableReferences which 44 * read or write that storage location. 45 */ 46 class Variable : public Symbol { 47 public: 48 using Storage = VariableStorage; 49 50 inline static constexpr Kind kIRNodeKind = Kind::kVariable; 51 Variable(Position pos,Position modifiersPosition,const Modifiers * modifiers,std::string_view name,const Type * type,bool builtin,Storage storage)52 Variable(Position pos, Position modifiersPosition, const Modifiers* modifiers, 53 std::string_view name, const Type* type, bool builtin, Storage storage) 54 : INHERITED(pos, kIRNodeKind, name, type) 55 , fModifiersPosition(modifiersPosition) 56 , fModifiers(modifiers) 57 , fStorage(storage) 58 , fBuiltin(builtin) {} 59 60 ~Variable() override; 61 62 static std::unique_ptr<Variable> Convert(const Context& context, Position pos, 63 Position modifiersPos, const Modifiers& modifiers, const Type* baseType, 64 Position namePos, std::string_view name, bool isArray, 65 std::unique_ptr<Expression> arraySize, Variable::Storage storage); 66 67 static std::unique_ptr<Variable> Make(const Context& context, Position pos, 68 Position modifiersPos, const Modifiers& modifiers, const Type* baseType, 69 std::string_view name, bool isArray, std::unique_ptr<Expression> arraySize, 70 Variable::Storage storage); 71 72 /** 73 * Creates a local scratch variable and the associated VarDeclaration statement. 74 * Useful when doing IR rewrites, e.g. inlining a function call. 75 */ 76 struct ScratchVariable { 77 const Variable* fVarSymbol; 78 std::unique_ptr<Statement> fVarDecl; 79 }; 80 static ScratchVariable MakeScratchVariable(const Context& context, 81 Mangler& mangler, 82 std::string_view baseName, 83 const Type* type, 84 const Modifiers& modifiers, 85 SymbolTable* symbolTable, 86 std::unique_ptr<Expression> initialValue); modifiers()87 const Modifiers& modifiers() const { 88 return *fModifiers; 89 } 90 setModifiers(const Modifiers * modifiers)91 void setModifiers(const Modifiers* modifiers) { 92 fModifiers = modifiers; 93 } 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 // InterfaceBlockVariable, declared below this class, which dedicates extra space to store the 124 // pointer 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 description()131 std::string description() const override { 132 return this->modifiers().description() + this->type().displayName() + " " + 133 std::string(this->name()); 134 } 135 136 std::string mangledName() const; 137 138 private: 139 IRNode* fDeclaringElement = nullptr; 140 // We don't store the position in the Modifiers object itself because they are pooled 141 Position fModifiersPosition; 142 const Modifiers* fModifiers; 143 VariableStorage fStorage; 144 bool fBuiltin; 145 146 using INHERITED = Symbol; 147 }; 148 149 /** 150 * This represents a Variable associated with an InterfaceBlock. Mostly a normal variable, but also 151 * has an extra pointer back to the InterfaceBlock element that owns it. 152 */ 153 class InterfaceBlockVariable final : public Variable { 154 public: 155 using Variable::Variable; 156 157 ~InterfaceBlockVariable() override; 158 interfaceBlock()159 InterfaceBlock* interfaceBlock() const override { return fInterfaceBlockElement; } 160 setInterfaceBlock(InterfaceBlock * elem)161 void setInterfaceBlock(InterfaceBlock* elem) override { 162 SkASSERT(!fInterfaceBlockElement); 163 fInterfaceBlockElement = elem; 164 } 165 detachDeadInterfaceBlock()166 void detachDeadInterfaceBlock() override { 167 // The InterfaceBlock is being deleted, so our reference to it has become stale. 168 fInterfaceBlockElement = nullptr; 169 } 170 171 private: 172 InterfaceBlock* fInterfaceBlockElement = nullptr; 173 174 using INHERITED = Variable; 175 }; 176 177 } // namespace SkSL 178 179 #endif 180