1 /*
2 * Copyright 2021 Google LLC
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/ir/SkSLVarDeclarations.h"
9
10 #include "include/sksl/SkSLErrorReporter.h"
11 #include "src/sksl/SkSLAnalysis.h"
12 #include "src/sksl/SkSLCompiler.h"
13 #include "src/sksl/SkSLContext.h"
14 #include "src/sksl/SkSLProgramSettings.h"
15 #include "src/sksl/SkSLThreadContext.h"
16
17 namespace SkSL {
18
clone() const19 std::unique_ptr<Statement> VarDeclaration::clone() const {
20 return std::make_unique<VarDeclaration>(&this->var(),
21 &this->baseType(),
22 fArraySize,
23 this->value() ? this->value()->clone() : nullptr);
24 }
25
description() const26 String VarDeclaration::description() const {
27 String result = this->var().modifiers().description() + this->baseType().description() + " " +
28 this->var().name();
29 if (this->arraySize() > 0) {
30 result.appendf("[%d]", this->arraySize());
31 }
32 if (this->value()) {
33 result += " = " + this->value()->description();
34 }
35 result += ";";
36 return result;
37 }
38
ErrorCheck(const Context & context,int line,const Modifiers & modifiers,const Type * baseType,Variable::Storage storage)39 void VarDeclaration::ErrorCheck(const Context& context, int line, const Modifiers& modifiers,
40 const Type* baseType, Variable::Storage storage) {
41 if (*baseType == *context.fTypes.fInvalid) {
42 context.fErrors->error(line, "invalid type");
43 return;
44 }
45 if (context.fConfig->strictES2Mode() && baseType->isArray()) {
46 context.fErrors->error(line, "array size must appear after variable name");
47 }
48
49 if (baseType->componentType().isOpaque() && storage != Variable::Storage::kGlobal) {
50 context.fErrors->error(line,
51 "variables of type '" + baseType->displayName() + "' must be global");
52 }
53 if ((modifiers.fFlags & Modifiers::kIn_Flag) && baseType->isMatrix()) {
54 context.fErrors->error(line, "'in' variables may not have matrix type");
55 }
56 if ((modifiers.fFlags & Modifiers::kIn_Flag) && (modifiers.fFlags & Modifiers::kUniform_Flag)) {
57 context.fErrors->error(line, "'in uniform' variables not permitted");
58 }
59 if (ProgramConfig::IsRuntimeEffect(context.fConfig->fKind)) {
60 if (modifiers.fFlags & Modifiers::kIn_Flag) {
61 context.fErrors->error(line, "'in' variables not permitted in runtime effects");
62 }
63 }
64 if (baseType->isEffectChild() && !(modifiers.fFlags & Modifiers::kUniform_Flag)) {
65 context.fErrors->error(line,
66 "variables of type '" + baseType->displayName() + "' must be uniform");
67 }
68 if (modifiers.fLayout.fFlags & Layout::kSRGBUnpremul_Flag) {
69 if (!ProgramConfig::IsRuntimeEffect(context.fConfig->fKind)) {
70 context.fErrors->error(line, "'srgb_unpremul' is only permitted in runtime effects");
71 }
72 if (!(modifiers.fFlags & Modifiers::kUniform_Flag)) {
73 context.fErrors->error(line,
74 "'srgb_unpremul' is only permitted on 'uniform' variables");
75 }
76 auto validColorXformType = [](const Type& t) {
77 return t.isVector() && t.componentType().isFloat() &&
78 (t.columns() == 3 || t.columns() == 4);
79 };
80 if (!validColorXformType(*baseType) && !(baseType->isArray() &&
81 validColorXformType(baseType->componentType()))) {
82 context.fErrors->error(line, "'srgb_unpremul' is only permitted on half3, half4, "
83 "float3, or float4 variables");
84 }
85 }
86 int permitted = Modifiers::kConst_Flag | Modifiers::kHighp_Flag | Modifiers::kMediump_Flag |
87 Modifiers::kLowp_Flag;
88 if (storage == Variable::Storage::kGlobal) {
89 permitted |= Modifiers::kIn_Flag | Modifiers::kOut_Flag | Modifiers::kUniform_Flag |
90 Modifiers::kFlat_Flag | Modifiers::kNoPerspective_Flag;
91 }
92 // TODO(skbug.com/11301): Migrate above checks into building a mask of permitted layout flags
93 modifiers.checkPermitted(context, line, permitted, /*permittedLayoutFlags=*/~0);
94 }
95
ErrorCheckAndCoerce(const Context & context,const Variable & var,std::unique_ptr<Expression> & value)96 bool VarDeclaration::ErrorCheckAndCoerce(const Context& context, const Variable& var,
97 std::unique_ptr<Expression>& value) {
98 const Type* baseType = &var.type();
99 if (baseType->isArray()) {
100 baseType = &baseType->componentType();
101 }
102 ErrorCheck(context, var.fLine, var.modifiers(), baseType, var.storage());
103 if (value) {
104 if (var.type().isOpaque()) {
105 context.fErrors->error(value->fLine,
106 "opaque type '" + var.type().name() + "' cannot use initializer expressions");
107 return false;
108 }
109 if (var.modifiers().fFlags & Modifiers::kIn_Flag) {
110 context.fErrors->error(value->fLine,
111 "'in' variables cannot use initializer expressions");
112 return false;
113 }
114 if (var.modifiers().fFlags & Modifiers::kUniform_Flag) {
115 context.fErrors->error(value->fLine,
116 "'uniform' variables cannot use initializer expressions");
117 return false;
118 }
119 if (var.storage() == Variable::Storage::kInterfaceBlock) {
120 context.fErrors->error(value->fLine,
121 "initializers are not permitted on interface block fields");
122 return false;
123 }
124 value = var.type().coerceExpression(std::move(value), context);
125 if (!value) {
126 return false;
127 }
128 }
129 if (var.modifiers().fFlags & Modifiers::kConst_Flag) {
130 if (!value) {
131 context.fErrors->error(var.fLine, "'const' variables must be initialized");
132 return false;
133 }
134 if (!Analysis::IsConstantExpression(*value)) {
135 context.fErrors->error(value->fLine,
136 "'const' variable initializer must be a constant expression");
137 return false;
138 }
139 }
140 if (var.storage() == Variable::Storage::kInterfaceBlock) {
141 if (var.type().isOpaque()) {
142 context.fErrors->error(var.fLine, "opaque type '" + var.type().name() +
143 "' is not permitted in an interface block");
144 return false;
145 }
146 }
147 if (var.storage() == Variable::Storage::kGlobal) {
148 if (value && !Analysis::IsConstantExpression(*value)) {
149 context.fErrors->error(value->fLine,
150 "global variable initializer must be a constant expression");
151 return false;
152 }
153 }
154 return true;
155 }
156
Convert(const Context & context,std::unique_ptr<Variable> var,std::unique_ptr<Expression> value,bool addToSymbolTable)157 std::unique_ptr<Statement> VarDeclaration::Convert(const Context& context,
158 std::unique_ptr<Variable> var, std::unique_ptr<Expression> value, bool addToSymbolTable) {
159 if (!ErrorCheckAndCoerce(context, *var, value)) {
160 return nullptr;
161 }
162 const Type* baseType = &var->type();
163 int arraySize = 0;
164 if (baseType->isArray()) {
165 arraySize = baseType->columns();
166 baseType = &baseType->componentType();
167 }
168 std::unique_ptr<Statement> varDecl = VarDeclaration::Make(context, var.get(), baseType,
169 arraySize, std::move(value));
170 if (!varDecl) {
171 return nullptr;
172 }
173
174 // Detect the declaration of magical variables.
175 if ((var->storage() == Variable::Storage::kGlobal) && var->name() == Compiler::FRAGCOLOR_NAME) {
176 // Silently ignore duplicate definitions of `sk_FragColor`.
177 const Symbol* symbol = (*ThreadContext::SymbolTable())[var->name()];
178 if (symbol) {
179 return nullptr;
180 }
181 } else if ((var->storage() == Variable::Storage::kGlobal ||
182 var->storage() == Variable::Storage::kInterfaceBlock) &&
183 var->name() == Compiler::RTADJUST_NAME) {
184 // `sk_RTAdjust` is special, and makes the IR generator emit position-fixup expressions.
185 if (ThreadContext::RTAdjustState().fVar || ThreadContext::RTAdjustState().fInterfaceBlock) {
186 context.fErrors->error(var->fLine, "duplicate definition of 'sk_RTAdjust'");
187 return nullptr;
188 }
189 if (var->type() != *context.fTypes.fFloat4) {
190 context.fErrors->error(var->fLine, "sk_RTAdjust must have type 'float4'");
191 return nullptr;
192 }
193 ThreadContext::RTAdjustState().fVar = var.get();
194 }
195
196 if (addToSymbolTable) {
197 ThreadContext::SymbolTable()->add(std::move(var));
198 } else {
199 ThreadContext::SymbolTable()->takeOwnershipOfSymbol(std::move(var));
200 }
201 return varDecl;
202 }
203
Make(const Context & context,Variable * var,const Type * baseType,int arraySize,std::unique_ptr<Expression> value)204 std::unique_ptr<Statement> VarDeclaration::Make(const Context& context, Variable* var,
205 const Type* baseType, int arraySize, std::unique_ptr<Expression> value) {
206 SkASSERT(!baseType->isArray());
207 // function parameters cannot have variable declarations
208 SkASSERT(var->storage() != Variable::Storage::kParameter);
209 // 'const' variables must be initialized
210 SkASSERT(!(var->modifiers().fFlags & Modifiers::kConst_Flag) || value);
211 // 'const' variable initializer must be a constant expression
212 SkASSERT(!(var->modifiers().fFlags & Modifiers::kConst_Flag) ||
213 Analysis::IsConstantExpression(*value));
214 // global variable initializer must be a constant expression
215 SkASSERT(!(value && var->storage() == Variable::Storage::kGlobal &&
216 !Analysis::IsConstantExpression(*value)));
217 // opaque type not permitted on an interface block
218 SkASSERT(!(var->storage() == Variable::Storage::kInterfaceBlock && var->type().isOpaque()));
219 // initializers are not permitted on interface block fields
220 SkASSERT(!(var->storage() == Variable::Storage::kInterfaceBlock && value));
221 // opaque type cannot use initializer expressions
222 SkASSERT(!(value && var->type().isOpaque()));
223 // 'in' variables cannot use initializer expressions
224 SkASSERT(!(value && (var->modifiers().fFlags & Modifiers::kIn_Flag)));
225 // 'uniform' variables cannot use initializer expressions
226 SkASSERT(!(value && (var->modifiers().fFlags & Modifiers::kUniform_Flag)));
227
228 auto result = std::make_unique<VarDeclaration>(var, baseType, arraySize, std::move(value));
229 var->setDeclaration(result.get());
230 return std::move(result);
231 }
232
233 } // namespace SkSL
234