blob: 156745ac57af0b99b44ff11657229f95c5b7c6cb [file] [log] [blame]
ethannicholasb3058bd2016-07-01 08:22:01 -07001/*
2 * Copyright 2016 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
Mike Klein6ad99092016-10-26 10:35:22 -04007
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "src/sksl/SkSLCompiler.h"
ethannicholasb3058bd2016-07-01 08:22:01 -07009
John Stilesfbd050b2020-08-03 13:21:46 -040010#include <memory>
John Stilesb8e010c2020-08-11 18:05:39 -040011#include <unordered_set>
John Stilesfbd050b2020-08-03 13:21:46 -040012
John Stiles270cec22021-02-17 12:59:36 -050013#include "src/core/SkScopeExit.h"
Leon Scrogginsb66214e2021-02-11 17:14:18 -050014#include "src/core/SkTraceEvent.h"
John Stilesb92641c2020-08-31 18:09:01 -040015#include "src/sksl/SkSLAnalysis.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050016#include "src/sksl/SkSLCPPCodeGenerator.h"
John Stilesf3a28db2021-03-10 23:00:47 -050017#include "src/sksl/SkSLConstantFolder.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050018#include "src/sksl/SkSLGLSLCodeGenerator.h"
19#include "src/sksl/SkSLHCodeGenerator.h"
20#include "src/sksl/SkSLIRGenerator.h"
21#include "src/sksl/SkSLMetalCodeGenerator.h"
Brian Osman00185012021-02-04 16:07:11 -050022#include "src/sksl/SkSLOperators.h"
John Stiles270cec22021-02-17 12:59:36 -050023#include "src/sksl/SkSLProgramSettings.h"
Ethan Nicholasc18bb512020-07-28 14:46:53 -040024#include "src/sksl/SkSLRehydrator.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050025#include "src/sksl/SkSLSPIRVCodeGenerator.h"
Brian Osmanc0243912020-02-19 15:35:26 -050026#include "src/sksl/SkSLSPIRVtoHLSL.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050027#include "src/sksl/ir/SkSLEnum.h"
28#include "src/sksl/ir/SkSLExpression.h"
29#include "src/sksl/ir/SkSLExpressionStatement.h"
30#include "src/sksl/ir/SkSLFunctionCall.h"
31#include "src/sksl/ir/SkSLIntLiteral.h"
32#include "src/sksl/ir/SkSLModifiersDeclaration.h"
33#include "src/sksl/ir/SkSLNop.h"
34#include "src/sksl/ir/SkSLSymbolTable.h"
35#include "src/sksl/ir/SkSLTernaryExpression.h"
36#include "src/sksl/ir/SkSLUnresolvedFunction.h"
37#include "src/sksl/ir/SkSLVarDeclarations.h"
John Stilese6150002020-10-05 12:03:53 -040038#include "src/utils/SkBitSet.h"
ethannicholasb3058bd2016-07-01 08:22:01 -070039
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -040040#include <fstream>
41
Ethan Nicholasa11035b2019-11-26 16:27:47 -050042#if !defined(SKSL_STANDALONE) & SK_SUPPORT_GPU
43#include "include/gpu/GrContextOptions.h"
44#include "src/gpu/GrShaderCaps.h"
45#endif
46
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -040047#ifdef SK_ENABLE_SPIRV_VALIDATION
48#include "spirv-tools/libspirv.hpp"
49#endif
50
Brian Osman3d87e9f2020-10-08 11:50:22 -040051#if defined(SKSL_STANDALONE)
Ethan Nicholasc18bb512020-07-28 14:46:53 -040052
Brian Osman3d87e9f2020-10-08 11:50:22 -040053// In standalone mode, we load the textual sksl source files. GN generates or copies these files
54// to the skslc executable directory. The "data" in this mode is just the filename.
55#define MODULE_DATA(name) MakeModulePath("sksl_" #name ".sksl")
56
57#else
58
59// At runtime, we load the dehydrated sksl data files. The data is a (pointer, size) pair.
Ethan Nicholasc18bb512020-07-28 14:46:53 -040060#include "src/sksl/generated/sksl_fp.dehydrated.sksl"
61#include "src/sksl/generated/sksl_frag.dehydrated.sksl"
62#include "src/sksl/generated/sksl_geom.dehydrated.sksl"
63#include "src/sksl/generated/sksl_gpu.dehydrated.sksl"
Brian Osmanb06301e2020-11-06 11:45:36 -050064#include "src/sksl/generated/sksl_public.dehydrated.sksl"
Brian Osman91946752020-12-21 13:20:40 -050065#include "src/sksl/generated/sksl_runtime.dehydrated.sksl"
Ethan Nicholasc18bb512020-07-28 14:46:53 -040066#include "src/sksl/generated/sksl_vert.dehydrated.sksl"
67
Brian Osman3d87e9f2020-10-08 11:50:22 -040068#define MODULE_DATA(name) MakeModuleData(SKSL_INCLUDE_sksl_##name,\
69 SKSL_INCLUDE_sksl_##name##_LENGTH)
Ethan Nicholasc18bb512020-07-28 14:46:53 -040070
71#endif
Ethan Nicholas0d997662019-04-08 09:46:01 -040072
ethannicholasb3058bd2016-07-01 08:22:01 -070073namespace SkSL {
74
John Stiles7247b482021-03-08 10:40:35 -050075// Set these flags to `false` to disable optimization passes unilaterally.
76// These flags allow tools like Viewer or Nanobench to override the compiler's ProgramSettings.
77bool gSkSLOptimizer = true;
78bool gSkSLInliner = true;
John Stiles8ef4d6c2021-03-05 16:01:45 -050079
John Stiles47c0a742021-02-09 09:30:35 -050080using RefKind = VariableReference::RefKind;
81
Brian Osman88cda172020-10-09 12:05:16 -040082class AutoSource {
83public:
84 AutoSource(Compiler* compiler, const String* source)
85 : fCompiler(compiler), fOldSource(fCompiler->fSource) {
86 fCompiler->fSource = source;
87 }
88
89 ~AutoSource() { fCompiler->fSource = fOldSource; }
90
91 Compiler* fCompiler;
92 const String* fOldSource;
93};
94
John Stilesa935c3f2021-02-25 10:35:49 -050095class AutoProgramConfig {
96public:
97 AutoProgramConfig(std::shared_ptr<Context>& context, ProgramConfig* config)
98 : fContext(context.get()) {
99 SkASSERT(!fContext->fConfig);
100 fContext->fConfig = config;
101 }
102
103 ~AutoProgramConfig() {
104 fContext->fConfig = nullptr;
105 }
106
107 Context* fContext;
108};
109
John Stilesd6a5f4492021-02-11 15:46:11 -0500110Compiler::Compiler(const ShaderCapsClass* caps)
John Stilesc1a98b82021-02-24 13:35:02 -0500111 : fContext(std::make_shared<Context>(/*errors=*/*this, *caps))
John Stiles7b920442020-12-17 10:43:41 -0500112 , fInliner(fContext.get())
Brian Osman0006ad02020-11-18 15:38:39 -0500113 , fErrorCount(0) {
John Stilesc1a98b82021-02-24 13:35:02 -0500114 SkASSERT(caps);
John Stiles7c3515b2020-10-16 18:38:39 -0400115 fRootSymbolTable = std::make_shared<SymbolTable>(this, /*builtin=*/true);
Brian Osmanb06301e2020-11-06 11:45:36 -0500116 fPrivateSymbolTable = std::make_shared<SymbolTable>(fRootSymbolTable, /*builtin=*/true);
John Stilesc1a98b82021-02-24 13:35:02 -0500117 fIRGenerator = std::make_unique<IRGenerator>(fContext.get());
ethannicholasb3058bd2016-07-01 08:22:01 -0700118
John Stiles54e7c052021-01-11 14:22:36 -0500119#define TYPE(t) fContext->fTypes.f ## t .get()
ethannicholasb3058bd2016-07-01 08:22:01 -0700120
Brian Osmanb06301e2020-11-06 11:45:36 -0500121 const SkSL::Symbol* rootTypes[] = {
122 TYPE(Void),
Brian Salomonbf7b6202016-11-11 16:08:03 -0500123
Brian Osmanb06301e2020-11-06 11:45:36 -0500124 TYPE( Float), TYPE( Float2), TYPE( Float3), TYPE( Float4),
125 TYPE( Half), TYPE( Half2), TYPE( Half3), TYPE( Half4),
126 TYPE( Int), TYPE( Int2), TYPE( Int3), TYPE( Int4),
Brian Osmanb06301e2020-11-06 11:45:36 -0500127 TYPE( Bool), TYPE( Bool2), TYPE( Bool3), TYPE( Bool4),
Brian Salomon2a51de82016-11-16 12:06:01 -0500128
Brian Osmanc0f2b642020-12-22 13:35:55 -0500129 TYPE(Float2x2), TYPE(Float3x3), TYPE(Float4x4),
Brian Osmanc63f4312020-12-23 11:44:14 -0500130 TYPE( Half2x2), TYPE( Half3x3), TYPE(Half4x4),
Greg Daniel64773e62016-11-22 09:44:03 -0500131
Brian Osmanc63f4312020-12-23 11:44:14 -0500132 TYPE(SquareMat), TYPE(SquareHMat),
ethannicholasb3058bd2016-07-01 08:22:01 -0700133
Brian Osman20fad322020-12-23 12:42:33 -0500134 TYPE(GenType), TYPE(GenHType), TYPE(GenIType), TYPE(GenBType),
135 TYPE(Vec), TYPE(HVec), TYPE(IVec), TYPE(BVec),
Brian Osmanb06301e2020-11-06 11:45:36 -0500136
137 TYPE(FragmentProcessor),
138 };
139
140 const SkSL::Symbol* privateTypes[] = {
Brian Osman20fad322020-12-23 12:42:33 -0500141 TYPE( UInt), TYPE( UInt2), TYPE( UInt3), TYPE( UInt4),
142 TYPE( Short), TYPE( Short2), TYPE( Short3), TYPE( Short4),
143 TYPE(UShort), TYPE(UShort2), TYPE(UShort3), TYPE(UShort4),
144 TYPE( Byte), TYPE( Byte2), TYPE( Byte3), TYPE( Byte4),
145 TYPE( UByte), TYPE( UByte2), TYPE( UByte3), TYPE( UByte4),
146
147 TYPE(GenUType), TYPE(UVec),
148 TYPE(SVec), TYPE(USVec), TYPE(ByteVec), TYPE(UByteVec),
149
Brian Osmanc0f2b642020-12-22 13:35:55 -0500150 TYPE(Float2x3), TYPE(Float2x4),
151 TYPE(Float3x2), TYPE(Float3x4),
152 TYPE(Float4x2), TYPE(Float4x3),
153
Brian Osmanc63f4312020-12-23 11:44:14 -0500154 TYPE(Half2x3), TYPE(Half2x4),
155 TYPE(Half3x2), TYPE(Half3x4),
156 TYPE(Half4x2), TYPE(Half4x3),
157
Brian Osmanc0f2b642020-12-22 13:35:55 -0500158 TYPE(Mat), TYPE(HMat),
159
Brian Osmanb06301e2020-11-06 11:45:36 -0500160 TYPE(Sampler1D), TYPE(Sampler2D), TYPE(Sampler3D),
161 TYPE(SamplerExternalOES),
Brian Osmanb06301e2020-11-06 11:45:36 -0500162 TYPE(Sampler2DRect),
Brian Osmanb06301e2020-11-06 11:45:36 -0500163
164 TYPE(ISampler2D),
Brian Osmanb06301e2020-11-06 11:45:36 -0500165 TYPE(SubpassInput), TYPE(SubpassInputMS),
166
Brian Osmanb06301e2020-11-06 11:45:36 -0500167 TYPE(Sampler),
168 TYPE(Texture2D),
169 };
170
171 for (const SkSL::Symbol* type : rootTypes) {
172 fRootSymbolTable->addWithoutOwnership(type);
173 }
174 for (const SkSL::Symbol* type : privateTypes) {
175 fPrivateSymbolTable->addWithoutOwnership(type);
176 }
177
178#undef TYPE
ethannicholasb3058bd2016-07-01 08:22:01 -0700179
Brian Osman3887a012020-09-30 13:22:27 -0400180 // sk_Caps is "builtin", but all references to it are resolved to Settings, so we don't need to
181 // treat it as builtin (ie, no need to clone it into the Program).
Brian Osmanb06301e2020-11-06 11:45:36 -0500182 fPrivateSymbolTable->add(
183 std::make_unique<Variable>(/*offset=*/-1,
John Stiles586df952020-11-12 18:27:13 -0500184 fIRGenerator->fModifiers->addToPool(Modifiers()),
Brian Osmanb06301e2020-11-06 11:45:36 -0500185 "sk_Caps",
John Stiles54e7c052021-01-11 14:22:36 -0500186 fContext->fTypes.fSkCaps.get(),
Brian Osmanb06301e2020-11-06 11:45:36 -0500187 /*builtin=*/false,
188 Variable::Storage::kGlobal));
Ethan Nicholas3605ace2016-11-21 15:59:48 -0500189
Brian Osman3d87e9f2020-10-08 11:50:22 -0400190 fRootModule = {fRootSymbolTable, /*fIntrinsics=*/nullptr};
Brian Osmanb06301e2020-11-06 11:45:36 -0500191 fPrivateModule = {fPrivateSymbolTable, /*fIntrinsics=*/nullptr};
ethannicholasb3058bd2016-07-01 08:22:01 -0700192}
193
John Stilesdd13dba2020-10-29 10:45:34 -0400194Compiler::~Compiler() {}
ethannicholasb3058bd2016-07-01 08:22:01 -0700195
Brian Osman56269982020-11-20 12:38:07 -0500196const ParsedModule& Compiler::loadGPUModule() {
197 if (!fGPUModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500198 fGPUModule = this->parseModule(ProgramKind::kFragment, MODULE_DATA(gpu), fPrivateModule);
Brian Osman56269982020-11-20 12:38:07 -0500199 }
200 return fGPUModule;
201}
202
203const ParsedModule& Compiler::loadFragmentModule() {
204 if (!fFragmentModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500205 fFragmentModule = this->parseModule(ProgramKind::kFragment, MODULE_DATA(frag),
Brian Osman56269982020-11-20 12:38:07 -0500206 this->loadGPUModule());
207 }
208 return fFragmentModule;
209}
210
211const ParsedModule& Compiler::loadVertexModule() {
212 if (!fVertexModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500213 fVertexModule = this->parseModule(ProgramKind::kVertex, MODULE_DATA(vert),
Brian Osman56269982020-11-20 12:38:07 -0500214 this->loadGPUModule());
215 }
216 return fVertexModule;
217}
218
Brian Osman88cda172020-10-09 12:05:16 -0400219const ParsedModule& Compiler::loadGeometryModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400220 if (!fGeometryModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500221 fGeometryModule = this->parseModule(ProgramKind::kGeometry, MODULE_DATA(geom),
Brian Osman56269982020-11-20 12:38:07 -0500222 this->loadGPUModule());
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400223 }
Brian Osman88cda172020-10-09 12:05:16 -0400224 return fGeometryModule;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400225}
226
Brian Osman88cda172020-10-09 12:05:16 -0400227const ParsedModule& Compiler::loadFPModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400228 if (!fFPModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500229 fFPModule = this->parseModule(ProgramKind::kFragmentProcessor, MODULE_DATA(fp),
Brian Osman56269982020-11-20 12:38:07 -0500230 this->loadGPUModule());
Brian Osman8e2ef022020-09-30 13:26:43 -0400231 }
Brian Osman88cda172020-10-09 12:05:16 -0400232 return fFPModule;
Brian Osman8e2ef022020-09-30 13:26:43 -0400233}
234
Brian Osmanb06301e2020-11-06 11:45:36 -0500235const ParsedModule& Compiler::loadPublicModule() {
236 if (!fPublicModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500237 fPublicModule = this->parseModule(ProgramKind::kGeneric, MODULE_DATA(public), fRootModule);
Brian Osmanb06301e2020-11-06 11:45:36 -0500238 }
239 return fPublicModule;
240}
241
Brian Osman91946752020-12-21 13:20:40 -0500242const ParsedModule& Compiler::loadRuntimeEffectModule() {
243 if (!fRuntimeEffectModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500244 fRuntimeEffectModule = this->parseModule(ProgramKind::kRuntimeEffect, MODULE_DATA(runtime),
Brian Osman91946752020-12-21 13:20:40 -0500245 this->loadPublicModule());
Brian Osmanf1319c32020-10-13 09:34:23 -0400246
Brian Osman91946752020-12-21 13:20:40 -0500247 // Add some aliases to the runtime effect module so that it's friendlier, and more like GLSL
John Stiles54e7c052021-01-11 14:22:36 -0500248 fRuntimeEffectModule.fSymbols->addAlias("shader", fContext->fTypes.fFragmentProcessor.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400249
John Stiles54e7c052021-01-11 14:22:36 -0500250 fRuntimeEffectModule.fSymbols->addAlias("vec2", fContext->fTypes.fFloat2.get());
251 fRuntimeEffectModule.fSymbols->addAlias("vec3", fContext->fTypes.fFloat3.get());
252 fRuntimeEffectModule.fSymbols->addAlias("vec4", fContext->fTypes.fFloat4.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400253
John Stiles54e7c052021-01-11 14:22:36 -0500254 fRuntimeEffectModule.fSymbols->addAlias("bvec2", fContext->fTypes.fBool2.get());
255 fRuntimeEffectModule.fSymbols->addAlias("bvec3", fContext->fTypes.fBool3.get());
256 fRuntimeEffectModule.fSymbols->addAlias("bvec4", fContext->fTypes.fBool4.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400257
John Stiles54e7c052021-01-11 14:22:36 -0500258 fRuntimeEffectModule.fSymbols->addAlias("mat2", fContext->fTypes.fFloat2x2.get());
259 fRuntimeEffectModule.fSymbols->addAlias("mat3", fContext->fTypes.fFloat3x3.get());
260 fRuntimeEffectModule.fSymbols->addAlias("mat4", fContext->fTypes.fFloat4x4.get());
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400261 }
Brian Osman91946752020-12-21 13:20:40 -0500262 return fRuntimeEffectModule;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400263}
264
John Stilesdbd4e6f2021-02-16 13:29:15 -0500265const ParsedModule& Compiler::moduleForProgramKind(ProgramKind kind) {
Brian Osman88cda172020-10-09 12:05:16 -0400266 switch (kind) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500267 case ProgramKind::kVertex: return this->loadVertexModule(); break;
268 case ProgramKind::kFragment: return this->loadFragmentModule(); break;
269 case ProgramKind::kGeometry: return this->loadGeometryModule(); break;
270 case ProgramKind::kFragmentProcessor: return this->loadFPModule(); break;
271 case ProgramKind::kRuntimeEffect: return this->loadRuntimeEffectModule(); break;
272 case ProgramKind::kGeneric: return this->loadPublicModule(); break;
Brian Osman88cda172020-10-09 12:05:16 -0400273 }
274 SkUNREACHABLE;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400275}
276
John Stilesdbd4e6f2021-02-16 13:29:15 -0500277LoadedModule Compiler::loadModule(ProgramKind kind,
Brian Osman3d87e9f2020-10-08 11:50:22 -0400278 ModuleData data,
John Stilesa935c3f2021-02-25 10:35:49 -0500279 std::shared_ptr<SymbolTable> base,
280 bool dehydrate) {
281 if (dehydrate) {
282 // NOTE: This is a workaround. When dehydrating includes, skslc doesn't know which module
283 // it's preparing, nor what the correct base module is. We can't use 'Root', because many
284 // GPU intrinsics reference private types, like samplers or textures. Today, 'Private' does
285 // contain the union of all known types, so this is safe. If we ever have types that only
286 // exist in 'Public' (for example), this logic needs to be smarter (by choosing the correct
287 // base for the module we're compiling).
Brian Osmanb06301e2020-11-06 11:45:36 -0500288 base = fPrivateSymbolTable;
Brian Osman3d87e9f2020-10-08 11:50:22 -0400289 }
John Stilesa935c3f2021-02-25 10:35:49 -0500290 SkASSERT(base);
291
292 // Built-in modules always use default program settings.
293 ProgramConfig config;
294 config.fKind = kind;
295 config.fSettings.fReplaceSettings = !dehydrate;
296 AutoProgramConfig autoConfig(fContext, &config);
Brian Osman3d87e9f2020-10-08 11:50:22 -0400297
298#if defined(SKSL_STANDALONE)
299 SkASSERT(data.fPath);
300 std::ifstream in(data.fPath);
Brian Osmane498b3c2020-09-23 14:42:11 -0400301 std::unique_ptr<String> text = std::make_unique<String>(std::istreambuf_iterator<char>(in),
302 std::istreambuf_iterator<char>());
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400303 if (in.rdstate()) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400304 printf("error reading %s\n", data.fPath);
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400305 abort();
306 }
Brian Osmane498b3c2020-09-23 14:42:11 -0400307 const String* source = fRootSymbolTable->takeOwnershipOfString(std::move(text));
Brian Osman88cda172020-10-09 12:05:16 -0400308 AutoSource as(this, source);
John Stilesd1204642021-02-17 16:30:02 -0500309
John Stiles881a10c2020-09-19 10:13:24 -0400310 SkASSERT(fIRGenerator->fCanInline);
311 fIRGenerator->fCanInline = false;
John Stilesd1204642021-02-17 16:30:02 -0500312
Brian Osman88cda172020-10-09 12:05:16 -0400313 ParsedModule baseModule = {base, /*fIntrinsics=*/nullptr};
John Stilesd1204642021-02-17 16:30:02 -0500314 IRGenerator::IRBundle ir = fIRGenerator->convertProgram(baseModule, /*isBuiltinCode=*/true,
315 source->c_str(), source->length(),
316 /*externalFunctions=*/nullptr);
Brian Osman133724c2020-10-28 14:14:39 -0400317 SkASSERT(ir.fSharedElements.empty());
Brian Osman0006ad02020-11-18 15:38:39 -0500318 LoadedModule module = { kind, std::move(ir.fSymbolTable), std::move(ir.fElements) };
John Stiles881a10c2020-09-19 10:13:24 -0400319 fIRGenerator->fCanInline = true;
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400320 if (this->fErrorCount) {
321 printf("Unexpected errors: %s\n", this->fErrorText.c_str());
Brian Osman3d87e9f2020-10-08 11:50:22 -0400322 SkDEBUGFAILF("%s %s\n", data.fPath, this->fErrorText.c_str());
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400323 }
Brian Osman88cda172020-10-09 12:05:16 -0400324 fModifiers.push_back(std::move(ir.fModifiers));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400325#else
326 SkASSERT(data.fData && (data.fSize != 0));
327 Rehydrator rehydrator(fContext.get(), fIRGenerator->fModifiers.get(), base, this,
328 data.fData, data.fSize);
Brian Osman0006ad02020-11-18 15:38:39 -0500329 LoadedModule module = { kind, rehydrator.symbolTable(), rehydrator.elements() };
Brian Osman3d87e9f2020-10-08 11:50:22 -0400330 fModifiers.push_back(fIRGenerator->releaseModifiers());
331#endif
332
333 return module;
334}
335
John Stilesdbd4e6f2021-02-16 13:29:15 -0500336ParsedModule Compiler::parseModule(ProgramKind kind, ModuleData data, const ParsedModule& base) {
John Stilesa935c3f2021-02-25 10:35:49 -0500337 LoadedModule module = this->loadModule(kind, data, base.fSymbols, /*dehydrate=*/false);
Brian Osman0006ad02020-11-18 15:38:39 -0500338 this->optimize(module);
Brian Osman3d87e9f2020-10-08 11:50:22 -0400339
340 // For modules that just declare (but don't define) intrinsic functions, there will be no new
341 // program elements. In that case, we can share our parent's intrinsic map:
Brian Osman0006ad02020-11-18 15:38:39 -0500342 if (module.fElements.empty()) {
343 return {module.fSymbols, base.fIntrinsics};
Brian Osman3d87e9f2020-10-08 11:50:22 -0400344 }
345
346 auto intrinsics = std::make_shared<IRIntrinsicMap>(base.fIntrinsics.get());
347
348 // Now, transfer all of the program elements to an intrinsic map. This maps certain types of
349 // global objects to the declaring ProgramElement.
Brian Osman0006ad02020-11-18 15:38:39 -0500350 for (std::unique_ptr<ProgramElement>& element : module.fElements) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400351 switch (element->kind()) {
352 case ProgramElement::Kind::kFunction: {
353 const FunctionDefinition& f = element->as<FunctionDefinition>();
Ethan Nicholas0a5d0962020-10-14 13:33:18 -0400354 SkASSERT(f.declaration().isBuiltin());
355 intrinsics->insertOrDie(f.declaration().description(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400356 break;
357 }
John Stiles569249b2020-11-03 12:18:22 -0500358 case ProgramElement::Kind::kFunctionPrototype: {
359 // These are already in the symbol table.
360 break;
361 }
Brian Osman3d87e9f2020-10-08 11:50:22 -0400362 case ProgramElement::Kind::kEnum: {
363 const Enum& e = element->as<Enum>();
364 SkASSERT(e.isBuiltin());
365 intrinsics->insertOrDie(e.typeName(), std::move(element));
366 break;
367 }
368 case ProgramElement::Kind::kGlobalVar: {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -0400369 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
370 const Variable& var = global.declaration()->as<VarDeclaration>().var();
371 SkASSERT(var.isBuiltin());
372 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400373 break;
374 }
375 case ProgramElement::Kind::kInterfaceBlock: {
Ethan Nicholaseaf47882020-10-15 10:10:08 -0400376 const Variable& var = element->as<InterfaceBlock>().variable();
377 SkASSERT(var.isBuiltin());
378 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400379 break;
380 }
381 default:
382 printf("Unsupported element: %s\n", element->description().c_str());
383 SkASSERT(false);
384 break;
385 }
386 }
387
Brian Osman0006ad02020-11-18 15:38:39 -0500388 return {module.fSymbols, std::move(intrinsics)};
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400389}
390
Brian Osman32d53552020-09-23 13:55:20 -0400391std::unique_ptr<Program> Compiler::convertProgram(
John Stilesdbd4e6f2021-02-16 13:29:15 -0500392 ProgramKind kind,
Brian Osman32d53552020-09-23 13:55:20 -0400393 String text,
394 const Program::Settings& settings,
Brian Osmanbe0b3b72021-01-06 14:27:35 -0500395 const std::vector<std::unique_ptr<ExternalFunction>>* externalFunctions) {
Brian Osmand010f652021-02-24 13:59:39 -0500396 TRACE_EVENT0("skia.gpu", "SkSL::Compiler::convertProgram");
Leon Scrogginsb66214e2021-02-11 17:14:18 -0500397
John Stilesdbd4e6f2021-02-16 13:29:15 -0500398 SkASSERT(!externalFunctions || (kind == ProgramKind::kGeneric));
Ethan Nicholas91164d12019-05-15 15:29:54 -0400399
Brian Osman0006ad02020-11-18 15:38:39 -0500400 // Loading and optimizing our base module might reset the inliner, so do that first,
401 // *then* configure the inliner with the settings for this program.
402 const ParsedModule& baseModule = this->moduleForProgramKind(kind);
403
John Stiles270cec22021-02-17 12:59:36 -0500404 // Update our context to point to the program configuration for the duration of compilation.
405 auto config = std::make_unique<ProgramConfig>(ProgramConfig{kind, settings});
John Stilesa935c3f2021-02-25 10:35:49 -0500406 AutoProgramConfig autoConfig(fContext, config.get());
John Stiles270cec22021-02-17 12:59:36 -0500407
John Stiles7247b482021-03-08 10:40:35 -0500408 // Honor our global optimization-disable flags.
409 config->fSettings.fOptimize &= gSkSLOptimizer;
John Stiles7247b482021-03-08 10:40:35 -0500410 config->fSettings.fInlineThreshold *= (int)gSkSLInliner;
411
412 // Disable optimization settings that depend on a parent setting which has been disabled.
John Stiles7247b482021-03-08 10:40:35 -0500413 config->fSettings.fInlineThreshold *= (int)config->fSettings.fOptimize;
John Stiles7247b482021-03-08 10:40:35 -0500414
ethannicholasb3058bd2016-07-01 08:22:01 -0700415 fErrorText = "";
416 fErrorCount = 0;
John Stilesd1204642021-02-17 16:30:02 -0500417 fInliner.reset(fIRGenerator->fModifiers.get());
Brian Osman88cda172020-10-09 12:05:16 -0400418
419 // Not using AutoSource, because caller is likely to call errorText() if we fail to compile
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700420 std::unique_ptr<String> textPtr(new String(std::move(text)));
421 fSource = textPtr.get();
Brian Osman88cda172020-10-09 12:05:16 -0400422
John Stiles5c7bb322020-10-22 11:09:15 -0400423 // Enable node pooling while converting and optimizing the program for a performance boost.
424 // The Program will take ownership of the pool.
Brian Osman28f702c2021-02-02 11:52:07 -0500425 std::unique_ptr<Pool> pool;
John Stilesc1a98b82021-02-24 13:35:02 -0500426 if (fContext->fCaps.useNodePools()) {
Brian Osman28f702c2021-02-02 11:52:07 -0500427 pool = Pool::Create();
428 pool->attachToThread();
429 }
John Stilesd1204642021-02-17 16:30:02 -0500430 IRGenerator::IRBundle ir = fIRGenerator->convertProgram(baseModule, /*isBuiltinCode=*/false,
431 textPtr->c_str(), textPtr->size(),
432 externalFunctions);
John Stiles270cec22021-02-17 12:59:36 -0500433 auto program = std::make_unique<Program>(std::move(textPtr),
434 std::move(config),
John Stiles5c7bb322020-10-22 11:09:15 -0400435 fContext,
436 std::move(ir.fElements),
Brian Osman133724c2020-10-28 14:14:39 -0400437 std::move(ir.fSharedElements),
John Stiles5c7bb322020-10-22 11:09:15 -0400438 std::move(ir.fModifiers),
439 std::move(ir.fSymbolTable),
440 std::move(pool),
441 ir.fInputs);
442 bool success = false;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500443 if (fErrorCount) {
John Stiles5c7bb322020-10-22 11:09:15 -0400444 // Do not return programs that failed to compile.
John Stiles7247b482021-03-08 10:40:35 -0500445 } else if (!this->optimize(*program)) {
John Stiles5c7bb322020-10-22 11:09:15 -0400446 // Do not return programs that failed to optimize.
447 } else {
448 // We have a successful program!
449 success = true;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500450 }
John Stiles5c7bb322020-10-22 11:09:15 -0400451
Brian Osman28f702c2021-02-02 11:52:07 -0500452 if (program->fPool) {
453 program->fPool->detachFromThread();
454 }
John Stiles5c7bb322020-10-22 11:09:15 -0400455 return success ? std::move(program) : nullptr;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500456}
457
John Stilesbb1505f2021-02-12 09:17:53 -0500458void Compiler::verifyStaticTests(const Program& program) {
459 class StaticTestVerifier : public ProgramVisitor {
460 public:
461 StaticTestVerifier(ErrorReporter* r) : fReporter(r) {}
462
463 using ProgramVisitor::visitProgramElement;
464
465 bool visitStatement(const Statement& stmt) override {
466 switch (stmt.kind()) {
467 case Statement::Kind::kIf:
468 if (stmt.as<IfStatement>().isStatic()) {
469 fReporter->error(stmt.fOffset, "static if has non-static test");
470 }
471 break;
472
473 case Statement::Kind::kSwitch:
474 if (stmt.as<SwitchStatement>().isStatic()) {
475 fReporter->error(stmt.fOffset, "static switch has non-static test");
476 }
477 break;
478
479 default:
480 break;
481 }
482 return INHERITED::visitStatement(stmt);
483 }
484
John Stiles59e34562021-02-12 16:56:39 -0500485 bool visitExpression(const Expression&) override {
486 // We aren't looking for anything inside an Expression, so skip them entirely.
487 return false;
488 }
489
John Stilesbb1505f2021-02-12 09:17:53 -0500490 private:
491 using INHERITED = ProgramVisitor;
492 ErrorReporter* fReporter;
493 };
494
495 // If invalid static tests are permitted, we don't need to check anything.
John Stilesd1204642021-02-17 16:30:02 -0500496 if (fContext->fConfig->fSettings.fPermitInvalidStaticTests) {
John Stilesbb1505f2021-02-12 09:17:53 -0500497 return;
498 }
499
500 // Check all of the program's owned elements. (Built-in elements are assumed to be valid.)
501 StaticTestVerifier visitor{this};
502 for (const std::unique_ptr<ProgramElement>& element : program.ownedElements()) {
503 if (element->is<FunctionDefinition>()) {
504 visitor.visitProgramElement(*element);
505 }
506 }
507}
508
Brian Osman0006ad02020-11-18 15:38:39 -0500509bool Compiler::optimize(LoadedModule& module) {
510 SkASSERT(!fErrorCount);
Brian Osman0006ad02020-11-18 15:38:39 -0500511
John Stiles270cec22021-02-17 12:59:36 -0500512 // Create a temporary program configuration with default settings.
513 ProgramConfig config;
514 config.fKind = module.fKind;
John Stilesa935c3f2021-02-25 10:35:49 -0500515 AutoProgramConfig autoConfig(fContext, &config);
John Stiles270cec22021-02-17 12:59:36 -0500516
John Stilesd1204642021-02-17 16:30:02 -0500517 // Reset the Inliner.
518 fInliner.reset(fModifiers.back().get());
John Stiles270cec22021-02-17 12:59:36 -0500519
520 std::unique_ptr<ProgramUsage> usage = Analysis::GetUsage(module);
Brian Osman0006ad02020-11-18 15:38:39 -0500521
522 while (fErrorCount == 0) {
Brian Osman0006ad02020-11-18 15:38:39 -0500523 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stilesf3a28db2021-03-10 23:00:47 -0500524 if (!fInliner.analyze(module.fElements, module.fSymbols, usage.get())) {
Brian Osman0006ad02020-11-18 15:38:39 -0500525 break;
526 }
527 }
528 return fErrorCount == 0;
529}
530
Ethan Nicholas00543112018-07-31 09:44:36 -0400531bool Compiler::optimize(Program& program) {
John Stiles7247b482021-03-08 10:40:35 -0500532 // The optimizer only needs to run when it is enabled.
533 if (!program.fConfig->fSettings.fOptimize) {
534 return true;
535 }
536
Ethan Nicholas00543112018-07-31 09:44:36 -0400537 SkASSERT(!fErrorCount);
Brian Osman010ce6a2020-10-19 16:34:10 -0400538 ProgramUsage* usage = program.fUsage.get();
John Stiles7954d6c2020-09-01 10:53:02 -0400539
Ethan Nicholas34b19c52020-09-14 11:33:47 -0400540 while (fErrorCount == 0) {
Ethan Nicholas34b19c52020-09-14 11:33:47 -0400541 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stilesf3a28db2021-03-10 23:00:47 -0500542 bool madeChanges = fInliner.analyze(program.ownedElements(), program.fSymbols, usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -0400543
John Stilesf3a28db2021-03-10 23:00:47 -0500544 // Remove dead functions.
John Stiles270cec22021-02-17 12:59:36 -0500545 if (program.fConfig->fSettings.fRemoveDeadFunctions) {
Brian Osman133724c2020-10-28 14:14:39 -0400546 auto isDeadFunction = [&](const ProgramElement* element) {
547 if (!element->is<FunctionDefinition>()) {
548 return false;
549 }
550 const FunctionDefinition& fn = element->as<FunctionDefinition>();
551 if (fn.declaration().name() != "main" && usage->get(fn.declaration()) == 0) {
552 usage->remove(*element);
553 madeChanges = true;
554 return true;
555 }
556 return false;
557 };
Ethan Nicholas34b19c52020-09-14 11:33:47 -0400558 program.fElements.erase(
Brian Osman133724c2020-10-28 14:14:39 -0400559 std::remove_if(program.fElements.begin(), program.fElements.end(),
Ethan Nicholas34b19c52020-09-14 11:33:47 -0400560 [&](const std::unique_ptr<ProgramElement>& element) {
Brian Osman133724c2020-10-28 14:14:39 -0400561 return isDeadFunction(element.get());
Ethan Nicholas34b19c52020-09-14 11:33:47 -0400562 }),
563 program.fElements.end());
Brian Osman133724c2020-10-28 14:14:39 -0400564 program.fSharedElements.erase(
565 std::remove_if(program.fSharedElements.begin(), program.fSharedElements.end(),
566 isDeadFunction),
567 program.fSharedElements.end());
Ethan Nicholas34b19c52020-09-14 11:33:47 -0400568 }
569
John Stiles270cec22021-02-17 12:59:36 -0500570 if (program.fConfig->fKind != ProgramKind::kFragmentProcessor) {
Brian Osmanc0213602020-10-06 14:43:32 -0400571 // Remove declarations of dead global variables
Brian Osman133724c2020-10-28 14:14:39 -0400572 auto isDeadVariable = [&](const ProgramElement* element) {
573 if (!element->is<GlobalVarDeclaration>()) {
574 return false;
575 }
576 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
577 const VarDeclaration& varDecl = global.declaration()->as<VarDeclaration>();
578 if (usage->isDead(varDecl.var())) {
579 madeChanges = true;
580 return true;
581 }
582 return false;
583 };
Ethan Nicholas34b19c52020-09-14 11:33:47 -0400584 program.fElements.erase(
585 std::remove_if(program.fElements.begin(), program.fElements.end(),
586 [&](const std::unique_ptr<ProgramElement>& element) {
Brian Osman133724c2020-10-28 14:14:39 -0400587 return isDeadVariable(element.get());
Ethan Nicholas34b19c52020-09-14 11:33:47 -0400588 }),
589 program.fElements.end());
Brian Osman133724c2020-10-28 14:14:39 -0400590 program.fSharedElements.erase(
591 std::remove_if(program.fSharedElements.begin(), program.fSharedElements.end(),
592 isDeadVariable),
593 program.fSharedElements.end());
Ethan Nicholas34b19c52020-09-14 11:33:47 -0400594 }
John Stiles73a6bff2020-09-09 13:40:37 -0400595
Ethan Nicholas34b19c52020-09-14 11:33:47 -0400596 if (!madeChanges) {
597 break;
Ethan Nicholas0dc80872019-02-08 15:46:24 -0500598 }
Ethan Nicholas00543112018-07-31 09:44:36 -0400599 }
John Stilesbb1505f2021-02-12 09:17:53 -0500600
601 if (fErrorCount == 0) {
602 this->verifyStaticTests(program);
603 }
604
Ethan Nicholas00543112018-07-31 09:44:36 -0400605 return fErrorCount == 0;
606}
607
Brian Osmanfb32ddf2019-06-18 10:14:20 -0400608#if defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
609
Ethan Nicholas00543112018-07-31 09:44:36 -0400610bool Compiler::toSPIRV(Program& program, OutputStream& out) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -0400611#ifdef SK_ENABLE_SPIRV_VALIDATION
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400612 StringStream buffer;
Brian Osman88cda172020-10-09 12:05:16 -0400613 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -0400614 SPIRVCodeGenerator cg(fContext.get(), &program, this, &buffer);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -0400615 bool result = cg.generateCode();
John Stiles270cec22021-02-17 12:59:36 -0500616 if (result && program.fConfig->fSettings.fValidateSPIRV) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -0400617 spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_0);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400618 const String& data = buffer.str();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400619 SkASSERT(0 == data.size() % 4);
Brian Osman8d09d4a2020-11-24 15:51:06 -0500620 String errors;
621 auto dumpmsg = [&errors](spv_message_level_t, const char*, const spv_position_t&,
622 const char* m) {
623 errors.appendf("SPIR-V validation error: %s\n", m);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -0400624 };
625 tools.SetMessageConsumer(dumpmsg);
Brian Osman8d09d4a2020-11-24 15:51:06 -0500626
627 // Verify that the SPIR-V we produced is valid. At runtime, we will abort() with a message
628 // explaining the error. In standalone mode (skslc), we will send the message, plus the
629 // entire disassembled SPIR-V (for easier context & debugging) as *our* error message.
630 result = tools.Validate((const uint32_t*) data.c_str(), data.size() / 4);
631
632 if (!result) {
633#if defined(SKSL_STANDALONE)
634 // Convert the string-stream to a SPIR-V disassembly.
635 std::string disassembly;
636 if (tools.Disassemble((const uint32_t*)data.data(), data.size() / 4, &disassembly)) {
637 errors.append(disassembly);
638 }
639 this->error(-1, errors);
640#else
641 SkDEBUGFAILF("%s", errors.c_str());
642#endif
643 }
Ethan Nicholas762466e2017-06-29 10:03:38 -0400644 out.write(data.c_str(), data.size());
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -0400645 }
646#else
Brian Osman88cda172020-10-09 12:05:16 -0400647 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -0400648 SPIRVCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500649 bool result = cg.generateCode();
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -0400650#endif
Ethan Nicholasce33f102016-12-09 17:22:59 -0500651 return result;
652}
653
Ethan Nicholas00543112018-07-31 09:44:36 -0400654bool Compiler::toSPIRV(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400655 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500656 bool result = this->toSPIRV(program, buffer);
657 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400658 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500659 }
660 return result;
661}
662
Ethan Nicholas00543112018-07-31 09:44:36 -0400663bool Compiler::toGLSL(Program& program, OutputStream& out) {
Brian Osmand010f652021-02-24 13:59:39 -0500664 TRACE_EVENT0("skia.gpu", "SkSL::Compiler::toGLSL");
Brian Osman88cda172020-10-09 12:05:16 -0400665 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400666 GLSLCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500667 bool result = cg.generateCode();
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500668 return result;
669}
670
Ethan Nicholas00543112018-07-31 09:44:36 -0400671bool Compiler::toGLSL(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400672 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500673 bool result = this->toGLSL(program, buffer);
674 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -0400675 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500676 }
677 return result;
678}
679
Brian Osmanc0243912020-02-19 15:35:26 -0500680bool Compiler::toHLSL(Program& program, String* out) {
681 String spirv;
682 if (!this->toSPIRV(program, &spirv)) {
683 return false;
684 }
685
686 return SPIRVtoHLSL(spirv, out);
687}
688
Ethan Nicholas00543112018-07-31 09:44:36 -0400689bool Compiler::toMetal(Program& program, OutputStream& out) {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400690 MetalCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholascc305772017-10-13 16:17:45 -0400691 bool result = cg.generateCode();
Ethan Nicholascc305772017-10-13 16:17:45 -0400692 return result;
693}
694
Ethan Nicholas00543112018-07-31 09:44:36 -0400695bool Compiler::toMetal(Program& program, String* out) {
Timothy Liangb8eeb802018-07-23 16:46:16 -0400696 StringStream buffer;
697 bool result = this->toMetal(program, buffer);
698 if (result) {
699 *out = buffer.str();
700 }
701 return result;
702}
703
Greg Daniela28ea672020-09-25 11:12:56 -0400704#if defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -0400705bool Compiler::toCPP(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -0400706 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400707 CPPCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400708 bool result = cg.generateCode();
Ethan Nicholas762466e2017-06-29 10:03:38 -0400709 return result;
710}
711
Ethan Nicholas00543112018-07-31 09:44:36 -0400712bool Compiler::toH(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -0400713 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400714 HCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -0400715 bool result = cg.generateCode();
Ethan Nicholas00543112018-07-31 09:44:36 -0400716 return result;
717}
Greg Daniela28ea672020-09-25 11:12:56 -0400718#endif // defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -0400719
Ethan Nicholas2a479a52020-08-18 16:29:45 -0400720#endif // defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
Brian Osman2e29ab52019-09-20 12:19:11 -0400721
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700722Position Compiler::position(int offset) {
Ethan Nicholas3c729892020-12-07 12:47:17 -0500723 if (fSource && offset >= 0) {
724 int line = 1;
725 int column = 1;
726 for (int i = 0; i < offset; i++) {
727 if ((*fSource)[i] == '\n') {
728 ++line;
729 column = 1;
730 }
731 else {
732 ++column;
733 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700734 }
Ethan Nicholas3c729892020-12-07 12:47:17 -0500735 return Position(line, column);
736 } else {
737 return Position(-1, -1);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700738 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700739}
740
741void Compiler::error(int offset, String msg) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700742 fErrorCount++;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700743 Position pos = this->position(offset);
John Stiles8d3642e2021-01-22 09:50:04 -0500744 fErrorTextLength.push_back(fErrorText.length());
Ethan Nicholas3c729892020-12-07 12:47:17 -0500745 fErrorText += "error: " + (pos.fLine >= 1 ? to_string(pos.fLine) + ": " : "") + msg + "\n";
ethannicholasb3058bd2016-07-01 08:22:01 -0700746}
747
John Stiles8d3642e2021-01-22 09:50:04 -0500748void Compiler::setErrorCount(int c) {
749 if (c < fErrorCount) {
750 fErrorText.resize(fErrorTextLength[c]);
751 fErrorTextLength.resize(c);
752 fErrorCount = c;
753 }
754}
755
Ethan Nicholas95046142021-01-07 10:57:27 -0500756String Compiler::errorText(bool showCount) {
757 if (showCount) {
758 this->writeErrorCount();
759 }
Ethan Nicholas00543112018-07-31 09:44:36 -0400760 fErrorCount = 0;
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400761 String result = fErrorText;
Ethan Nicholas95046142021-01-07 10:57:27 -0500762 fErrorText = "";
ethannicholasb3058bd2016-07-01 08:22:01 -0700763 return result;
764}
765
766void Compiler::writeErrorCount() {
767 if (fErrorCount) {
768 fErrorText += to_string(fErrorCount) + " error";
769 if (fErrorCount > 1) {
770 fErrorText += "s";
771 }
772 fErrorText += "\n";
773 }
774}
775
John Stilesa6841be2020-08-06 14:11:56 -0400776} // namespace SkSL