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