From: Mikko Rasa Date: Sun, 17 Dec 2023 12:16:14 +0000 (+0200) Subject: Rearrange invocation of passes the GLSL compiler frontend X-Git-Url: https://git.tdb.fi/?a=commitdiff_plain;h=5f1e6c25f679a8377ce07abae9c27aa12eb321f0;p=libs%2Fgl.git Rearrange invocation of passes the GLSL compiler frontend It's getting hard to divide the operations into sensibly named groups which can be called one after another, because some of them need to be run on the entire module and in specific order with per-stage ops. --- diff --git a/source/glsl/compiler.cpp b/source/glsl/compiler.cpp index 7d1db5a3..2953961a 100644 --- a/source/glsl/compiler.cpp +++ b/source/glsl/compiler.cpp @@ -23,6 +23,63 @@ namespace Msp { namespace GL { namespace SL { +namespace { + +enum ResolveFlags +{ + RESOLVE_NONE = 0, + RESOLVE_BLOCKS = 1, + RESOLVE_TYPES = 2, + RESOLVE_VARIABLES = 4, + RESOLVE_EXPRESSIONS = 8, + RESOLVE_FUNCTIONS = 16, + RESOLVE_ALL = 31 +}; + +template +auto run(Args &&... args) +{ + return [&args...](Stage &s){ T().apply(s, args...); }; +} + +template +bool resolve(Stage &stage, unsigned &flags, unsigned bit) +{ + if(!(flags&bit)) + return false; + + flags &= ~bit; + return T().apply(stage); +} + +/** Resolves various references between nodes. Flags can be specified to +request resolving particular aspects. Resolving may ripple into other +aspects as necessary. */ +void resolve(Stage &stage, unsigned flags) +{ + while(flags) + { + if(resolve(stage, flags, RESOLVE_BLOCKS)) + ; + else if(resolve(stage, flags, RESOLVE_TYPES)) + flags |= RESOLVE_BLOCKS|RESOLVE_VARIABLES|RESOLVE_EXPRESSIONS; + else if(resolve(stage, flags, RESOLVE_VARIABLES)) + flags |= RESOLVE_EXPRESSIONS; + else if(resolve(stage, flags, RESOLVE_FUNCTIONS)) + flags |= RESOLVE_EXPRESSIONS; + else if(resolve(stage, flags, RESOLVE_EXPRESSIONS)) + flags |= RESOLVE_VARIABLES|RESOLVE_FUNCTIONS; + } +} + +auto resolve(unsigned flags) +{ + return [flags](Stage &s){ resolve(s, flags); }; +} + +} + + Compiler::Compiler(const Features &f): features(f) { } @@ -72,15 +129,27 @@ void Compiler::compile(Mode mode) if(specialized && mode!=PROGRAM) throw invalid_operation("Compiler::compile"); - for(Stage &s: module->stages) - generate(s); + // Generate any implicitly defined syntactic structures + for_stages([this](Stage &s){ compose(s); }, + resolve(RESOLVE_ALL), + run(), + resolve(RESOLVE_BLOCKS|RESOLVE_TYPES|RESOLVE_VARIABLES), + run(), + run(), + resolve(RESOLVE_EXPRESSIONS)); ConstantIdAssigner().apply(*module, features); LocationAllocator().apply(*module, features, false); - for(Stage &s: module->stages) - validate(s); + // Run validators, recording diagnostic messages in each stage + for_stages(run(features), + run(), + run(), + run(), + run(), + run()); GlobalInterfaceValidator().apply(*module); + // Abort compilation if any stage had errors in it bool valid = true; for(Stage &s: module->stages) if(!check_errors(s)) @@ -88,22 +157,23 @@ void Compiler::compile(Mode mode) if(!valid) throw invalid_shader_source(get_diagnostics()); + // Apply specializations and target-specific code generation if(specialized) - { - for(Stage &s: module->stages) - ConstantSpecializer().apply(s, spec_values); - } + for_stages(run(spec_values)); if(mode==PROGRAM) DepthRangeConverter().apply(*module, features); + + // Optimize for(auto i=module->stages.begin(); i!=module->stages.end(); ) { - OptimizeResult result = optimize(*i); + StageResult result = optimize(*i); if(result==REDO_PREVIOUS) i = module->stages.begin(); else if(result!=REDO_STAGE) ++i; } + // Remove any stages from which all functions were optimized out Stage *prev_stage = nullptr; for(auto i=module->stages.begin(); i!=module->stages.end(); ) { @@ -117,17 +187,22 @@ void Compiler::compile(Mode mode) } } + // Perform final adjustments based on target features if(mode!=MODULE) - { - for(Stage &s: module->stages) - { - StructuralFeatureConverter().apply(s, features); - resolve(s, RESOLVE_VARIABLES|RESOLVE_FUNCTIONS); - } - } + for_stages(run(features), + resolve(RESOLVE_VARIABLES|RESOLVE_FUNCTIONS)); LocationAllocator().apply(*module, features); - for(Stage &s: module->stages) - finalize(s, mode); + if(mode!=MODULE) + for_stages(run(features), + run()); + if(mode==SPIRV) + for_stages(run()); + + // Collect bindings from all stages into the shared stage's maps + for_stages([&shared = module->shared](Stage &s){ + shared.texture_bindings.insert(s.texture_bindings.begin(), s.texture_bindings.end()); + shared.uniform_block_bindings.insert(s.uniform_block_bindings.begin(), s.uniform_block_bindings.end()); + }); compiled = true; } @@ -245,6 +320,13 @@ string Compiler::get_diagnostics() const return combined; } +template +void Compiler::for_stages(const Fs &... funcs) +{ + for(Stage &s: module->stages) + (funcs(s), ...); +} + void Compiler::append_module(const Module &mod, ModuleCache &mod_cache) { module->source_map.merge_from(mod.source_map); @@ -298,7 +380,7 @@ void Compiler::import(ModuleCache &mod_cache, const string &name) append_module(mod_cache.get_module(name), mod_cache); } -void Compiler::generate(Stage &stage) +void Compiler::compose(Stage &stage) { stage.required_features.target_api = features.target_api; if(stage.required_features.glsl_versionshared.required_features.glsl_version) @@ -309,55 +391,6 @@ void Compiler::generate(Stage &stage) inject_block(stage.content, builtins->content); if(const Stage *builtins = get_builtins(Stage::SHARED)) inject_block(stage.content, builtins->content); - - // Initial resolving pass - resolve(stage); - - /* All variables local to a stage have been resolved. Resolve non-local - variables through interfaces. */ - InterfaceGenerator().apply(stage); - resolve(stage, RESOLVE_BLOCKS|RESOLVE_TYPES|RESOLVE_VARIABLES); - - LayoutDefaulter().apply(stage); - ArraySizer().apply(stage); - resolve(stage, RESOLVE_EXPRESSIONS); -} - -template -bool Compiler::resolve(Stage &stage, unsigned &flags, unsigned bit) -{ - if(!(flags&bit)) - return false; - - flags &= ~bit; - return T().apply(stage); -} - -void Compiler::resolve(Stage &stage, unsigned flags) -{ - while(flags) - { - if(resolve(stage, flags, RESOLVE_BLOCKS)) - ; - else if(resolve(stage, flags, RESOLVE_TYPES)) - flags |= RESOLVE_BLOCKS|RESOLVE_VARIABLES|RESOLVE_EXPRESSIONS; - else if(resolve(stage, flags, RESOLVE_VARIABLES)) - flags |= RESOLVE_EXPRESSIONS; - else if(resolve(stage, flags, RESOLVE_FUNCTIONS)) - flags |= RESOLVE_EXPRESSIONS; - else if(resolve(stage, flags, RESOLVE_EXPRESSIONS)) - flags |= RESOLVE_VARIABLES|RESOLVE_FUNCTIONS; - } -} - -void Compiler::validate(Stage &stage) -{ - DeclarationValidator().apply(stage, features); - IdentifierValidator().apply(stage); - ReferenceValidator().apply(stage); - ExpressionValidator().apply(stage); - FlowControlValidator().apply(stage); - StageInterfaceValidator().apply(stage); } bool Compiler::check_errors(Stage &stage) @@ -416,21 +449,6 @@ Compiler::OptimizeResult Compiler::optimize(Stage &stage) return any_removed ? REDO_PREVIOUS : any_inlined ? REDO_STAGE : NEXT_STAGE; } -void Compiler::finalize(Stage &stage, Mode mode) -{ - if(mode!=MODULE) - { - QualifierConverter().apply(stage, features); - PrecisionConverter().apply(stage); - } - if(mode==SPIRV) - StructOrganizer().apply(stage); - - // Collect bindings from all stages into the shared stage's maps - module->shared.texture_bindings.insert(stage.texture_bindings.begin(), stage.texture_bindings.end()); - module->shared.uniform_block_bindings.insert(stage.uniform_block_bindings.begin(), stage.uniform_block_bindings.end()); -} - void Compiler::inject_block(Block &target, const Block &source) { auto insert_point = target.body.begin(); diff --git a/source/glsl/compiler.h b/source/glsl/compiler.h index 223c6e1e..247b77f7 100644 --- a/source/glsl/compiler.h +++ b/source/glsl/compiler.h @@ -30,16 +30,6 @@ private: REDO_PREVIOUS }; - enum ResolveFlags - { - RESOLVE_BLOCKS = 1, - RESOLVE_TYPES = 2, - RESOLVE_VARIABLES = 4, - RESOLVE_EXPRESSIONS = 8, - RESOLVE_FUNCTIONS = 16, - RESOLVE_ALL = 31 - }; - Features features; Module *module = nullptr; std::vector imported_names; @@ -125,6 +115,9 @@ public: std::string get_diagnostics() const; private: + template + void for_stages(const Fs &... funcs); + /** Appends a module to the target, processing any imports found in it. */ void append_module(const Module &, ModuleCache &); @@ -134,21 +127,8 @@ private: /** Imports a module by name and appends it to the target. */ void import(ModuleCache &, const std::string &); - /** Generates any implicitly defines syntactic structures and resolves - variables. */ - void generate(Stage &); - - template - bool resolve(Stage &, unsigned &, unsigned); - - /** Resolves various references between nodes. Flags can be specified to - request resolving particular aspects. Resolving may ripple into other - aspects as necessary. */ - void resolve(Stage &, unsigned = RESOLVE_ALL); - - /** Runs validators on a stage. Diagnostic messages are recorded in the - stage for later inspection. */ - void validate(Stage &); + /** Adds the shared part and builtins to each stage. */ + void compose(Stage &); /** Checks a stage's recorded diagnostics for errors. If any are found, returns true. */ @@ -160,9 +140,6 @@ private: stage should be optimized next. */ OptimizeResult optimize(Stage &); - /** Performs final adjustments on a stage after compilation. */ - void finalize(Stage &, Mode); - static void inject_block(Block &, const Block &); };