]> git.tdb.fi Git - libs/gl.git/blob - source/glsl/compiler.cpp
Fix a name conflict in certain inlining scenarios
[libs/gl.git] / source / glsl / compiler.cpp
1 #include <msp/core/algorithm.h>
2 #include <msp/strings/format.h>
3 #include <msp/strings/utils.h>
4 #include "builtin.h"
5 #include "compiler.h"
6 #include "debug.h"
7 #include "error.h"
8 #include "finalize.h"
9 #include "generate.h"
10 #include "glsl_error.h"
11 #include "modulecache.h"
12 #include "optimize.h"
13 #include "output.h"
14 #include "resolve.h"
15 #include "spirv.h"
16 #include "validate.h"
17
18 #undef interface
19
20 using namespace std;
21
22 namespace Msp {
23 namespace GL {
24 namespace SL {
25
26 Compiler::Compiler(const Features &f):
27         features(f)
28 { }
29
30 Compiler::~Compiler()
31 {
32         delete module;
33 }
34
35 void Compiler::clear()
36 {
37         delete module;
38         module = new Module();
39         imported_names.clear();
40         module->source_map.set_name(0, "<generated>");
41 }
42
43 void Compiler::set_source(const string &source, const string &src_name)
44 {
45         clear();
46         imported_names.push_back(src_name);
47         ModuleCache mod_cache(0);
48         append_module(mod_cache.add_module(source, src_name), mod_cache);
49 }
50
51 void Compiler::load_source(IO::Base &io, DataFile::Collection *res, const string &src_name)
52 {
53         clear();
54         imported_names.push_back(src_name);
55         ModuleCache mod_cache(res);
56         append_module(mod_cache.add_module(io, src_name), mod_cache);
57 }
58
59 void Compiler::load_source(IO::Base &io, const string &src_name)
60 {
61         load_source(io, 0, src_name);
62 }
63
64 void Compiler::specialize(const map<string, int> &sv)
65 {
66         specialized = true;
67         spec_values = sv;
68 }
69
70 void Compiler::compile(Mode mode)
71 {
72         if(specialized && mode!=PROGRAM)
73                 throw invalid_operation("Compiler::compile");
74
75         for(Stage &s: module->stages)
76                 generate(s);
77         ConstantIdAssigner().apply(*module, features);
78         LocationAllocator().apply(*module, features, false);
79
80         for(Stage &s: module->stages)
81                 validate(s);
82         GlobalInterfaceValidator().apply(*module);
83
84         bool valid = true;
85         for(Stage &s: module->stages)
86                 if(!check_errors(s))
87                         valid = false;
88         if(!valid)
89                 throw invalid_shader_source(get_diagnostics());
90
91         if(specialized)
92         {
93                 for(Stage &s: module->stages)
94                         ConstantSpecializer().apply(s, spec_values);
95         }
96         for(auto i=module->stages.begin(); i!=module->stages.end(); )
97         {
98                 OptimizeResult result = optimize(*i);
99                 if(result==REDO_PREVIOUS)
100                         i = module->stages.begin();
101                 else if(result!=REDO_STAGE)
102                         ++i;
103         }
104
105         for(Stage &s: module->stages)
106         {
107                 StructuralFeatureConverter().apply(s, features);
108                 resolve(s, RESOLVE_VARIABLES|RESOLVE_FUNCTIONS);
109         }
110         LocationAllocator().apply(*module, features);
111         for(Stage &s: module->stages)
112                 finalize(s, mode);
113
114         compiled = true;
115 }
116
117 string Compiler::get_combined_glsl() const
118 {
119         if(!compiled)
120                 throw invalid_operation("Compiler::get_combined_glsl");
121
122         string glsl;
123
124         unsigned source_count = module->source_map.get_count();
125         for(unsigned i=1; i<source_count; ++i)
126                 glsl += format("#pragma MSP source(%d, \"%s\")\n", i, module->source_map.get_name(i));
127         for(Stage &s: module->stages)
128         {
129                 glsl += format("#pragma MSP stage(%s)\n", Stage::get_stage_name(s.type));
130                 glsl += Formatter().apply(s);
131                 glsl += '\n';
132         }
133
134         return glsl;
135 }
136
137 vector<Stage::Type> Compiler::get_stages() const
138 {
139         vector<Stage::Type> stage_types;
140         stage_types.reserve(module->stages.size());
141         for(const Stage &s: module->stages)
142                 stage_types.push_back(s.type);
143         return stage_types;
144 }
145
146 string Compiler::get_stage_glsl(Stage::Type stage_type) const
147 {
148         if(!compiled)
149                 throw invalid_operation("Compiler::get_stage_glsl");
150         auto i = find_member(module->stages, stage_type, &Stage::type);
151         if(i!=module->stages.end())
152                 return Formatter().apply(*i);
153         throw key_error(Stage::get_stage_name(stage_type));
154 }
155
156 vector<uint32_t> Compiler::get_combined_spirv() const
157 {
158         if(!compiled)
159                 throw invalid_operation("Compiler::get_combined_spirv");
160         SpirVGenerator gen;
161         gen.apply(*module);
162         return gen.get_code();
163 }
164
165 const map<string, unsigned> &Compiler::get_vertex_attributes() const
166 {
167         if(!compiled)
168                 throw invalid_operation("Compiler::get_vertex_attributes");
169         auto i = find_member(module->stages, Stage::VERTEX, &Stage::type);
170         if(i!=module->stages.end())
171                 return i->locations;
172         throw invalid_operation("Compiler::get_vertex_attributes");
173 }
174
175 const map<string, unsigned> &Compiler::get_fragment_outputs() const
176 {
177         if(!compiled)
178                 throw invalid_operation("Compiler::get_fragment_outputs");
179         auto i = find_member(module->stages, Stage::FRAGMENT, &Stage::type);
180         if(i!=module->stages.end())
181                 return i->locations;
182         throw invalid_operation("Compiler::get_fragment_outputs");
183 }
184
185 const map<string, unsigned> &Compiler::get_texture_bindings() const
186 {
187         if(!compiled)
188                 throw invalid_operation("Compiler::get_texture_bindings");
189         return module->shared.texture_bindings;
190 }
191
192 const map<string, unsigned> &Compiler::get_uniform_block_bindings() const
193 {
194         if(!compiled)
195                 throw invalid_operation("Compiler::get_uniform_block_bindings");
196         return module->shared.uniform_block_bindings;
197 }
198
199 unsigned Compiler::get_n_clip_distances() const
200 {
201         if(!compiled)
202                 throw invalid_operation("Compiler::get_n_clip_distances");
203         auto i = find_member(module->stages, Stage::VERTEX, &Stage::type);
204         return (i!=module->stages.end() ? i->n_clip_distances : 0);
205 }
206
207 const SourceMap &Compiler::get_source_map() const
208 {
209         return module->source_map;
210 }
211
212 string Compiler::get_stage_debug(Stage::Type stage_type) const
213 {
214         auto i = find_member(module->stages, stage_type, &Stage::type);
215         if(i!=module->stages.end())
216                 return DumpTree().apply(*i);
217         throw key_error(Stage::get_stage_name(stage_type));
218 }
219
220 string Compiler::get_diagnostics() const
221 {
222         string combined;
223         for(const Stage &s: module->stages)
224                 for(const Diagnostic &d: s.diagnostics)
225                         if(d.source!=INTERNAL_SOURCE)
226                                 append(combined, "\n", format("%s:%d: %s", module->source_map.get_name(d.source), d.line, d.message));
227         return combined;
228 }
229
230 void Compiler::append_module(const Module &mod, ModuleCache &mod_cache)
231 {
232         module->source_map.merge_from(mod.source_map);
233
234         vector<Import *> imports;
235         for(const RefPtr<Statement> &s: mod.shared.content.body)
236                 if(Import *imp = dynamic_cast<Import *>(s.get()))
237                         imports.push_back(imp);
238         for(Import *i: imports)
239                 import(mod_cache, i->module);
240
241         append_stage(mod.shared);
242         for(const Stage &s: mod.stages)
243                 append_stage(s);
244 }
245
246 void Compiler::append_stage(const Stage &stage)
247 {
248         Stage *target = 0;
249         if(stage.type==Stage::SHARED)
250                 target = &module->shared;
251         else
252         {
253                 auto i = find_if(module->stages, [&stage](const Stage &s){ return s.type>=stage.type; });
254                 if(i==module->stages.end() || i->type>stage.type)
255                 {
256                         auto j = module->stages.insert(i, stage.type);
257                         if(i!=module->stages.end())
258                                 i->previous = &*j;
259                         i = j;
260                         if(i!=module->stages.begin())
261                                 i->previous = &*--j;
262                 }
263
264                 target = &*i;
265         }
266
267         if(stage.required_features.glsl_version>target->required_features.glsl_version)
268                 target->required_features.glsl_version = stage.required_features.glsl_version;
269         for(const RefPtr<Statement> &s: stage.content.body)
270                 if(!dynamic_cast<Import *>(s.get()))
271                         target->content.body.push_back(s);
272 }
273
274 void Compiler::import(ModuleCache &mod_cache, const string &name)
275 {
276         if(find(imported_names, name)!=imported_names.end())
277                 return;
278         imported_names.push_back(name);
279
280         append_module(mod_cache.get_module(name), mod_cache);
281 }
282
283 void Compiler::generate(Stage &stage)
284 {
285         stage.required_features.target_api = features.target_api;
286         if(module->shared.required_features.glsl_version>stage.required_features.glsl_version)
287                 stage.required_features.glsl_version = module->shared.required_features.glsl_version;
288
289         inject_block(stage.content, module->shared.content);
290         if(const Stage *builtins = get_builtins(stage.type))
291                 inject_block(stage.content, builtins->content);
292         if(const Stage *builtins = get_builtins(Stage::SHARED))
293                 inject_block(stage.content, builtins->content);
294
295         // Initial resolving pass
296         resolve(stage);
297
298         /* All variables local to a stage have been resolved.  Resolve non-local
299         variables through interfaces. */
300         InterfaceGenerator().apply(stage);
301         resolve(stage, RESOLVE_BLOCKS|RESOLVE_TYPES|RESOLVE_VARIABLES);
302 }
303
304 template<typename T>
305 bool Compiler::resolve(Stage &stage, unsigned &flags, unsigned bit)
306 {
307         if(!(flags&bit))
308                 return false;
309
310         flags &= ~bit;
311         return T().apply(stage);
312 }
313
314 void Compiler::resolve(Stage &stage, unsigned flags)
315 {
316         while(flags)
317         {
318                 if(resolve<BlockHierarchyResolver>(stage, flags, RESOLVE_BLOCKS))
319                         ;
320                 else if(resolve<TypeResolver>(stage, flags, RESOLVE_TYPES))
321                         flags |= RESOLVE_BLOCKS|RESOLVE_VARIABLES|RESOLVE_EXPRESSIONS;
322                 else if(resolve<VariableResolver>(stage, flags, RESOLVE_VARIABLES))
323                         flags |= RESOLVE_EXPRESSIONS;
324                 else if(resolve<FunctionResolver>(stage, flags, RESOLVE_FUNCTIONS))
325                         flags |= RESOLVE_EXPRESSIONS;
326                 else if(resolve<ExpressionResolver>(stage, flags, RESOLVE_EXPRESSIONS))
327                         flags |= RESOLVE_VARIABLES|RESOLVE_FUNCTIONS;
328         }
329 }
330
331 void Compiler::validate(Stage &stage)
332 {
333         DeclarationValidator().apply(stage, features);
334         IdentifierValidator().apply(stage);
335         ReferenceValidator().apply(stage);
336         ExpressionValidator().apply(stage);
337         FlowControlValidator().apply(stage);
338         StageInterfaceValidator().apply(stage);
339 }
340
341 bool Compiler::check_errors(Stage &stage)
342 {
343         stable_sort(stage.diagnostics, &diagnostic_line_order);
344         return !any_of(stage.diagnostics.begin(), stage.diagnostics.end(),
345                 [](const Diagnostic &d){ return d.severity==Diagnostic::ERR; });
346 }
347
348 bool Compiler::diagnostic_line_order(const Diagnostic &diag1, const Diagnostic &diag2)
349 {
350         if(diag1.provoking_source!=diag2.provoking_source)
351         {
352                 // Sort builtins first and imported modules according to import order.
353                 if(diag1.provoking_source<=BUILTIN_SOURCE)
354                         return diag1.provoking_source<diag2.provoking_source;
355                 else if(diag2.provoking_source<=BUILTIN_SOURCE)
356                         return false;
357                 else
358                         return diag1.provoking_source>diag2.provoking_source;
359         }
360         return diag1.provoking_line<diag2.provoking_line;
361 }
362
363 Compiler::OptimizeResult Compiler::optimize(Stage &stage)
364 {
365         if(ConstantFolder().apply(stage))
366                 resolve(stage, RESOLVE_EXPRESSIONS);
367         ConstantConditionEliminator().apply(stage);
368
369         bool any_inlined = false;
370         if(FunctionInliner().apply(stage))
371         {
372                 resolve(stage, RESOLVE_TYPES|RESOLVE_VARIABLES|RESOLVE_FUNCTIONS|RESOLVE_EXPRESSIONS);
373                 any_inlined = true;
374         }
375         if(AggregateDismantler().apply(stage))
376         {
377                 resolve(stage, RESOLVE_TYPES|RESOLVE_VARIABLES|RESOLVE_FUNCTIONS|RESOLVE_EXPRESSIONS);
378                 any_inlined = true;
379         }
380         if(ExpressionInliner().apply(stage))
381         {
382                 resolve(stage, RESOLVE_VARIABLES|RESOLVE_FUNCTIONS|RESOLVE_EXPRESSIONS);
383                 any_inlined = true;
384         }
385
386         /* Removing variables or functions may cause things from the previous stage
387         to become unused. */
388         bool any_removed = UnreachableCodeRemover().apply(stage);
389         any_removed |= UnusedVariableRemover().apply(stage);
390         any_removed |= UnusedFunctionRemover().apply(stage);
391         any_removed |= UnusedTypeRemover().apply(stage);
392
393         return any_removed ? REDO_PREVIOUS : any_inlined ? REDO_STAGE : NEXT_STAGE;
394 }
395
396 void Compiler::finalize(Stage &stage, Mode mode)
397 {
398         QualifierConverter().apply(stage, features);
399         PrecisionConverter().apply(stage);
400         if(mode==SPIRV)
401                 StructOrganizer().apply(stage);
402
403         // Collect bindings from all stages into the shared stage's maps
404         module->shared.texture_bindings.insert(stage.texture_bindings.begin(), stage.texture_bindings.end());
405         module->shared.uniform_block_bindings.insert(stage.uniform_block_bindings.begin(), stage.uniform_block_bindings.end());
406 }
407
408 void Compiler::inject_block(Block &target, const Block &source)
409 {
410         auto insert_point = target.body.begin();
411         for(const RefPtr<Statement> &s: source.body)
412                 target.body.insert(insert_point, s->clone());
413 }
414
415 } // namespace SL
416 } // namespace GL
417 } // namespace Msp