blob: 23971d7d6244c532c39766a7de2f8405ed39f689 [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
Mike Kleinc0bd9f92019-04-23 12:05:21 -050013#include "src/sksl/SkSLByteCodeGenerator.h"
14#include "src/sksl/SkSLCFGGenerator.h"
15#include "src/sksl/SkSLCPPCodeGenerator.h"
16#include "src/sksl/SkSLGLSLCodeGenerator.h"
17#include "src/sksl/SkSLHCodeGenerator.h"
18#include "src/sksl/SkSLIRGenerator.h"
19#include "src/sksl/SkSLMetalCodeGenerator.h"
20#include "src/sksl/SkSLPipelineStageCodeGenerator.h"
Ethan Nicholasc18bb512020-07-28 14:46:53 -040021#include "src/sksl/SkSLRehydrator.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050022#include "src/sksl/SkSLSPIRVCodeGenerator.h"
Brian Osmanc0243912020-02-19 15:35:26 -050023#include "src/sksl/SkSLSPIRVtoHLSL.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050024#include "src/sksl/ir/SkSLEnum.h"
25#include "src/sksl/ir/SkSLExpression.h"
26#include "src/sksl/ir/SkSLExpressionStatement.h"
27#include "src/sksl/ir/SkSLFunctionCall.h"
28#include "src/sksl/ir/SkSLIntLiteral.h"
29#include "src/sksl/ir/SkSLModifiersDeclaration.h"
30#include "src/sksl/ir/SkSLNop.h"
31#include "src/sksl/ir/SkSLSymbolTable.h"
32#include "src/sksl/ir/SkSLTernaryExpression.h"
33#include "src/sksl/ir/SkSLUnresolvedFunction.h"
34#include "src/sksl/ir/SkSLVarDeclarations.h"
ethannicholasb3058bd2016-07-01 08:22:01 -070035
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -040036#include <fstream>
37
Ethan Nicholasa11035b2019-11-26 16:27:47 -050038#if !defined(SKSL_STANDALONE) & SK_SUPPORT_GPU
39#include "include/gpu/GrContextOptions.h"
40#include "src/gpu/GrShaderCaps.h"
41#endif
42
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -040043#ifdef SK_ENABLE_SPIRV_VALIDATION
44#include "spirv-tools/libspirv.hpp"
45#endif
46
Brian Osmandd496172020-08-08 08:17:18 -040047#if !SKSL_STANDALONE
Ethan Nicholasc18bb512020-07-28 14:46:53 -040048
49#include "src/sksl/generated/sksl_fp.dehydrated.sksl"
50#include "src/sksl/generated/sksl_frag.dehydrated.sksl"
51#include "src/sksl/generated/sksl_geom.dehydrated.sksl"
52#include "src/sksl/generated/sksl_gpu.dehydrated.sksl"
53#include "src/sksl/generated/sksl_interp.dehydrated.sksl"
54#include "src/sksl/generated/sksl_pipeline.dehydrated.sksl"
55#include "src/sksl/generated/sksl_vert.dehydrated.sksl"
56
57#else
58
Brian Osmandd496172020-08-08 08:17:18 -040059// GN generates or copies all of these files to the skslc executable directory
60static const char SKSL_GPU_INCLUDE[] = "sksl_gpu.sksl";
61static const char SKSL_INTERP_INCLUDE[] = "sksl_interp.sksl";
62static const char SKSL_VERT_INCLUDE[] = "sksl_vert.sksl";
63static const char SKSL_FRAG_INCLUDE[] = "sksl_frag.sksl";
64static const char SKSL_GEOM_INCLUDE[] = "sksl_geom.sksl";
65static const char SKSL_FP_INCLUDE[] = "sksl_fp.sksl";
66static const char SKSL_PIPELINE_INCLUDE[] = "sksl_pipeline.sksl";
Ethan Nicholasc18bb512020-07-28 14:46:53 -040067
68#endif
Ethan Nicholas0d997662019-04-08 09:46:01 -040069
ethannicholasb3058bd2016-07-01 08:22:01 -070070namespace SkSL {
71
Ethan Nicholasdb80f692019-11-22 14:06:12 -050072static void grab_intrinsics(std::vector<std::unique_ptr<ProgramElement>>* src,
Brian Osman08f986d2020-05-13 17:06:46 -040073 std::map<String, std::pair<std::unique_ptr<ProgramElement>, bool>>* target) {
74 for (auto iter = src->begin(); iter != src->end(); ) {
75 std::unique_ptr<ProgramElement>& element = *iter;
Ethan Nicholasdb80f692019-11-22 14:06:12 -050076 switch (element->fKind) {
77 case ProgramElement::kFunction_Kind: {
78 FunctionDefinition& f = (FunctionDefinition&) *element;
Brian Osman08f986d2020-05-13 17:06:46 -040079 SkASSERT(f.fDeclaration.fBuiltin);
Ethan Nicholasc18bb512020-07-28 14:46:53 -040080 String key = f.fDeclaration.description();
Brian Osman08f986d2020-05-13 17:06:46 -040081 SkASSERT(target->find(key) == target->end());
82 (*target)[key] = std::make_pair(std::move(element), false);
83 iter = src->erase(iter);
Ethan Nicholasdb80f692019-11-22 14:06:12 -050084 break;
85 }
86 case ProgramElement::kEnum_Kind: {
87 Enum& e = (Enum&) *element;
88 StringFragment name = e.fTypeName;
89 SkASSERT(target->find(name) == target->end());
90 (*target)[name] = std::make_pair(std::move(element), false);
Brian Osman08f986d2020-05-13 17:06:46 -040091 iter = src->erase(iter);
Ethan Nicholasdb80f692019-11-22 14:06:12 -050092 break;
93 }
94 default:
95 printf("unsupported include file element\n");
96 SkASSERT(false);
97 }
98 }
99}
100
Ethan Nicholas6e1cbc02017-07-14 10:12:15 -0400101Compiler::Compiler(Flags flags)
102: fFlags(flags)
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400103, fContext(new Context())
Ethan Nicholas6e1cbc02017-07-14 10:12:15 -0400104, fErrorCount(0) {
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400105 auto symbols = std::shared_ptr<SymbolTable>(new SymbolTable(this));
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400106 fIRGenerator = new IRGenerator(fContext.get(), symbols, *this);
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400107 #define ADD_TYPE(t) symbols->addWithoutOwnership(fContext->f ## t ## _Type->fName, \
108 fContext->f ## t ## _Type.get())
ethannicholasb3058bd2016-07-01 08:22:01 -0700109 ADD_TYPE(Void);
110 ADD_TYPE(Float);
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400111 ADD_TYPE(Float2);
112 ADD_TYPE(Float3);
113 ADD_TYPE(Float4);
Ethan Nicholasdcba08e2017-08-02 10:52:54 -0400114 ADD_TYPE(Half);
115 ADD_TYPE(Half2);
116 ADD_TYPE(Half3);
117 ADD_TYPE(Half4);
ethannicholasb3058bd2016-07-01 08:22:01 -0700118 ADD_TYPE(Int);
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400119 ADD_TYPE(Int2);
120 ADD_TYPE(Int3);
121 ADD_TYPE(Int4);
ethannicholasb3058bd2016-07-01 08:22:01 -0700122 ADD_TYPE(UInt);
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400123 ADD_TYPE(UInt2);
124 ADD_TYPE(UInt3);
125 ADD_TYPE(UInt4);
Ethan Nicholasdcba08e2017-08-02 10:52:54 -0400126 ADD_TYPE(Short);
127 ADD_TYPE(Short2);
128 ADD_TYPE(Short3);
129 ADD_TYPE(Short4);
130 ADD_TYPE(UShort);
131 ADD_TYPE(UShort2);
132 ADD_TYPE(UShort3);
133 ADD_TYPE(UShort4);
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400134 ADD_TYPE(Byte);
135 ADD_TYPE(Byte2);
136 ADD_TYPE(Byte3);
137 ADD_TYPE(Byte4);
138 ADD_TYPE(UByte);
139 ADD_TYPE(UByte2);
140 ADD_TYPE(UByte3);
141 ADD_TYPE(UByte4);
ethannicholasb3058bd2016-07-01 08:22:01 -0700142 ADD_TYPE(Bool);
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400143 ADD_TYPE(Bool2);
144 ADD_TYPE(Bool3);
145 ADD_TYPE(Bool4);
146 ADD_TYPE(Float2x2);
147 ADD_TYPE(Float2x3);
148 ADD_TYPE(Float2x4);
149 ADD_TYPE(Float3x2);
150 ADD_TYPE(Float3x3);
151 ADD_TYPE(Float3x4);
152 ADD_TYPE(Float4x2);
153 ADD_TYPE(Float4x3);
154 ADD_TYPE(Float4x4);
Ethan Nicholasdcba08e2017-08-02 10:52:54 -0400155 ADD_TYPE(Half2x2);
156 ADD_TYPE(Half2x3);
157 ADD_TYPE(Half2x4);
158 ADD_TYPE(Half3x2);
159 ADD_TYPE(Half3x3);
160 ADD_TYPE(Half3x4);
161 ADD_TYPE(Half4x2);
162 ADD_TYPE(Half4x3);
163 ADD_TYPE(Half4x4);
ethannicholasb3058bd2016-07-01 08:22:01 -0700164 ADD_TYPE(GenType);
Ethan Nicholasdcba08e2017-08-02 10:52:54 -0400165 ADD_TYPE(GenHType);
ethannicholasb3058bd2016-07-01 08:22:01 -0700166 ADD_TYPE(GenIType);
167 ADD_TYPE(GenUType);
168 ADD_TYPE(GenBType);
169 ADD_TYPE(Mat);
170 ADD_TYPE(Vec);
171 ADD_TYPE(GVec);
172 ADD_TYPE(GVec2);
173 ADD_TYPE(GVec3);
174 ADD_TYPE(GVec4);
Ethan Nicholasdcba08e2017-08-02 10:52:54 -0400175 ADD_TYPE(HVec);
ethannicholasb3058bd2016-07-01 08:22:01 -0700176 ADD_TYPE(IVec);
177 ADD_TYPE(UVec);
Ethan Nicholasdcba08e2017-08-02 10:52:54 -0400178 ADD_TYPE(SVec);
179 ADD_TYPE(USVec);
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400180 ADD_TYPE(ByteVec);
181 ADD_TYPE(UByteVec);
ethannicholasb3058bd2016-07-01 08:22:01 -0700182 ADD_TYPE(BVec);
183
184 ADD_TYPE(Sampler1D);
185 ADD_TYPE(Sampler2D);
186 ADD_TYPE(Sampler3D);
ethannicholas5961bc92016-10-12 06:39:56 -0700187 ADD_TYPE(SamplerExternalOES);
ethannicholasb3058bd2016-07-01 08:22:01 -0700188 ADD_TYPE(SamplerCube);
189 ADD_TYPE(Sampler2DRect);
190 ADD_TYPE(Sampler1DArray);
191 ADD_TYPE(Sampler2DArray);
192 ADD_TYPE(SamplerCubeArray);
193 ADD_TYPE(SamplerBuffer);
194 ADD_TYPE(Sampler2DMS);
195 ADD_TYPE(Sampler2DMSArray);
196
Brian Salomonbf7b6202016-11-11 16:08:03 -0500197 ADD_TYPE(ISampler2D);
198
Brian Salomon2a51de82016-11-16 12:06:01 -0500199 ADD_TYPE(Image2D);
200 ADD_TYPE(IImage2D);
201
Greg Daniel64773e62016-11-22 09:44:03 -0500202 ADD_TYPE(SubpassInput);
203 ADD_TYPE(SubpassInputMS);
204
ethannicholasb3058bd2016-07-01 08:22:01 -0700205 ADD_TYPE(GSampler1D);
206 ADD_TYPE(GSampler2D);
207 ADD_TYPE(GSampler3D);
208 ADD_TYPE(GSamplerCube);
209 ADD_TYPE(GSampler2DRect);
210 ADD_TYPE(GSampler1DArray);
211 ADD_TYPE(GSampler2DArray);
212 ADD_TYPE(GSamplerCubeArray);
213 ADD_TYPE(GSamplerBuffer);
214 ADD_TYPE(GSampler2DMS);
215 ADD_TYPE(GSampler2DMSArray);
216
217 ADD_TYPE(Sampler1DShadow);
218 ADD_TYPE(Sampler2DShadow);
219 ADD_TYPE(SamplerCubeShadow);
220 ADD_TYPE(Sampler2DRectShadow);
221 ADD_TYPE(Sampler1DArrayShadow);
222 ADD_TYPE(Sampler2DArrayShadow);
223 ADD_TYPE(SamplerCubeArrayShadow);
224 ADD_TYPE(GSampler2DArrayShadow);
225 ADD_TYPE(GSamplerCubeArrayShadow);
Ethan Nicholasc9472af2017-10-10 16:30:21 -0400226 ADD_TYPE(FragmentProcessor);
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400227 ADD_TYPE(Sampler);
228 ADD_TYPE(Texture2D);
ethannicholasb3058bd2016-07-01 08:22:01 -0700229
Brian Osman28590d52020-03-23 16:59:08 -0400230 StringFragment fpAliasName("shader");
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400231 symbols->addWithoutOwnership(fpAliasName, fContext->fFragmentProcessor_Type.get());
Brian Osman28590d52020-03-23 16:59:08 -0400232
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700233 StringFragment skCapsName("sk_Caps");
234 Variable* skCaps = new Variable(-1, Modifiers(), skCapsName,
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400235 *fContext->fSkCaps_Type, Variable::kGlobal_Storage);
Ethan Nicholas3605ace2016-11-21 15:59:48 -0500236 fIRGenerator->fSymbolTable->add(skCapsName, std::unique_ptr<Symbol>(skCaps));
237
Ethan Nicholasdb80f692019-11-22 14:06:12 -0500238 fIRGenerator->fIntrinsics = &fGPUIntrinsics;
239 std::vector<std::unique_ptr<ProgramElement>> gpuIntrinsics;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400240 std::vector<std::unique_ptr<ProgramElement>> interpIntrinsics;
Brian Osmandd496172020-08-08 08:17:18 -0400241#if SKSL_STANDALONE
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400242 this->processIncludeFile(Program::kFragment_Kind, SKSL_GPU_INCLUDE, symbols, &gpuIntrinsics,
243 &fGpuSymbolTable);
244 this->processIncludeFile(Program::kVertex_Kind, SKSL_VERT_INCLUDE, fGpuSymbolTable,
245 &fVertexInclude, &fVertexSymbolTable);
246 this->processIncludeFile(Program::kFragment_Kind, SKSL_FRAG_INCLUDE, fGpuSymbolTable,
247 &fFragmentInclude, &fFragmentSymbolTable);
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400248#else
249 {
250 Rehydrator rehydrator(fContext.get(), symbols, this, SKSL_INCLUDE_sksl_gpu,
251 SKSL_INCLUDE_sksl_gpu_LENGTH);
252 fGpuSymbolTable = rehydrator.symbolTable();
253 gpuIntrinsics = rehydrator.elements();
254 }
255 {
256 Rehydrator rehydrator(fContext.get(), fGpuSymbolTable, this, SKSL_INCLUDE_sksl_vert,
257 SKSL_INCLUDE_sksl_vert_LENGTH);
258 fVertexSymbolTable = rehydrator.symbolTable();
259 fVertexInclude = rehydrator.elements();
260 }
261 {
262 Rehydrator rehydrator(fContext.get(), fGpuSymbolTable, this, SKSL_INCLUDE_sksl_frag,
263 SKSL_INCLUDE_sksl_frag_LENGTH);
264 fFragmentSymbolTable = rehydrator.symbolTable();
265 fFragmentInclude = rehydrator.elements();
266 }
267#endif
268 grab_intrinsics(&gpuIntrinsics, &fGPUIntrinsics);
Brian Osmanb08cc022020-04-02 11:38:40 -0400269 grab_intrinsics(&interpIntrinsics, &fInterpreterIntrinsics);
ethannicholasb3058bd2016-07-01 08:22:01 -0700270}
271
272Compiler::~Compiler() {
273 delete fIRGenerator;
274}
275
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400276void Compiler::loadGeometryIntrinsics() {
277 if (fGeometrySymbolTable) {
278 return;
279 }
Brian Osmandd496172020-08-08 08:17:18 -0400280 #if !SKSL_STANDALONE
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400281 {
282 Rehydrator rehydrator(fContext.get(), fGpuSymbolTable, this, SKSL_INCLUDE_sksl_geom,
283 SKSL_INCLUDE_sksl_geom_LENGTH);
284 fGeometrySymbolTable = rehydrator.symbolTable();
285 fGeometryInclude = rehydrator.elements();
286 }
287 #else
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400288 this->processIncludeFile(Program::kGeometry_Kind, SKSL_GEOM_INCLUDE, fGpuSymbolTable,
289 &fGeometryInclude, &fGeometrySymbolTable);
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400290 #endif
291}
292
293void Compiler::loadPipelineIntrinsics() {
294 if (fPipelineSymbolTable) {
295 return;
296 }
Brian Osmandd496172020-08-08 08:17:18 -0400297 #if !SKSL_STANDALONE
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400298 {
299 Rehydrator rehydrator(fContext.get(), fGpuSymbolTable, this,
300 SKSL_INCLUDE_sksl_pipeline,
301 SKSL_INCLUDE_sksl_pipeline_LENGTH);
302 fPipelineSymbolTable = rehydrator.symbolTable();
303 fPipelineInclude = rehydrator.elements();
304 }
305 #else
306 this->processIncludeFile(Program::kPipelineStage_Kind, SKSL_PIPELINE_INCLUDE,
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400307 fGpuSymbolTable, &fPipelineInclude, &fPipelineSymbolTable);
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400308 #endif
309}
310
311void Compiler::loadInterpreterIntrinsics() {
312 if (fInterpreterSymbolTable) {
313 return;
314 }
315 this->loadPipelineIntrinsics();
Brian Osmandd496172020-08-08 08:17:18 -0400316 #if !SKSL_STANDALONE
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400317 {
318 Rehydrator rehydrator(fContext.get(), fPipelineSymbolTable, this,
319 SKSL_INCLUDE_sksl_interp,
320 SKSL_INCLUDE_sksl_interp_LENGTH);
321 fInterpreterSymbolTable = rehydrator.symbolTable();
322 fInterpreterInclude = rehydrator.elements();
323 }
324 #else
325 this->processIncludeFile(Program::kGeneric_Kind, SKSL_INTERP_INCLUDE,
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400326 fIRGenerator->fSymbolTable, &fInterpreterInclude,
327 &fInterpreterSymbolTable);
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400328 #endif
329}
330
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400331void Compiler::processIncludeFile(Program::Kind kind, const char* path,
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400332 std::shared_ptr<SymbolTable> base,
333 std::vector<std::unique_ptr<ProgramElement>>* outElements,
334 std::shared_ptr<SymbolTable>* outSymbolTable) {
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400335 std::ifstream in(path);
336 std::string stdText{std::istreambuf_iterator<char>(in),
337 std::istreambuf_iterator<char>()};
338 if (in.rdstate()) {
339 printf("error reading %s\n", path);
340 abort();
341 }
342 if (!base) {
343 base = fIRGenerator->fSymbolTable;
344 }
345 SkASSERT(base);
346 const String* source = base->takeOwnershipOfString(std::make_unique<String>(stdText.c_str()));
347 fSource = source;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400348 std::shared_ptr<SymbolTable> old = fIRGenerator->fSymbolTable;
349 if (base) {
350 fIRGenerator->fSymbolTable = std::move(base);
351 }
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400352 Program::Settings settings;
Ethan Nicholasa11035b2019-11-26 16:27:47 -0500353#if !defined(SKSL_STANDALONE) & SK_SUPPORT_GPU
354 GrContextOptions opts;
355 GrShaderCaps caps(opts);
356 settings.fCaps = &caps;
357#endif
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400358 SkASSERT(fIRGenerator->fCanInline);
359 fIRGenerator->fCanInline = false;
360 fIRGenerator->start(&settings, nullptr, true);
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400361 fIRGenerator->convertProgram(kind, source->c_str(), source->length(), outElements);
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400362 fIRGenerator->fCanInline = true;
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400363 if (this->fErrorCount) {
364 printf("Unexpected errors: %s\n", this->fErrorText.c_str());
365 }
366 SkASSERT(!fErrorCount);
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400367 *outSymbolTable = fIRGenerator->fSymbolTable;
Ethan Nicholasa11035b2019-11-26 16:27:47 -0500368#ifdef SK_DEBUG
369 fSource = nullptr;
370#endif
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400371 fIRGenerator->fSymbolTable = std::move(old);
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400372}
373
ethannicholas22f939e2016-10-13 13:25:34 -0700374// add the definition created by assigning to the lvalue to the definition set
Ethan Nicholas86a43402017-01-19 13:32:00 -0500375void Compiler::addDefinition(const Expression* lvalue, std::unique_ptr<Expression>* expr,
376 DefinitionMap* definitions) {
ethannicholas22f939e2016-10-13 13:25:34 -0700377 switch (lvalue->fKind) {
378 case Expression::kVariableReference_Kind: {
379 const Variable& var = ((VariableReference*) lvalue)->fVariable;
380 if (var.fStorage == Variable::kLocal_Storage) {
381 (*definitions)[&var] = expr;
382 }
383 break;
384 }
385 case Expression::kSwizzle_Kind:
386 // We consider the variable written to as long as at least some of its components have
387 // been written to. This will lead to some false negatives (we won't catch it if you
388 // write to foo.x and then read foo.y), but being stricter could lead to false positives
Mike Klein6ad99092016-10-26 10:35:22 -0400389 // (we write to foo.x, and then pass foo to a function which happens to only read foo.x,
390 // 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 -0700391 // more complicated whole-program analysis. This is probably good enough.
Mike Klein6ad99092016-10-26 10:35:22 -0400392 this->addDefinition(((Swizzle*) lvalue)->fBase.get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400393 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
ethannicholas22f939e2016-10-13 13:25:34 -0700394 definitions);
395 break;
396 case Expression::kIndex_Kind:
397 // see comments in Swizzle
Mike Klein6ad99092016-10-26 10:35:22 -0400398 this->addDefinition(((IndexExpression*) lvalue)->fBase.get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400399 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
ethannicholas22f939e2016-10-13 13:25:34 -0700400 definitions);
401 break;
402 case Expression::kFieldAccess_Kind:
403 // see comments in Swizzle
Mike Klein6ad99092016-10-26 10:35:22 -0400404 this->addDefinition(((FieldAccess*) lvalue)->fBase.get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400405 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
ethannicholas22f939e2016-10-13 13:25:34 -0700406 definitions);
407 break;
Ethan Nicholasa583b812018-01-18 13:32:11 -0500408 case Expression::kTernary_Kind:
409 // To simplify analysis, we just pretend that we write to both sides of the ternary.
410 // This allows for false positives (meaning we fail to detect that a variable might not
411 // have been assigned), but is preferable to false negatives.
412 this->addDefinition(((TernaryExpression*) lvalue)->fIfTrue.get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400413 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
Ethan Nicholasa583b812018-01-18 13:32:11 -0500414 definitions);
415 this->addDefinition(((TernaryExpression*) lvalue)->fIfFalse.get(),
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400416 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
Ethan Nicholasa583b812018-01-18 13:32:11 -0500417 definitions);
418 break;
Ethan Nicholas91164d12019-05-15 15:29:54 -0400419 case Expression::kExternalValue_Kind:
420 break;
ethannicholas22f939e2016-10-13 13:25:34 -0700421 default:
422 // not an lvalue, can't happen
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400423 SkASSERT(false);
ethannicholas22f939e2016-10-13 13:25:34 -0700424 }
425}
426
427// add local variables defined by this node to the set
Mike Klein6ad99092016-10-26 10:35:22 -0400428void Compiler::addDefinitions(const BasicBlock::Node& node,
Ethan Nicholas86a43402017-01-19 13:32:00 -0500429 DefinitionMap* definitions) {
ethannicholas22f939e2016-10-13 13:25:34 -0700430 switch (node.fKind) {
431 case BasicBlock::Node::kExpression_Kind: {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400432 SkASSERT(node.expression());
Ethan Nicholascb670962017-04-20 19:31:52 -0400433 const Expression* expr = (Expression*) node.expression()->get();
Ethan Nicholas86a43402017-01-19 13:32:00 -0500434 switch (expr->fKind) {
435 case Expression::kBinary_Kind: {
436 BinaryExpression* b = (BinaryExpression*) expr;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400437 if (b->fOperator == Token::Kind::TK_EQ) {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500438 this->addDefinition(b->fLeft.get(), &b->fRight, definitions);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700439 } else if (Compiler::IsAssignment(b->fOperator)) {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500440 this->addDefinition(
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400441 b->fLeft.get(),
442 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
443 definitions);
Ethan Nicholas86a43402017-01-19 13:32:00 -0500444
445 }
446 break;
ethannicholas22f939e2016-10-13 13:25:34 -0700447 }
Ethan Nicholasc6a19f12018-03-29 16:46:56 -0400448 case Expression::kFunctionCall_Kind: {
449 const FunctionCall& c = (const FunctionCall&) *expr;
450 for (size_t i = 0; i < c.fFunction.fParameters.size(); ++i) {
451 if (c.fFunction.fParameters[i]->fModifiers.fFlags & Modifiers::kOut_Flag) {
452 this->addDefinition(
453 c.fArguments[i].get(),
454 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
455 definitions);
456 }
457 }
458 break;
459 }
Ethan Nicholas86a43402017-01-19 13:32:00 -0500460 case Expression::kPrefix_Kind: {
461 const PrefixExpression* p = (PrefixExpression*) expr;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400462 if (p->fOperator == Token::Kind::TK_MINUSMINUS ||
463 p->fOperator == Token::Kind::TK_PLUSPLUS) {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500464 this->addDefinition(
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400465 p->fOperand.get(),
466 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
467 definitions);
Ethan Nicholas86a43402017-01-19 13:32:00 -0500468 }
469 break;
470 }
471 case Expression::kPostfix_Kind: {
472 const PostfixExpression* p = (PostfixExpression*) expr;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400473 if (p->fOperator == Token::Kind::TK_MINUSMINUS ||
474 p->fOperator == Token::Kind::TK_PLUSPLUS) {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500475 this->addDefinition(
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400476 p->fOperand.get(),
477 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
478 definitions);
Ethan Nicholas86a43402017-01-19 13:32:00 -0500479 }
480 break;
481 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400482 case Expression::kVariableReference_Kind: {
483 const VariableReference* v = (VariableReference*) expr;
484 if (v->fRefKind != VariableReference::kRead_RefKind) {
485 this->addDefinition(
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400486 v,
487 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression,
488 definitions);
Ethan Nicholascb670962017-04-20 19:31:52 -0400489 }
John Stiles30212b72020-06-11 17:55:07 -0400490 break;
Ethan Nicholascb670962017-04-20 19:31:52 -0400491 }
Ethan Nicholas86a43402017-01-19 13:32:00 -0500492 default:
493 break;
ethannicholas22f939e2016-10-13 13:25:34 -0700494 }
495 break;
496 }
497 case BasicBlock::Node::kStatement_Kind: {
Ethan Nicholascb670962017-04-20 19:31:52 -0400498 const Statement* stmt = (Statement*) node.statement()->get();
Ethan Nicholas82a62d22017-11-07 14:42:10 +0000499 if (stmt->fKind == Statement::kVarDeclaration_Kind) {
500 VarDeclaration& vd = (VarDeclaration&) *stmt;
501 if (vd.fValue) {
502 (*definitions)[vd.fVar] = &vd.fValue;
ethannicholas22f939e2016-10-13 13:25:34 -0700503 }
504 }
505 break;
506 }
507 }
508}
509
510void Compiler::scanCFG(CFG* cfg, BlockId blockId, std::set<BlockId>* workList) {
511 BasicBlock& block = cfg->fBlocks[blockId];
512
513 // compute definitions after this block
Ethan Nicholas86a43402017-01-19 13:32:00 -0500514 DefinitionMap after = block.fBefore;
ethannicholas22f939e2016-10-13 13:25:34 -0700515 for (const BasicBlock::Node& n : block.fNodes) {
516 this->addDefinitions(n, &after);
517 }
518
519 // propagate definitions to exits
520 for (BlockId exitId : block.fExits) {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400521 if (exitId == blockId) {
522 continue;
523 }
ethannicholas22f939e2016-10-13 13:25:34 -0700524 BasicBlock& exit = cfg->fBlocks[exitId];
525 for (const auto& pair : after) {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500526 std::unique_ptr<Expression>* e1 = pair.second;
527 auto found = exit.fBefore.find(pair.first);
528 if (found == exit.fBefore.end()) {
529 // exit has no definition for it, just copy it
530 workList->insert(exitId);
ethannicholas22f939e2016-10-13 13:25:34 -0700531 exit.fBefore[pair.first] = e1;
532 } else {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500533 // exit has a (possibly different) value already defined
534 std::unique_ptr<Expression>* e2 = exit.fBefore[pair.first];
ethannicholas22f939e2016-10-13 13:25:34 -0700535 if (e1 != e2) {
536 // definition has changed, merge and add exit block to worklist
537 workList->insert(exitId);
Ethan Nicholasaf197692017-02-27 13:26:45 -0500538 if (e1 && e2) {
539 exit.fBefore[pair.first] =
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400540 (std::unique_ptr<Expression>*) &fContext->fDefined_Expression;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500541 } else {
542 exit.fBefore[pair.first] = nullptr;
543 }
ethannicholas22f939e2016-10-13 13:25:34 -0700544 }
545 }
546 }
547 }
548}
549
550// returns a map which maps all local variables in the function to null, indicating that their value
551// is initially unknown
Ethan Nicholas86a43402017-01-19 13:32:00 -0500552static DefinitionMap compute_start_state(const CFG& cfg) {
553 DefinitionMap result;
Mike Klein6ad99092016-10-26 10:35:22 -0400554 for (const auto& block : cfg.fBlocks) {
555 for (const auto& node : block.fNodes) {
ethannicholas22f939e2016-10-13 13:25:34 -0700556 if (node.fKind == BasicBlock::Node::kStatement_Kind) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400557 SkASSERT(node.statement());
Ethan Nicholascb670962017-04-20 19:31:52 -0400558 const Statement* s = node.statement()->get();
ethannicholas22f939e2016-10-13 13:25:34 -0700559 if (s->fKind == Statement::kVarDeclarations_Kind) {
560 const VarDeclarationsStatement* vd = (const VarDeclarationsStatement*) s;
Ethan Nicholas82a62d22017-11-07 14:42:10 +0000561 for (const auto& decl : vd->fDeclaration->fVars) {
562 if (decl->fKind == Statement::kVarDeclaration_Kind) {
563 result[((VarDeclaration&) *decl).fVar] = nullptr;
564 }
Mike Klein6ad99092016-10-26 10:35:22 -0400565 }
ethannicholas22f939e2016-10-13 13:25:34 -0700566 }
567 }
568 }
569 }
570 return result;
571}
572
Ethan Nicholascb670962017-04-20 19:31:52 -0400573/**
574 * Returns true if assigning to this lvalue has no effect.
575 */
576static bool is_dead(const Expression& lvalue) {
577 switch (lvalue.fKind) {
578 case Expression::kVariableReference_Kind:
579 return ((VariableReference&) lvalue).fVariable.dead();
580 case Expression::kSwizzle_Kind:
581 return is_dead(*((Swizzle&) lvalue).fBase);
582 case Expression::kFieldAccess_Kind:
583 return is_dead(*((FieldAccess&) lvalue).fBase);
584 case Expression::kIndex_Kind: {
585 const IndexExpression& idx = (IndexExpression&) lvalue;
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500586 return is_dead(*idx.fBase) &&
587 !idx.fIndex->hasProperty(Expression::Property::kSideEffects);
Ethan Nicholascb670962017-04-20 19:31:52 -0400588 }
Ethan Nicholasa583b812018-01-18 13:32:11 -0500589 case Expression::kTernary_Kind: {
590 const TernaryExpression& t = (TernaryExpression&) lvalue;
591 return !t.fTest->hasSideEffects() && is_dead(*t.fIfTrue) && is_dead(*t.fIfFalse);
592 }
Ethan Nicholas91164d12019-05-15 15:29:54 -0400593 case Expression::kExternalValue_Kind:
594 return false;
Ethan Nicholascb670962017-04-20 19:31:52 -0400595 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500596#ifdef SK_DEBUG
Ethan Nicholascb670962017-04-20 19:31:52 -0400597 ABORT("invalid lvalue: %s\n", lvalue.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500598#endif
599 return false;
Ethan Nicholascb670962017-04-20 19:31:52 -0400600 }
601}
ethannicholas22f939e2016-10-13 13:25:34 -0700602
Ethan Nicholascb670962017-04-20 19:31:52 -0400603/**
604 * Returns true if this is an assignment which can be collapsed down to just the right hand side due
605 * to a dead target and lack of side effects on the left hand side.
606 */
607static bool dead_assignment(const BinaryExpression& b) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700608 if (!Compiler::IsAssignment(b.fOperator)) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400609 return false;
610 }
611 return is_dead(*b.fLeft);
612}
613
614void Compiler::computeDataFlow(CFG* cfg) {
615 cfg->fBlocks[cfg->fStart].fBefore = compute_start_state(*cfg);
ethannicholas22f939e2016-10-13 13:25:34 -0700616 std::set<BlockId> workList;
Ethan Nicholascb670962017-04-20 19:31:52 -0400617 for (BlockId i = 0; i < cfg->fBlocks.size(); i++) {
ethannicholas22f939e2016-10-13 13:25:34 -0700618 workList.insert(i);
619 }
620 while (workList.size()) {
621 BlockId next = *workList.begin();
622 workList.erase(workList.begin());
Ethan Nicholascb670962017-04-20 19:31:52 -0400623 this->scanCFG(cfg, next, &workList);
ethannicholas22f939e2016-10-13 13:25:34 -0700624 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400625}
626
627/**
628 * Attempts to replace the expression pointed to by iter with a new one (in both the CFG and the
629 * IR). If the expression can be cleanly removed, returns true and updates the iterator to point to
630 * the newly-inserted element. Otherwise updates only the IR and returns false (and the CFG will
631 * need to be regenerated).
632 */
633bool try_replace_expression(BasicBlock* b,
634 std::vector<BasicBlock::Node>::iterator* iter,
635 std::unique_ptr<Expression>* newExpression) {
636 std::unique_ptr<Expression>* target = (*iter)->expression();
637 if (!b->tryRemoveExpression(iter)) {
638 *target = std::move(*newExpression);
639 return false;
640 }
641 *target = std::move(*newExpression);
642 return b->tryInsertExpression(iter, target);
643}
644
645/**
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400646 * Returns true if the expression is a constant numeric literal with the specified value, or a
647 * constant vector with all elements equal to the specified value.
Ethan Nicholascb670962017-04-20 19:31:52 -0400648 */
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400649bool is_constant(const Expression& expr, double value) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400650 switch (expr.fKind) {
651 case Expression::kIntLiteral_Kind:
652 return ((IntLiteral&) expr).fValue == value;
653 case Expression::kFloatLiteral_Kind:
654 return ((FloatLiteral&) expr).fValue == value;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400655 case Expression::kConstructor_Kind: {
656 Constructor& c = (Constructor&) expr;
Ethan Nicholasd188c182019-06-10 15:55:38 -0400657 bool isFloat = c.fType.columns() > 1 ? c.fType.componentType().isFloat()
658 : c.fType.isFloat();
Brian Osmanb6b95732020-06-30 11:44:27 -0400659 if (c.fType.kind() == Type::kVector_Kind && c.isCompileTimeConstant()) {
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400660 for (int i = 0; i < c.fType.columns(); ++i) {
Ethan Nicholasd188c182019-06-10 15:55:38 -0400661 if (isFloat) {
662 if (c.getFVecComponent(i) != value) {
663 return false;
664 }
665 } else if (c.getIVecComponent(i) != value) {
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400666 return false;
667 }
668 }
669 return true;
670 }
671 return false;
672 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400673 default:
674 return false;
675 }
676}
677
678/**
679 * Collapses the binary expression pointed to by iter down to just the right side (in both the IR
680 * and CFG structures).
681 */
682void delete_left(BasicBlock* b,
683 std::vector<BasicBlock::Node>::iterator* iter,
684 bool* outUpdated,
685 bool* outNeedsRescan) {
686 *outUpdated = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400687 std::unique_ptr<Expression>* target = (*iter)->expression();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400688 SkASSERT((*target)->fKind == Expression::kBinary_Kind);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400689 BinaryExpression& bin = (BinaryExpression&) **target;
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400690 SkASSERT(!bin.fLeft->hasSideEffects());
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400691 bool result;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400692 if (bin.fOperator == Token::Kind::TK_EQ) {
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400693 result = b->tryRemoveLValueBefore(iter, bin.fLeft.get());
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400694 } else {
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400695 result = b->tryRemoveExpressionBefore(iter, bin.fLeft.get());
Ethan Nicholascb670962017-04-20 19:31:52 -0400696 }
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400697 *target = std::move(bin.fRight);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400698 if (!result) {
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400699 *outNeedsRescan = true;
700 return;
701 }
702 if (*iter == b->fNodes.begin()) {
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400703 *outNeedsRescan = true;
704 return;
705 }
706 --(*iter);
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400707 if ((*iter)->fKind != BasicBlock::Node::kExpression_Kind ||
708 (*iter)->expression() != &bin.fRight) {
709 *outNeedsRescan = true;
710 return;
711 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400712 *iter = b->fNodes.erase(*iter);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400713 SkASSERT((*iter)->expression() == target);
Ethan Nicholascb670962017-04-20 19:31:52 -0400714}
715
716/**
717 * Collapses the binary expression pointed to by iter down to just the left side (in both the IR and
718 * CFG structures).
719 */
720void delete_right(BasicBlock* b,
721 std::vector<BasicBlock::Node>::iterator* iter,
722 bool* outUpdated,
723 bool* outNeedsRescan) {
724 *outUpdated = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400725 std::unique_ptr<Expression>* target = (*iter)->expression();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400726 SkASSERT((*target)->fKind == Expression::kBinary_Kind);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400727 BinaryExpression& bin = (BinaryExpression&) **target;
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400728 SkASSERT(!bin.fRight->hasSideEffects());
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400729 if (!b->tryRemoveExpressionBefore(iter, bin.fRight.get())) {
730 *target = std::move(bin.fLeft);
Ethan Nicholascb670962017-04-20 19:31:52 -0400731 *outNeedsRescan = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400732 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400733 }
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400734 *target = std::move(bin.fLeft);
735 if (*iter == b->fNodes.begin()) {
736 *outNeedsRescan = true;
737 return;
738 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400739 --(*iter);
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400740 if (((*iter)->fKind != BasicBlock::Node::kExpression_Kind ||
741 (*iter)->expression() != &bin.fLeft)) {
742 *outNeedsRescan = true;
743 return;
744 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400745 *iter = b->fNodes.erase(*iter);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400746 SkASSERT((*iter)->expression() == target);
Ethan Nicholascb670962017-04-20 19:31:52 -0400747}
748
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400749/**
750 * Constructs the specified type using a single argument.
751 */
752static std::unique_ptr<Expression> construct(const Type& type, std::unique_ptr<Expression> v) {
753 std::vector<std::unique_ptr<Expression>> args;
754 args.push_back(std::move(v));
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700755 auto result = std::unique_ptr<Expression>(new Constructor(-1, type, std::move(args)));
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400756 return result;
757}
758
759/**
760 * Used in the implementations of vectorize_left and vectorize_right. Given a vector type and an
761 * expression x, deletes the expression pointed to by iter and replaces it with <type>(x).
762 */
763static void vectorize(BasicBlock* b,
764 std::vector<BasicBlock::Node>::iterator* iter,
765 const Type& type,
766 std::unique_ptr<Expression>* otherExpression,
767 bool* outUpdated,
768 bool* outNeedsRescan) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400769 SkASSERT((*(*iter)->expression())->fKind == Expression::kBinary_Kind);
770 SkASSERT(type.kind() == Type::kVector_Kind);
771 SkASSERT((*otherExpression)->fType.kind() == Type::kScalar_Kind);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400772 *outUpdated = true;
773 std::unique_ptr<Expression>* target = (*iter)->expression();
774 if (!b->tryRemoveExpression(iter)) {
775 *target = construct(type, std::move(*otherExpression));
776 *outNeedsRescan = true;
777 } else {
778 *target = construct(type, std::move(*otherExpression));
779 if (!b->tryInsertExpression(iter, target)) {
780 *outNeedsRescan = true;
781 }
782 }
783}
784
785/**
786 * Given a binary expression of the form x <op> vec<n>(y), deletes the right side and vectorizes the
787 * left to yield vec<n>(x).
788 */
789static void vectorize_left(BasicBlock* b,
790 std::vector<BasicBlock::Node>::iterator* iter,
791 bool* outUpdated,
792 bool* outNeedsRescan) {
793 BinaryExpression& bin = (BinaryExpression&) **(*iter)->expression();
794 vectorize(b, iter, bin.fRight->fType, &bin.fLeft, outUpdated, outNeedsRescan);
795}
796
797/**
798 * Given a binary expression of the form vec<n>(x) <op> y, deletes the left side and vectorizes the
799 * right to yield vec<n>(y).
800 */
801static void vectorize_right(BasicBlock* b,
802 std::vector<BasicBlock::Node>::iterator* iter,
803 bool* outUpdated,
804 bool* outNeedsRescan) {
805 BinaryExpression& bin = (BinaryExpression&) **(*iter)->expression();
806 vectorize(b, iter, bin.fLeft->fType, &bin.fRight, outUpdated, outNeedsRescan);
807}
808
809// Mark that an expression which we were writing to is no longer being written to
810void clear_write(const Expression& expr) {
811 switch (expr.fKind) {
812 case Expression::kVariableReference_Kind: {
813 ((VariableReference&) expr).setRefKind(VariableReference::kRead_RefKind);
814 break;
815 }
816 case Expression::kFieldAccess_Kind:
817 clear_write(*((FieldAccess&) expr).fBase);
818 break;
819 case Expression::kSwizzle_Kind:
820 clear_write(*((Swizzle&) expr).fBase);
821 break;
822 case Expression::kIndex_Kind:
823 clear_write(*((IndexExpression&) expr).fBase);
824 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,
834 std::unordered_set<const Variable*>* undefinedVariables,
835 bool* outUpdated,
836 bool* outNeedsRescan) {
837 Expression* expr = (*iter)->expression()->get();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400838 SkASSERT(expr);
Ethan Nicholascb670962017-04-20 19:31:52 -0400839 if ((*iter)->fConstantPropagation) {
840 std::unique_ptr<Expression> optimized = expr->constantPropagate(*fIRGenerator, definitions);
841 if (optimized) {
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400842 *outUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -0400843 if (!try_replace_expression(&b, iter, &optimized)) {
844 *outNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400845 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400846 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400847 SkASSERT((*iter)->fKind == BasicBlock::Node::kExpression_Kind);
Ethan Nicholascb670962017-04-20 19:31:52 -0400848 expr = (*iter)->expression()->get();
Ethan Nicholascb670962017-04-20 19:31:52 -0400849 }
850 }
851 switch (expr->fKind) {
852 case Expression::kVariableReference_Kind: {
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400853 const VariableReference& ref = (VariableReference&) *expr;
854 const Variable& var = ref.fVariable;
855 if (ref.refKind() != VariableReference::kWrite_RefKind &&
856 ref.refKind() != VariableReference::kPointer_RefKind &&
857 var.fStorage == Variable::kLocal_Storage && !definitions[&var] &&
Ethan Nicholascb670962017-04-20 19:31:52 -0400858 (*undefinedVariables).find(&var) == (*undefinedVariables).end()) {
859 (*undefinedVariables).insert(&var);
Ethan Nicholas82a62d22017-11-07 14:42:10 +0000860 this->error(expr->fOffset,
861 "'" + var.fName + "' has not been assigned");
Ethan Nicholascb670962017-04-20 19:31:52 -0400862 }
863 break;
864 }
865 case Expression::kTernary_Kind: {
866 TernaryExpression* t = (TernaryExpression*) expr;
867 if (t->fTest->fKind == Expression::kBoolLiteral_Kind) {
868 // ternary has a constant test, replace it with either the true or
869 // false branch
870 if (((BoolLiteral&) *t->fTest).fValue) {
871 (*iter)->setExpression(std::move(t->fIfTrue));
872 } else {
873 (*iter)->setExpression(std::move(t->fIfFalse));
874 }
875 *outUpdated = true;
876 *outNeedsRescan = true;
877 }
878 break;
879 }
880 case Expression::kBinary_Kind: {
Ethan Nicholascb670962017-04-20 19:31:52 -0400881 BinaryExpression* bin = (BinaryExpression*) expr;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400882 if (dead_assignment(*bin)) {
883 delete_left(&b, iter, outUpdated, outNeedsRescan);
884 break;
885 }
886 // collapse useless expressions like x * 1 or x + 0
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400887 if (((bin->fLeft->fType.kind() != Type::kScalar_Kind) &&
888 (bin->fLeft->fType.kind() != Type::kVector_Kind)) ||
889 ((bin->fRight->fType.kind() != Type::kScalar_Kind) &&
890 (bin->fRight->fType.kind() != Type::kVector_Kind))) {
891 break;
892 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400893 switch (bin->fOperator) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400894 case Token::Kind::TK_STAR:
Ethan Nicholascb670962017-04-20 19:31:52 -0400895 if (is_constant(*bin->fLeft, 1)) {
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400896 if (bin->fLeft->fType.kind() == Type::kVector_Kind &&
897 bin->fRight->fType.kind() == Type::kScalar_Kind) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400898 // float4(1) * x -> float4(x)
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400899 vectorize_right(&b, iter, outUpdated, outNeedsRescan);
900 } else {
901 // 1 * x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400902 // 1 * float4(x) -> float4(x)
903 // float4(1) * float4(x) -> float4(x)
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400904 delete_left(&b, iter, outUpdated, outNeedsRescan);
905 }
906 }
907 else if (is_constant(*bin->fLeft, 0)) {
908 if (bin->fLeft->fType.kind() == Type::kScalar_Kind &&
Ethan Nicholas08dae922018-01-23 10:31:56 -0500909 bin->fRight->fType.kind() == Type::kVector_Kind &&
910 !bin->fRight->hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400911 // 0 * float4(x) -> float4(0)
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400912 vectorize_left(&b, iter, outUpdated, outNeedsRescan);
913 } else {
914 // 0 * x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400915 // float4(0) * x -> float4(0)
916 // float4(0) * float4(x) -> float4(0)
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500917 if (!bin->fRight->hasSideEffects()) {
918 delete_right(&b, iter, outUpdated, outNeedsRescan);
919 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400920 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400921 }
922 else if (is_constant(*bin->fRight, 1)) {
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400923 if (bin->fLeft->fType.kind() == Type::kScalar_Kind &&
924 bin->fRight->fType.kind() == Type::kVector_Kind) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400925 // x * float4(1) -> float4(x)
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400926 vectorize_left(&b, iter, outUpdated, outNeedsRescan);
927 } else {
928 // x * 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400929 // float4(x) * 1 -> float4(x)
930 // float4(x) * float4(1) -> float4(x)
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400931 delete_right(&b, iter, outUpdated, outNeedsRescan);
932 }
933 }
934 else if (is_constant(*bin->fRight, 0)) {
935 if (bin->fLeft->fType.kind() == Type::kVector_Kind &&
Ethan Nicholas08dae922018-01-23 10:31:56 -0500936 bin->fRight->fType.kind() == Type::kScalar_Kind &&
937 !bin->fLeft->hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400938 // float4(x) * 0 -> float4(0)
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400939 vectorize_right(&b, iter, outUpdated, outNeedsRescan);
940 } else {
941 // x * 0 -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400942 // x * float4(0) -> float4(0)
943 // float4(x) * float4(0) -> float4(0)
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500944 if (!bin->fLeft->hasSideEffects()) {
945 delete_left(&b, iter, outUpdated, outNeedsRescan);
946 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400947 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400948 }
949 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400950 case Token::Kind::TK_PLUS:
Ethan Nicholascb670962017-04-20 19:31:52 -0400951 if (is_constant(*bin->fLeft, 0)) {
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400952 if (bin->fLeft->fType.kind() == Type::kVector_Kind &&
953 bin->fRight->fType.kind() == Type::kScalar_Kind) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400954 // float4(0) + x -> float4(x)
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400955 vectorize_right(&b, iter, outUpdated, outNeedsRescan);
956 } else {
957 // 0 + x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400958 // 0 + float4(x) -> float4(x)
959 // float4(0) + float4(x) -> float4(x)
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400960 delete_left(&b, iter, outUpdated, outNeedsRescan);
961 }
962 } else if (is_constant(*bin->fRight, 0)) {
963 if (bin->fLeft->fType.kind() == Type::kScalar_Kind &&
964 bin->fRight->fType.kind() == Type::kVector_Kind) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400965 // x + float4(0) -> float4(x)
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400966 vectorize_left(&b, iter, outUpdated, outNeedsRescan);
967 } else {
968 // x + 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400969 // float4(x) + 0 -> float4(x)
970 // float4(x) + float4(0) -> float4(x)
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400971 delete_right(&b, iter, outUpdated, outNeedsRescan);
972 }
Ethan Nicholas56e42712017-04-21 10:23:37 -0400973 }
974 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400975 case Token::Kind::TK_MINUS:
Ethan Nicholas56e42712017-04-21 10:23:37 -0400976 if (is_constant(*bin->fRight, 0)) {
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400977 if (bin->fLeft->fType.kind() == Type::kScalar_Kind &&
978 bin->fRight->fType.kind() == Type::kVector_Kind) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400979 // x - float4(0) -> float4(x)
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400980 vectorize_left(&b, iter, outUpdated, outNeedsRescan);
981 } else {
982 // x - 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400983 // float4(x) - 0 -> float4(x)
984 // float4(x) - float4(0) -> float4(x)
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400985 delete_right(&b, iter, outUpdated, outNeedsRescan);
986 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400987 }
988 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400989 case Token::Kind::TK_SLASH:
Ethan Nicholascb670962017-04-20 19:31:52 -0400990 if (is_constant(*bin->fRight, 1)) {
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400991 if (bin->fLeft->fType.kind() == Type::kScalar_Kind &&
992 bin->fRight->fType.kind() == Type::kVector_Kind) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400993 // x / float4(1) -> float4(x)
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400994 vectorize_left(&b, iter, outUpdated, outNeedsRescan);
995 } else {
996 // x / 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400997 // float4(x) / 1 -> float4(x)
998 // float4(x) / float4(1) -> float4(x)
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400999 delete_right(&b, iter, outUpdated, outNeedsRescan);
1000 }
1001 } else if (is_constant(*bin->fLeft, 0)) {
1002 if (bin->fLeft->fType.kind() == Type::kScalar_Kind &&
Ethan Nicholas08dae922018-01-23 10:31:56 -05001003 bin->fRight->fType.kind() == Type::kVector_Kind &&
1004 !bin->fRight->hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001005 // 0 / float4(x) -> float4(0)
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001006 vectorize_left(&b, iter, outUpdated, outNeedsRescan);
1007 } else {
1008 // 0 / x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001009 // float4(0) / x -> float4(0)
1010 // float4(0) / float4(x) -> float4(0)
Ethan Nicholas51493ee2017-12-11 12:34:33 -05001011 if (!bin->fRight->hasSideEffects()) {
1012 delete_right(&b, iter, outUpdated, outNeedsRescan);
1013 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001014 }
1015 }
1016 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001017 case Token::Kind::TK_PLUSEQ:
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001018 if (is_constant(*bin->fRight, 0)) {
1019 clear_write(*bin->fLeft);
1020 delete_right(&b, iter, outUpdated, outNeedsRescan);
1021 }
1022 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001023 case Token::Kind::TK_MINUSEQ:
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001024 if (is_constant(*bin->fRight, 0)) {
1025 clear_write(*bin->fLeft);
1026 delete_right(&b, iter, outUpdated, outNeedsRescan);
1027 }
1028 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001029 case Token::Kind::TK_STAREQ:
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001030 if (is_constant(*bin->fRight, 1)) {
1031 clear_write(*bin->fLeft);
1032 delete_right(&b, iter, outUpdated, outNeedsRescan);
1033 }
1034 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001035 case Token::Kind::TK_SLASHEQ:
Ethan Nicholasfe53e582017-04-27 16:24:51 -04001036 if (is_constant(*bin->fRight, 1)) {
1037 clear_write(*bin->fLeft);
Ethan Nicholascb670962017-04-20 19:31:52 -04001038 delete_right(&b, iter, outUpdated, outNeedsRescan);
1039 }
1040 break;
1041 default:
1042 break;
1043 }
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001044 break;
1045 }
1046 case Expression::kSwizzle_Kind: {
1047 Swizzle& s = (Swizzle&) *expr;
1048 // detect identity swizzles like foo.rgba
1049 if ((int) s.fComponents.size() == s.fBase->fType.columns()) {
1050 bool identity = true;
1051 for (int i = 0; i < (int) s.fComponents.size(); ++i) {
1052 if (s.fComponents[i] != i) {
1053 identity = false;
1054 break;
1055 }
1056 }
1057 if (identity) {
1058 *outUpdated = true;
1059 if (!try_replace_expression(&b, iter, &s.fBase)) {
1060 *outNeedsRescan = true;
1061 return;
1062 }
1063 SkASSERT((*iter)->fKind == BasicBlock::Node::kExpression_Kind);
1064 break;
1065 }
1066 }
1067 // detect swizzles of swizzles, e.g. replace foo.argb.r000 with foo.a000
1068 if (s.fBase->fKind == Expression::kSwizzle_Kind) {
1069 Swizzle& base = (Swizzle&) *s.fBase;
1070 std::vector<int> final;
1071 for (int c : s.fComponents) {
1072 if (c == SKSL_SWIZZLE_0 || c == SKSL_SWIZZLE_1) {
1073 final.push_back(c);
1074 } else {
1075 final.push_back(base.fComponents[c]);
1076 }
1077 }
1078 *outUpdated = true;
1079 std::unique_ptr<Expression> replacement(new Swizzle(*fContext, base.fBase->clone(),
1080 std::move(final)));
1081 if (!try_replace_expression(&b, iter, &replacement)) {
1082 *outNeedsRescan = true;
1083 return;
1084 }
1085 SkASSERT((*iter)->fKind == BasicBlock::Node::kExpression_Kind);
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001086 }
John Stiles30212b72020-06-11 17:55:07 -04001087 break;
Ethan Nicholascb670962017-04-20 19:31:52 -04001088 }
1089 default:
1090 break;
1091 }
1092}
1093
John Stiles92219b42020-06-15 12:32:24 -04001094// Implementation-detail recursive helper function for `contains_conditional_break`.
1095static bool contains_conditional_break_impl(Statement& s, bool inConditional) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001096 switch (s.fKind) {
1097 case Statement::kBlock_Kind:
John Stiles92219b42020-06-15 12:32:24 -04001098 for (const std::unique_ptr<Statement>& sub : static_cast<Block&>(s).fStatements) {
1099 if (contains_conditional_break_impl(*sub, inConditional)) {
Ethan Nicholas5005a222018-08-24 13:06:27 -04001100 return true;
1101 }
1102 }
1103 return false;
John Stiles92219b42020-06-15 12:32:24 -04001104
Ethan Nicholas5005a222018-08-24 13:06:27 -04001105 case Statement::kBreak_Kind:
1106 return inConditional;
John Stiles92219b42020-06-15 12:32:24 -04001107
Ethan Nicholas5005a222018-08-24 13:06:27 -04001108 case Statement::kIf_Kind: {
John Stiles92219b42020-06-15 12:32:24 -04001109 const IfStatement& i = static_cast<IfStatement&>(s);
1110 return contains_conditional_break_impl(*i.fIfTrue, /*inConditional=*/true) ||
1111 (i.fIfFalse &&
1112 contains_conditional_break_impl(*i.fIfFalse, /*inConditional=*/true));
Ethan Nicholas5005a222018-08-24 13:06:27 -04001113 }
John Stiles92219b42020-06-15 12:32:24 -04001114
Ethan Nicholas5005a222018-08-24 13:06:27 -04001115 default:
1116 return false;
1117 }
1118}
1119
John Stiles92219b42020-06-15 12:32:24 -04001120// Returns true if this statement could potentially execute a break at the current level. We ignore
1121// nested loops and switches, since any breaks inside of them will merely break the loop / switch.
1122static bool contains_conditional_break(Statement& s) {
1123 return contains_conditional_break_impl(s, /*inConditional=*/false);
1124}
1125
Ethan Nicholas5005a222018-08-24 13:06:27 -04001126// returns true if this statement definitely executes a break at the current level (we ignore
1127// nested loops and switches, since any breaks inside of them will merely break the loop / switch)
1128static bool contains_unconditional_break(Statement& s) {
1129 switch (s.fKind) {
1130 case Statement::kBlock_Kind:
John Stiles92219b42020-06-15 12:32:24 -04001131 for (const std::unique_ptr<Statement>& sub : static_cast<Block&>(s).fStatements) {
Ethan Nicholas5005a222018-08-24 13:06:27 -04001132 if (contains_unconditional_break(*sub)) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001133 return true;
1134 }
1135 }
1136 return false;
John Stiles92219b42020-06-15 12:32:24 -04001137
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001138 case Statement::kBreak_Kind:
1139 return true;
John Stiles92219b42020-06-15 12:32:24 -04001140
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001141 default:
1142 return false;
1143 }
1144}
1145
John Stiles92219b42020-06-15 12:32:24 -04001146static void move_all_but_break(std::unique_ptr<Statement>& stmt,
1147 std::vector<std::unique_ptr<Statement>>* target) {
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001148 switch (stmt->fKind) {
John Stiles92219b42020-06-15 12:32:24 -04001149 case Statement::kBlock_Kind: {
1150 // Recurse into the block.
1151 Block& block = static_cast<Block&>(*stmt);
1152
1153 std::vector<std::unique_ptr<Statement>> blockStmts;
1154 blockStmts.reserve(block.fStatements.size());
1155 for (std::unique_ptr<Statement>& statementInBlock : block.fStatements) {
1156 move_all_but_break(statementInBlock, &blockStmts);
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001157 }
John Stiles92219b42020-06-15 12:32:24 -04001158
1159 target->push_back(std::make_unique<Block>(block.fOffset, std::move(blockStmts),
1160 block.fSymbols, block.fIsScope));
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001161 break;
John Stiles92219b42020-06-15 12:32:24 -04001162 }
1163
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001164 case Statement::kBreak_Kind:
John Stiles92219b42020-06-15 12:32:24 -04001165 // Do not append a break to the target.
1166 break;
1167
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001168 default:
John Stiles92219b42020-06-15 12:32:24 -04001169 // Append normal statements to the target.
1170 target->push_back(std::move(stmt));
1171 break;
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001172 }
1173}
1174
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001175// Returns a block containing all of the statements that will be run if the given case matches
1176// (which, owing to the statements being owned by unique_ptrs, means the switch itself will be
1177// broken by this call and must then be discarded).
1178// Returns null (and leaves the switch unmodified) if no such simple reduction is possible, such as
1179// when break statements appear inside conditionals.
John Stiles92219b42020-06-15 12:32:24 -04001180static std::unique_ptr<Statement> block_for_case(SwitchStatement* switchStatement,
1181 SwitchCase* caseToCapture) {
1182 // We have to be careful to not move any of the pointers until after we're sure we're going to
1183 // succeed, so before we make any changes at all, we check the switch-cases to decide on a plan
1184 // of action. First, find the switch-case we are interested in.
1185 auto iter = switchStatement->fCases.begin();
1186 for (; iter != switchStatement->fCases.end(); ++iter) {
1187 if (iter->get() == caseToCapture) {
1188 break;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001189 }
John Stiles92219b42020-06-15 12:32:24 -04001190 }
1191
1192 // Next, walk forward through the rest of the switch. If we find a conditional break, we're
1193 // stuck and can't simplify at all. If we find an unconditional break, we have a range of
1194 // statements that we can use for simplification.
1195 auto startIter = iter;
1196 Statement* unconditionalBreakStmt = nullptr;
1197 for (; iter != switchStatement->fCases.end(); ++iter) {
1198 for (std::unique_ptr<Statement>& stmt : (*iter)->fStatements) {
1199 if (contains_conditional_break(*stmt)) {
1200 // We can't reduce switch-cases to a block when they have conditional breaks.
1201 return nullptr;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001202 }
John Stiles92219b42020-06-15 12:32:24 -04001203
1204 if (contains_unconditional_break(*stmt)) {
1205 // We found an unconditional break. We can use this block, but we need to strip
1206 // out the break statement.
1207 unconditionalBreakStmt = stmt.get();
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001208 break;
1209 }
1210 }
John Stiles92219b42020-06-15 12:32:24 -04001211
1212 if (unconditionalBreakStmt != nullptr) {
1213 break;
1214 }
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001215 }
John Stiles92219b42020-06-15 12:32:24 -04001216
1217 // We fell off the bottom of the switch or encountered a break. We know the range of statements
1218 // that we need to move over, and we know it's safe to do so.
1219 std::vector<std::unique_ptr<Statement>> caseStmts;
1220
1221 // We can move over most of the statements as-is.
1222 while (startIter != iter) {
1223 for (std::unique_ptr<Statement>& stmt : (*startIter)->fStatements) {
1224 caseStmts.push_back(std::move(stmt));
1225 }
1226 ++startIter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001227 }
John Stiles92219b42020-06-15 12:32:24 -04001228
1229 // If we found an unconditional break at the end, we need to move what we can while avoiding
1230 // that break.
1231 if (unconditionalBreakStmt != nullptr) {
1232 for (std::unique_ptr<Statement>& stmt : (*startIter)->fStatements) {
1233 if (stmt.get() == unconditionalBreakStmt) {
1234 move_all_but_break(stmt, &caseStmts);
1235 unconditionalBreakStmt = nullptr;
1236 break;
1237 }
1238
1239 caseStmts.push_back(std::move(stmt));
1240 }
1241 }
1242
1243 SkASSERT(unconditionalBreakStmt == nullptr); // Verify that we fixed the unconditional break.
1244
1245 // Return our newly-synthesized block.
1246 return std::make_unique<Block>(/*offset=*/-1, std::move(caseStmts), switchStatement->fSymbols);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001247}
1248
Ethan Nicholascb670962017-04-20 19:31:52 -04001249void Compiler::simplifyStatement(DefinitionMap& definitions,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001250 BasicBlock& b,
1251 std::vector<BasicBlock::Node>::iterator* iter,
1252 std::unordered_set<const Variable*>* undefinedVariables,
1253 bool* outUpdated,
1254 bool* outNeedsRescan) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001255 Statement* stmt = (*iter)->statement()->get();
1256 switch (stmt->fKind) {
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001257 case Statement::kVarDeclaration_Kind: {
1258 const auto& varDecl = (VarDeclaration&) *stmt;
1259 if (varDecl.fVar->dead() &&
1260 (!varDecl.fValue ||
1261 !varDecl.fValue->hasSideEffects())) {
1262 if (varDecl.fValue) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001263 SkASSERT((*iter)->statement()->get() == stmt);
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001264 if (!b.tryRemoveExpressionBefore(iter, varDecl.fValue.get())) {
1265 *outNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001266 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001267 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001268 (*iter)->setStatement(std::unique_ptr<Statement>(new Nop()));
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001269 *outUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001270 }
1271 break;
1272 }
1273 case Statement::kIf_Kind: {
1274 IfStatement& i = (IfStatement&) *stmt;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001275 if (i.fTest->fKind == Expression::kBoolLiteral_Kind) {
1276 // constant if, collapse down to a single branch
1277 if (((BoolLiteral&) *i.fTest).fValue) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001278 SkASSERT(i.fIfTrue);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001279 (*iter)->setStatement(std::move(i.fIfTrue));
1280 } else {
1281 if (i.fIfFalse) {
1282 (*iter)->setStatement(std::move(i.fIfFalse));
1283 } else {
1284 (*iter)->setStatement(std::unique_ptr<Statement>(new Nop()));
1285 }
1286 }
1287 *outUpdated = true;
1288 *outNeedsRescan = true;
1289 break;
1290 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001291 if (i.fIfFalse && i.fIfFalse->isEmpty()) {
1292 // else block doesn't do anything, remove it
1293 i.fIfFalse.reset();
1294 *outUpdated = true;
1295 *outNeedsRescan = true;
1296 }
1297 if (!i.fIfFalse && i.fIfTrue->isEmpty()) {
1298 // if block doesn't do anything, no else block
1299 if (i.fTest->hasSideEffects()) {
1300 // test has side effects, keep it
1301 (*iter)->setStatement(std::unique_ptr<Statement>(
1302 new ExpressionStatement(std::move(i.fTest))));
1303 } else {
1304 // no if, no else, no test side effects, kill the whole if
1305 // statement
1306 (*iter)->setStatement(std::unique_ptr<Statement>(new Nop()));
1307 }
1308 *outUpdated = true;
1309 *outNeedsRescan = true;
1310 }
1311 break;
1312 }
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001313 case Statement::kSwitch_Kind: {
1314 SwitchStatement& s = (SwitchStatement&) *stmt;
Brian Osmanb6b95732020-06-30 11:44:27 -04001315 if (s.fValue->isCompileTimeConstant()) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001316 // switch is constant, replace it with the case that matches
1317 bool found = false;
1318 SwitchCase* defaultCase = nullptr;
1319 for (const auto& c : s.fCases) {
1320 if (!c->fValue) {
1321 defaultCase = c.get();
1322 continue;
1323 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001324 SkASSERT(c->fValue->fKind == s.fValue->fKind);
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001325 found = c->fValue->compareConstant(*fContext, *s.fValue);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001326 if (found) {
1327 std::unique_ptr<Statement> newBlock = block_for_case(&s, c.get());
1328 if (newBlock) {
1329 (*iter)->setStatement(std::move(newBlock));
1330 break;
1331 } else {
Ethan Nicholas6e1cbc02017-07-14 10:12:15 -04001332 if (s.fIsStatic && !(fFlags & kPermitInvalidStaticTests_Flag)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001333 this->error(s.fOffset,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001334 "static switch contains non-static conditional break");
1335 s.fIsStatic = false;
1336 }
1337 return; // can't simplify
1338 }
1339 }
1340 }
1341 if (!found) {
1342 // no matching case. use default if it exists, or kill the whole thing
1343 if (defaultCase) {
1344 std::unique_ptr<Statement> newBlock = block_for_case(&s, defaultCase);
1345 if (newBlock) {
1346 (*iter)->setStatement(std::move(newBlock));
1347 } else {
Ethan Nicholas6e1cbc02017-07-14 10:12:15 -04001348 if (s.fIsStatic && !(fFlags & kPermitInvalidStaticTests_Flag)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001349 this->error(s.fOffset,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001350 "static switch contains non-static conditional break");
1351 s.fIsStatic = false;
1352 }
1353 return; // can't simplify
1354 }
1355 } else {
1356 (*iter)->setStatement(std::unique_ptr<Statement>(new Nop()));
1357 }
1358 }
1359 *outUpdated = true;
1360 *outNeedsRescan = true;
1361 }
1362 break;
1363 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001364 case Statement::kExpression_Kind: {
1365 ExpressionStatement& e = (ExpressionStatement&) *stmt;
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001366 SkASSERT((*iter)->statement()->get() == &e);
Ethan Nicholascb670962017-04-20 19:31:52 -04001367 if (!e.fExpression->hasSideEffects()) {
1368 // Expression statement with no side effects, kill it
1369 if (!b.tryRemoveExpressionBefore(iter, e.fExpression.get())) {
1370 *outNeedsRescan = true;
1371 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001372 SkASSERT((*iter)->statement()->get() == stmt);
Ethan Nicholascb670962017-04-20 19:31:52 -04001373 (*iter)->setStatement(std::unique_ptr<Statement>(new Nop()));
1374 *outUpdated = true;
1375 }
1376 break;
1377 }
1378 default:
1379 break;
1380 }
1381}
1382
1383void Compiler::scanCFG(FunctionDefinition& f) {
1384 CFG cfg = CFGGenerator().getCFG(f);
1385 this->computeDataFlow(&cfg);
ethannicholas22f939e2016-10-13 13:25:34 -07001386
1387 // check for unreachable code
1388 for (size_t i = 0; i < cfg.fBlocks.size(); i++) {
Mike Klein6ad99092016-10-26 10:35:22 -04001389 if (i != cfg.fStart && !cfg.fBlocks[i].fEntrances.size() &&
ethannicholas22f939e2016-10-13 13:25:34 -07001390 cfg.fBlocks[i].fNodes.size()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001391 int offset;
Ethan Nicholas86a43402017-01-19 13:32:00 -05001392 switch (cfg.fBlocks[i].fNodes[0].fKind) {
1393 case BasicBlock::Node::kStatement_Kind:
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001394 offset = (*cfg.fBlocks[i].fNodes[0].statement())->fOffset;
Ethan Nicholas86a43402017-01-19 13:32:00 -05001395 break;
1396 case BasicBlock::Node::kExpression_Kind:
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001397 offset = (*cfg.fBlocks[i].fNodes[0].expression())->fOffset;
Ethan Nicholas70728ef2020-05-28 07:09:00 -04001398 if ((*cfg.fBlocks[i].fNodes[0].expression())->fKind ==
1399 Expression::kBoolLiteral_Kind) {
1400 // Function inlining can generate do { ... } while(false) loops which always
1401 // break, so the boolean condition is considered unreachable. Since not
1402 // being able to reach a literal is a non-issue in the first place, we
1403 // don't report an error in this case.
1404 continue;
1405 }
Ethan Nicholas86a43402017-01-19 13:32:00 -05001406 break;
1407 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001408 this->error(offset, String("unreachable"));
ethannicholas22f939e2016-10-13 13:25:34 -07001409 }
1410 }
1411 if (fErrorCount) {
1412 return;
1413 }
1414
Ethan Nicholascb670962017-04-20 19:31:52 -04001415 // check for dead code & undefined variables, perform constant propagation
1416 std::unordered_set<const Variable*> undefinedVariables;
1417 bool updated;
1418 bool needsRescan = false;
1419 do {
1420 if (needsRescan) {
1421 cfg = CFGGenerator().getCFG(f);
1422 this->computeDataFlow(&cfg);
1423 needsRescan = false;
Ethan Nicholas113628d2017-02-02 16:11:39 -05001424 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001425
1426 updated = false;
Ethan Nicholas1de14812020-06-19 15:32:49 -04001427 bool first = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001428 for (BasicBlock& b : cfg.fBlocks) {
Ethan Nicholas1de14812020-06-19 15:32:49 -04001429 if (!first && b.fEntrances.empty()) {
1430 // Block was reachable before optimization, but has since become unreachable. In
1431 // addition to being dead code, it's broken - since control flow can't reach it, no
1432 // prior variable definitions can reach it, and therefore variables might look to
1433 // have not been properly assigned. Kill it.
1434 for (BasicBlock::Node& node : b.fNodes) {
1435 if (node.fKind == BasicBlock::Node::kStatement_Kind &&
1436 (*node.statement())->fKind != Statement::kNop_Kind) {
1437 node.setStatement(std::unique_ptr<Statement>(new Nop()));
1438 }
1439 }
1440 continue;
1441 }
1442 first = false;
Ethan Nicholascb670962017-04-20 19:31:52 -04001443 DefinitionMap definitions = b.fBefore;
1444
1445 for (auto iter = b.fNodes.begin(); iter != b.fNodes.end() && !needsRescan; ++iter) {
1446 if (iter->fKind == BasicBlock::Node::kExpression_Kind) {
1447 this->simplifyExpression(definitions, b, &iter, &undefinedVariables, &updated,
1448 &needsRescan);
1449 } else {
1450 this->simplifyStatement(definitions, b, &iter, &undefinedVariables, &updated,
1451 &needsRescan);
1452 }
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001453 if (needsRescan) {
1454 break;
1455 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001456 this->addDefinitions(*iter, &definitions);
1457 }
1458 }
1459 } while (updated);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001460 SkASSERT(!needsRescan);
ethannicholas22f939e2016-10-13 13:25:34 -07001461
Ethan Nicholas91a10532017-06-22 11:24:38 -04001462 // verify static ifs & switches, clean up dead variable decls
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001463 for (BasicBlock& b : cfg.fBlocks) {
1464 DefinitionMap definitions = b.fBefore;
1465
Ethan Nicholas91a10532017-06-22 11:24:38 -04001466 for (auto iter = b.fNodes.begin(); iter != b.fNodes.end() && !needsRescan;) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001467 if (iter->fKind == BasicBlock::Node::kStatement_Kind) {
1468 const Statement& s = **iter->statement();
1469 switch (s.fKind) {
1470 case Statement::kIf_Kind:
Ethan Nicholas6e1cbc02017-07-14 10:12:15 -04001471 if (((const IfStatement&) s).fIsStatic &&
1472 !(fFlags & kPermitInvalidStaticTests_Flag)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001473 this->error(s.fOffset, "static if has non-static test");
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001474 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001475 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001476 break;
1477 case Statement::kSwitch_Kind:
Ethan Nicholas6e1cbc02017-07-14 10:12:15 -04001478 if (((const SwitchStatement&) s).fIsStatic &&
1479 !(fFlags & kPermitInvalidStaticTests_Flag)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001480 this->error(s.fOffset, "static switch has non-static test");
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001481 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001482 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001483 break;
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001484 case Statement::kVarDeclarations_Kind: {
1485 VarDeclarations& decls = *((VarDeclarationsStatement&) s).fDeclaration;
1486 for (auto varIter = decls.fVars.begin(); varIter != decls.fVars.end();) {
1487 if ((*varIter)->fKind == Statement::kNop_Kind) {
1488 varIter = decls.fVars.erase(varIter);
1489 } else {
1490 ++varIter;
1491 }
1492 }
1493 if (!decls.fVars.size()) {
1494 iter = b.fNodes.erase(iter);
1495 } else {
1496 ++iter;
1497 }
1498 break;
1499 }
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001500 default:
Ethan Nicholas91a10532017-06-22 11:24:38 -04001501 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001502 break;
1503 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001504 } else {
1505 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001506 }
1507 }
1508 }
1509
ethannicholas22f939e2016-10-13 13:25:34 -07001510 // check for missing return
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001511 if (f.fDeclaration.fReturnType != *fContext->fVoid_Type) {
ethannicholas22f939e2016-10-13 13:25:34 -07001512 if (cfg.fBlocks[cfg.fExit].fEntrances.size()) {
Ethan Nicholasdb80f692019-11-22 14:06:12 -05001513 this->error(f.fOffset, String("function '" + String(f.fDeclaration.fName) +
1514 "' can exit without returning a value"));
ethannicholas22f939e2016-10-13 13:25:34 -07001515 }
1516 }
1517}
1518
Ethan Nicholas91164d12019-05-15 15:29:54 -04001519void Compiler::registerExternalValue(ExternalValue* value) {
1520 fIRGenerator->fRootSymbolTable->addWithoutOwnership(value->fName, value);
1521}
1522
Ethan Nicholasc18bb512020-07-28 14:46:53 -04001523const Symbol* Compiler::takeOwnership(std::unique_ptr<const Symbol> symbol) {
John Stiles3ae071e2020-08-05 15:29:29 -04001524 return fIRGenerator->fRootSymbolTable->takeOwnershipOfSymbol(std::move(symbol));
Ethan Nicholas91164d12019-05-15 15:29:54 -04001525}
1526
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001527std::unique_ptr<Program> Compiler::convertProgram(Program::Kind kind, String text,
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001528 const Program::Settings& settings) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001529 fErrorText = "";
1530 fErrorCount = 0;
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04001531 std::vector<std::unique_ptr<ProgramElement>>* inherited;
ethannicholasd598f792016-07-25 10:08:54 -07001532 std::vector<std::unique_ptr<ProgramElement>> elements;
ethannicholasb3058bd2016-07-01 08:22:01 -07001533 switch (kind) {
1534 case Program::kVertex_Kind:
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04001535 inherited = &fVertexInclude;
1536 fIRGenerator->fSymbolTable = fVertexSymbolTable;
Ethan Nicholasdb80f692019-11-22 14:06:12 -05001537 fIRGenerator->fIntrinsics = &fGPUIntrinsics;
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04001538 fIRGenerator->start(&settings, inherited);
ethannicholasb3058bd2016-07-01 08:22:01 -07001539 break;
1540 case Program::kFragment_Kind:
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04001541 inherited = &fFragmentInclude;
1542 fIRGenerator->fSymbolTable = fFragmentSymbolTable;
Ethan Nicholasdb80f692019-11-22 14:06:12 -05001543 fIRGenerator->fIntrinsics = &fGPUIntrinsics;
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04001544 fIRGenerator->start(&settings, inherited);
ethannicholasb3058bd2016-07-01 08:22:01 -07001545 break;
Ethan Nicholas52cad152017-02-16 16:37:32 -05001546 case Program::kGeometry_Kind:
Ethan Nicholasc18bb512020-07-28 14:46:53 -04001547 this->loadGeometryIntrinsics();
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04001548 inherited = &fGeometryInclude;
1549 fIRGenerator->fSymbolTable = fGeometrySymbolTable;
Ethan Nicholasdb80f692019-11-22 14:06:12 -05001550 fIRGenerator->fIntrinsics = &fGPUIntrinsics;
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04001551 fIRGenerator->start(&settings, inherited);
Ethan Nicholas52cad152017-02-16 16:37:32 -05001552 break;
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -04001553 case Program::kFragmentProcessor_Kind: {
Brian Osmandd496172020-08-08 08:17:18 -04001554#if !SKSL_STANDALONE
Ethan Nicholasc18bb512020-07-28 14:46:53 -04001555 {
1556 Rehydrator rehydrator(fContext.get(), fGpuSymbolTable, this,
1557 SKSL_INCLUDE_sksl_fp,
1558 SKSL_INCLUDE_sksl_fp_LENGTH);
1559 fFPSymbolTable = rehydrator.symbolTable();
1560 fFPInclude = rehydrator.elements();
1561 }
1562 inherited = &fFPInclude;
1563 fIRGenerator->fSymbolTable = fFPSymbolTable;
1564 fIRGenerator->fIntrinsics = &fGPUIntrinsics;
1565 fIRGenerator->start(&settings, inherited);
1566 break;
1567#else
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04001568 inherited = nullptr;
Ethan Nicholas8da1e652019-05-24 11:01:59 -04001569 fIRGenerator->fSymbolTable = fGpuSymbolTable;
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -04001570 fIRGenerator->start(&settings, /*inherited=*/nullptr, /*builtin=*/true);
Ethan Nicholasdb80f692019-11-22 14:06:12 -05001571 fIRGenerator->fIntrinsics = &fGPUIntrinsics;
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -04001572 std::ifstream in(SKSL_FP_INCLUDE);
1573 std::string stdText{std::istreambuf_iterator<char>(in),
1574 std::istreambuf_iterator<char>()};
1575 if (in.rdstate()) {
1576 printf("error reading %s\n", SKSL_FP_INCLUDE);
1577 abort();
1578 }
1579 const String* source = fGpuSymbolTable->takeOwnershipOfString(
1580 std::make_unique<String>(stdText.c_str()));
1581 fIRGenerator->convertProgram(kind, source->c_str(), source->length(), &elements);
Ethan Nicholasc18bb512020-07-28 14:46:53 -04001582 fIRGenerator->fIsBuiltinCode = false;
Ethan Nicholas762466e2017-06-29 10:03:38 -04001583 break;
Ethan Nicholasc18bb512020-07-28 14:46:53 -04001584#endif
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -04001585 }
Ethan Nicholas8da1e652019-05-24 11:01:59 -04001586 case Program::kPipelineStage_Kind:
Ethan Nicholasc18bb512020-07-28 14:46:53 -04001587 this->loadPipelineIntrinsics();
Ethan Nicholas8da1e652019-05-24 11:01:59 -04001588 inherited = &fPipelineInclude;
1589 fIRGenerator->fSymbolTable = fPipelineSymbolTable;
Ethan Nicholasdb80f692019-11-22 14:06:12 -05001590 fIRGenerator->fIntrinsics = &fGPUIntrinsics;
Ethan Nicholas8da1e652019-05-24 11:01:59 -04001591 fIRGenerator->start(&settings, inherited);
1592 break;
Ethan Nicholas746035a2019-04-23 13:31:09 -04001593 case Program::kGeneric_Kind:
Ethan Nicholasc18bb512020-07-28 14:46:53 -04001594 this->loadInterpreterIntrinsics();
Ethan Nicholas8da1e652019-05-24 11:01:59 -04001595 inherited = &fInterpreterInclude;
1596 fIRGenerator->fSymbolTable = fInterpreterSymbolTable;
Ethan Nicholasdb80f692019-11-22 14:06:12 -05001597 fIRGenerator->fIntrinsics = &fInterpreterIntrinsics;
Ethan Nicholas8da1e652019-05-24 11:01:59 -04001598 fIRGenerator->start(&settings, inherited);
Ethan Nicholas0d997662019-04-08 09:46:01 -04001599 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07001600 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001601 std::unique_ptr<String> textPtr(new String(std::move(text)));
1602 fSource = textPtr.get();
Ethan Nicholasc18bb512020-07-28 14:46:53 -04001603 fIRGenerator->convertProgram(kind, textPtr->c_str(), textPtr->size(), &elements);
John Stilesfbd050b2020-08-03 13:21:46 -04001604 auto result = std::make_unique<Program>(kind,
1605 std::move(textPtr),
1606 settings,
1607 fContext,
1608 inherited,
1609 std::move(elements),
1610 fIRGenerator->fSymbolTable,
1611 fIRGenerator->fInputs);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001612 if (fErrorCount) {
1613 return nullptr;
1614 }
1615 return result;
1616}
1617
Ethan Nicholas00543112018-07-31 09:44:36 -04001618bool Compiler::optimize(Program& program) {
1619 SkASSERT(!fErrorCount);
1620 if (!program.fIsOptimized) {
1621 program.fIsOptimized = true;
1622 fIRGenerator->fKind = program.fKind;
1623 fIRGenerator->fSettings = &program.fSettings;
1624 for (auto& element : program) {
1625 if (element.fKind == ProgramElement::kFunction_Kind) {
1626 this->scanCFG((FunctionDefinition&) element);
1627 }
1628 }
Ethan Nicholase8ad02c2020-06-03 16:58:20 -04001629 // we wait until after analysis to remove dead functions so that we still report errors
1630 // even in unused code
1631 if (program.fSettings.fRemoveDeadFunctions) {
1632 for (auto iter = program.fElements.begin(); iter != program.fElements.end(); ) {
1633 if ((*iter)->fKind == ProgramElement::kFunction_Kind) {
1634 const FunctionDefinition& f = (const FunctionDefinition&) **iter;
1635 if (!f.fDeclaration.fCallCount && f.fDeclaration.fName != "main") {
1636 iter = program.fElements.erase(iter);
1637 continue;
1638 }
1639 }
1640 ++iter;
1641 }
1642 }
Ethan Nicholas0dc80872019-02-08 15:46:24 -05001643 if (program.fKind != Program::kFragmentProcessor_Kind) {
1644 for (auto iter = program.fElements.begin(); iter != program.fElements.end();) {
1645 if ((*iter)->fKind == ProgramElement::kVar_Kind) {
1646 VarDeclarations& vars = (VarDeclarations&) **iter;
1647 for (auto varIter = vars.fVars.begin(); varIter != vars.fVars.end();) {
1648 const Variable& var = *((VarDeclaration&) **varIter).fVar;
1649 if (var.dead()) {
1650 varIter = vars.fVars.erase(varIter);
1651 } else {
1652 ++varIter;
1653 }
1654 }
1655 if (vars.fVars.size() == 0) {
1656 iter = program.fElements.erase(iter);
1657 continue;
1658 }
1659 }
1660 ++iter;
1661 }
1662 }
Ethan Nicholas00543112018-07-31 09:44:36 -04001663 }
1664 return fErrorCount == 0;
1665}
1666
Brian Osmanfb32ddf2019-06-18 10:14:20 -04001667#if defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
1668
Ethan Nicholas00543112018-07-31 09:44:36 -04001669bool Compiler::toSPIRV(Program& program, OutputStream& out) {
1670 if (!this->optimize(program)) {
1671 return false;
1672 }
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001673#ifdef SK_ENABLE_SPIRV_VALIDATION
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001674 StringStream buffer;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001675 fSource = program.fSource.get();
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001676 SPIRVCodeGenerator cg(fContext.get(), &program, this, &buffer);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001677 bool result = cg.generateCode();
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001678 fSource = nullptr;
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001679 if (result) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001680 spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_0);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001681 const String& data = buffer.str();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001682 SkASSERT(0 == data.size() % 4);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001683 auto dumpmsg = [](spv_message_level_t, const char*, const spv_position_t&, const char* m) {
1684 SkDebugf("SPIR-V validation error: %s\n", m);
1685 };
1686 tools.SetMessageConsumer(dumpmsg);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001687 // Verify that the SPIR-V we produced is valid. If this SkASSERT fails, check the logs prior
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001688 // to the failure to see the validation errors.
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001689 SkAssertResult(tools.Validate((const uint32_t*) data.c_str(), data.size() / 4));
Ethan Nicholas762466e2017-06-29 10:03:38 -04001690 out.write(data.c_str(), data.size());
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001691 }
1692#else
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001693 fSource = program.fSource.get();
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001694 SPIRVCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001695 bool result = cg.generateCode();
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001696 fSource = nullptr;
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001697#endif
Ethan Nicholasce33f102016-12-09 17:22:59 -05001698 return result;
1699}
1700
Ethan Nicholas00543112018-07-31 09:44:36 -04001701bool Compiler::toSPIRV(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001702 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001703 bool result = this->toSPIRV(program, buffer);
1704 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001705 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001706 }
1707 return result;
1708}
1709
Ethan Nicholas00543112018-07-31 09:44:36 -04001710bool Compiler::toGLSL(Program& program, OutputStream& out) {
1711 if (!this->optimize(program)) {
1712 return false;
1713 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001714 fSource = program.fSource.get();
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001715 GLSLCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001716 bool result = cg.generateCode();
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001717 fSource = nullptr;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001718 return result;
1719}
1720
Ethan Nicholas00543112018-07-31 09:44:36 -04001721bool Compiler::toGLSL(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001722 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001723 bool result = this->toGLSL(program, buffer);
1724 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001725 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001726 }
1727 return result;
1728}
1729
Brian Osmanc0243912020-02-19 15:35:26 -05001730bool Compiler::toHLSL(Program& program, String* out) {
1731 String spirv;
1732 if (!this->toSPIRV(program, &spirv)) {
1733 return false;
1734 }
1735
1736 return SPIRVtoHLSL(spirv, out);
1737}
1738
Ethan Nicholas00543112018-07-31 09:44:36 -04001739bool Compiler::toMetal(Program& program, OutputStream& out) {
1740 if (!this->optimize(program)) {
1741 return false;
1742 }
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001743 MetalCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholascc305772017-10-13 16:17:45 -04001744 bool result = cg.generateCode();
Ethan Nicholascc305772017-10-13 16:17:45 -04001745 return result;
1746}
1747
Ethan Nicholas00543112018-07-31 09:44:36 -04001748bool Compiler::toMetal(Program& program, String* out) {
1749 if (!this->optimize(program)) {
1750 return false;
1751 }
Timothy Liangb8eeb802018-07-23 16:46:16 -04001752 StringStream buffer;
1753 bool result = this->toMetal(program, buffer);
1754 if (result) {
1755 *out = buffer.str();
1756 }
1757 return result;
1758}
1759
Ethan Nicholas00543112018-07-31 09:44:36 -04001760bool Compiler::toCPP(Program& program, String name, OutputStream& out) {
1761 if (!this->optimize(program)) {
1762 return false;
1763 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001764 fSource = program.fSource.get();
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001765 CPPCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001766 bool result = cg.generateCode();
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001767 fSource = nullptr;
Ethan Nicholas762466e2017-06-29 10:03:38 -04001768 return result;
1769}
1770
Ethan Nicholas00543112018-07-31 09:44:36 -04001771bool Compiler::toH(Program& program, String name, OutputStream& out) {
1772 if (!this->optimize(program)) {
1773 return false;
1774 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001775 fSource = program.fSource.get();
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001776 HCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001777 bool result = cg.generateCode();
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001778 fSource = nullptr;
Ethan Nicholas00543112018-07-31 09:44:36 -04001779 return result;
1780}
1781
Brian Osman2e29ab52019-09-20 12:19:11 -04001782#endif
1783
1784#if !defined(SKSL_STANDALONE) && SK_SUPPORT_GPU
Brian Osmana4b91692020-08-10 14:26:16 -04001785bool Compiler::toPipelineStage(Program& program, PipelineStageArgs* outArgs) {
1786 if (!this->optimize(program)) {
1787 return false;
1788 }
Ethan Nicholas00543112018-07-31 09:44:36 -04001789 fSource = program.fSource.get();
1790 StringStream buffer;
Brian Osman300fe1d2020-01-23 15:42:43 -05001791 PipelineStageCodeGenerator cg(fContext.get(), &program, this, &buffer, outArgs);
Ethan Nicholas00543112018-07-31 09:44:36 -04001792 bool result = cg.generateCode();
1793 fSource = nullptr;
1794 if (result) {
Brian Osman107c6662019-12-30 15:02:30 -05001795 outArgs->fCode = buffer.str();
Ethan Nicholas00543112018-07-31 09:44:36 -04001796 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001797 return result;
1798}
Brian Osmanfb32ddf2019-06-18 10:14:20 -04001799#endif
1800
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001801std::unique_ptr<ByteCode> Compiler::toByteCode(Program& program) {
Brian Osman489cf882019-07-09 10:48:28 -04001802#if defined(SK_ENABLE_SKSL_INTERPRETER)
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001803 if (!this->optimize(program)) {
1804 return nullptr;
1805 }
Brian Osman808f0212020-01-21 15:36:47 -05001806 fSource = program.fSource.get();
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001807 std::unique_ptr<ByteCode> result(new ByteCode());
Brian Osmanb08cc022020-04-02 11:38:40 -04001808 ByteCodeGenerator cg(fContext.get(), &program, this, result.get());
1809 bool success = cg.generateCode();
1810 fSource = nullptr;
1811 if (success) {
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001812 return result;
1813 }
Brian Osman489cf882019-07-09 10:48:28 -04001814#else
1815 ABORT("ByteCode interpreter not enabled");
1816#endif
Ethan Nicholas0e9401d2019-03-21 11:05:37 -04001817 return nullptr;
1818}
1819
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001820const char* Compiler::OperatorName(Token::Kind kind) {
1821 switch (kind) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001822 case Token::Kind::TK_PLUS: return "+";
1823 case Token::Kind::TK_MINUS: return "-";
1824 case Token::Kind::TK_STAR: return "*";
1825 case Token::Kind::TK_SLASH: return "/";
1826 case Token::Kind::TK_PERCENT: return "%";
1827 case Token::Kind::TK_SHL: return "<<";
1828 case Token::Kind::TK_SHR: return ">>";
1829 case Token::Kind::TK_LOGICALNOT: return "!";
1830 case Token::Kind::TK_LOGICALAND: return "&&";
1831 case Token::Kind::TK_LOGICALOR: return "||";
1832 case Token::Kind::TK_LOGICALXOR: return "^^";
1833 case Token::Kind::TK_BITWISENOT: return "~";
1834 case Token::Kind::TK_BITWISEAND: return "&";
1835 case Token::Kind::TK_BITWISEOR: return "|";
1836 case Token::Kind::TK_BITWISEXOR: return "^";
1837 case Token::Kind::TK_EQ: return "=";
1838 case Token::Kind::TK_EQEQ: return "==";
1839 case Token::Kind::TK_NEQ: return "!=";
1840 case Token::Kind::TK_LT: return "<";
1841 case Token::Kind::TK_GT: return ">";
1842 case Token::Kind::TK_LTEQ: return "<=";
1843 case Token::Kind::TK_GTEQ: return ">=";
1844 case Token::Kind::TK_PLUSEQ: return "+=";
1845 case Token::Kind::TK_MINUSEQ: return "-=";
1846 case Token::Kind::TK_STAREQ: return "*=";
1847 case Token::Kind::TK_SLASHEQ: return "/=";
1848 case Token::Kind::TK_PERCENTEQ: return "%=";
1849 case Token::Kind::TK_SHLEQ: return "<<=";
1850 case Token::Kind::TK_SHREQ: return ">>=";
1851 case Token::Kind::TK_LOGICALANDEQ: return "&&=";
1852 case Token::Kind::TK_LOGICALOREQ: return "||=";
1853 case Token::Kind::TK_LOGICALXOREQ: return "^^=";
1854 case Token::Kind::TK_BITWISEANDEQ: return "&=";
1855 case Token::Kind::TK_BITWISEOREQ: return "|=";
1856 case Token::Kind::TK_BITWISEXOREQ: return "^=";
1857 case Token::Kind::TK_PLUSPLUS: return "++";
1858 case Token::Kind::TK_MINUSMINUS: return "--";
1859 case Token::Kind::TK_COMMA: return ",";
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001860 default:
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001861 ABORT("unsupported operator: %d\n", (int) kind);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001862 }
1863}
1864
1865
1866bool Compiler::IsAssignment(Token::Kind op) {
1867 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001868 case Token::Kind::TK_EQ: // fall through
1869 case Token::Kind::TK_PLUSEQ: // fall through
1870 case Token::Kind::TK_MINUSEQ: // fall through
1871 case Token::Kind::TK_STAREQ: // fall through
1872 case Token::Kind::TK_SLASHEQ: // fall through
1873 case Token::Kind::TK_PERCENTEQ: // fall through
1874 case Token::Kind::TK_SHLEQ: // fall through
1875 case Token::Kind::TK_SHREQ: // fall through
1876 case Token::Kind::TK_BITWISEOREQ: // fall through
1877 case Token::Kind::TK_BITWISEXOREQ: // fall through
1878 case Token::Kind::TK_BITWISEANDEQ: // fall through
1879 case Token::Kind::TK_LOGICALOREQ: // fall through
1880 case Token::Kind::TK_LOGICALXOREQ: // fall through
1881 case Token::Kind::TK_LOGICALANDEQ:
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001882 return true;
1883 default:
1884 return false;
1885 }
1886}
1887
1888Position Compiler::position(int offset) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001889 SkASSERT(fSource);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001890 int line = 1;
1891 int column = 1;
1892 for (int i = 0; i < offset; i++) {
1893 if ((*fSource)[i] == '\n') {
1894 ++line;
1895 column = 1;
1896 }
1897 else {
1898 ++column;
1899 }
1900 }
1901 return Position(line, column);
1902}
1903
1904void Compiler::error(int offset, String msg) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001905 fErrorCount++;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001906 Position pos = this->position(offset);
1907 fErrorText += "error: " + to_string(pos.fLine) + ": " + msg.c_str() + "\n";
ethannicholasb3058bd2016-07-01 08:22:01 -07001908}
1909
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001910String Compiler::errorText() {
Ethan Nicholas00543112018-07-31 09:44:36 -04001911 this->writeErrorCount();
1912 fErrorCount = 0;
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001913 String result = fErrorText;
ethannicholasb3058bd2016-07-01 08:22:01 -07001914 return result;
1915}
1916
1917void Compiler::writeErrorCount() {
1918 if (fErrorCount) {
1919 fErrorText += to_string(fErrorCount) + " error";
1920 if (fErrorCount > 1) {
1921 fErrorText += "s";
1922 }
1923 fErrorText += "\n";
1924 }
1925}
1926
John Stilesa6841be2020-08-06 14:11:56 -04001927} // namespace SkSL