blob: 31fe35dae88dff014be55335a4d88838438ff2be [file] [log] [blame]
ethannicholasb3058bd2016-07-01 08:22:01 -07001/*
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 */
Mike Klein6ad99092016-10-26 10:35:22 -04007
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "src/sksl/SkSLCompiler.h"
ethannicholasb3058bd2016-07-01 08:22:01 -07009
John Stilesfbd050b2020-08-03 13:21:46 -040010#include <memory>
John Stilesb8e010c2020-08-11 18:05:39 -040011#include <unordered_set>
John Stilesfbd050b2020-08-03 13:21:46 -040012
John Stilesb92641c2020-08-31 18:09:01 -040013#include "src/sksl/SkSLAnalysis.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050014#include "src/sksl/SkSLByteCodeGenerator.h"
15#include "src/sksl/SkSLCFGGenerator.h"
16#include "src/sksl/SkSLCPPCodeGenerator.h"
17#include "src/sksl/SkSLGLSLCodeGenerator.h"
18#include "src/sksl/SkSLHCodeGenerator.h"
19#include "src/sksl/SkSLIRGenerator.h"
20#include "src/sksl/SkSLMetalCodeGenerator.h"
21#include "src/sksl/SkSLPipelineStageCodeGenerator.h"
Ethan Nicholasc18bb512020-07-28 14:46:53 -040022#include "src/sksl/SkSLRehydrator.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050023#include "src/sksl/SkSLSPIRVCodeGenerator.h"
Brian Osmanc0243912020-02-19 15:35:26 -050024#include "src/sksl/SkSLSPIRVtoHLSL.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050025#include "src/sksl/ir/SkSLEnum.h"
26#include "src/sksl/ir/SkSLExpression.h"
27#include "src/sksl/ir/SkSLExpressionStatement.h"
28#include "src/sksl/ir/SkSLFunctionCall.h"
29#include "src/sksl/ir/SkSLIntLiteral.h"
30#include "src/sksl/ir/SkSLModifiersDeclaration.h"
31#include "src/sksl/ir/SkSLNop.h"
32#include "src/sksl/ir/SkSLSymbolTable.h"
33#include "src/sksl/ir/SkSLTernaryExpression.h"
34#include "src/sksl/ir/SkSLUnresolvedFunction.h"
35#include "src/sksl/ir/SkSLVarDeclarations.h"
John Stilese6150002020-10-05 12:03:53 -040036#include "src/utils/SkBitSet.h"
ethannicholasb3058bd2016-07-01 08:22:01 -070037
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -040038#include <fstream>
39
Ethan Nicholasa11035b2019-11-26 16:27:47 -050040#if !defined(SKSL_STANDALONE) & SK_SUPPORT_GPU
41#include "include/gpu/GrContextOptions.h"
42#include "src/gpu/GrShaderCaps.h"
43#endif
44
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -040045#ifdef SK_ENABLE_SPIRV_VALIDATION
46#include "spirv-tools/libspirv.hpp"
47#endif
48
Brian Osman3d87e9f2020-10-08 11:50:22 -040049#if defined(SKSL_STANDALONE)
Ethan Nicholasc18bb512020-07-28 14:46:53 -040050
Brian Osman3d87e9f2020-10-08 11:50:22 -040051// In standalone mode, we load the textual sksl source files. GN generates or copies these files
52// to the skslc executable directory. The "data" in this mode is just the filename.
53#define MODULE_DATA(name) MakeModulePath("sksl_" #name ".sksl")
54
55#else
56
57// At runtime, we load the dehydrated sksl data files. The data is a (pointer, size) pair.
Ethan Nicholasc18bb512020-07-28 14:46:53 -040058#include "src/sksl/generated/sksl_fp.dehydrated.sksl"
59#include "src/sksl/generated/sksl_frag.dehydrated.sksl"
60#include "src/sksl/generated/sksl_geom.dehydrated.sksl"
61#include "src/sksl/generated/sksl_gpu.dehydrated.sksl"
62#include "src/sksl/generated/sksl_interp.dehydrated.sksl"
63#include "src/sksl/generated/sksl_pipeline.dehydrated.sksl"
Brian Osmanb06301e2020-11-06 11:45:36 -050064#include "src/sksl/generated/sksl_public.dehydrated.sksl"
Ethan Nicholasc18bb512020-07-28 14:46:53 -040065#include "src/sksl/generated/sksl_vert.dehydrated.sksl"
66
Brian Osman3d87e9f2020-10-08 11:50:22 -040067#define MODULE_DATA(name) MakeModuleData(SKSL_INCLUDE_sksl_##name,\
68 SKSL_INCLUDE_sksl_##name##_LENGTH)
Ethan Nicholasc18bb512020-07-28 14:46:53 -040069
70#endif
Ethan Nicholas0d997662019-04-08 09:46:01 -040071
ethannicholasb3058bd2016-07-01 08:22:01 -070072namespace SkSL {
73
Brian Osman88cda172020-10-09 12:05:16 -040074class AutoSource {
75public:
76 AutoSource(Compiler* compiler, const String* source)
77 : fCompiler(compiler), fOldSource(fCompiler->fSource) {
78 fCompiler->fSource = source;
79 }
80
81 ~AutoSource() { fCompiler->fSource = fOldSource; }
82
83 Compiler* fCompiler;
84 const String* fOldSource;
85};
86
Brian Osmand7e76592020-11-02 12:26:22 -050087Compiler::Compiler(const ShaderCapsClass* caps, Flags flags)
88: fCaps(caps)
89, fFlags(flags)
John Stiles810c8cf2020-08-26 19:46:27 -040090, fContext(std::make_shared<Context>())
Ethan Nicholas6e1cbc02017-07-14 10:12:15 -040091, fErrorCount(0) {
John Stiles7c3515b2020-10-16 18:38:39 -040092 fRootSymbolTable = std::make_shared<SymbolTable>(this, /*builtin=*/true);
Brian Osmanb06301e2020-11-06 11:45:36 -050093 fPrivateSymbolTable = std::make_shared<SymbolTable>(fRootSymbolTable, /*builtin=*/true);
John Stiles4c412bc2020-10-13 11:19:41 -040094 fIRGenerator = std::make_unique<IRGenerator>(fContext.get(), &fInliner, *this);
ethannicholasb3058bd2016-07-01 08:22:01 -070095
Brian Osmanb06301e2020-11-06 11:45:36 -050096#define TYPE(t) fContext->f##t##_Type.get()
ethannicholasb3058bd2016-07-01 08:22:01 -070097
Brian Osmanb06301e2020-11-06 11:45:36 -050098 const SkSL::Symbol* rootTypes[] = {
99 TYPE(Void),
Brian Salomonbf7b6202016-11-11 16:08:03 -0500100
Brian Osmanb06301e2020-11-06 11:45:36 -0500101 TYPE( Float), TYPE( Float2), TYPE( Float3), TYPE( Float4),
102 TYPE( Half), TYPE( Half2), TYPE( Half3), TYPE( Half4),
103 TYPE( Int), TYPE( Int2), TYPE( Int3), TYPE( Int4),
104 TYPE( UInt), TYPE( UInt2), TYPE( UInt3), TYPE( UInt4),
105 TYPE( Short), TYPE( Short2), TYPE( Short3), TYPE( Short4),
106 TYPE(UShort), TYPE(UShort2), TYPE(UShort3), TYPE(UShort4),
107 TYPE( Byte), TYPE( Byte2), TYPE( Byte3), TYPE( Byte4),
108 TYPE( UByte), TYPE( UByte2), TYPE( UByte3), TYPE( UByte4),
109 TYPE( Bool), TYPE( Bool2), TYPE( Bool3), TYPE( Bool4),
Brian Salomon2a51de82016-11-16 12:06:01 -0500110
Brian Osmanb06301e2020-11-06 11:45:36 -0500111 TYPE(Float2x2), TYPE(Float2x3), TYPE(Float2x4),
112 TYPE(Float3x2), TYPE(Float3x3), TYPE(Float3x4),
113 TYPE(Float4x2), TYPE(Float4x3), TYPE(Float4x4),
Greg Daniel64773e62016-11-22 09:44:03 -0500114
Brian Osmanb06301e2020-11-06 11:45:36 -0500115 TYPE(Half2x2), TYPE(Half2x3), TYPE(Half2x4),
116 TYPE(Half3x2), TYPE(Half3x3), TYPE(Half3x4),
117 TYPE(Half4x2), TYPE(Half4x3), TYPE(Half4x4),
ethannicholasb3058bd2016-07-01 08:22:01 -0700118
Brian Osmanb06301e2020-11-06 11:45:36 -0500119 TYPE(GenType), TYPE(GenHType), TYPE(GenIType), TYPE(GenUType), TYPE(GenBType),
120 TYPE(Mat), TYPE(Vec),
121 TYPE(GVec), TYPE(GVec2), TYPE(GVec3), TYPE(GVec4),
122 TYPE(HVec), TYPE(IVec), TYPE(UVec), TYPE(SVec), TYPE(USVec),
123 TYPE(ByteVec), TYPE(UByteVec), TYPE(BVec),
124
125 TYPE(FragmentProcessor),
126 };
127
128 const SkSL::Symbol* privateTypes[] = {
129 TYPE(Sampler1D), TYPE(Sampler2D), TYPE(Sampler3D),
130 TYPE(SamplerExternalOES),
131 TYPE(SamplerCube),
132 TYPE(Sampler2DRect),
133 TYPE(Sampler1DArray), TYPE(Sampler2DArray), TYPE(SamplerCubeArray),
134 TYPE(SamplerBuffer),
135 TYPE(Sampler2DMS), TYPE(Sampler2DMSArray),
136
137 TYPE(ISampler2D),
138 TYPE(Image2D), TYPE(IImage2D),
139 TYPE(SubpassInput), TYPE(SubpassInputMS),
140
141 TYPE(GSampler1D), TYPE(GSampler2D), TYPE(GSampler3D),
142 TYPE(GSamplerCube),
143 TYPE(GSampler2DRect),
144 TYPE(GSampler1DArray), TYPE(GSampler2DArray), TYPE(GSamplerCubeArray),
145 TYPE(GSamplerBuffer),
146 TYPE(GSampler2DMS), TYPE(GSampler2DMSArray),
147
148 TYPE(Sampler1DShadow), TYPE(Sampler2DShadow), TYPE(SamplerCubeShadow),
149 TYPE(Sampler2DRectShadow),
150 TYPE(Sampler1DArrayShadow), TYPE(Sampler2DArrayShadow), TYPE(SamplerCubeArrayShadow),
151
152 TYPE(GSampler2DArrayShadow), TYPE(GSamplerCubeArrayShadow),
153 TYPE(Sampler),
154 TYPE(Texture2D),
155 };
156
157 for (const SkSL::Symbol* type : rootTypes) {
158 fRootSymbolTable->addWithoutOwnership(type);
159 }
160 for (const SkSL::Symbol* type : privateTypes) {
161 fPrivateSymbolTable->addWithoutOwnership(type);
162 }
163
164#undef TYPE
ethannicholasb3058bd2016-07-01 08:22:01 -0700165
Brian Osman3887a012020-09-30 13:22:27 -0400166 // sk_Caps is "builtin", but all references to it are resolved to Settings, so we don't need to
167 // treat it as builtin (ie, no need to clone it into the Program).
Brian Osmanb06301e2020-11-06 11:45:36 -0500168 fPrivateSymbolTable->add(
169 std::make_unique<Variable>(/*offset=*/-1,
John Stiles586df952020-11-12 18:27:13 -0500170 fIRGenerator->fModifiers->addToPool(Modifiers()),
Brian Osmanb06301e2020-11-06 11:45:36 -0500171 "sk_Caps",
172 fContext->fSkCaps_Type.get(),
173 /*builtin=*/false,
174 Variable::Storage::kGlobal));
Ethan Nicholas3605ace2016-11-21 15:59:48 -0500175
Brian Osman3d87e9f2020-10-08 11:50:22 -0400176 fRootModule = {fRootSymbolTable, /*fIntrinsics=*/nullptr};
Brian Osmanb06301e2020-11-06 11:45:36 -0500177 fPrivateModule = {fPrivateSymbolTable, /*fIntrinsics=*/nullptr};
John Stilesbc0c29e2020-09-28 13:13:40 -0400178
Brian Osmanb06301e2020-11-06 11:45:36 -0500179 fGPUModule = this->parseModule(Program::kFragment_Kind, MODULE_DATA(gpu), fPrivateModule);
Brian Osman3d87e9f2020-10-08 11:50:22 -0400180 fVertexModule = this->parseModule(Program::kVertex_Kind, MODULE_DATA(vert), fGPUModule);
181 fFragmentModule = this->parseModule(Program::kFragment_Kind, MODULE_DATA(frag), fGPUModule);
ethannicholasb3058bd2016-07-01 08:22:01 -0700182}
183
John Stilesdd13dba2020-10-29 10:45:34 -0400184Compiler::~Compiler() {}
ethannicholasb3058bd2016-07-01 08:22:01 -0700185
Brian Osman88cda172020-10-09 12:05:16 -0400186const ParsedModule& Compiler::loadGeometryModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400187 if (!fGeometryModule.fSymbols) {
188 fGeometryModule = this->parseModule(Program::kGeometry_Kind, MODULE_DATA(geom), fGPUModule);
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400189 }
Brian Osman88cda172020-10-09 12:05:16 -0400190 return fGeometryModule;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400191}
192
Brian Osman88cda172020-10-09 12:05:16 -0400193const ParsedModule& Compiler::loadFPModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400194 if (!fFPModule.fSymbols) {
195 fFPModule =
196 this->parseModule(Program::kFragmentProcessor_Kind, MODULE_DATA(fp), fGPUModule);
Brian Osman8e2ef022020-09-30 13:26:43 -0400197 }
Brian Osman88cda172020-10-09 12:05:16 -0400198 return fFPModule;
Brian Osman8e2ef022020-09-30 13:26:43 -0400199}
200
Brian Osmanb06301e2020-11-06 11:45:36 -0500201const ParsedModule& Compiler::loadPublicModule() {
202 if (!fPublicModule.fSymbols) {
203 fPublicModule = this->parseModule(Program::kGeneric_Kind, MODULE_DATA(public), fRootModule);
204 }
205 return fPublicModule;
206}
207
Brian Osman88cda172020-10-09 12:05:16 -0400208const ParsedModule& Compiler::loadPipelineModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400209 if (!fPipelineModule.fSymbols) {
Brian Osmanb06301e2020-11-06 11:45:36 -0500210 fPipelineModule = this->parseModule(Program::kPipelineStage_Kind, MODULE_DATA(pipeline),
211 this->loadPublicModule());
Brian Osmanf1319c32020-10-13 09:34:23 -0400212
213 // Add some aliases to the pipeline module so that it's friendlier, and more like GLSL
214 fPipelineModule.fSymbols->addAlias("shader", fContext->fFragmentProcessor_Type.get());
215
216 fPipelineModule.fSymbols->addAlias("vec2", fContext->fFloat2_Type.get());
217 fPipelineModule.fSymbols->addAlias("vec3", fContext->fFloat3_Type.get());
218 fPipelineModule.fSymbols->addAlias("vec4", fContext->fFloat4_Type.get());
219
220 fPipelineModule.fSymbols->addAlias("bvec2", fContext->fBool2_Type.get());
221 fPipelineModule.fSymbols->addAlias("bvec3", fContext->fBool3_Type.get());
222 fPipelineModule.fSymbols->addAlias("bvec4", fContext->fBool4_Type.get());
223
224 fPipelineModule.fSymbols->addAlias("mat2", fContext->fFloat2x2_Type.get());
225 fPipelineModule.fSymbols->addAlias("mat3", fContext->fFloat3x3_Type.get());
226 fPipelineModule.fSymbols->addAlias("mat4", fContext->fFloat4x4_Type.get());
227
228 fPipelineModule.fSymbols->addAlias("mat2x2", fContext->fFloat2x2_Type.get());
229 fPipelineModule.fSymbols->addAlias("mat2x3", fContext->fFloat2x3_Type.get());
230 fPipelineModule.fSymbols->addAlias("mat2x4", fContext->fFloat2x4_Type.get());
231
232 fPipelineModule.fSymbols->addAlias("mat3x2", fContext->fFloat3x2_Type.get());
233 fPipelineModule.fSymbols->addAlias("mat3x3", fContext->fFloat3x3_Type.get());
234 fPipelineModule.fSymbols->addAlias("mat3x4", fContext->fFloat3x4_Type.get());
235
236 fPipelineModule.fSymbols->addAlias("mat4x2", fContext->fFloat4x2_Type.get());
237 fPipelineModule.fSymbols->addAlias("mat4x3", fContext->fFloat4x3_Type.get());
238 fPipelineModule.fSymbols->addAlias("mat4x4", fContext->fFloat4x4_Type.get());
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400239 }
Brian Osman88cda172020-10-09 12:05:16 -0400240 return fPipelineModule;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400241}
242
Brian Osman88cda172020-10-09 12:05:16 -0400243const ParsedModule& Compiler::loadInterpreterModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400244 if (!fInterpreterModule.fSymbols) {
Brian Osmanb06301e2020-11-06 11:45:36 -0500245 fInterpreterModule = this->parseModule(Program::kGeneric_Kind, MODULE_DATA(interp),
246 this->loadPublicModule());
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400247 }
Brian Osman88cda172020-10-09 12:05:16 -0400248 return fInterpreterModule;
249}
250
251const ParsedModule& Compiler::moduleForProgramKind(Program::Kind kind) {
252 switch (kind) {
253 case Program::kVertex_Kind: return fVertexModule; break;
254 case Program::kFragment_Kind: return fFragmentModule; break;
255 case Program::kGeometry_Kind: return this->loadGeometryModule(); break;
256 case Program::kFragmentProcessor_Kind: return this->loadFPModule(); break;
257 case Program::kPipelineStage_Kind: return this->loadPipelineModule(); break;
258 case Program::kGeneric_Kind: return this->loadInterpreterModule(); break;
259 }
260 SkUNREACHABLE;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400261}
262
Brian Osman3d87e9f2020-10-08 11:50:22 -0400263LoadedModule Compiler::loadModule(Program::Kind kind,
264 ModuleData data,
265 std::shared_ptr<SymbolTable> base) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400266 if (!base) {
Brian Osmanb06301e2020-11-06 11:45:36 -0500267 // NOTE: This is a workaround. The only time 'base' is null is when dehydrating includes.
268 // In that case, skslc doesn't know which module it's preparing, nor what the correct base
269 // module is. We can't use 'Root', because many GPU intrinsics reference private types,
270 // like samplers or textures. Today, 'Private' does contain the union of all known types,
271 // so this is safe. If we ever have types that only exist in 'Public' (for example), this
272 // logic needs to be smarter (by choosing the correct base for the module we're compiling).
273 base = fPrivateSymbolTable;
Brian Osman3d87e9f2020-10-08 11:50:22 -0400274 }
275
276#if defined(SKSL_STANDALONE)
277 SkASSERT(data.fPath);
278 std::ifstream in(data.fPath);
Brian Osmane498b3c2020-09-23 14:42:11 -0400279 std::unique_ptr<String> text = std::make_unique<String>(std::istreambuf_iterator<char>(in),
280 std::istreambuf_iterator<char>());
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400281 if (in.rdstate()) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400282 printf("error reading %s\n", data.fPath);
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400283 abort();
284 }
Brian Osmane498b3c2020-09-23 14:42:11 -0400285 const String* source = fRootSymbolTable->takeOwnershipOfString(std::move(text));
Brian Osman88cda172020-10-09 12:05:16 -0400286 AutoSource as(this, source);
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400287 Program::Settings settings;
John Stiles881a10c2020-09-19 10:13:24 -0400288 SkASSERT(fIRGenerator->fCanInline);
289 fIRGenerator->fCanInline = false;
Brian Osman88cda172020-10-09 12:05:16 -0400290 ParsedModule baseModule = {base, /*fIntrinsics=*/nullptr};
Brian Osmand7e76592020-11-02 12:26:22 -0500291 IRGenerator::IRBundle ir =
292 fIRGenerator->convertProgram(kind, &settings, &standaloneCaps, baseModule,
293 /*isBuiltinCode=*/true, source->c_str(), source->length(),
294 /*externalValues=*/nullptr);
295 LoadedModule module = {std::move(ir.fSymbolTable), std::move(ir.fElements)};
John Stiles881a10c2020-09-19 10:13:24 -0400296 fIRGenerator->fCanInline = true;
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400297 if (this->fErrorCount) {
298 printf("Unexpected errors: %s\n", this->fErrorText.c_str());
Brian Osman3d87e9f2020-10-08 11:50:22 -0400299 SkDEBUGFAILF("%s %s\n", data.fPath, this->fErrorText.c_str());
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400300 }
Brian Osman88cda172020-10-09 12:05:16 -0400301 fModifiers.push_back(std::move(ir.fModifiers));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400302#else
303 SkASSERT(data.fData && (data.fSize != 0));
304 Rehydrator rehydrator(fContext.get(), fIRGenerator->fModifiers.get(), base, this,
305 data.fData, data.fSize);
Brian Osman88cda172020-10-09 12:05:16 -0400306 LoadedModule module = { rehydrator.symbolTable(), rehydrator.elements() };
Brian Osman3d87e9f2020-10-08 11:50:22 -0400307 fModifiers.push_back(fIRGenerator->releaseModifiers());
308#endif
309
310 return module;
311}
312
313ParsedModule Compiler::parseModule(Program::Kind kind, ModuleData data, const ParsedModule& base) {
314 auto [symbols, elements] = this->loadModule(kind, data, base.fSymbols);
315
316 // For modules that just declare (but don't define) intrinsic functions, there will be no new
317 // program elements. In that case, we can share our parent's intrinsic map:
318 if (elements.empty()) {
319 return {symbols, base.fIntrinsics};
320 }
321
322 auto intrinsics = std::make_shared<IRIntrinsicMap>(base.fIntrinsics.get());
323
324 // Now, transfer all of the program elements to an intrinsic map. This maps certain types of
325 // global objects to the declaring ProgramElement.
326 for (std::unique_ptr<ProgramElement>& element : elements) {
327 switch (element->kind()) {
328 case ProgramElement::Kind::kFunction: {
329 const FunctionDefinition& f = element->as<FunctionDefinition>();
Ethan Nicholas0a5d0962020-10-14 13:33:18 -0400330 SkASSERT(f.declaration().isBuiltin());
331 intrinsics->insertOrDie(f.declaration().description(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400332 break;
333 }
John Stiles569249b2020-11-03 12:18:22 -0500334 case ProgramElement::Kind::kFunctionPrototype: {
335 // These are already in the symbol table.
336 break;
337 }
Brian Osman3d87e9f2020-10-08 11:50:22 -0400338 case ProgramElement::Kind::kEnum: {
339 const Enum& e = element->as<Enum>();
340 SkASSERT(e.isBuiltin());
341 intrinsics->insertOrDie(e.typeName(), std::move(element));
342 break;
343 }
344 case ProgramElement::Kind::kGlobalVar: {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -0400345 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
346 const Variable& var = global.declaration()->as<VarDeclaration>().var();
347 SkASSERT(var.isBuiltin());
348 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400349 break;
350 }
351 case ProgramElement::Kind::kInterfaceBlock: {
Ethan Nicholaseaf47882020-10-15 10:10:08 -0400352 const Variable& var = element->as<InterfaceBlock>().variable();
353 SkASSERT(var.isBuiltin());
354 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400355 break;
356 }
357 default:
358 printf("Unsupported element: %s\n", element->description().c_str());
359 SkASSERT(false);
360 break;
361 }
362 }
363
364 return {symbols, std::move(intrinsics)};
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400365}
366
ethannicholas22f939e2016-10-13 13:25:34 -0700367// add the definition created by assigning to the lvalue to the definition set
Ethan Nicholas86a43402017-01-19 13:32:00 -0500368void Compiler::addDefinition(const Expression* lvalue, std::unique_ptr<Expression>* expr,
369 DefinitionMap* definitions) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400370 switch (lvalue->kind()) {
371 case Expression::Kind::kVariableReference: {
Ethan Nicholas78686922020-10-08 06:46:27 -0400372 const Variable& var = *lvalue->as<VariableReference>().variable();
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400373 if (var.storage() == Variable::Storage::kLocal) {
John Stiles796cdb72020-10-08 12:06:53 -0400374 definitions->set(&var, expr);
ethannicholas22f939e2016-10-13 13:25:34 -0700375 }
376 break;
377 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400378 case Expression::Kind::kSwizzle:
ethannicholas22f939e2016-10-13 13:25:34 -0700379 // We consider the variable written to as long as at least some of its components have
380 // been written to. This will lead to some false negatives (we won't catch it if you
381 // write to foo.x and then read foo.y), but being stricter could lead to false positives
Mike Klein6ad99092016-10-26 10:35:22 -0400382 // (we write to foo.x, and then pass foo to a function which happens to only read foo.x,
383 // but since we pass foo as a whole it is flagged as an error) unless we perform a much
ethannicholas22f939e2016-10-13 13:25:34 -0700384 // more complicated whole-program analysis. This is probably good enough.
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400385 this->addDefinition(lvalue->as<Swizzle>().base().get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400386 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
ethannicholas22f939e2016-10-13 13:25:34 -0700387 definitions);
388 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400389 case Expression::Kind::kIndex:
ethannicholas22f939e2016-10-13 13:25:34 -0700390 // see comments in Swizzle
Ethan Nicholas2a4952d2020-10-08 15:35:56 -0400391 this->addDefinition(lvalue->as<IndexExpression>().base().get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400392 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
ethannicholas22f939e2016-10-13 13:25:34 -0700393 definitions);
394 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400395 case Expression::Kind::kFieldAccess:
ethannicholas22f939e2016-10-13 13:25:34 -0700396 // see comments in Swizzle
Ethan Nicholas7a95b202020-10-09 11:55:40 -0400397 this->addDefinition(lvalue->as<FieldAccess>().base().get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400398 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
ethannicholas22f939e2016-10-13 13:25:34 -0700399 definitions);
400 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400401 case Expression::Kind::kTernary:
Ethan Nicholasa583b812018-01-18 13:32:11 -0500402 // To simplify analysis, we just pretend that we write to both sides of the ternary.
403 // This allows for false positives (meaning we fail to detect that a variable might not
404 // have been assigned), but is preferable to false negatives.
Ethan Nicholasdd218162020-10-08 05:48:01 -0400405 this->addDefinition(lvalue->as<TernaryExpression>().ifTrue().get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400406 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
Ethan Nicholasa583b812018-01-18 13:32:11 -0500407 definitions);
Ethan Nicholasdd218162020-10-08 05:48:01 -0400408 this->addDefinition(lvalue->as<TernaryExpression>().ifFalse().get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400409 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
Ethan Nicholasa583b812018-01-18 13:32:11 -0500410 definitions);
411 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400412 case Expression::Kind::kExternalValue:
Ethan Nicholas91164d12019-05-15 15:29:54 -0400413 break;
ethannicholas22f939e2016-10-13 13:25:34 -0700414 default:
415 // not an lvalue, can't happen
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400416 SkASSERT(false);
ethannicholas22f939e2016-10-13 13:25:34 -0700417 }
418}
419
420// add local variables defined by this node to the set
John Stiles796cdb72020-10-08 12:06:53 -0400421void Compiler::addDefinitions(const BasicBlock::Node& node, DefinitionMap* definitions) {
John Stiles70025e52020-09-28 16:08:58 -0400422 if (node.isExpression()) {
423 Expression* expr = node.expression()->get();
424 switch (expr->kind()) {
425 case Expression::Kind::kBinary: {
426 BinaryExpression* b = &expr->as<BinaryExpression>();
427 if (b->getOperator() == Token::Kind::TK_EQ) {
John Stiles2d4f9592020-10-30 10:29:12 -0400428 this->addDefinition(b->left().get(), &b->right(), definitions);
John Stiles70025e52020-09-28 16:08:58 -0400429 } else if (Compiler::IsAssignment(b->getOperator())) {
430 this->addDefinition(
John Stiles2d4f9592020-10-30 10:29:12 -0400431 b->left().get(),
John Stiles70025e52020-09-28 16:08:58 -0400432 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
433 definitions);
Ethan Nicholas86a43402017-01-19 13:32:00 -0500434
ethannicholas22f939e2016-10-13 13:25:34 -0700435 }
John Stiles70025e52020-09-28 16:08:58 -0400436 break;
ethannicholas22f939e2016-10-13 13:25:34 -0700437 }
John Stiles70025e52020-09-28 16:08:58 -0400438 case Expression::Kind::kFunctionCall: {
439 const FunctionCall& c = expr->as<FunctionCall>();
Brian Osman5bf3e202020-10-13 10:34:18 -0400440 const std::vector<const Variable*>& parameters = c.function().parameters();
Ethan Nicholased84b732020-10-08 11:45:44 -0400441 for (size_t i = 0; i < parameters.size(); ++i) {
442 if (parameters[i]->modifiers().fFlags & Modifiers::kOut_Flag) {
John Stiles70025e52020-09-28 16:08:58 -0400443 this->addDefinition(
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400444 c.arguments()[i].get(),
John Stiles70025e52020-09-28 16:08:58 -0400445 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
446 definitions);
447 }
448 }
449 break;
450 }
451 case Expression::Kind::kPrefix: {
452 const PrefixExpression* p = &expr->as<PrefixExpression>();
Ethan Nicholas444ccc62020-10-09 10:16:22 -0400453 if (p->getOperator() == Token::Kind::TK_MINUSMINUS ||
454 p->getOperator() == Token::Kind::TK_PLUSPLUS) {
John Stiles70025e52020-09-28 16:08:58 -0400455 this->addDefinition(
Ethan Nicholas444ccc62020-10-09 10:16:22 -0400456 p->operand().get(),
John Stiles70025e52020-09-28 16:08:58 -0400457 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
458 definitions);
459 }
460 break;
461 }
462 case Expression::Kind::kPostfix: {
463 const PostfixExpression* p = &expr->as<PostfixExpression>();
Ethan Nicholas444ccc62020-10-09 10:16:22 -0400464 if (p->getOperator() == Token::Kind::TK_MINUSMINUS ||
465 p->getOperator() == Token::Kind::TK_PLUSPLUS) {
John Stiles70025e52020-09-28 16:08:58 -0400466 this->addDefinition(
Ethan Nicholas444ccc62020-10-09 10:16:22 -0400467 p->operand().get(),
John Stiles70025e52020-09-28 16:08:58 -0400468 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
469 definitions);
470 }
471 break;
472 }
473 case Expression::Kind::kVariableReference: {
474 const VariableReference* v = &expr->as<VariableReference>();
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400475 if (v->refKind() != VariableReference::RefKind::kRead) {
John Stiles70025e52020-09-28 16:08:58 -0400476 this->addDefinition(
477 v,
478 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
479 definitions);
480 }
481 break;
482 }
483 default:
484 break;
ethannicholas22f939e2016-10-13 13:25:34 -0700485 }
John Stiles70025e52020-09-28 16:08:58 -0400486 } else if (node.isStatement()) {
487 Statement* stmt = node.statement()->get();
488 if (stmt->is<VarDeclaration>()) {
489 VarDeclaration& vd = stmt->as<VarDeclaration>();
Ethan Nicholasc51f33e2020-10-13 13:49:44 -0400490 if (vd.value()) {
491 definitions->set(&vd.var(), &vd.value());
ethannicholas22f939e2016-10-13 13:25:34 -0700492 }
ethannicholas22f939e2016-10-13 13:25:34 -0700493 }
494 }
495}
496
John Stilese6150002020-10-05 12:03:53 -0400497void Compiler::scanCFG(CFG* cfg, BlockId blockId, SkBitSet* processedSet) {
ethannicholas22f939e2016-10-13 13:25:34 -0700498 BasicBlock& block = cfg->fBlocks[blockId];
499
500 // compute definitions after this block
Ethan Nicholas86a43402017-01-19 13:32:00 -0500501 DefinitionMap after = block.fBefore;
ethannicholas22f939e2016-10-13 13:25:34 -0700502 for (const BasicBlock::Node& n : block.fNodes) {
503 this->addDefinitions(n, &after);
504 }
505
506 // propagate definitions to exits
507 for (BlockId exitId : block.fExits) {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400508 if (exitId == blockId) {
509 continue;
510 }
ethannicholas22f939e2016-10-13 13:25:34 -0700511 BasicBlock& exit = cfg->fBlocks[exitId];
John Stiles796cdb72020-10-08 12:06:53 -0400512 after.foreach([&](const Variable* var, std::unique_ptr<Expression>** e1Ptr) {
513 std::unique_ptr<Expression>* e1 = *e1Ptr;
514 std::unique_ptr<Expression>** exitDef = exit.fBefore.find(var);
515 if (!exitDef) {
John Stilese6150002020-10-05 12:03:53 -0400516 // exit has no definition for it, just copy it and reprocess exit block
517 processedSet->reset(exitId);
John Stiles796cdb72020-10-08 12:06:53 -0400518 exit.fBefore[var] = e1;
ethannicholas22f939e2016-10-13 13:25:34 -0700519 } else {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500520 // exit has a (possibly different) value already defined
John Stiles796cdb72020-10-08 12:06:53 -0400521 std::unique_ptr<Expression>* e2 = *exitDef;
ethannicholas22f939e2016-10-13 13:25:34 -0700522 if (e1 != e2) {
John Stilese6150002020-10-05 12:03:53 -0400523 // definition has changed, merge and reprocess the exit block
524 processedSet->reset(exitId);
Ethan Nicholasaf197692017-02-27 13:26:45 -0500525 if (e1 && e2) {
John Stiles796cdb72020-10-08 12:06:53 -0400526 *exitDef = (std::unique_ptr<Expression>*)&fContext->fDefined_Expression;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500527 } else {
John Stiles796cdb72020-10-08 12:06:53 -0400528 *exitDef = nullptr;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500529 }
ethannicholas22f939e2016-10-13 13:25:34 -0700530 }
531 }
John Stiles796cdb72020-10-08 12:06:53 -0400532 });
ethannicholas22f939e2016-10-13 13:25:34 -0700533 }
534}
535
536// returns a map which maps all local variables in the function to null, indicating that their value
537// is initially unknown
Ethan Nicholas86a43402017-01-19 13:32:00 -0500538static DefinitionMap compute_start_state(const CFG& cfg) {
539 DefinitionMap result;
Mike Klein6ad99092016-10-26 10:35:22 -0400540 for (const auto& block : cfg.fBlocks) {
541 for (const auto& node : block.fNodes) {
John Stiles70025e52020-09-28 16:08:58 -0400542 if (node.isStatement()) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400543 const Statement* s = node.statement()->get();
Brian Osmanc0213602020-10-06 14:43:32 -0400544 if (s->is<VarDeclaration>()) {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -0400545 result[&s->as<VarDeclaration>().var()] = nullptr;
ethannicholas22f939e2016-10-13 13:25:34 -0700546 }
547 }
548 }
549 }
550 return result;
551}
552
Ethan Nicholascb670962017-04-20 19:31:52 -0400553/**
554 * Returns true if assigning to this lvalue has no effect.
555 */
Brian Osman010ce6a2020-10-19 16:34:10 -0400556static bool is_dead(const Expression& lvalue, ProgramUsage* usage) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400557 switch (lvalue.kind()) {
558 case Expression::Kind::kVariableReference:
Brian Osman010ce6a2020-10-19 16:34:10 -0400559 return usage->isDead(*lvalue.as<VariableReference>().variable());
Ethan Nicholase6592142020-09-08 10:22:09 -0400560 case Expression::Kind::kSwizzle:
Brian Osman010ce6a2020-10-19 16:34:10 -0400561 return is_dead(*lvalue.as<Swizzle>().base(), usage);
Ethan Nicholase6592142020-09-08 10:22:09 -0400562 case Expression::Kind::kFieldAccess:
Brian Osman010ce6a2020-10-19 16:34:10 -0400563 return is_dead(*lvalue.as<FieldAccess>().base(), usage);
Ethan Nicholase6592142020-09-08 10:22:09 -0400564 case Expression::Kind::kIndex: {
John Stilesa5a97b42020-08-18 11:19:07 -0400565 const IndexExpression& idx = lvalue.as<IndexExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400566 return is_dead(*idx.base(), usage) &&
Ethan Nicholas2a4952d2020-10-08 15:35:56 -0400567 !idx.index()->hasProperty(Expression::Property::kSideEffects);
Ethan Nicholascb670962017-04-20 19:31:52 -0400568 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400569 case Expression::Kind::kTernary: {
John Stilesa5a97b42020-08-18 11:19:07 -0400570 const TernaryExpression& t = lvalue.as<TernaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400571 return !t.test()->hasSideEffects() &&
572 is_dead(*t.ifTrue(), usage) &&
573 is_dead(*t.ifFalse(), usage);
Ethan Nicholasa583b812018-01-18 13:32:11 -0500574 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400575 case Expression::Kind::kExternalValue:
Ethan Nicholas91164d12019-05-15 15:29:54 -0400576 return false;
Ethan Nicholascb670962017-04-20 19:31:52 -0400577 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500578#ifdef SK_DEBUG
Ethan Nicholascb670962017-04-20 19:31:52 -0400579 ABORT("invalid lvalue: %s\n", lvalue.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500580#endif
581 return false;
Ethan Nicholascb670962017-04-20 19:31:52 -0400582 }
583}
ethannicholas22f939e2016-10-13 13:25:34 -0700584
Ethan Nicholascb670962017-04-20 19:31:52 -0400585/**
586 * Returns true if this is an assignment which can be collapsed down to just the right hand side due
587 * to a dead target and lack of side effects on the left hand side.
588 */
Brian Osman010ce6a2020-10-19 16:34:10 -0400589static bool dead_assignment(const BinaryExpression& b, ProgramUsage* usage) {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400590 if (!Compiler::IsAssignment(b.getOperator())) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400591 return false;
592 }
John Stiles2d4f9592020-10-30 10:29:12 -0400593 return is_dead(*b.left(), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400594}
595
596void Compiler::computeDataFlow(CFG* cfg) {
597 cfg->fBlocks[cfg->fStart].fBefore = compute_start_state(*cfg);
John Stilese6150002020-10-05 12:03:53 -0400598
599 // We set bits in the "processed" set after a block has been scanned.
600 SkBitSet processedSet(cfg->fBlocks.size());
601 while (SkBitSet::OptionalIndex blockId = processedSet.findFirstUnset()) {
602 processedSet.set(*blockId);
603 this->scanCFG(cfg, *blockId, &processedSet);
ethannicholas22f939e2016-10-13 13:25:34 -0700604 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400605}
606
607/**
608 * Attempts to replace the expression pointed to by iter with a new one (in both the CFG and the
609 * IR). If the expression can be cleanly removed, returns true and updates the iterator to point to
610 * the newly-inserted element. Otherwise updates only the IR and returns false (and the CFG will
611 * need to be regenerated).
612 */
John Stilesafbf8992020-08-18 10:08:21 -0400613static bool try_replace_expression(BasicBlock* b,
614 std::vector<BasicBlock::Node>::iterator* iter,
615 std::unique_ptr<Expression>* newExpression) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400616 std::unique_ptr<Expression>* target = (*iter)->expression();
617 if (!b->tryRemoveExpression(iter)) {
618 *target = std::move(*newExpression);
619 return false;
620 }
621 *target = std::move(*newExpression);
622 return b->tryInsertExpression(iter, target);
623}
624
625/**
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400626 * Returns true if the expression is a constant numeric literal with the specified value, or a
627 * constant vector with all elements equal to the specified value.
Ethan Nicholascb670962017-04-20 19:31:52 -0400628 */
Ethan Nicholasa3f22f12020-10-01 12:13:17 -0400629template <typename T = SKSL_FLOAT>
John Stiles9d944232020-08-19 09:56:49 -0400630static bool is_constant(const Expression& expr, T value) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400631 switch (expr.kind()) {
632 case Expression::Kind::kIntLiteral:
Ethan Nicholase96cdd12020-09-28 16:27:18 -0400633 return expr.as<IntLiteral>().value() == value;
John Stiles9d944232020-08-19 09:56:49 -0400634
Ethan Nicholase6592142020-09-08 10:22:09 -0400635 case Expression::Kind::kFloatLiteral:
Ethan Nicholasa3f22f12020-10-01 12:13:17 -0400636 return expr.as<FloatLiteral>().value() == value;
John Stiles9d944232020-08-19 09:56:49 -0400637
Ethan Nicholase6592142020-09-08 10:22:09 -0400638 case Expression::Kind::kConstructor: {
John Stiles9d944232020-08-19 09:56:49 -0400639 const Constructor& constructor = expr.as<Constructor>();
640 if (constructor.isCompileTimeConstant()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400641 const Type& constructorType = constructor.type();
642 bool isFloat = constructorType.columns() > 1
643 ? constructorType.componentType().isFloat()
644 : constructorType.isFloat();
645 switch (constructorType.typeKind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400646 case Type::TypeKind::kVector:
Ethan Nicholas30d30222020-09-11 12:27:26 -0400647 for (int i = 0; i < constructorType.columns(); ++i) {
John Stiles9d944232020-08-19 09:56:49 -0400648 if (isFloat) {
649 if (constructor.getFVecComponent(i) != value) {
650 return false;
651 }
652 } else {
653 if (constructor.getIVecComponent(i) != value) {
654 return false;
655 }
656 }
Ethan Nicholasd188c182019-06-10 15:55:38 -0400657 }
John Stiles9d944232020-08-19 09:56:49 -0400658 return true;
659
Ethan Nicholase6592142020-09-08 10:22:09 -0400660 case Type::TypeKind::kScalar:
Ethan Nicholasf70f0442020-09-29 12:41:35 -0400661 SkASSERT(constructor.arguments().size() == 1);
662 return is_constant<T>(*constructor.arguments()[0], value);
John Stiles9d944232020-08-19 09:56:49 -0400663
664 default:
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400665 return false;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400666 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400667 }
668 return false;
669 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400670 default:
671 return false;
672 }
673}
674
675/**
676 * Collapses the binary expression pointed to by iter down to just the right side (in both the IR
677 * and CFG structures).
678 */
John Stilesafbf8992020-08-18 10:08:21 -0400679static void delete_left(BasicBlock* b,
680 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400681 Compiler::OptimizationContext* optimizationContext) {
682 optimizationContext->fUpdated = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400683 std::unique_ptr<Expression>* target = (*iter)->expression();
John Stilesa5a97b42020-08-18 11:19:07 -0400684 BinaryExpression& bin = (*target)->as<BinaryExpression>();
John Stiles2d4f9592020-10-30 10:29:12 -0400685 Expression& left = *bin.left();
686 std::unique_ptr<Expression>& rightPointer = bin.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400687 SkASSERT(!left.hasSideEffects());
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400688 bool result;
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400689 if (bin.getOperator() == Token::Kind::TK_EQ) {
690 result = b->tryRemoveLValueBefore(iter, &left);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400691 } else {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400692 result = b->tryRemoveExpressionBefore(iter, &left);
Ethan Nicholascb670962017-04-20 19:31:52 -0400693 }
Brian Osman010ce6a2020-10-19 16:34:10 -0400694 // Remove references within LHS.
695 optimizationContext->fUsage->remove(&left);
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400696 *target = std::move(rightPointer);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400697 if (!result) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400698 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400699 return;
700 }
701 if (*iter == b->fNodes.begin()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400702 optimizationContext->fNeedsRescan = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400703 return;
704 }
705 --(*iter);
John Stiles70025e52020-09-28 16:08:58 -0400706 if (!(*iter)->isExpression() || (*iter)->expression() != &rightPointer) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400707 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400708 return;
709 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400710 *iter = b->fNodes.erase(*iter);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400711 SkASSERT((*iter)->expression() == target);
Ethan Nicholascb670962017-04-20 19:31:52 -0400712}
713
714/**
715 * Collapses the binary expression pointed to by iter down to just the left side (in both the IR and
716 * CFG structures).
717 */
John Stilesafbf8992020-08-18 10:08:21 -0400718static void delete_right(BasicBlock* b,
719 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400720 Compiler::OptimizationContext* optimizationContext) {
721 optimizationContext->fUpdated = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400722 std::unique_ptr<Expression>* target = (*iter)->expression();
John Stilesa5a97b42020-08-18 11:19:07 -0400723 BinaryExpression& bin = (*target)->as<BinaryExpression>();
John Stiles2d4f9592020-10-30 10:29:12 -0400724 std::unique_ptr<Expression>& leftPointer = bin.left();
725 Expression& right = *bin.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400726 SkASSERT(!right.hasSideEffects());
Brian Osman010ce6a2020-10-19 16:34:10 -0400727 // Remove references within RHS.
728 optimizationContext->fUsage->remove(&right);
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400729 if (!b->tryRemoveExpressionBefore(iter, &right)) {
730 *target = std::move(leftPointer);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400731 optimizationContext->fNeedsRescan = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400732 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400733 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400734 *target = std::move(leftPointer);
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400735 if (*iter == b->fNodes.begin()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400736 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400737 return;
738 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400739 --(*iter);
John Stiles70025e52020-09-28 16:08:58 -0400740 if ((!(*iter)->isExpression() || (*iter)->expression() != &leftPointer)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400741 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400742 return;
743 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400744 *iter = b->fNodes.erase(*iter);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400745 SkASSERT((*iter)->expression() == target);
Ethan Nicholascb670962017-04-20 19:31:52 -0400746}
747
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400748/**
749 * Constructs the specified type using a single argument.
750 */
Ethan Nicholas30d30222020-09-11 12:27:26 -0400751static std::unique_ptr<Expression> construct(const Type* type, std::unique_ptr<Expression> v) {
John Stiles8e3b6be2020-10-13 11:14:08 -0400752 ExpressionArray args;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400753 args.push_back(std::move(v));
Ethan Nicholase6592142020-09-08 10:22:09 -0400754 std::unique_ptr<Expression> result = std::make_unique<Constructor>(-1, type, std::move(args));
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400755 return result;
756}
757
758/**
759 * Used in the implementations of vectorize_left and vectorize_right. Given a vector type and an
760 * expression x, deletes the expression pointed to by iter and replaces it with <type>(x).
761 */
762static void vectorize(BasicBlock* b,
763 std::vector<BasicBlock::Node>::iterator* iter,
764 const Type& type,
765 std::unique_ptr<Expression>* otherExpression,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400766 Compiler::OptimizationContext* optimizationContext) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400767 SkASSERT((*(*iter)->expression())->kind() == Expression::Kind::kBinary);
768 SkASSERT(type.typeKind() == Type::TypeKind::kVector);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400769 SkASSERT((*otherExpression)->type().typeKind() == Type::TypeKind::kScalar);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400770 optimizationContext->fUpdated = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400771 std::unique_ptr<Expression>* target = (*iter)->expression();
772 if (!b->tryRemoveExpression(iter)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400773 *target = construct(&type, std::move(*otherExpression));
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400774 optimizationContext->fNeedsRescan = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400775 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400776 *target = construct(&type, std::move(*otherExpression));
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400777 if (!b->tryInsertExpression(iter, target)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400778 optimizationContext->fNeedsRescan = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400779 }
780 }
781}
782
783/**
784 * Given a binary expression of the form x <op> vec<n>(y), deletes the right side and vectorizes the
785 * left to yield vec<n>(x).
786 */
787static void vectorize_left(BasicBlock* b,
788 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400789 Compiler::OptimizationContext* optimizationContext) {
John Stilesa5a97b42020-08-18 11:19:07 -0400790 BinaryExpression& bin = (*(*iter)->expression())->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400791 // Remove references within RHS. Vectorization of LHS doesn't change reference counts.
John Stiles2d4f9592020-10-30 10:29:12 -0400792 optimizationContext->fUsage->remove(bin.right().get());
793 vectorize(b, iter, bin.right()->type(), &bin.left(), optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400794}
795
796/**
797 * Given a binary expression of the form vec<n>(x) <op> y, deletes the left side and vectorizes the
798 * right to yield vec<n>(y).
799 */
800static void vectorize_right(BasicBlock* b,
801 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400802 Compiler::OptimizationContext* optimizationContext) {
John Stilesa5a97b42020-08-18 11:19:07 -0400803 BinaryExpression& bin = (*(*iter)->expression())->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400804 // Remove references within LHS. Vectorization of RHS doesn't change reference counts.
John Stiles2d4f9592020-10-30 10:29:12 -0400805 optimizationContext->fUsage->remove(bin.left().get());
806 vectorize(b, iter, bin.left()->type(), &bin.right(), optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400807}
808
809// Mark that an expression which we were writing to is no longer being written to
John Stilesa5a97b42020-08-18 11:19:07 -0400810static void clear_write(Expression& expr) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400811 switch (expr.kind()) {
812 case Expression::Kind::kVariableReference: {
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400813 expr.as<VariableReference>().setRefKind(VariableReference::RefKind::kRead);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400814 break;
815 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400816 case Expression::Kind::kFieldAccess:
Ethan Nicholas7a95b202020-10-09 11:55:40 -0400817 clear_write(*expr.as<FieldAccess>().base());
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400818 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400819 case Expression::Kind::kSwizzle:
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400820 clear_write(*expr.as<Swizzle>().base());
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400821 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400822 case Expression::Kind::kIndex:
Ethan Nicholas2a4952d2020-10-08 15:35:56 -0400823 clear_write(*expr.as<IndexExpression>().base());
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400824 break;
825 default:
826 ABORT("shouldn't be writing to this kind of expression\n");
827 break;
828 }
829}
830
Ethan Nicholascb670962017-04-20 19:31:52 -0400831void Compiler::simplifyExpression(DefinitionMap& definitions,
832 BasicBlock& b,
833 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400834 OptimizationContext* optimizationContext) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400835 Expression* expr = (*iter)->expression()->get();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400836 SkASSERT(expr);
Ethan Nicholascb670962017-04-20 19:31:52 -0400837 if ((*iter)->fConstantPropagation) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400838 std::unique_ptr<Expression> optimized = expr->constantPropagate(*fIRGenerator,
839 definitions);
Ethan Nicholascb670962017-04-20 19:31:52 -0400840 if (optimized) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400841 optimizationContext->fUpdated = true;
Ethan Nicholas30d30222020-09-11 12:27:26 -0400842 optimized = fIRGenerator->coerce(std::move(optimized), expr->type());
Ethan Nicholas1d881522020-09-11 09:32:54 -0400843 SkASSERT(optimized);
Brian Osman010ce6a2020-10-19 16:34:10 -0400844 // Remove references within 'expr', add references within 'optimized'
845 optimizationContext->fUsage->replace(expr, optimized.get());
Ethan Nicholascb670962017-04-20 19:31:52 -0400846 if (!try_replace_expression(&b, iter, &optimized)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400847 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400848 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400849 }
John Stiles70025e52020-09-28 16:08:58 -0400850 SkASSERT((*iter)->isExpression());
Ethan Nicholascb670962017-04-20 19:31:52 -0400851 expr = (*iter)->expression()->get();
Ethan Nicholascb670962017-04-20 19:31:52 -0400852 }
853 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400854 switch (expr->kind()) {
855 case Expression::Kind::kVariableReference: {
John Stilesa5a97b42020-08-18 11:19:07 -0400856 const VariableReference& ref = expr->as<VariableReference>();
Ethan Nicholas78686922020-10-08 06:46:27 -0400857 const Variable* var = ref.variable();
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400858 if (ref.refKind() != VariableReference::RefKind::kWrite &&
859 ref.refKind() != VariableReference::RefKind::kPointer &&
860 var->storage() == Variable::Storage::kLocal && !definitions[var] &&
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400861 optimizationContext->fSilences.find(var) == optimizationContext->fSilences.end()) {
862 optimizationContext->fSilences.insert(var);
Ethan Nicholas82a62d22017-11-07 14:42:10 +0000863 this->error(expr->fOffset,
Ethan Nicholase2c49992020-10-05 11:49:11 -0400864 "'" + var->name() + "' has not been assigned");
Ethan Nicholascb670962017-04-20 19:31:52 -0400865 }
866 break;
867 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400868 case Expression::Kind::kTernary: {
John Stiles403a3632020-08-20 12:11:48 -0400869 TernaryExpression* t = &expr->as<TernaryExpression>();
Ethan Nicholasdd218162020-10-08 05:48:01 -0400870 if (t->test()->is<BoolLiteral>()) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400871 // ternary has a constant test, replace it with either the true or
872 // false branch
Ethan Nicholasdd218162020-10-08 05:48:01 -0400873 if (t->test()->as<BoolLiteral>().value()) {
Brian Osman010ce6a2020-10-19 16:34:10 -0400874 (*iter)->setExpression(std::move(t->ifTrue()), optimizationContext->fUsage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400875 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -0400876 (*iter)->setExpression(std::move(t->ifFalse()), optimizationContext->fUsage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400877 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400878 optimizationContext->fUpdated = true;
879 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -0400880 }
881 break;
882 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400883 case Expression::Kind::kBinary: {
John Stiles403a3632020-08-20 12:11:48 -0400884 BinaryExpression* bin = &expr->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400885 if (dead_assignment(*bin, optimizationContext->fUsage)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400886 delete_left(&b, iter, optimizationContext);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400887 break;
888 }
John Stiles2d4f9592020-10-30 10:29:12 -0400889 Expression& left = *bin->left();
890 Expression& right = *bin->right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400891 const Type& leftType = left.type();
892 const Type& rightType = right.type();
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400893 // collapse useless expressions like x * 1 or x + 0
Ethan Nicholas30d30222020-09-11 12:27:26 -0400894 if (((leftType.typeKind() != Type::TypeKind::kScalar) &&
895 (leftType.typeKind() != Type::TypeKind::kVector)) ||
896 ((rightType.typeKind() != Type::TypeKind::kScalar) &&
897 (rightType.typeKind() != Type::TypeKind::kVector))) {
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400898 break;
899 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400900 switch (bin->getOperator()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400901 case Token::Kind::TK_STAR:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400902 if (is_constant(left, 1)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400903 if (leftType.typeKind() == Type::TypeKind::kVector &&
904 rightType.typeKind() == Type::TypeKind::kScalar) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400905 // float4(1) * x -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400906 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400907 } else {
908 // 1 * x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400909 // 1 * float4(x) -> float4(x)
910 // float4(1) * float4(x) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400911 delete_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400912 }
913 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400914 else if (is_constant(left, 0)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400915 if (leftType.typeKind() == Type::TypeKind::kScalar &&
916 rightType.typeKind() == Type::TypeKind::kVector &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400917 !right.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400918 // 0 * float4(x) -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400919 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400920 } else {
921 // 0 * x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400922 // float4(0) * x -> float4(0)
923 // float4(0) * float4(x) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400924 if (!right.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400925 delete_right(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500926 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400927 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400928 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400929 else if (is_constant(right, 1)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400930 if (leftType.typeKind() == Type::TypeKind::kScalar &&
931 rightType.typeKind() == Type::TypeKind::kVector) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400932 // x * float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400933 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400934 } else {
935 // x * 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400936 // float4(x) * 1 -> float4(x)
937 // float4(x) * float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400938 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400939 }
940 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400941 else if (is_constant(right, 0)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400942 if (leftType.typeKind() == Type::TypeKind::kVector &&
943 rightType.typeKind() == Type::TypeKind::kScalar &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400944 !left.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400945 // float4(x) * 0 -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400946 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400947 } else {
948 // x * 0 -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400949 // x * float4(0) -> float4(0)
950 // float4(x) * float4(0) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400951 if (!left.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400952 delete_left(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500953 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400954 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400955 }
956 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400957 case Token::Kind::TK_PLUS:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400958 if (is_constant(left, 0)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400959 if (leftType.typeKind() == Type::TypeKind::kVector &&
960 rightType.typeKind() == Type::TypeKind::kScalar) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400961 // float4(0) + x -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400962 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400963 } else {
964 // 0 + x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400965 // 0 + float4(x) -> float4(x)
966 // float4(0) + float4(x) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400967 delete_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400968 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400969 } else if (is_constant(right, 0)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400970 if (leftType.typeKind() == Type::TypeKind::kScalar &&
971 rightType.typeKind() == Type::TypeKind::kVector) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400972 // x + float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400973 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400974 } else {
975 // x + 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400976 // float4(x) + 0 -> float4(x)
977 // float4(x) + float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400978 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400979 }
Ethan Nicholas56e42712017-04-21 10:23:37 -0400980 }
981 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400982 case Token::Kind::TK_MINUS:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400983 if (is_constant(right, 0)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400984 if (leftType.typeKind() == Type::TypeKind::kScalar &&
985 rightType.typeKind() == Type::TypeKind::kVector) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400986 // x - float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400987 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400988 } else {
989 // x - 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400990 // float4(x) - 0 -> float4(x)
991 // float4(x) - float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400992 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400993 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400994 }
995 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400996 case Token::Kind::TK_SLASH:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400997 if (is_constant(right, 1)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400998 if (leftType.typeKind() == Type::TypeKind::kScalar &&
999 rightType.typeKind() == Type::TypeKind::kVector) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001000 // x / float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001001 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001002 } else {
1003 // x / 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001004 // float4(x) / 1 -> float4(x)
1005 // float4(x) / float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001006 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001007 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001008 } else if (is_constant(left, 0)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001009 if (leftType.typeKind() == Type::TypeKind::kScalar &&
1010 rightType.typeKind() == Type::TypeKind::kVector &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001011 !right.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001012 // 0 / float4(x) -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001013 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001014 } else {
1015 // 0 / x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001016 // float4(0) / x -> float4(0)
1017 // float4(0) / float4(x) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001018 if (!right.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001019 delete_right(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -05001020 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001021 }
1022 }
1023 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001024 case Token::Kind::TK_PLUSEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001025 if (is_constant(right, 0)) {
1026 clear_write(left);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001027 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001028 }
1029 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001030 case Token::Kind::TK_MINUSEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001031 if (is_constant(right, 0)) {
1032 clear_write(left);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001033 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001034 }
1035 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001036 case Token::Kind::TK_STAREQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001037 if (is_constant(right, 1)) {
1038 clear_write(left);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001039 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001040 }
1041 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001042 case Token::Kind::TK_SLASHEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001043 if (is_constant(right, 1)) {
1044 clear_write(left);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001045 delete_right(&b, iter, optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001046 }
1047 break;
1048 default:
1049 break;
1050 }
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001051 break;
1052 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001053 case Expression::Kind::kSwizzle: {
John Stiles403a3632020-08-20 12:11:48 -04001054 Swizzle& s = expr->as<Swizzle>();
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001055 // detect identity swizzles like foo.rgba
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001056 if ((int) s.components().size() == s.base()->type().columns()) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001057 bool identity = true;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001058 for (int i = 0; i < (int) s.components().size(); ++i) {
1059 if (s.components()[i] != i) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001060 identity = false;
1061 break;
1062 }
1063 }
1064 if (identity) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001065 optimizationContext->fUpdated = true;
Brian Osman010ce6a2020-10-19 16:34:10 -04001066 // No fUsage change: foo.rgba and foo have equivalent reference counts
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001067 if (!try_replace_expression(&b, iter, &s.base())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001068 optimizationContext->fNeedsRescan = true;
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001069 return;
1070 }
John Stiles70025e52020-09-28 16:08:58 -04001071 SkASSERT((*iter)->isExpression());
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001072 break;
1073 }
1074 }
1075 // detect swizzles of swizzles, e.g. replace foo.argb.r000 with foo.a000
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001076 if (s.base()->kind() == Expression::Kind::kSwizzle) {
1077 Swizzle& base = s.base()->as<Swizzle>();
John Stiles750109b2020-10-30 13:45:46 -04001078 ComponentArray final;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001079 for (int c : s.components()) {
1080 final.push_back(base.components()[c]);
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001081 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001082 optimizationContext->fUpdated = true;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001083 std::unique_ptr<Expression> replacement(new Swizzle(*fContext, base.base()->clone(),
John Stiles750109b2020-10-30 13:45:46 -04001084 final));
Brian Osman010ce6a2020-10-19 16:34:10 -04001085 // No fUsage change: foo.gbr.gbr and foo.brg have equivalent reference counts
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001086 if (!try_replace_expression(&b, iter, &replacement)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001087 optimizationContext->fNeedsRescan = true;
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001088 return;
1089 }
John Stiles70025e52020-09-28 16:08:58 -04001090 SkASSERT((*iter)->isExpression());
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001091 }
John Stiles30212b72020-06-11 17:55:07 -04001092 break;
Ethan Nicholascb670962017-04-20 19:31:52 -04001093 }
1094 default:
1095 break;
1096 }
1097}
1098
John Stiles92219b42020-06-15 12:32:24 -04001099// Returns true if this statement could potentially execute a break at the current level. We ignore
1100// nested loops and switches, since any breaks inside of them will merely break the loop / switch.
John Stilesb92641c2020-08-31 18:09:01 -04001101static bool contains_conditional_break(Statement& stmt) {
1102 class ContainsConditionalBreak : public ProgramVisitor {
1103 public:
1104 bool visitStatement(const Statement& stmt) override {
Ethan Nicholase6592142020-09-08 10:22:09 -04001105 switch (stmt.kind()) {
1106 case Statement::Kind::kBlock:
John Stilesb92641c2020-08-31 18:09:01 -04001107 return this->INHERITED::visitStatement(stmt);
1108
Ethan Nicholase6592142020-09-08 10:22:09 -04001109 case Statement::Kind::kBreak:
John Stilesb92641c2020-08-31 18:09:01 -04001110 return fInConditional > 0;
1111
Ethan Nicholase6592142020-09-08 10:22:09 -04001112 case Statement::Kind::kIf: {
John Stilesb92641c2020-08-31 18:09:01 -04001113 ++fInConditional;
1114 bool result = this->INHERITED::visitStatement(stmt);
1115 --fInConditional;
1116 return result;
1117 }
1118
1119 default:
1120 return false;
1121 }
1122 }
1123
1124 int fInConditional = 0;
1125 using INHERITED = ProgramVisitor;
1126 };
1127
1128 return ContainsConditionalBreak{}.visitStatement(stmt);
John Stiles92219b42020-06-15 12:32:24 -04001129}
1130
Ethan Nicholas5005a222018-08-24 13:06:27 -04001131// returns true if this statement definitely executes a break at the current level (we ignore
1132// nested loops and switches, since any breaks inside of them will merely break the loop / switch)
John Stilesb92641c2020-08-31 18:09:01 -04001133static bool contains_unconditional_break(Statement& stmt) {
1134 class ContainsUnconditionalBreak : public ProgramVisitor {
1135 public:
1136 bool visitStatement(const Statement& stmt) override {
Ethan Nicholase6592142020-09-08 10:22:09 -04001137 switch (stmt.kind()) {
1138 case Statement::Kind::kBlock:
John Stilesb92641c2020-08-31 18:09:01 -04001139 return this->INHERITED::visitStatement(stmt);
1140
Ethan Nicholase6592142020-09-08 10:22:09 -04001141 case Statement::Kind::kBreak:
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001142 return true;
John Stilesb92641c2020-08-31 18:09:01 -04001143
1144 default:
1145 return false;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001146 }
John Stilesb92641c2020-08-31 18:09:01 -04001147 }
John Stiles92219b42020-06-15 12:32:24 -04001148
John Stilesb92641c2020-08-31 18:09:01 -04001149 using INHERITED = ProgramVisitor;
1150 };
John Stiles92219b42020-06-15 12:32:24 -04001151
John Stilesb92641c2020-08-31 18:09:01 -04001152 return ContainsUnconditionalBreak{}.visitStatement(stmt);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001153}
1154
John Stiles8f2a0cf2020-10-13 12:48:21 -04001155static void move_all_but_break(std::unique_ptr<Statement>& stmt, StatementArray* target) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001156 switch (stmt->kind()) {
1157 case Statement::Kind::kBlock: {
John Stiles92219b42020-06-15 12:32:24 -04001158 // Recurse into the block.
1159 Block& block = static_cast<Block&>(*stmt);
1160
John Stiles8f2a0cf2020-10-13 12:48:21 -04001161 StatementArray blockStmts;
John Stilesf4bda742020-10-14 16:57:41 -04001162 blockStmts.reserve_back(block.children().size());
Ethan Nicholas7bd60432020-09-25 14:31:59 -04001163 for (std::unique_ptr<Statement>& stmt : block.children()) {
1164 move_all_but_break(stmt, &blockStmts);
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001165 }
John Stiles92219b42020-06-15 12:32:24 -04001166
1167 target->push_back(std::make_unique<Block>(block.fOffset, std::move(blockStmts),
Ethan Nicholas7bd60432020-09-25 14:31:59 -04001168 block.symbolTable(), block.isScope()));
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001169 break;
John Stiles92219b42020-06-15 12:32:24 -04001170 }
1171
Ethan Nicholase6592142020-09-08 10:22:09 -04001172 case Statement::Kind::kBreak:
John Stiles92219b42020-06-15 12:32:24 -04001173 // Do not append a break to the target.
1174 break;
1175
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001176 default:
John Stiles92219b42020-06-15 12:32:24 -04001177 // Append normal statements to the target.
1178 target->push_back(std::move(stmt));
1179 break;
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001180 }
1181}
1182
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001183// Returns a block containing all of the statements that will be run if the given case matches
1184// (which, owing to the statements being owned by unique_ptrs, means the switch itself will be
1185// broken by this call and must then be discarded).
1186// Returns null (and leaves the switch unmodified) if no such simple reduction is possible, such as
1187// when break statements appear inside conditionals.
John Stiles92219b42020-06-15 12:32:24 -04001188static std::unique_ptr<Statement> block_for_case(SwitchStatement* switchStatement,
1189 SwitchCase* caseToCapture) {
1190 // We have to be careful to not move any of the pointers until after we're sure we're going to
1191 // succeed, so before we make any changes at all, we check the switch-cases to decide on a plan
1192 // of action. First, find the switch-case we are interested in.
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001193 auto iter = switchStatement->cases().begin();
1194 for (; iter != switchStatement->cases().end(); ++iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001195 if (iter->get() == caseToCapture) {
John Stiles92219b42020-06-15 12:32:24 -04001196 break;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001197 }
John Stiles92219b42020-06-15 12:32:24 -04001198 }
1199
1200 // Next, walk forward through the rest of the switch. If we find a conditional break, we're
1201 // stuck and can't simplify at all. If we find an unconditional break, we have a range of
1202 // statements that we can use for simplification.
1203 auto startIter = iter;
1204 Statement* unconditionalBreakStmt = nullptr;
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001205 for (; iter != switchStatement->cases().end(); ++iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001206 for (std::unique_ptr<Statement>& stmt : (*iter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001207 if (contains_conditional_break(*stmt)) {
1208 // We can't reduce switch-cases to a block when they have conditional breaks.
1209 return nullptr;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001210 }
John Stiles92219b42020-06-15 12:32:24 -04001211
1212 if (contains_unconditional_break(*stmt)) {
1213 // We found an unconditional break. We can use this block, but we need to strip
1214 // out the break statement.
1215 unconditionalBreakStmt = stmt.get();
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001216 break;
1217 }
1218 }
John Stiles92219b42020-06-15 12:32:24 -04001219
1220 if (unconditionalBreakStmt != nullptr) {
1221 break;
1222 }
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001223 }
John Stiles92219b42020-06-15 12:32:24 -04001224
1225 // We fell off the bottom of the switch or encountered a break. We know the range of statements
1226 // that we need to move over, and we know it's safe to do so.
John Stiles8f2a0cf2020-10-13 12:48:21 -04001227 StatementArray caseStmts;
John Stiles92219b42020-06-15 12:32:24 -04001228
1229 // We can move over most of the statements as-is.
1230 while (startIter != iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001231 for (std::unique_ptr<Statement>& stmt : (*startIter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001232 caseStmts.push_back(std::move(stmt));
1233 }
1234 ++startIter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001235 }
John Stiles92219b42020-06-15 12:32:24 -04001236
1237 // If we found an unconditional break at the end, we need to move what we can while avoiding
1238 // that break.
1239 if (unconditionalBreakStmt != nullptr) {
John Stiles2d4f9592020-10-30 10:29:12 -04001240 for (std::unique_ptr<Statement>& stmt : (*startIter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001241 if (stmt.get() == unconditionalBreakStmt) {
1242 move_all_but_break(stmt, &caseStmts);
1243 unconditionalBreakStmt = nullptr;
1244 break;
1245 }
1246
1247 caseStmts.push_back(std::move(stmt));
1248 }
1249 }
1250
1251 SkASSERT(unconditionalBreakStmt == nullptr); // Verify that we fixed the unconditional break.
1252
1253 // Return our newly-synthesized block.
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001254 return std::make_unique<Block>(/*offset=*/-1, std::move(caseStmts), switchStatement->symbols());
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001255}
1256
Ethan Nicholascb670962017-04-20 19:31:52 -04001257void Compiler::simplifyStatement(DefinitionMap& definitions,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001258 BasicBlock& b,
1259 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001260 OptimizationContext* optimizationContext) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001261 ProgramUsage* usage = optimizationContext->fUsage;
Ethan Nicholascb670962017-04-20 19:31:52 -04001262 Statement* stmt = (*iter)->statement()->get();
Ethan Nicholase6592142020-09-08 10:22:09 -04001263 switch (stmt->kind()) {
1264 case Statement::Kind::kVarDeclaration: {
John Stilesa5a97b42020-08-18 11:19:07 -04001265 const auto& varDecl = stmt->as<VarDeclaration>();
Brian Osman010ce6a2020-10-19 16:34:10 -04001266 if (usage->isDead(varDecl.var()) &&
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001267 (!varDecl.value() ||
1268 !varDecl.value()->hasSideEffects())) {
1269 if (varDecl.value()) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001270 SkASSERT((*iter)->statement()->get() == stmt);
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001271 if (!b.tryRemoveExpressionBefore(iter, varDecl.value().get())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001272 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001273 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001274 }
Brian Osman010ce6a2020-10-19 16:34:10 -04001275 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001276 optimizationContext->fUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001277 }
1278 break;
1279 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001280 case Statement::Kind::kIf: {
John Stilesa5a97b42020-08-18 11:19:07 -04001281 IfStatement& i = stmt->as<IfStatement>();
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001282 if (i.test()->kind() == Expression::Kind::kBoolLiteral) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001283 // constant if, collapse down to a single branch
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001284 if (i.test()->as<BoolLiteral>().value()) {
1285 SkASSERT(i.ifTrue());
Brian Osman010ce6a2020-10-19 16:34:10 -04001286 (*iter)->setStatement(std::move(i.ifTrue()), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001287 } else {
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001288 if (i.ifFalse()) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001289 (*iter)->setStatement(std::move(i.ifFalse()), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001290 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -04001291 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001292 }
1293 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001294 optimizationContext->fUpdated = true;
1295 optimizationContext->fNeedsRescan = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001296 break;
1297 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001298 if (i.ifFalse() && i.ifFalse()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001299 // else block doesn't do anything, remove it
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001300 i.ifFalse().reset();
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001301 optimizationContext->fUpdated = true;
1302 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001303 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001304 if (!i.ifFalse() && i.ifTrue()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001305 // if block doesn't do anything, no else block
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001306 if (i.test()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001307 // test has side effects, keep it
Brian Osman010ce6a2020-10-19 16:34:10 -04001308 (*iter)->setStatement(
1309 std::make_unique<ExpressionStatement>(std::move(i.test())), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -04001310 } else {
1311 // no if, no else, no test side effects, kill the whole if
1312 // statement
Brian Osman010ce6a2020-10-19 16:34:10 -04001313 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -04001314 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001315 optimizationContext->fUpdated = true;
1316 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001317 }
1318 break;
1319 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001320 case Statement::Kind::kSwitch: {
John Stilesa5a97b42020-08-18 11:19:07 -04001321 SwitchStatement& s = stmt->as<SwitchStatement>();
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001322 int64_t switchValue;
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001323 if (fIRGenerator->getConstantInt(*s.value(), &switchValue)) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001324 // switch is constant, replace it with the case that matches
1325 bool found = false;
1326 SwitchCase* defaultCase = nullptr;
John Stiles2d4f9592020-10-30 10:29:12 -04001327 for (const std::unique_ptr<SwitchCase>& c : s.cases()) {
1328 if (!c->value()) {
1329 defaultCase = c.get();
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001330 continue;
1331 }
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001332 int64_t caseValue;
John Stiles2d4f9592020-10-30 10:29:12 -04001333 SkAssertResult(fIRGenerator->getConstantInt(*c->value(), &caseValue));
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001334 if (caseValue == switchValue) {
John Stiles2d4f9592020-10-30 10:29:12 -04001335 std::unique_ptr<Statement> newBlock = block_for_case(&s, c.get());
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001336 if (newBlock) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001337 (*iter)->setStatement(std::move(newBlock), usage);
John Stiles9d944232020-08-19 09:56:49 -04001338 found = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001339 break;
1340 } else {
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001341 if (s.isStatic() && !(fFlags & kPermitInvalidStaticTests_Flag) &&
1342 optimizationContext->fSilences.find(&s) ==
1343 optimizationContext->fSilences.end()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001344 this->error(s.fOffset,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001345 "static switch contains non-static conditional break");
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001346 optimizationContext->fSilences.insert(&s);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001347 }
1348 return; // can't simplify
1349 }
1350 }
1351 }
1352 if (!found) {
1353 // no matching case. use default if it exists, or kill the whole thing
1354 if (defaultCase) {
1355 std::unique_ptr<Statement> newBlock = block_for_case(&s, defaultCase);
1356 if (newBlock) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001357 (*iter)->setStatement(std::move(newBlock), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001358 } else {
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001359 if (s.isStatic() && !(fFlags & kPermitInvalidStaticTests_Flag) &&
1360 optimizationContext->fSilences.find(&s) ==
1361 optimizationContext->fSilences.end()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001362 this->error(s.fOffset,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001363 "static switch contains non-static conditional break");
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001364 optimizationContext->fSilences.insert(&s);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001365 }
1366 return; // can't simplify
1367 }
1368 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -04001369 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001370 }
1371 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001372 optimizationContext->fUpdated = true;
1373 optimizationContext->fNeedsRescan = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001374 }
1375 break;
1376 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001377 case Statement::Kind::kExpression: {
John Stilesa5a97b42020-08-18 11:19:07 -04001378 ExpressionStatement& e = stmt->as<ExpressionStatement>();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001379 SkASSERT((*iter)->statement()->get() == &e);
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001380 if (!e.expression()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001381 // Expression statement with no side effects, kill it
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001382 if (!b.tryRemoveExpressionBefore(iter, e.expression().get())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001383 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001384 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001385 SkASSERT((*iter)->statement()->get() == stmt);
Brian Osman010ce6a2020-10-19 16:34:10 -04001386 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001387 optimizationContext->fUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001388 }
1389 break;
1390 }
1391 default:
1392 break;
1393 }
1394}
1395
Brian Osman010ce6a2020-10-19 16:34:10 -04001396bool Compiler::scanCFG(FunctionDefinition& f, ProgramUsage* usage) {
John Stiles0cc193a2020-09-09 09:39:34 -04001397 bool madeChanges = false;
1398
Ethan Nicholascb670962017-04-20 19:31:52 -04001399 CFG cfg = CFGGenerator().getCFG(f);
1400 this->computeDataFlow(&cfg);
ethannicholas22f939e2016-10-13 13:25:34 -07001401
1402 // check for unreachable code
1403 for (size_t i = 0; i < cfg.fBlocks.size(); i++) {
John Stiles0cc193a2020-09-09 09:39:34 -04001404 const BasicBlock& block = cfg.fBlocks[i];
John Stiles61e75e32020-10-01 15:42:37 -04001405 if (i != cfg.fStart && !block.fIsReachable && block.fNodes.size()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001406 int offset;
John Stiles0cc193a2020-09-09 09:39:34 -04001407 const BasicBlock::Node& node = block.fNodes[0];
John Stiles70025e52020-09-28 16:08:58 -04001408 if (node.isStatement()) {
1409 offset = (*node.statement())->fOffset;
1410 } else {
1411 offset = (*node.expression())->fOffset;
1412 if ((*node.expression())->is<BoolLiteral>()) {
1413 // Function inlining can generate do { ... } while(false) loops which always
1414 // break, so the boolean condition is considered unreachable. Since not being
1415 // able to reach a literal is a non-issue in the first place, we don't report an
1416 // error in this case.
1417 continue;
1418 }
Ethan Nicholas86a43402017-01-19 13:32:00 -05001419 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001420 this->error(offset, String("unreachable"));
ethannicholas22f939e2016-10-13 13:25:34 -07001421 }
1422 }
1423 if (fErrorCount) {
John Stiles0cc193a2020-09-09 09:39:34 -04001424 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001425 }
1426
Ethan Nicholascb670962017-04-20 19:31:52 -04001427 // check for dead code & undefined variables, perform constant propagation
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001428 OptimizationContext optimizationContext;
Brian Osman010ce6a2020-10-19 16:34:10 -04001429 optimizationContext.fUsage = usage;
John Stiles7d3f0892020-11-03 11:35:01 -05001430 SkBitSet eliminatedBlockIds(cfg.fBlocks.size());
Ethan Nicholascb670962017-04-20 19:31:52 -04001431 do {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001432 if (optimizationContext.fNeedsRescan) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001433 cfg = CFGGenerator().getCFG(f);
1434 this->computeDataFlow(&cfg);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001435 optimizationContext.fNeedsRescan = false;
Ethan Nicholas113628d2017-02-02 16:11:39 -05001436 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001437
John Stiles7d3f0892020-11-03 11:35:01 -05001438 eliminatedBlockIds.reset();
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001439 optimizationContext.fUpdated = false;
John Stiles7d3f0892020-11-03 11:35:01 -05001440
1441 for (BlockId blockId = 0; blockId < cfg.fBlocks.size(); ++blockId) {
1442 if (eliminatedBlockIds.test(blockId)) {
1443 // We reached a block ID that might have been eliminated. Be cautious and rescan.
1444 optimizationContext.fUpdated = true;
1445 optimizationContext.fNeedsRescan = true;
1446 break;
1447 }
1448
1449 BasicBlock& b = cfg.fBlocks[blockId];
1450 if (blockId > 0 && !b.fIsReachable) {
Ethan Nicholas1de14812020-06-19 15:32:49 -04001451 // Block was reachable before optimization, but has since become unreachable. In
1452 // addition to being dead code, it's broken - since control flow can't reach it, no
1453 // prior variable definitions can reach it, and therefore variables might look to
Brian Osmanc0213602020-10-06 14:43:32 -04001454 // have not been properly assigned. Kill it by replacing all statements with Nops.
Ethan Nicholas1de14812020-06-19 15:32:49 -04001455 for (BasicBlock::Node& node : b.fNodes) {
John Stiles70025e52020-09-28 16:08:58 -04001456 if (node.isStatement() && !(*node.statement())->is<Nop>()) {
John Stiles7d3f0892020-11-03 11:35:01 -05001457 // Eliminating a node runs the risk of eliminating that node's exits as
1458 // well. Keep track of this and do a rescan if we are about to access one
1459 // of these.
1460 for (BlockId id : b.fExits) {
1461 eliminatedBlockIds.set(id);
1462 }
Brian Osman010ce6a2020-10-19 16:34:10 -04001463 node.setStatement(std::make_unique<Nop>(), usage);
John Stiles0cc193a2020-09-09 09:39:34 -04001464 madeChanges = true;
Ethan Nicholas1de14812020-06-19 15:32:49 -04001465 }
1466 }
1467 continue;
1468 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001469 DefinitionMap definitions = b.fBefore;
1470
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001471 for (auto iter = b.fNodes.begin(); iter != b.fNodes.end() &&
1472 !optimizationContext.fNeedsRescan; ++iter) {
John Stiles70025e52020-09-28 16:08:58 -04001473 if (iter->isExpression()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001474 this->simplifyExpression(definitions, b, &iter, &optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001475 } else {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001476 this->simplifyStatement(definitions, b, &iter, &optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001477 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001478 if (optimizationContext.fNeedsRescan) {
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001479 break;
1480 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001481 this->addDefinitions(*iter, &definitions);
1482 }
Brian Osman01a3eb42020-09-14 11:32:49 -04001483
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001484 if (optimizationContext.fNeedsRescan) {
Brian Osman01a3eb42020-09-14 11:32:49 -04001485 break;
1486 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001487 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001488 madeChanges |= optimizationContext.fUpdated;
1489 } while (optimizationContext.fUpdated);
1490 SkASSERT(!optimizationContext.fNeedsRescan);
ethannicholas22f939e2016-10-13 13:25:34 -07001491
Ethan Nicholas91a10532017-06-22 11:24:38 -04001492 // verify static ifs & switches, clean up dead variable decls
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001493 for (BasicBlock& b : cfg.fBlocks) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001494 for (auto iter = b.fNodes.begin(); iter != b.fNodes.end() &&
1495 !optimizationContext.fNeedsRescan;) {
John Stiles70025e52020-09-28 16:08:58 -04001496 if (iter->isStatement()) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001497 const Statement& s = **iter->statement();
Ethan Nicholase6592142020-09-08 10:22:09 -04001498 switch (s.kind()) {
1499 case Statement::Kind::kIf:
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001500 if (s.as<IfStatement>().isStatic() &&
Ethan Nicholas6e1cbc02017-07-14 10:12:15 -04001501 !(fFlags & kPermitInvalidStaticTests_Flag)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001502 this->error(s.fOffset, "static if has non-static test");
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001503 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001504 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001505 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001506 case Statement::Kind::kSwitch:
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001507 if (s.as<SwitchStatement>().isStatic() &&
1508 !(fFlags & kPermitInvalidStaticTests_Flag) &&
1509 optimizationContext.fSilences.find(&s) ==
1510 optimizationContext.fSilences.end()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001511 this->error(s.fOffset, "static switch has non-static test");
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001512 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001513 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001514 break;
1515 default:
Ethan Nicholas91a10532017-06-22 11:24:38 -04001516 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001517 break;
1518 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001519 } else {
1520 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001521 }
1522 }
1523 }
1524
ethannicholas22f939e2016-10-13 13:25:34 -07001525 // check for missing return
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04001526 if (f.declaration().returnType() != *fContext->fVoid_Type) {
John Stiles61e75e32020-10-01 15:42:37 -04001527 if (cfg.fBlocks[cfg.fExit].fIsReachable) {
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04001528 this->error(f.fOffset, String("function '" + String(f.declaration().name()) +
Ethan Nicholasdb80f692019-11-22 14:06:12 -05001529 "' can exit without returning a value"));
ethannicholas22f939e2016-10-13 13:25:34 -07001530 }
1531 }
John Stiles0cc193a2020-09-09 09:39:34 -04001532
1533 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001534}
1535
Brian Osman32d53552020-09-23 13:55:20 -04001536std::unique_ptr<Program> Compiler::convertProgram(
1537 Program::Kind kind,
1538 String text,
1539 const Program::Settings& settings,
1540 const std::vector<std::unique_ptr<ExternalValue>>* externalValues) {
1541 SkASSERT(!externalValues || (kind == Program::kGeneric_Kind));
Ethan Nicholas91164d12019-05-15 15:29:54 -04001542
ethannicholasb3058bd2016-07-01 08:22:01 -07001543 fErrorText = "";
1544 fErrorCount = 0;
Brian Osmand7e76592020-11-02 12:26:22 -05001545 fInliner.reset(fContext.get(), fIRGenerator->fModifiers.get(), &settings, fCaps);
Brian Osman88cda172020-10-09 12:05:16 -04001546
1547 // Not using AutoSource, because caller is likely to call errorText() if we fail to compile
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001548 std::unique_ptr<String> textPtr(new String(std::move(text)));
1549 fSource = textPtr.get();
Brian Osman88cda172020-10-09 12:05:16 -04001550
1551 const ParsedModule& baseModule = this->moduleForProgramKind(kind);
1552
John Stiles5c7bb322020-10-22 11:09:15 -04001553 // Enable node pooling while converting and optimizing the program for a performance boost.
1554 // The Program will take ownership of the pool.
John Stiles2d68ea32020-10-22 15:42:27 -04001555 std::unique_ptr<Pool> pool = Pool::Create();
1556 pool->attachToThread();
Brian Osmand7e76592020-11-02 12:26:22 -05001557 IRGenerator::IRBundle ir = fIRGenerator->convertProgram(
1558 kind, &settings, fCaps, baseModule, /*isBuiltinCode=*/false, textPtr->c_str(),
1559 textPtr->size(), externalValues);
John Stiles5c7bb322020-10-22 11:09:15 -04001560 auto program = std::make_unique<Program>(kind,
1561 std::move(textPtr),
1562 settings,
Brian Osmand7e76592020-11-02 12:26:22 -05001563 fCaps,
John Stiles5c7bb322020-10-22 11:09:15 -04001564 fContext,
1565 std::move(ir.fElements),
1566 std::move(ir.fModifiers),
1567 std::move(ir.fSymbolTable),
1568 std::move(pool),
1569 ir.fInputs);
1570 bool success = false;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001571 if (fErrorCount) {
John Stiles5c7bb322020-10-22 11:09:15 -04001572 // Do not return programs that failed to compile.
1573 } else if (settings.fOptimize && !this->optimize(*program)) {
1574 // Do not return programs that failed to optimize.
1575 } else {
1576 // We have a successful program!
1577 success = true;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001578 }
John Stiles5c7bb322020-10-22 11:09:15 -04001579
1580 program->fPool->detachFromThread();
1581 return success ? std::move(program) : nullptr;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001582}
1583
Ethan Nicholas00543112018-07-31 09:44:36 -04001584bool Compiler::optimize(Program& program) {
1585 SkASSERT(!fErrorCount);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001586 fIRGenerator->fKind = program.fKind;
1587 fIRGenerator->fSettings = &program.fSettings;
Brian Osman010ce6a2020-10-19 16:34:10 -04001588 ProgramUsage* usage = program.fUsage.get();
John Stiles7954d6c2020-09-01 10:53:02 -04001589
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001590 while (fErrorCount == 0) {
1591 bool madeChanges = false;
John Stiles7954d6c2020-09-01 10:53:02 -04001592
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001593 // Scan and optimize based on the control-flow graph for each function.
Brian Osman1179fcf2020-10-08 16:04:40 -04001594 for (const auto& element : program.elements()) {
1595 if (element->is<FunctionDefinition>()) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001596 madeChanges |= this->scanCFG(element->as<FunctionDefinition>(), usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001597 }
1598 }
1599
1600 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stiles881a10c2020-09-19 10:13:24 -04001601 madeChanges |= fInliner.analyze(program);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001602
1603 // Remove dead functions. We wait until after analysis so that we still report errors,
1604 // even in unused code.
1605 if (program.fSettings.fRemoveDeadFunctions) {
1606 program.fElements.erase(
1607 std::remove_if(program.fElements.begin(),
1608 program.fElements.end(),
1609 [&](const std::unique_ptr<ProgramElement>& element) {
1610 if (!element->is<FunctionDefinition>()) {
1611 return false;
1612 }
1613 const auto& fn = element->as<FunctionDefinition>();
Brian Osman2e25ff42020-10-15 10:32:04 -04001614 bool dead = fn.declaration().name() != "main" &&
Brian Osman010ce6a2020-10-19 16:34:10 -04001615 usage->get(fn.declaration()) == 0;
1616 if (dead) {
1617 madeChanges = true;
1618 usage->remove(*element);
1619 }
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001620 return dead;
1621 }),
1622 program.fElements.end());
1623 }
1624
1625 if (program.fKind != Program::kFragmentProcessor_Kind) {
Brian Osmanc0213602020-10-06 14:43:32 -04001626 // Remove declarations of dead global variables
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001627 program.fElements.erase(
1628 std::remove_if(program.fElements.begin(), program.fElements.end(),
1629 [&](const std::unique_ptr<ProgramElement>& element) {
Brian Osmanc0213602020-10-06 14:43:32 -04001630 if (!element->is<GlobalVarDeclaration>()) {
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001631 return false;
1632 }
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001633 const auto& global = element->as<GlobalVarDeclaration>();
1634 const auto& varDecl =
1635 global.declaration()->as<VarDeclaration>();
Brian Osman010ce6a2020-10-19 16:34:10 -04001636 bool dead = usage->isDead(varDecl.var());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001637 madeChanges |= dead;
1638 return dead;
1639 }),
1640 program.fElements.end());
1641 }
John Stiles73a6bff2020-09-09 13:40:37 -04001642
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001643 if (!madeChanges) {
1644 break;
Ethan Nicholas0dc80872019-02-08 15:46:24 -05001645 }
Ethan Nicholas00543112018-07-31 09:44:36 -04001646 }
1647 return fErrorCount == 0;
1648}
1649
Brian Osmanfb32ddf2019-06-18 10:14:20 -04001650#if defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
1651
Ethan Nicholas00543112018-07-31 09:44:36 -04001652bool Compiler::toSPIRV(Program& program, OutputStream& out) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001653#ifdef SK_ENABLE_SPIRV_VALIDATION
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001654 StringStream buffer;
Brian Osman88cda172020-10-09 12:05:16 -04001655 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001656 SPIRVCodeGenerator cg(fContext.get(), &program, this, &buffer);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001657 bool result = cg.generateCode();
Ethan Nicholasba9a04f2020-11-06 09:28:04 -05001658 if (result && program.fSettings.fValidateSPIRV) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001659 spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_0);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001660 const String& data = buffer.str();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001661 SkASSERT(0 == data.size() % 4);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001662 auto dumpmsg = [](spv_message_level_t, const char*, const spv_position_t&, const char* m) {
1663 SkDebugf("SPIR-V validation error: %s\n", m);
1664 };
1665 tools.SetMessageConsumer(dumpmsg);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001666 // Verify that the SPIR-V we produced is valid. If this SkASSERT fails, check the logs prior
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001667 // to the failure to see the validation errors.
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001668 SkAssertResult(tools.Validate((const uint32_t*) data.c_str(), data.size() / 4));
Ethan Nicholas762466e2017-06-29 10:03:38 -04001669 out.write(data.c_str(), data.size());
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001670 }
1671#else
Brian Osman88cda172020-10-09 12:05:16 -04001672 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001673 SPIRVCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001674 bool result = cg.generateCode();
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001675#endif
Ethan Nicholasce33f102016-12-09 17:22:59 -05001676 return result;
1677}
1678
Ethan Nicholas00543112018-07-31 09:44:36 -04001679bool Compiler::toSPIRV(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001680 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001681 bool result = this->toSPIRV(program, buffer);
1682 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001683 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001684 }
1685 return result;
1686}
1687
Ethan Nicholas00543112018-07-31 09:44:36 -04001688bool Compiler::toGLSL(Program& program, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001689 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001690 GLSLCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001691 bool result = cg.generateCode();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001692 return result;
1693}
1694
Ethan Nicholas00543112018-07-31 09:44:36 -04001695bool Compiler::toGLSL(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001696 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001697 bool result = this->toGLSL(program, buffer);
1698 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001699 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001700 }
1701 return result;
1702}
1703
Brian Osmanc0243912020-02-19 15:35:26 -05001704bool Compiler::toHLSL(Program& program, String* out) {
1705 String spirv;
1706 if (!this->toSPIRV(program, &spirv)) {
1707 return false;
1708 }
1709
1710 return SPIRVtoHLSL(spirv, out);
1711}
1712
Ethan Nicholas00543112018-07-31 09:44:36 -04001713bool Compiler::toMetal(Program& program, OutputStream& out) {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001714 MetalCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholascc305772017-10-13 16:17:45 -04001715 bool result = cg.generateCode();
Ethan Nicholascc305772017-10-13 16:17:45 -04001716 return result;
1717}
1718
Ethan Nicholas00543112018-07-31 09:44:36 -04001719bool Compiler::toMetal(Program& program, String* out) {
Timothy Liangb8eeb802018-07-23 16:46:16 -04001720 StringStream buffer;
1721 bool result = this->toMetal(program, buffer);
1722 if (result) {
1723 *out = buffer.str();
1724 }
1725 return result;
1726}
1727
Greg Daniela28ea672020-09-25 11:12:56 -04001728#if defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04001729bool Compiler::toCPP(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001730 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001731 CPPCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001732 bool result = cg.generateCode();
Ethan Nicholas762466e2017-06-29 10:03:38 -04001733 return result;
1734}
1735
Ethan Nicholas00543112018-07-31 09:44:36 -04001736bool Compiler::toH(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001737 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001738 HCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001739 bool result = cg.generateCode();
Ethan Nicholas00543112018-07-31 09:44:36 -04001740 return result;
1741}
Greg Daniela28ea672020-09-25 11:12:56 -04001742#endif // defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04001743
Ethan Nicholas2a479a52020-08-18 16:29:45 -04001744#endif // defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
Brian Osman2e29ab52019-09-20 12:19:11 -04001745
1746#if !defined(SKSL_STANDALONE) && SK_SUPPORT_GPU
Brian Osmana4b91692020-08-10 14:26:16 -04001747bool Compiler::toPipelineStage(Program& program, PipelineStageArgs* outArgs) {
Brian Osman88cda172020-10-09 12:05:16 -04001748 AutoSource as(this, program.fSource.get());
Ethan Nicholas00543112018-07-31 09:44:36 -04001749 StringStream buffer;
Brian Osman300fe1d2020-01-23 15:42:43 -05001750 PipelineStageCodeGenerator cg(fContext.get(), &program, this, &buffer, outArgs);
Ethan Nicholas00543112018-07-31 09:44:36 -04001751 bool result = cg.generateCode();
Ethan Nicholas00543112018-07-31 09:44:36 -04001752 if (result) {
Brian Osman107c6662019-12-30 15:02:30 -05001753 outArgs->fCode = buffer.str();
Ethan Nicholas00543112018-07-31 09:44:36 -04001754 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001755 return result;
1756}
Brian Osmanfb32ddf2019-06-18 10:14:20 -04001757#endif
1758
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001759std::unique_ptr<ByteCode> Compiler::toByteCode(Program& program) {
Mike Klein853d4ed2020-08-20 00:41:00 +00001760#if defined(SK_ENABLE_SKSL_INTERPRETER)
Brian Osman88cda172020-10-09 12:05:16 -04001761 AutoSource as(this, program.fSource.get());
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001762 std::unique_ptr<ByteCode> result(new ByteCode());
Brian Osmanb08cc022020-04-02 11:38:40 -04001763 ByteCodeGenerator cg(fContext.get(), &program, this, result.get());
1764 bool success = cg.generateCode();
Brian Osmanb08cc022020-04-02 11:38:40 -04001765 if (success) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001766 return result;
1767 }
Mike Klein853d4ed2020-08-20 00:41:00 +00001768#else
1769 ABORT("ByteCode interpreter not enabled");
1770#endif
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001771 return nullptr;
1772}
1773
Brian Osman401a0092020-09-10 14:47:24 -04001774const char* Compiler::OperatorName(Token::Kind op) {
1775 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001776 case Token::Kind::TK_PLUS: return "+";
1777 case Token::Kind::TK_MINUS: return "-";
1778 case Token::Kind::TK_STAR: return "*";
1779 case Token::Kind::TK_SLASH: return "/";
1780 case Token::Kind::TK_PERCENT: return "%";
1781 case Token::Kind::TK_SHL: return "<<";
1782 case Token::Kind::TK_SHR: return ">>";
1783 case Token::Kind::TK_LOGICALNOT: return "!";
1784 case Token::Kind::TK_LOGICALAND: return "&&";
1785 case Token::Kind::TK_LOGICALOR: return "||";
1786 case Token::Kind::TK_LOGICALXOR: return "^^";
1787 case Token::Kind::TK_BITWISENOT: return "~";
1788 case Token::Kind::TK_BITWISEAND: return "&";
1789 case Token::Kind::TK_BITWISEOR: return "|";
1790 case Token::Kind::TK_BITWISEXOR: return "^";
1791 case Token::Kind::TK_EQ: return "=";
1792 case Token::Kind::TK_EQEQ: return "==";
1793 case Token::Kind::TK_NEQ: return "!=";
1794 case Token::Kind::TK_LT: return "<";
1795 case Token::Kind::TK_GT: return ">";
1796 case Token::Kind::TK_LTEQ: return "<=";
1797 case Token::Kind::TK_GTEQ: return ">=";
1798 case Token::Kind::TK_PLUSEQ: return "+=";
1799 case Token::Kind::TK_MINUSEQ: return "-=";
1800 case Token::Kind::TK_STAREQ: return "*=";
1801 case Token::Kind::TK_SLASHEQ: return "/=";
1802 case Token::Kind::TK_PERCENTEQ: return "%=";
1803 case Token::Kind::TK_SHLEQ: return "<<=";
1804 case Token::Kind::TK_SHREQ: return ">>=";
1805 case Token::Kind::TK_LOGICALANDEQ: return "&&=";
1806 case Token::Kind::TK_LOGICALOREQ: return "||=";
1807 case Token::Kind::TK_LOGICALXOREQ: return "^^=";
1808 case Token::Kind::TK_BITWISEANDEQ: return "&=";
1809 case Token::Kind::TK_BITWISEOREQ: return "|=";
1810 case Token::Kind::TK_BITWISEXOREQ: return "^=";
1811 case Token::Kind::TK_PLUSPLUS: return "++";
1812 case Token::Kind::TK_MINUSMINUS: return "--";
1813 case Token::Kind::TK_COMMA: return ",";
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001814 default:
Brian Osman401a0092020-09-10 14:47:24 -04001815 ABORT("unsupported operator: %d\n", (int) op);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001816 }
1817}
1818
1819
1820bool Compiler::IsAssignment(Token::Kind op) {
1821 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001822 case Token::Kind::TK_EQ: // fall through
1823 case Token::Kind::TK_PLUSEQ: // fall through
1824 case Token::Kind::TK_MINUSEQ: // fall through
1825 case Token::Kind::TK_STAREQ: // fall through
1826 case Token::Kind::TK_SLASHEQ: // fall through
1827 case Token::Kind::TK_PERCENTEQ: // fall through
1828 case Token::Kind::TK_SHLEQ: // fall through
1829 case Token::Kind::TK_SHREQ: // fall through
1830 case Token::Kind::TK_BITWISEOREQ: // fall through
1831 case Token::Kind::TK_BITWISEXOREQ: // fall through
1832 case Token::Kind::TK_BITWISEANDEQ: // fall through
1833 case Token::Kind::TK_LOGICALOREQ: // fall through
1834 case Token::Kind::TK_LOGICALXOREQ: // fall through
1835 case Token::Kind::TK_LOGICALANDEQ:
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001836 return true;
1837 default:
1838 return false;
1839 }
1840}
1841
Brian Osman401a0092020-09-10 14:47:24 -04001842Token::Kind Compiler::RemoveAssignment(Token::Kind op) {
1843 switch (op) {
1844 case Token::Kind::TK_PLUSEQ: return Token::Kind::TK_PLUS;
1845 case Token::Kind::TK_MINUSEQ: return Token::Kind::TK_MINUS;
1846 case Token::Kind::TK_STAREQ: return Token::Kind::TK_STAR;
1847 case Token::Kind::TK_SLASHEQ: return Token::Kind::TK_SLASH;
1848 case Token::Kind::TK_PERCENTEQ: return Token::Kind::TK_PERCENT;
1849 case Token::Kind::TK_SHLEQ: return Token::Kind::TK_SHL;
1850 case Token::Kind::TK_SHREQ: return Token::Kind::TK_SHR;
1851 case Token::Kind::TK_BITWISEOREQ: return Token::Kind::TK_BITWISEOR;
1852 case Token::Kind::TK_BITWISEXOREQ: return Token::Kind::TK_BITWISEXOR;
1853 case Token::Kind::TK_BITWISEANDEQ: return Token::Kind::TK_BITWISEAND;
1854 case Token::Kind::TK_LOGICALOREQ: return Token::Kind::TK_LOGICALOR;
1855 case Token::Kind::TK_LOGICALXOREQ: return Token::Kind::TK_LOGICALXOR;
1856 case Token::Kind::TK_LOGICALANDEQ: return Token::Kind::TK_LOGICALAND;
1857 default: return op;
1858 }
1859}
1860
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001861Position Compiler::position(int offset) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001862 SkASSERT(fSource);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001863 int line = 1;
1864 int column = 1;
1865 for (int i = 0; i < offset; i++) {
1866 if ((*fSource)[i] == '\n') {
1867 ++line;
1868 column = 1;
1869 }
1870 else {
1871 ++column;
1872 }
1873 }
1874 return Position(line, column);
1875}
1876
1877void Compiler::error(int offset, String msg) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001878 fErrorCount++;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001879 Position pos = this->position(offset);
1880 fErrorText += "error: " + to_string(pos.fLine) + ": " + msg.c_str() + "\n";
ethannicholasb3058bd2016-07-01 08:22:01 -07001881}
1882
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001883String Compiler::errorText() {
Ethan Nicholas00543112018-07-31 09:44:36 -04001884 this->writeErrorCount();
1885 fErrorCount = 0;
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001886 String result = fErrorText;
ethannicholasb3058bd2016-07-01 08:22:01 -07001887 return result;
1888}
1889
1890void Compiler::writeErrorCount() {
1891 if (fErrorCount) {
1892 fErrorText += to_string(fErrorCount) + " error";
1893 if (fErrorCount > 1) {
1894 fErrorText += "s";
1895 }
1896 fErrorText += "\n";
1897 }
1898}
1899
John Stilesa6841be2020-08-06 14:11:56 -04001900} // namespace SkSL