blob: 9fc3d3e89ae207dd3344f55daf6d87f1538b67a1 [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);
John Stiles108bbe22020-11-18 11:10:38 -0500837
Ethan Nicholascb670962017-04-20 19:31:52 -0400838 if ((*iter)->fConstantPropagation) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400839 std::unique_ptr<Expression> optimized = expr->constantPropagate(*fIRGenerator,
840 definitions);
Ethan Nicholascb670962017-04-20 19:31:52 -0400841 if (optimized) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400842 optimizationContext->fUpdated = true;
Ethan Nicholas30d30222020-09-11 12:27:26 -0400843 optimized = fIRGenerator->coerce(std::move(optimized), expr->type());
Ethan Nicholas1d881522020-09-11 09:32:54 -0400844 SkASSERT(optimized);
Brian Osman010ce6a2020-10-19 16:34:10 -0400845 // Remove references within 'expr', add references within 'optimized'
846 optimizationContext->fUsage->replace(expr, optimized.get());
Ethan Nicholascb670962017-04-20 19:31:52 -0400847 if (!try_replace_expression(&b, iter, &optimized)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400848 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400849 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400850 }
John Stiles70025e52020-09-28 16:08:58 -0400851 SkASSERT((*iter)->isExpression());
Ethan Nicholascb670962017-04-20 19:31:52 -0400852 expr = (*iter)->expression()->get();
Ethan Nicholascb670962017-04-20 19:31:52 -0400853 }
854 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400855 switch (expr->kind()) {
856 case Expression::Kind::kVariableReference: {
John Stilesa5a97b42020-08-18 11:19:07 -0400857 const VariableReference& ref = expr->as<VariableReference>();
Ethan Nicholas78686922020-10-08 06:46:27 -0400858 const Variable* var = ref.variable();
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400859 if (ref.refKind() != VariableReference::RefKind::kWrite &&
860 ref.refKind() != VariableReference::RefKind::kPointer &&
861 var->storage() == Variable::Storage::kLocal && !definitions[var] &&
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400862 optimizationContext->fSilences.find(var) == optimizationContext->fSilences.end()) {
863 optimizationContext->fSilences.insert(var);
Ethan Nicholas82a62d22017-11-07 14:42:10 +0000864 this->error(expr->fOffset,
Ethan Nicholase2c49992020-10-05 11:49:11 -0400865 "'" + var->name() + "' has not been assigned");
Ethan Nicholascb670962017-04-20 19:31:52 -0400866 }
867 break;
868 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400869 case Expression::Kind::kTernary: {
John Stiles403a3632020-08-20 12:11:48 -0400870 TernaryExpression* t = &expr->as<TernaryExpression>();
Ethan Nicholasdd218162020-10-08 05:48:01 -0400871 if (t->test()->is<BoolLiteral>()) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400872 // ternary has a constant test, replace it with either the true or
873 // false branch
Ethan Nicholasdd218162020-10-08 05:48:01 -0400874 if (t->test()->as<BoolLiteral>().value()) {
Brian Osman010ce6a2020-10-19 16:34:10 -0400875 (*iter)->setExpression(std::move(t->ifTrue()), optimizationContext->fUsage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400876 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -0400877 (*iter)->setExpression(std::move(t->ifFalse()), optimizationContext->fUsage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400878 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400879 optimizationContext->fUpdated = true;
880 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -0400881 }
882 break;
883 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400884 case Expression::Kind::kBinary: {
John Stiles403a3632020-08-20 12:11:48 -0400885 BinaryExpression* bin = &expr->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400886 if (dead_assignment(*bin, optimizationContext->fUsage)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400887 delete_left(&b, iter, optimizationContext);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400888 break;
889 }
John Stiles2d4f9592020-10-30 10:29:12 -0400890 Expression& left = *bin->left();
891 Expression& right = *bin->right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400892 const Type& leftType = left.type();
893 const Type& rightType = right.type();
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400894 // collapse useless expressions like x * 1 or x + 0
Ethan Nicholas30d30222020-09-11 12:27:26 -0400895 if (((leftType.typeKind() != Type::TypeKind::kScalar) &&
896 (leftType.typeKind() != Type::TypeKind::kVector)) ||
897 ((rightType.typeKind() != Type::TypeKind::kScalar) &&
898 (rightType.typeKind() != Type::TypeKind::kVector))) {
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400899 break;
900 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400901 switch (bin->getOperator()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400902 case Token::Kind::TK_STAR:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400903 if (is_constant(left, 1)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400904 if (leftType.typeKind() == Type::TypeKind::kVector &&
905 rightType.typeKind() == Type::TypeKind::kScalar) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400906 // float4(1) * x -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400907 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400908 } else {
909 // 1 * x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400910 // 1 * float4(x) -> float4(x)
911 // float4(1) * float4(x) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400912 delete_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400913 }
914 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400915 else if (is_constant(left, 0)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400916 if (leftType.typeKind() == Type::TypeKind::kScalar &&
917 rightType.typeKind() == Type::TypeKind::kVector &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400918 !right.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400919 // 0 * float4(x) -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400920 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400921 } else {
922 // 0 * x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400923 // float4(0) * x -> float4(0)
924 // float4(0) * float4(x) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400925 if (!right.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400926 delete_right(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500927 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400928 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400929 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400930 else if (is_constant(right, 1)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400931 if (leftType.typeKind() == Type::TypeKind::kScalar &&
932 rightType.typeKind() == Type::TypeKind::kVector) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400933 // x * float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400934 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400935 } else {
936 // x * 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400937 // float4(x) * 1 -> float4(x)
938 // float4(x) * float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400939 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400940 }
941 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400942 else if (is_constant(right, 0)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400943 if (leftType.typeKind() == Type::TypeKind::kVector &&
944 rightType.typeKind() == Type::TypeKind::kScalar &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400945 !left.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400946 // float4(x) * 0 -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400947 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400948 } else {
949 // x * 0 -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400950 // x * float4(0) -> float4(0)
951 // float4(x) * float4(0) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400952 if (!left.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400953 delete_left(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500954 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400955 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400956 }
957 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400958 case Token::Kind::TK_PLUS:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400959 if (is_constant(left, 0)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400960 if (leftType.typeKind() == Type::TypeKind::kVector &&
961 rightType.typeKind() == Type::TypeKind::kScalar) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400962 // float4(0) + x -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400963 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400964 } else {
965 // 0 + x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400966 // 0 + float4(x) -> float4(x)
967 // float4(0) + float4(x) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400968 delete_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400969 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400970 } else if (is_constant(right, 0)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400971 if (leftType.typeKind() == Type::TypeKind::kScalar &&
972 rightType.typeKind() == Type::TypeKind::kVector) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400973 // x + float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400974 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400975 } else {
976 // x + 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400977 // float4(x) + 0 -> float4(x)
978 // float4(x) + float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400979 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400980 }
Ethan Nicholas56e42712017-04-21 10:23:37 -0400981 }
982 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400983 case Token::Kind::TK_MINUS:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400984 if (is_constant(right, 0)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400985 if (leftType.typeKind() == Type::TypeKind::kScalar &&
986 rightType.typeKind() == Type::TypeKind::kVector) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400987 // x - float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400988 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400989 } else {
990 // x - 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400991 // float4(x) - 0 -> float4(x)
992 // float4(x) - float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400993 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400994 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400995 }
996 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400997 case Token::Kind::TK_SLASH:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400998 if (is_constant(right, 1)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400999 if (leftType.typeKind() == Type::TypeKind::kScalar &&
1000 rightType.typeKind() == Type::TypeKind::kVector) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001001 // x / float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001002 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001003 } else {
1004 // x / 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001005 // float4(x) / 1 -> float4(x)
1006 // float4(x) / float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001007 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001008 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001009 } else if (is_constant(left, 0)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001010 if (leftType.typeKind() == Type::TypeKind::kScalar &&
1011 rightType.typeKind() == Type::TypeKind::kVector &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001012 !right.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001013 // 0 / float4(x) -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001014 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001015 } else {
1016 // 0 / x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001017 // float4(0) / x -> float4(0)
1018 // float4(0) / float4(x) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001019 if (!right.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001020 delete_right(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -05001021 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001022 }
1023 }
1024 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001025 case Token::Kind::TK_PLUSEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001026 if (is_constant(right, 0)) {
1027 clear_write(left);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001028 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001029 }
1030 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001031 case Token::Kind::TK_MINUSEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001032 if (is_constant(right, 0)) {
1033 clear_write(left);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001034 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001035 }
1036 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001037 case Token::Kind::TK_STAREQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001038 if (is_constant(right, 1)) {
1039 clear_write(left);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001040 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001041 }
1042 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001043 case Token::Kind::TK_SLASHEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04001044 if (is_constant(right, 1)) {
1045 clear_write(left);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001046 delete_right(&b, iter, optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001047 }
1048 break;
1049 default:
1050 break;
1051 }
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001052 break;
1053 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001054 case Expression::Kind::kSwizzle: {
John Stiles403a3632020-08-20 12:11:48 -04001055 Swizzle& s = expr->as<Swizzle>();
John Stiles108bbe22020-11-18 11:10:38 -05001056 // Detect identity swizzles like `foo.rgba`.
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001057 if ((int) s.components().size() == s.base()->type().columns()) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001058 bool identity = true;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001059 for (int i = 0; i < (int) s.components().size(); ++i) {
1060 if (s.components()[i] != i) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001061 identity = false;
1062 break;
1063 }
1064 }
1065 if (identity) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001066 optimizationContext->fUpdated = true;
Brian Osman010ce6a2020-10-19 16:34:10 -04001067 // No fUsage change: foo.rgba and foo have equivalent reference counts
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001068 if (!try_replace_expression(&b, iter, &s.base())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001069 optimizationContext->fNeedsRescan = true;
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001070 return;
1071 }
John Stiles70025e52020-09-28 16:08:58 -04001072 SkASSERT((*iter)->isExpression());
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001073 break;
1074 }
1075 }
John Stiles108bbe22020-11-18 11:10:38 -05001076 // Detect swizzles of swizzles, e.g. replace `foo.argb.r000` with `foo.a000`.
1077 if (s.base()->is<Swizzle>()) {
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001078 Swizzle& base = s.base()->as<Swizzle>();
John Stiles750109b2020-10-30 13:45:46 -04001079 ComponentArray final;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001080 for (int c : s.components()) {
1081 final.push_back(base.components()[c]);
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001082 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001083 optimizationContext->fUpdated = true;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001084 std::unique_ptr<Expression> replacement(new Swizzle(*fContext, base.base()->clone(),
John Stiles750109b2020-10-30 13:45:46 -04001085 final));
John Stiles108bbe22020-11-18 11:10:38 -05001086 // No fUsage change: `foo.gbr.gbr` and `foo.brg` have equivalent reference counts
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001087 if (!try_replace_expression(&b, iter, &replacement)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001088 optimizationContext->fNeedsRescan = true;
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001089 return;
1090 }
John Stiles70025e52020-09-28 16:08:58 -04001091 SkASSERT((*iter)->isExpression());
John Stiles108bbe22020-11-18 11:10:38 -05001092 break;
1093 }
1094 // Optimize swizzles of constructors.
1095 if (s.base()->is<Constructor>()) {
1096 Constructor& base = s.base()->as<Constructor>();
1097 std::unique_ptr<Expression> replacement;
1098 const Type& componentType = base.type().componentType();
1099 int swizzleSize = s.components().size();
1100
1101 // The IR generator has already converted any zero/one swizzle components into
1102 // constructors containing zero/one args. Confirm that this is true by checking that
1103 // our swizzle components are all `xyzw` (values 0 through 3).
1104 SkASSERT(std::all_of(s.components().begin(), s.components().end(),
1105 [](int8_t c) { return c >= 0 && c <= 3; }));
1106
1107 if (base.arguments().size() == 1 &&
1108 base.arguments().front()->type().typeKind() == Type::TypeKind::kScalar) {
1109 // `half4(scalar).zyy` can be optimized to `half3(scalar)`. The swizzle
1110 // components don't actually matter since all fields are the same.
1111 ExpressionArray newArgs;
1112 newArgs.push_back(base.arguments().front()->clone());
1113 replacement = std::make_unique<Constructor>(
1114 base.fOffset,
1115 &componentType.toCompound(*fContext, swizzleSize, /*rows=*/1),
1116 std::move(newArgs));
1117
1118 // No fUsage change: `half4(foo).xy` and `half2(foo)` have equivalent reference
1119 // counts.
John Stiles0777ac42020-11-19 11:06:47 -05001120 optimizationContext->fUpdated = true;
John Stiles108bbe22020-11-18 11:10:38 -05001121 if (!try_replace_expression(&b, iter, &replacement)) {
1122 optimizationContext->fNeedsRescan = true;
1123 return;
1124 }
1125 SkASSERT((*iter)->isExpression());
1126 break;
1127 }
1128
John Stiles0777ac42020-11-19 11:06:47 -05001129 // Swizzles can duplicate some elements and discard others, e.g.
1130 // `half4(1, 2, 3, 4).xxz` --> `half3(1, 1, 3)`. However, there are constraints:
1131 // - Expressions with side effects need to occur exactly once, even if they
1132 // would otherwise be swizzle-eliminated
1133 // - Non-trivial expressions should not be repeated, but elimination is OK.
1134 //
1135 // Look up the argument for the constructor at each index. This is typically simple
1136 // but for weird cases like `half4(bar.yz, half2(foo))`, it can be harder than it
1137 // seems. This example would result in:
1138 // argMap[0] = {.fArgIndex = 0, .fComponent = 0} (bar.yz .x)
1139 // argMap[1] = {.fArgIndex = 0, .fComponent = 1} (bar.yz .y)
1140 // argMap[2] = {.fArgIndex = 1, .fComponent = 0} (half2(foo) .x)
1141 // argMap[3] = {.fArgIndex = 1, .fComponent = 1} (half2(foo) .y)
1142 struct ConstructorArgMap {
1143 int8_t fArgIndex;
1144 int8_t fComponent;
1145 };
1146
1147 int numConstructorArgs = base.type().columns();
1148 ConstructorArgMap argMap[4] = {};
1149 int writeIdx = 0;
1150 for (int argIdx = 0; argIdx < (int) base.arguments().size(); ++argIdx) {
1151 const Expression& expr = *base.arguments()[argIdx];
1152 int argWidth = expr.type().columns();
1153 for (int componentIdx = 0; componentIdx < argWidth; ++componentIdx) {
1154 argMap[writeIdx].fArgIndex = argIdx;
1155 argMap[writeIdx].fComponent = componentIdx;
1156 ++writeIdx;
1157 }
1158 }
1159 SkASSERT(writeIdx == numConstructorArgs);
1160
1161 // Count up the number of times each constructor argument is used by the
1162 // swizzle.
1163 // `half4(bar.yz, half2(foo)).xwxy` -> { 3, 1 }
1164 // - bar.yz is referenced 3 times, by `.x_xy`
1165 // - half(foo) is referenced 1 time, by `._w__`
1166 int8_t exprUsed[4] = {};
1167 for (int c : s.components()) {
1168 exprUsed[argMap[c].fArgIndex]++;
1169 }
1170
1171 bool safeToOptimize = true;
1172 for (int index = 0; index < numConstructorArgs; ++index) {
1173 int8_t constructorArgIndex = argMap[index].fArgIndex;
1174 const Expression& baseArg = *base.arguments()[constructorArgIndex];
1175
1176 // Check that non-trivial expressions are not swizzled in more than once.
1177 if (exprUsed[constructorArgIndex] > 1 && !baseArg.isConstantOrUniform()) {
1178 safeToOptimize = false;
1179 break;
1180 }
1181 // Check that side-effect-bearing expressions are swizzled in exactly once.
1182 if (exprUsed[constructorArgIndex] != 1 && baseArg.hasSideEffects()) {
1183 safeToOptimize = false;
1184 break;
1185 }
1186 }
1187
1188 if (safeToOptimize) {
1189 // Create a new constructor, with the arguments from the original constructor
1190 // reordered and swizzled to match the original swizzle permutation. Note that
1191 // we expect followup passes to optimize things like `bar.yz.x` into `bar.y`.
1192 ExpressionArray newArgs;
1193 newArgs.reserve_back(swizzleSize);
1194 for (int c : s.components()) {
1195 const ConstructorArgMap& argument = argMap[c];
1196 const Expression& baseArg = *base.arguments()[argument.fArgIndex];
1197
1198 if (baseArg.type().typeKind() == Type::TypeKind::kScalar) {
1199 SkASSERT(argument.fComponent == 0);
1200 newArgs.push_back(baseArg.clone());
1201 } else {
1202 SkASSERT(argument.fComponent < baseArg.type().columns());
1203 newArgs.push_back(std::make_unique<Swizzle>(
1204 *fContext, baseArg.clone(),
1205 ComponentArray{argument.fComponent}));
1206 }
1207 }
1208 replacement = std::make_unique<Constructor>(
1209 base.fOffset,
1210 &componentType.toCompound(*fContext, swizzleSize, /*rows=*/1),
1211 std::move(newArgs));
1212
1213 // Remove references within 'expr', add references within 'optimized'
1214 optimizationContext->fUpdated = true;
1215 optimizationContext->fUsage->replace(expr, replacement.get());
1216 if (!try_replace_expression(&b, iter, &replacement)) {
1217 optimizationContext->fNeedsRescan = true;
1218 return;
1219 }
1220 SkASSERT((*iter)->isExpression());
1221 }
John Stiles108bbe22020-11-18 11:10:38 -05001222 break;
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001223 }
John Stiles30212b72020-06-11 17:55:07 -04001224 break;
Ethan Nicholascb670962017-04-20 19:31:52 -04001225 }
1226 default:
1227 break;
1228 }
1229}
1230
John Stiles92219b42020-06-15 12:32:24 -04001231// Returns true if this statement could potentially execute a break at the current level. We ignore
1232// nested loops and switches, since any breaks inside of them will merely break the loop / switch.
John Stilesb92641c2020-08-31 18:09:01 -04001233static bool contains_conditional_break(Statement& stmt) {
1234 class ContainsConditionalBreak : public ProgramVisitor {
1235 public:
1236 bool visitStatement(const Statement& stmt) override {
Ethan Nicholase6592142020-09-08 10:22:09 -04001237 switch (stmt.kind()) {
1238 case Statement::Kind::kBlock:
John Stilesb92641c2020-08-31 18:09:01 -04001239 return this->INHERITED::visitStatement(stmt);
1240
Ethan Nicholase6592142020-09-08 10:22:09 -04001241 case Statement::Kind::kBreak:
John Stilesb92641c2020-08-31 18:09:01 -04001242 return fInConditional > 0;
1243
Ethan Nicholase6592142020-09-08 10:22:09 -04001244 case Statement::Kind::kIf: {
John Stilesb92641c2020-08-31 18:09:01 -04001245 ++fInConditional;
1246 bool result = this->INHERITED::visitStatement(stmt);
1247 --fInConditional;
1248 return result;
1249 }
1250
1251 default:
1252 return false;
1253 }
1254 }
1255
1256 int fInConditional = 0;
1257 using INHERITED = ProgramVisitor;
1258 };
1259
1260 return ContainsConditionalBreak{}.visitStatement(stmt);
John Stiles92219b42020-06-15 12:32:24 -04001261}
1262
Ethan Nicholas5005a222018-08-24 13:06:27 -04001263// returns true if this statement definitely executes a break at the current level (we ignore
1264// nested loops and switches, since any breaks inside of them will merely break the loop / switch)
John Stilesb92641c2020-08-31 18:09:01 -04001265static bool contains_unconditional_break(Statement& stmt) {
1266 class ContainsUnconditionalBreak : public ProgramVisitor {
1267 public:
1268 bool visitStatement(const Statement& stmt) override {
Ethan Nicholase6592142020-09-08 10:22:09 -04001269 switch (stmt.kind()) {
1270 case Statement::Kind::kBlock:
John Stilesb92641c2020-08-31 18:09:01 -04001271 return this->INHERITED::visitStatement(stmt);
1272
Ethan Nicholase6592142020-09-08 10:22:09 -04001273 case Statement::Kind::kBreak:
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001274 return true;
John Stilesb92641c2020-08-31 18:09:01 -04001275
1276 default:
1277 return false;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001278 }
John Stilesb92641c2020-08-31 18:09:01 -04001279 }
John Stiles92219b42020-06-15 12:32:24 -04001280
John Stilesb92641c2020-08-31 18:09:01 -04001281 using INHERITED = ProgramVisitor;
1282 };
John Stiles92219b42020-06-15 12:32:24 -04001283
John Stilesb92641c2020-08-31 18:09:01 -04001284 return ContainsUnconditionalBreak{}.visitStatement(stmt);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001285}
1286
John Stiles8f2a0cf2020-10-13 12:48:21 -04001287static void move_all_but_break(std::unique_ptr<Statement>& stmt, StatementArray* target) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001288 switch (stmt->kind()) {
1289 case Statement::Kind::kBlock: {
John Stiles92219b42020-06-15 12:32:24 -04001290 // Recurse into the block.
1291 Block& block = static_cast<Block&>(*stmt);
1292
John Stiles8f2a0cf2020-10-13 12:48:21 -04001293 StatementArray blockStmts;
John Stilesf4bda742020-10-14 16:57:41 -04001294 blockStmts.reserve_back(block.children().size());
Ethan Nicholas7bd60432020-09-25 14:31:59 -04001295 for (std::unique_ptr<Statement>& stmt : block.children()) {
1296 move_all_but_break(stmt, &blockStmts);
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001297 }
John Stiles92219b42020-06-15 12:32:24 -04001298
1299 target->push_back(std::make_unique<Block>(block.fOffset, std::move(blockStmts),
Ethan Nicholas7bd60432020-09-25 14:31:59 -04001300 block.symbolTable(), block.isScope()));
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001301 break;
John Stiles92219b42020-06-15 12:32:24 -04001302 }
1303
Ethan Nicholase6592142020-09-08 10:22:09 -04001304 case Statement::Kind::kBreak:
John Stiles92219b42020-06-15 12:32:24 -04001305 // Do not append a break to the target.
1306 break;
1307
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001308 default:
John Stiles92219b42020-06-15 12:32:24 -04001309 // Append normal statements to the target.
1310 target->push_back(std::move(stmt));
1311 break;
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001312 }
1313}
1314
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001315// Returns a block containing all of the statements that will be run if the given case matches
1316// (which, owing to the statements being owned by unique_ptrs, means the switch itself will be
1317// broken by this call and must then be discarded).
1318// Returns null (and leaves the switch unmodified) if no such simple reduction is possible, such as
1319// when break statements appear inside conditionals.
John Stiles92219b42020-06-15 12:32:24 -04001320static std::unique_ptr<Statement> block_for_case(SwitchStatement* switchStatement,
1321 SwitchCase* caseToCapture) {
1322 // We have to be careful to not move any of the pointers until after we're sure we're going to
1323 // succeed, so before we make any changes at all, we check the switch-cases to decide on a plan
1324 // of action. First, find the switch-case we are interested in.
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001325 auto iter = switchStatement->cases().begin();
1326 for (; iter != switchStatement->cases().end(); ++iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001327 if (iter->get() == caseToCapture) {
John Stiles92219b42020-06-15 12:32:24 -04001328 break;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001329 }
John Stiles92219b42020-06-15 12:32:24 -04001330 }
1331
1332 // Next, walk forward through the rest of the switch. If we find a conditional break, we're
1333 // stuck and can't simplify at all. If we find an unconditional break, we have a range of
1334 // statements that we can use for simplification.
1335 auto startIter = iter;
1336 Statement* unconditionalBreakStmt = nullptr;
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001337 for (; iter != switchStatement->cases().end(); ++iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001338 for (std::unique_ptr<Statement>& stmt : (*iter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001339 if (contains_conditional_break(*stmt)) {
1340 // We can't reduce switch-cases to a block when they have conditional breaks.
1341 return nullptr;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001342 }
John Stiles92219b42020-06-15 12:32:24 -04001343
1344 if (contains_unconditional_break(*stmt)) {
1345 // We found an unconditional break. We can use this block, but we need to strip
1346 // out the break statement.
1347 unconditionalBreakStmt = stmt.get();
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001348 break;
1349 }
1350 }
John Stiles92219b42020-06-15 12:32:24 -04001351
1352 if (unconditionalBreakStmt != nullptr) {
1353 break;
1354 }
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001355 }
John Stiles92219b42020-06-15 12:32:24 -04001356
1357 // We fell off the bottom of the switch or encountered a break. We know the range of statements
1358 // that we need to move over, and we know it's safe to do so.
John Stiles8f2a0cf2020-10-13 12:48:21 -04001359 StatementArray caseStmts;
John Stiles92219b42020-06-15 12:32:24 -04001360
1361 // We can move over most of the statements as-is.
1362 while (startIter != iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001363 for (std::unique_ptr<Statement>& stmt : (*startIter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001364 caseStmts.push_back(std::move(stmt));
1365 }
1366 ++startIter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001367 }
John Stiles92219b42020-06-15 12:32:24 -04001368
1369 // If we found an unconditional break at the end, we need to move what we can while avoiding
1370 // that break.
1371 if (unconditionalBreakStmt != nullptr) {
John Stiles2d4f9592020-10-30 10:29:12 -04001372 for (std::unique_ptr<Statement>& stmt : (*startIter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001373 if (stmt.get() == unconditionalBreakStmt) {
1374 move_all_but_break(stmt, &caseStmts);
1375 unconditionalBreakStmt = nullptr;
1376 break;
1377 }
1378
1379 caseStmts.push_back(std::move(stmt));
1380 }
1381 }
1382
1383 SkASSERT(unconditionalBreakStmt == nullptr); // Verify that we fixed the unconditional break.
1384
1385 // Return our newly-synthesized block.
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001386 return std::make_unique<Block>(/*offset=*/-1, std::move(caseStmts), switchStatement->symbols());
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001387}
1388
Ethan Nicholascb670962017-04-20 19:31:52 -04001389void Compiler::simplifyStatement(DefinitionMap& definitions,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001390 BasicBlock& b,
1391 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001392 OptimizationContext* optimizationContext) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001393 ProgramUsage* usage = optimizationContext->fUsage;
Ethan Nicholascb670962017-04-20 19:31:52 -04001394 Statement* stmt = (*iter)->statement()->get();
Ethan Nicholase6592142020-09-08 10:22:09 -04001395 switch (stmt->kind()) {
1396 case Statement::Kind::kVarDeclaration: {
John Stilesa5a97b42020-08-18 11:19:07 -04001397 const auto& varDecl = stmt->as<VarDeclaration>();
Brian Osman010ce6a2020-10-19 16:34:10 -04001398 if (usage->isDead(varDecl.var()) &&
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001399 (!varDecl.value() ||
1400 !varDecl.value()->hasSideEffects())) {
1401 if (varDecl.value()) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001402 SkASSERT((*iter)->statement()->get() == stmt);
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001403 if (!b.tryRemoveExpressionBefore(iter, varDecl.value().get())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001404 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001405 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001406 }
Brian Osman010ce6a2020-10-19 16:34:10 -04001407 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001408 optimizationContext->fUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001409 }
1410 break;
1411 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001412 case Statement::Kind::kIf: {
John Stilesa5a97b42020-08-18 11:19:07 -04001413 IfStatement& i = stmt->as<IfStatement>();
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001414 if (i.test()->kind() == Expression::Kind::kBoolLiteral) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001415 // constant if, collapse down to a single branch
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001416 if (i.test()->as<BoolLiteral>().value()) {
1417 SkASSERT(i.ifTrue());
Brian Osman010ce6a2020-10-19 16:34:10 -04001418 (*iter)->setStatement(std::move(i.ifTrue()), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001419 } else {
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001420 if (i.ifFalse()) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001421 (*iter)->setStatement(std::move(i.ifFalse()), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001422 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -04001423 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001424 }
1425 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001426 optimizationContext->fUpdated = true;
1427 optimizationContext->fNeedsRescan = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001428 break;
1429 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001430 if (i.ifFalse() && i.ifFalse()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001431 // else block doesn't do anything, remove it
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001432 i.ifFalse().reset();
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001433 optimizationContext->fUpdated = true;
1434 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001435 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001436 if (!i.ifFalse() && i.ifTrue()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001437 // if block doesn't do anything, no else block
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001438 if (i.test()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001439 // test has side effects, keep it
Brian Osman010ce6a2020-10-19 16:34:10 -04001440 (*iter)->setStatement(
1441 std::make_unique<ExpressionStatement>(std::move(i.test())), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -04001442 } else {
1443 // no if, no else, no test side effects, kill the whole if
1444 // statement
Brian Osman010ce6a2020-10-19 16:34:10 -04001445 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -04001446 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001447 optimizationContext->fUpdated = true;
1448 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001449 }
1450 break;
1451 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001452 case Statement::Kind::kSwitch: {
John Stilesa5a97b42020-08-18 11:19:07 -04001453 SwitchStatement& s = stmt->as<SwitchStatement>();
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001454 int64_t switchValue;
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001455 if (fIRGenerator->getConstantInt(*s.value(), &switchValue)) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001456 // switch is constant, replace it with the case that matches
1457 bool found = false;
1458 SwitchCase* defaultCase = nullptr;
John Stiles2d4f9592020-10-30 10:29:12 -04001459 for (const std::unique_ptr<SwitchCase>& c : s.cases()) {
1460 if (!c->value()) {
1461 defaultCase = c.get();
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001462 continue;
1463 }
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001464 int64_t caseValue;
John Stiles2d4f9592020-10-30 10:29:12 -04001465 SkAssertResult(fIRGenerator->getConstantInt(*c->value(), &caseValue));
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001466 if (caseValue == switchValue) {
John Stiles2d4f9592020-10-30 10:29:12 -04001467 std::unique_ptr<Statement> newBlock = block_for_case(&s, c.get());
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001468 if (newBlock) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001469 (*iter)->setStatement(std::move(newBlock), usage);
John Stiles9d944232020-08-19 09:56:49 -04001470 found = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001471 break;
1472 } else {
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001473 if (s.isStatic() && !(fFlags & kPermitInvalidStaticTests_Flag) &&
1474 optimizationContext->fSilences.find(&s) ==
1475 optimizationContext->fSilences.end()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001476 this->error(s.fOffset,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001477 "static switch contains non-static conditional break");
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001478 optimizationContext->fSilences.insert(&s);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001479 }
1480 return; // can't simplify
1481 }
1482 }
1483 }
1484 if (!found) {
1485 // no matching case. use default if it exists, or kill the whole thing
1486 if (defaultCase) {
1487 std::unique_ptr<Statement> newBlock = block_for_case(&s, defaultCase);
1488 if (newBlock) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001489 (*iter)->setStatement(std::move(newBlock), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001490 } else {
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001491 if (s.isStatic() && !(fFlags & kPermitInvalidStaticTests_Flag) &&
1492 optimizationContext->fSilences.find(&s) ==
1493 optimizationContext->fSilences.end()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001494 this->error(s.fOffset,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001495 "static switch contains non-static conditional break");
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001496 optimizationContext->fSilences.insert(&s);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001497 }
1498 return; // can't simplify
1499 }
1500 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -04001501 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001502 }
1503 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001504 optimizationContext->fUpdated = true;
1505 optimizationContext->fNeedsRescan = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001506 }
1507 break;
1508 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001509 case Statement::Kind::kExpression: {
John Stilesa5a97b42020-08-18 11:19:07 -04001510 ExpressionStatement& e = stmt->as<ExpressionStatement>();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001511 SkASSERT((*iter)->statement()->get() == &e);
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001512 if (!e.expression()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001513 // Expression statement with no side effects, kill it
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001514 if (!b.tryRemoveExpressionBefore(iter, e.expression().get())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001515 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001516 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001517 SkASSERT((*iter)->statement()->get() == stmt);
Brian Osman010ce6a2020-10-19 16:34:10 -04001518 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001519 optimizationContext->fUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001520 }
1521 break;
1522 }
1523 default:
1524 break;
1525 }
1526}
1527
Brian Osman010ce6a2020-10-19 16:34:10 -04001528bool Compiler::scanCFG(FunctionDefinition& f, ProgramUsage* usage) {
John Stiles0cc193a2020-09-09 09:39:34 -04001529 bool madeChanges = false;
1530
Ethan Nicholascb670962017-04-20 19:31:52 -04001531 CFG cfg = CFGGenerator().getCFG(f);
1532 this->computeDataFlow(&cfg);
ethannicholas22f939e2016-10-13 13:25:34 -07001533
1534 // check for unreachable code
1535 for (size_t i = 0; i < cfg.fBlocks.size(); i++) {
John Stiles0cc193a2020-09-09 09:39:34 -04001536 const BasicBlock& block = cfg.fBlocks[i];
John Stiles61e75e32020-10-01 15:42:37 -04001537 if (i != cfg.fStart && !block.fIsReachable && block.fNodes.size()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001538 int offset;
John Stiles0cc193a2020-09-09 09:39:34 -04001539 const BasicBlock::Node& node = block.fNodes[0];
John Stiles70025e52020-09-28 16:08:58 -04001540 if (node.isStatement()) {
1541 offset = (*node.statement())->fOffset;
1542 } else {
1543 offset = (*node.expression())->fOffset;
1544 if ((*node.expression())->is<BoolLiteral>()) {
1545 // Function inlining can generate do { ... } while(false) loops which always
1546 // break, so the boolean condition is considered unreachable. Since not being
1547 // able to reach a literal is a non-issue in the first place, we don't report an
1548 // error in this case.
1549 continue;
1550 }
Ethan Nicholas86a43402017-01-19 13:32:00 -05001551 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001552 this->error(offset, String("unreachable"));
ethannicholas22f939e2016-10-13 13:25:34 -07001553 }
1554 }
1555 if (fErrorCount) {
John Stiles0cc193a2020-09-09 09:39:34 -04001556 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001557 }
1558
Ethan Nicholascb670962017-04-20 19:31:52 -04001559 // check for dead code & undefined variables, perform constant propagation
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001560 OptimizationContext optimizationContext;
Brian Osman010ce6a2020-10-19 16:34:10 -04001561 optimizationContext.fUsage = usage;
John Stiles7d3f0892020-11-03 11:35:01 -05001562 SkBitSet eliminatedBlockIds(cfg.fBlocks.size());
Ethan Nicholascb670962017-04-20 19:31:52 -04001563 do {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001564 if (optimizationContext.fNeedsRescan) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001565 cfg = CFGGenerator().getCFG(f);
1566 this->computeDataFlow(&cfg);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001567 optimizationContext.fNeedsRescan = false;
Ethan Nicholas113628d2017-02-02 16:11:39 -05001568 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001569
John Stiles7d3f0892020-11-03 11:35:01 -05001570 eliminatedBlockIds.reset();
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001571 optimizationContext.fUpdated = false;
John Stiles7d3f0892020-11-03 11:35:01 -05001572
1573 for (BlockId blockId = 0; blockId < cfg.fBlocks.size(); ++blockId) {
1574 if (eliminatedBlockIds.test(blockId)) {
1575 // We reached a block ID that might have been eliminated. Be cautious and rescan.
1576 optimizationContext.fUpdated = true;
1577 optimizationContext.fNeedsRescan = true;
1578 break;
1579 }
1580
1581 BasicBlock& b = cfg.fBlocks[blockId];
1582 if (blockId > 0 && !b.fIsReachable) {
Ethan Nicholas1de14812020-06-19 15:32:49 -04001583 // Block was reachable before optimization, but has since become unreachable. In
1584 // addition to being dead code, it's broken - since control flow can't reach it, no
1585 // prior variable definitions can reach it, and therefore variables might look to
Brian Osmanc0213602020-10-06 14:43:32 -04001586 // have not been properly assigned. Kill it by replacing all statements with Nops.
Ethan Nicholas1de14812020-06-19 15:32:49 -04001587 for (BasicBlock::Node& node : b.fNodes) {
John Stiles70025e52020-09-28 16:08:58 -04001588 if (node.isStatement() && !(*node.statement())->is<Nop>()) {
John Stiles7d3f0892020-11-03 11:35:01 -05001589 // Eliminating a node runs the risk of eliminating that node's exits as
1590 // well. Keep track of this and do a rescan if we are about to access one
1591 // of these.
1592 for (BlockId id : b.fExits) {
1593 eliminatedBlockIds.set(id);
1594 }
Brian Osman010ce6a2020-10-19 16:34:10 -04001595 node.setStatement(std::make_unique<Nop>(), usage);
John Stiles0cc193a2020-09-09 09:39:34 -04001596 madeChanges = true;
Ethan Nicholas1de14812020-06-19 15:32:49 -04001597 }
1598 }
1599 continue;
1600 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001601 DefinitionMap definitions = b.fBefore;
1602
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001603 for (auto iter = b.fNodes.begin(); iter != b.fNodes.end() &&
1604 !optimizationContext.fNeedsRescan; ++iter) {
John Stiles70025e52020-09-28 16:08:58 -04001605 if (iter->isExpression()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001606 this->simplifyExpression(definitions, b, &iter, &optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001607 } else {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001608 this->simplifyStatement(definitions, b, &iter, &optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001609 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001610 if (optimizationContext.fNeedsRescan) {
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001611 break;
1612 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001613 this->addDefinitions(*iter, &definitions);
1614 }
Brian Osman01a3eb42020-09-14 11:32:49 -04001615
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001616 if (optimizationContext.fNeedsRescan) {
Brian Osman01a3eb42020-09-14 11:32:49 -04001617 break;
1618 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001619 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001620 madeChanges |= optimizationContext.fUpdated;
1621 } while (optimizationContext.fUpdated);
1622 SkASSERT(!optimizationContext.fNeedsRescan);
ethannicholas22f939e2016-10-13 13:25:34 -07001623
Ethan Nicholas91a10532017-06-22 11:24:38 -04001624 // verify static ifs & switches, clean up dead variable decls
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001625 for (BasicBlock& b : cfg.fBlocks) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001626 for (auto iter = b.fNodes.begin(); iter != b.fNodes.end() &&
1627 !optimizationContext.fNeedsRescan;) {
John Stiles70025e52020-09-28 16:08:58 -04001628 if (iter->isStatement()) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001629 const Statement& s = **iter->statement();
Ethan Nicholase6592142020-09-08 10:22:09 -04001630 switch (s.kind()) {
1631 case Statement::Kind::kIf:
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001632 if (s.as<IfStatement>().isStatic() &&
Ethan Nicholas6e1cbc02017-07-14 10:12:15 -04001633 !(fFlags & kPermitInvalidStaticTests_Flag)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001634 this->error(s.fOffset, "static if has non-static test");
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001635 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001636 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001637 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001638 case Statement::Kind::kSwitch:
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001639 if (s.as<SwitchStatement>().isStatic() &&
1640 !(fFlags & kPermitInvalidStaticTests_Flag) &&
1641 optimizationContext.fSilences.find(&s) ==
1642 optimizationContext.fSilences.end()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001643 this->error(s.fOffset, "static switch has non-static test");
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001644 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001645 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001646 break;
1647 default:
Ethan Nicholas91a10532017-06-22 11:24:38 -04001648 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001649 break;
1650 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001651 } else {
1652 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001653 }
1654 }
1655 }
1656
ethannicholas22f939e2016-10-13 13:25:34 -07001657 // check for missing return
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04001658 if (f.declaration().returnType() != *fContext->fVoid_Type) {
John Stiles61e75e32020-10-01 15:42:37 -04001659 if (cfg.fBlocks[cfg.fExit].fIsReachable) {
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04001660 this->error(f.fOffset, String("function '" + String(f.declaration().name()) +
Ethan Nicholasdb80f692019-11-22 14:06:12 -05001661 "' can exit without returning a value"));
ethannicholas22f939e2016-10-13 13:25:34 -07001662 }
1663 }
John Stiles0cc193a2020-09-09 09:39:34 -04001664
1665 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001666}
1667
Brian Osman32d53552020-09-23 13:55:20 -04001668std::unique_ptr<Program> Compiler::convertProgram(
1669 Program::Kind kind,
1670 String text,
1671 const Program::Settings& settings,
1672 const std::vector<std::unique_ptr<ExternalValue>>* externalValues) {
1673 SkASSERT(!externalValues || (kind == Program::kGeneric_Kind));
Ethan Nicholas91164d12019-05-15 15:29:54 -04001674
ethannicholasb3058bd2016-07-01 08:22:01 -07001675 fErrorText = "";
1676 fErrorCount = 0;
Brian Osmand7e76592020-11-02 12:26:22 -05001677 fInliner.reset(fContext.get(), fIRGenerator->fModifiers.get(), &settings, fCaps);
Brian Osman88cda172020-10-09 12:05:16 -04001678
1679 // Not using AutoSource, because caller is likely to call errorText() if we fail to compile
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001680 std::unique_ptr<String> textPtr(new String(std::move(text)));
1681 fSource = textPtr.get();
Brian Osman88cda172020-10-09 12:05:16 -04001682
1683 const ParsedModule& baseModule = this->moduleForProgramKind(kind);
1684
John Stiles5c7bb322020-10-22 11:09:15 -04001685 // Enable node pooling while converting and optimizing the program for a performance boost.
1686 // The Program will take ownership of the pool.
John Stiles2d68ea32020-10-22 15:42:27 -04001687 std::unique_ptr<Pool> pool = Pool::Create();
1688 pool->attachToThread();
Brian Osmand7e76592020-11-02 12:26:22 -05001689 IRGenerator::IRBundle ir = fIRGenerator->convertProgram(
1690 kind, &settings, fCaps, baseModule, /*isBuiltinCode=*/false, textPtr->c_str(),
1691 textPtr->size(), externalValues);
John Stiles5c7bb322020-10-22 11:09:15 -04001692 auto program = std::make_unique<Program>(kind,
1693 std::move(textPtr),
1694 settings,
Brian Osmand7e76592020-11-02 12:26:22 -05001695 fCaps,
John Stiles5c7bb322020-10-22 11:09:15 -04001696 fContext,
1697 std::move(ir.fElements),
1698 std::move(ir.fModifiers),
1699 std::move(ir.fSymbolTable),
1700 std::move(pool),
1701 ir.fInputs);
1702 bool success = false;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001703 if (fErrorCount) {
John Stiles5c7bb322020-10-22 11:09:15 -04001704 // Do not return programs that failed to compile.
1705 } else if (settings.fOptimize && !this->optimize(*program)) {
1706 // Do not return programs that failed to optimize.
1707 } else {
1708 // We have a successful program!
1709 success = true;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001710 }
John Stiles5c7bb322020-10-22 11:09:15 -04001711
1712 program->fPool->detachFromThread();
1713 return success ? std::move(program) : nullptr;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001714}
1715
Ethan Nicholas00543112018-07-31 09:44:36 -04001716bool Compiler::optimize(Program& program) {
1717 SkASSERT(!fErrorCount);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001718 fIRGenerator->fKind = program.fKind;
1719 fIRGenerator->fSettings = &program.fSettings;
Brian Osman010ce6a2020-10-19 16:34:10 -04001720 ProgramUsage* usage = program.fUsage.get();
John Stiles7954d6c2020-09-01 10:53:02 -04001721
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001722 while (fErrorCount == 0) {
1723 bool madeChanges = false;
John Stiles7954d6c2020-09-01 10:53:02 -04001724
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001725 // Scan and optimize based on the control-flow graph for each function.
Brian Osman1179fcf2020-10-08 16:04:40 -04001726 for (const auto& element : program.elements()) {
1727 if (element->is<FunctionDefinition>()) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001728 madeChanges |= this->scanCFG(element->as<FunctionDefinition>(), usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001729 }
1730 }
1731
1732 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stiles881a10c2020-09-19 10:13:24 -04001733 madeChanges |= fInliner.analyze(program);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001734
1735 // Remove dead functions. We wait until after analysis so that we still report errors,
1736 // even in unused code.
1737 if (program.fSettings.fRemoveDeadFunctions) {
1738 program.fElements.erase(
1739 std::remove_if(program.fElements.begin(),
1740 program.fElements.end(),
1741 [&](const std::unique_ptr<ProgramElement>& element) {
1742 if (!element->is<FunctionDefinition>()) {
1743 return false;
1744 }
1745 const auto& fn = element->as<FunctionDefinition>();
Brian Osman2e25ff42020-10-15 10:32:04 -04001746 bool dead = fn.declaration().name() != "main" &&
Brian Osman010ce6a2020-10-19 16:34:10 -04001747 usage->get(fn.declaration()) == 0;
1748 if (dead) {
1749 madeChanges = true;
1750 usage->remove(*element);
1751 }
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001752 return dead;
1753 }),
1754 program.fElements.end());
1755 }
1756
1757 if (program.fKind != Program::kFragmentProcessor_Kind) {
Brian Osmanc0213602020-10-06 14:43:32 -04001758 // Remove declarations of dead global variables
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001759 program.fElements.erase(
1760 std::remove_if(program.fElements.begin(), program.fElements.end(),
1761 [&](const std::unique_ptr<ProgramElement>& element) {
Brian Osmanc0213602020-10-06 14:43:32 -04001762 if (!element->is<GlobalVarDeclaration>()) {
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001763 return false;
1764 }
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001765 const auto& global = element->as<GlobalVarDeclaration>();
1766 const auto& varDecl =
1767 global.declaration()->as<VarDeclaration>();
Brian Osman010ce6a2020-10-19 16:34:10 -04001768 bool dead = usage->isDead(varDecl.var());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001769 madeChanges |= dead;
1770 return dead;
1771 }),
1772 program.fElements.end());
1773 }
John Stiles73a6bff2020-09-09 13:40:37 -04001774
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001775 if (!madeChanges) {
1776 break;
Ethan Nicholas0dc80872019-02-08 15:46:24 -05001777 }
Ethan Nicholas00543112018-07-31 09:44:36 -04001778 }
1779 return fErrorCount == 0;
1780}
1781
Brian Osmanfb32ddf2019-06-18 10:14:20 -04001782#if defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
1783
Ethan Nicholas00543112018-07-31 09:44:36 -04001784bool Compiler::toSPIRV(Program& program, OutputStream& out) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001785#ifdef SK_ENABLE_SPIRV_VALIDATION
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001786 StringStream buffer;
Brian Osman88cda172020-10-09 12:05:16 -04001787 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001788 SPIRVCodeGenerator cg(fContext.get(), &program, this, &buffer);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001789 bool result = cg.generateCode();
Ethan Nicholasba9a04f2020-11-06 09:28:04 -05001790 if (result && program.fSettings.fValidateSPIRV) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001791 spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_0);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001792 const String& data = buffer.str();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001793 SkASSERT(0 == data.size() % 4);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001794 auto dumpmsg = [](spv_message_level_t, const char*, const spv_position_t&, const char* m) {
1795 SkDebugf("SPIR-V validation error: %s\n", m);
1796 };
1797 tools.SetMessageConsumer(dumpmsg);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001798 // Verify that the SPIR-V we produced is valid. If this SkASSERT fails, check the logs prior
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001799 // to the failure to see the validation errors.
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001800 SkAssertResult(tools.Validate((const uint32_t*) data.c_str(), data.size() / 4));
Ethan Nicholas762466e2017-06-29 10:03:38 -04001801 out.write(data.c_str(), data.size());
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001802 }
1803#else
Brian Osman88cda172020-10-09 12:05:16 -04001804 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001805 SPIRVCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001806 bool result = cg.generateCode();
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001807#endif
Ethan Nicholasce33f102016-12-09 17:22:59 -05001808 return result;
1809}
1810
Ethan Nicholas00543112018-07-31 09:44:36 -04001811bool Compiler::toSPIRV(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001812 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001813 bool result = this->toSPIRV(program, buffer);
1814 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001815 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001816 }
1817 return result;
1818}
1819
Ethan Nicholas00543112018-07-31 09:44:36 -04001820bool Compiler::toGLSL(Program& program, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001821 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001822 GLSLCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001823 bool result = cg.generateCode();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001824 return result;
1825}
1826
Ethan Nicholas00543112018-07-31 09:44:36 -04001827bool Compiler::toGLSL(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001828 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001829 bool result = this->toGLSL(program, buffer);
1830 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001831 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001832 }
1833 return result;
1834}
1835
Brian Osmanc0243912020-02-19 15:35:26 -05001836bool Compiler::toHLSL(Program& program, String* out) {
1837 String spirv;
1838 if (!this->toSPIRV(program, &spirv)) {
1839 return false;
1840 }
1841
1842 return SPIRVtoHLSL(spirv, out);
1843}
1844
Ethan Nicholas00543112018-07-31 09:44:36 -04001845bool Compiler::toMetal(Program& program, OutputStream& out) {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001846 MetalCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholascc305772017-10-13 16:17:45 -04001847 bool result = cg.generateCode();
Ethan Nicholascc305772017-10-13 16:17:45 -04001848 return result;
1849}
1850
Ethan Nicholas00543112018-07-31 09:44:36 -04001851bool Compiler::toMetal(Program& program, String* out) {
Timothy Liangb8eeb802018-07-23 16:46:16 -04001852 StringStream buffer;
1853 bool result = this->toMetal(program, buffer);
1854 if (result) {
1855 *out = buffer.str();
1856 }
1857 return result;
1858}
1859
Greg Daniela28ea672020-09-25 11:12:56 -04001860#if defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04001861bool Compiler::toCPP(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001862 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001863 CPPCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001864 bool result = cg.generateCode();
Ethan Nicholas762466e2017-06-29 10:03:38 -04001865 return result;
1866}
1867
Ethan Nicholas00543112018-07-31 09:44:36 -04001868bool Compiler::toH(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001869 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001870 HCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001871 bool result = cg.generateCode();
Ethan Nicholas00543112018-07-31 09:44:36 -04001872 return result;
1873}
Greg Daniela28ea672020-09-25 11:12:56 -04001874#endif // defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04001875
Ethan Nicholas2a479a52020-08-18 16:29:45 -04001876#endif // defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
Brian Osman2e29ab52019-09-20 12:19:11 -04001877
1878#if !defined(SKSL_STANDALONE) && SK_SUPPORT_GPU
Brian Osmana4b91692020-08-10 14:26:16 -04001879bool Compiler::toPipelineStage(Program& program, PipelineStageArgs* outArgs) {
Brian Osman88cda172020-10-09 12:05:16 -04001880 AutoSource as(this, program.fSource.get());
Ethan Nicholas00543112018-07-31 09:44:36 -04001881 StringStream buffer;
Brian Osman300fe1d2020-01-23 15:42:43 -05001882 PipelineStageCodeGenerator cg(fContext.get(), &program, this, &buffer, outArgs);
Ethan Nicholas00543112018-07-31 09:44:36 -04001883 bool result = cg.generateCode();
Ethan Nicholas00543112018-07-31 09:44:36 -04001884 if (result) {
Brian Osman107c6662019-12-30 15:02:30 -05001885 outArgs->fCode = buffer.str();
Ethan Nicholas00543112018-07-31 09:44:36 -04001886 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001887 return result;
1888}
Brian Osmanfb32ddf2019-06-18 10:14:20 -04001889#endif
1890
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001891std::unique_ptr<ByteCode> Compiler::toByteCode(Program& program) {
Brian Osman88cda172020-10-09 12:05:16 -04001892 AutoSource as(this, program.fSource.get());
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001893 std::unique_ptr<ByteCode> result(new ByteCode());
Brian Osmanb08cc022020-04-02 11:38:40 -04001894 ByteCodeGenerator cg(fContext.get(), &program, this, result.get());
1895 bool success = cg.generateCode();
Brian Osmanb08cc022020-04-02 11:38:40 -04001896 if (success) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001897 return result;
1898 }
1899 return nullptr;
1900}
1901
Brian Osman401a0092020-09-10 14:47:24 -04001902const char* Compiler::OperatorName(Token::Kind op) {
1903 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001904 case Token::Kind::TK_PLUS: return "+";
1905 case Token::Kind::TK_MINUS: return "-";
1906 case Token::Kind::TK_STAR: return "*";
1907 case Token::Kind::TK_SLASH: return "/";
1908 case Token::Kind::TK_PERCENT: return "%";
1909 case Token::Kind::TK_SHL: return "<<";
1910 case Token::Kind::TK_SHR: return ">>";
1911 case Token::Kind::TK_LOGICALNOT: return "!";
1912 case Token::Kind::TK_LOGICALAND: return "&&";
1913 case Token::Kind::TK_LOGICALOR: return "||";
1914 case Token::Kind::TK_LOGICALXOR: return "^^";
1915 case Token::Kind::TK_BITWISENOT: return "~";
1916 case Token::Kind::TK_BITWISEAND: return "&";
1917 case Token::Kind::TK_BITWISEOR: return "|";
1918 case Token::Kind::TK_BITWISEXOR: return "^";
1919 case Token::Kind::TK_EQ: return "=";
1920 case Token::Kind::TK_EQEQ: return "==";
1921 case Token::Kind::TK_NEQ: return "!=";
1922 case Token::Kind::TK_LT: return "<";
1923 case Token::Kind::TK_GT: return ">";
1924 case Token::Kind::TK_LTEQ: return "<=";
1925 case Token::Kind::TK_GTEQ: return ">=";
1926 case Token::Kind::TK_PLUSEQ: return "+=";
1927 case Token::Kind::TK_MINUSEQ: return "-=";
1928 case Token::Kind::TK_STAREQ: return "*=";
1929 case Token::Kind::TK_SLASHEQ: return "/=";
1930 case Token::Kind::TK_PERCENTEQ: return "%=";
1931 case Token::Kind::TK_SHLEQ: return "<<=";
1932 case Token::Kind::TK_SHREQ: return ">>=";
1933 case Token::Kind::TK_LOGICALANDEQ: return "&&=";
1934 case Token::Kind::TK_LOGICALOREQ: return "||=";
1935 case Token::Kind::TK_LOGICALXOREQ: return "^^=";
1936 case Token::Kind::TK_BITWISEANDEQ: return "&=";
1937 case Token::Kind::TK_BITWISEOREQ: return "|=";
1938 case Token::Kind::TK_BITWISEXOREQ: return "^=";
1939 case Token::Kind::TK_PLUSPLUS: return "++";
1940 case Token::Kind::TK_MINUSMINUS: return "--";
1941 case Token::Kind::TK_COMMA: return ",";
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001942 default:
Brian Osman401a0092020-09-10 14:47:24 -04001943 ABORT("unsupported operator: %d\n", (int) op);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001944 }
1945}
1946
1947
1948bool Compiler::IsAssignment(Token::Kind op) {
1949 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001950 case Token::Kind::TK_EQ: // fall through
1951 case Token::Kind::TK_PLUSEQ: // fall through
1952 case Token::Kind::TK_MINUSEQ: // fall through
1953 case Token::Kind::TK_STAREQ: // fall through
1954 case Token::Kind::TK_SLASHEQ: // fall through
1955 case Token::Kind::TK_PERCENTEQ: // fall through
1956 case Token::Kind::TK_SHLEQ: // fall through
1957 case Token::Kind::TK_SHREQ: // fall through
1958 case Token::Kind::TK_BITWISEOREQ: // fall through
1959 case Token::Kind::TK_BITWISEXOREQ: // fall through
1960 case Token::Kind::TK_BITWISEANDEQ: // fall through
1961 case Token::Kind::TK_LOGICALOREQ: // fall through
1962 case Token::Kind::TK_LOGICALXOREQ: // fall through
1963 case Token::Kind::TK_LOGICALANDEQ:
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001964 return true;
1965 default:
1966 return false;
1967 }
1968}
1969
Brian Osman401a0092020-09-10 14:47:24 -04001970Token::Kind Compiler::RemoveAssignment(Token::Kind op) {
1971 switch (op) {
1972 case Token::Kind::TK_PLUSEQ: return Token::Kind::TK_PLUS;
1973 case Token::Kind::TK_MINUSEQ: return Token::Kind::TK_MINUS;
1974 case Token::Kind::TK_STAREQ: return Token::Kind::TK_STAR;
1975 case Token::Kind::TK_SLASHEQ: return Token::Kind::TK_SLASH;
1976 case Token::Kind::TK_PERCENTEQ: return Token::Kind::TK_PERCENT;
1977 case Token::Kind::TK_SHLEQ: return Token::Kind::TK_SHL;
1978 case Token::Kind::TK_SHREQ: return Token::Kind::TK_SHR;
1979 case Token::Kind::TK_BITWISEOREQ: return Token::Kind::TK_BITWISEOR;
1980 case Token::Kind::TK_BITWISEXOREQ: return Token::Kind::TK_BITWISEXOR;
1981 case Token::Kind::TK_BITWISEANDEQ: return Token::Kind::TK_BITWISEAND;
1982 case Token::Kind::TK_LOGICALOREQ: return Token::Kind::TK_LOGICALOR;
1983 case Token::Kind::TK_LOGICALXOREQ: return Token::Kind::TK_LOGICALXOR;
1984 case Token::Kind::TK_LOGICALANDEQ: return Token::Kind::TK_LOGICALAND;
1985 default: return op;
1986 }
1987}
1988
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001989Position Compiler::position(int offset) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001990 SkASSERT(fSource);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001991 int line = 1;
1992 int column = 1;
1993 for (int i = 0; i < offset; i++) {
1994 if ((*fSource)[i] == '\n') {
1995 ++line;
1996 column = 1;
1997 }
1998 else {
1999 ++column;
2000 }
2001 }
2002 return Position(line, column);
2003}
2004
2005void Compiler::error(int offset, String msg) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002006 fErrorCount++;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002007 Position pos = this->position(offset);
2008 fErrorText += "error: " + to_string(pos.fLine) + ": " + msg.c_str() + "\n";
ethannicholasb3058bd2016-07-01 08:22:01 -07002009}
2010
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002011String Compiler::errorText() {
Ethan Nicholas00543112018-07-31 09:44:36 -04002012 this->writeErrorCount();
2013 fErrorCount = 0;
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002014 String result = fErrorText;
ethannicholasb3058bd2016-07-01 08:22:01 -07002015 return result;
2016}
2017
2018void Compiler::writeErrorCount() {
2019 if (fErrorCount) {
2020 fErrorText += to_string(fErrorCount) + " error";
2021 if (fErrorCount > 1) {
2022 fErrorText += "s";
2023 }
2024 fErrorText += "\n";
2025 }
2026}
2027
John Stilesa6841be2020-08-06 14:11:56 -04002028} // namespace SkSL