]> git.tdb.fi Git - libs/gl.git/commitdiff
Rearrange invocation of passes the GLSL compiler frontend
authorMikko Rasa <tdb@tdb.fi>
Sun, 17 Dec 2023 12:16:14 +0000 (14:16 +0200)
committerMikko Rasa <tdb@tdb.fi>
Sun, 17 Dec 2023 12:16:14 +0000 (14:16 +0200)
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.

source/glsl/compiler.cpp
source/glsl/compiler.h

index 7d1db5a3b664a6851e248606a432c7a9dfc64276..2953961ad06b7d66afd5359447d13e4b7bc66c96 100644 (file)
@@ -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<typename T, typename... Args>
+auto run(Args &&... args)
+{
+       return [&args...](Stage &s){ T().apply(s, args...); };
+}
+
+template<typename T>
+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<BlockHierarchyResolver>(stage, flags, RESOLVE_BLOCKS))
+                       ;
+               else if(resolve<TypeResolver>(stage, flags, RESOLVE_TYPES))
+                       flags |= RESOLVE_BLOCKS|RESOLVE_VARIABLES|RESOLVE_EXPRESSIONS;
+               else if(resolve<VariableResolver>(stage, flags, RESOLVE_VARIABLES))
+                       flags |= RESOLVE_EXPRESSIONS;
+               else if(resolve<FunctionResolver>(stage, flags, RESOLVE_FUNCTIONS))
+                       flags |= RESOLVE_EXPRESSIONS;
+               else if(resolve<ExpressionResolver>(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<InterfaceGenerator>(),
+               resolve(RESOLVE_BLOCKS|RESOLVE_TYPES|RESOLVE_VARIABLES),
+               run<LayoutDefaulter>(),
+               run<ArraySizer>(),
+               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<DeclarationValidator>(features),
+               run<IdentifierValidator>(),
+               run<ReferenceValidator>(),
+               run<ExpressionValidator>(),
+               run<FlowControlValidator>(),
+               run<StageInterfaceValidator>());
        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<ConstantSpecializer>(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<StructuralFeatureConverter>(features),
+                       resolve(RESOLVE_VARIABLES|RESOLVE_FUNCTIONS));
        LocationAllocator().apply(*module, features);
-       for(Stage &s: module->stages)
-               finalize(s, mode);
+       if(mode!=MODULE)
+               for_stages(run<QualifierConverter>(features),
+                       run<PrecisionConverter>());
+       if(mode==SPIRV)
+               for_stages(run<StructOrganizer>());
+
+       // 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<typename... Fs>
+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_version<module->shared.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<typename T>
-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<BlockHierarchyResolver>(stage, flags, RESOLVE_BLOCKS))
-                       ;
-               else if(resolve<TypeResolver>(stage, flags, RESOLVE_TYPES))
-                       flags |= RESOLVE_BLOCKS|RESOLVE_VARIABLES|RESOLVE_EXPRESSIONS;
-               else if(resolve<VariableResolver>(stage, flags, RESOLVE_VARIABLES))
-                       flags |= RESOLVE_EXPRESSIONS;
-               else if(resolve<FunctionResolver>(stage, flags, RESOLVE_FUNCTIONS))
-                       flags |= RESOLVE_EXPRESSIONS;
-               else if(resolve<ExpressionResolver>(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();
index 223c6e1e0858b594a4179dc5a59698b945eaa4e3..247b77f7b7912de37ac283c7e852bbe53869c373 100644 (file)
@@ -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<std::string> imported_names;
@@ -125,6 +115,9 @@ public:
        std::string get_diagnostics() const;
 
 private:
+       template<typename... Fs>
+       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<typename T>
-       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 &);
 };