text: /*
   * Copyright 2016 Google Inc.
   *
   * Use of this source code is governed by a BSD-style license that can be
   * found in the LICENSE file.
   */
  
  #ifndef SKSL_COMPILER
  #define SKSL_COMPILER
  
  #include <set>
  #include <unordered_set>
  #include <vector>
  #include "src/sksl/SkSLASTFile.h"
  #include "src/sksl/SkSLAnalysis.h"
  #include "src/sksl/SkSLContext.h"
  #include "src/sksl/SkSLInliner.h"
  #include "src/sksl/SkSLParsedModule.h"
  #include "src/sksl/ir/SkSLProgram.h"
  #include "src/sksl/ir/SkSLSymbolTable.h"
  
  #if !defined(SKSL_STANDALONE) && SK_SUPPORT_GPU
  #include "src/gpu/GrShaderVar.h"
  #endif
  
  #define SK_FRAGCOLOR_BUILTIN           10001
  #define SK_IN_BUILTIN                  10002
  #define SK_OUT_BUILTIN                 10007
  #define SK_LASTFRAGCOLOR_BUILTIN       10008
  #define SK_MAIN_COORDS_BUILTIN         10009
  #define SK_INPUT_COLOR_BUILTIN         10010
  #define SK_DEST_COLOR_BUILTIN          10011
  #define SK_FRAGCOORD_BUILTIN              15
  #define SK_CLOCKWISE_BUILTIN              17
  #define SK_VERTEXID_BUILTIN               42
  #define SK_INSTANCEID_BUILTIN             43
  #define SK_INVOCATIONID_BUILTIN            8
  #define SK_POSITION_BUILTIN                0
  
  class SkBitSet;
  class SkSLCompileBench;
  
  namespace SkSL {
  
  namespace dsl {
      class DSLCore;
      class DSLWriter;
  }
  
  class ExternalFunction;
  class FunctionDeclaration;
  class IRGenerator;
  class IRIntrinsicMap;
  class ProgramUsage;
  
  struct LoadedModule {
      ProgramKind                                  fKind;
      std::shared_ptr<SymbolTable>                 fSymbols;
      std::vector<std::unique_ptr<ProgramElement>> fElements;
  };
  
  /**
   * Main compiler entry point. This is a traditional compiler design which first parses the .sksl
   * file into an abstract syntax tree (a tree of ASTNodes), then performs semantic analysis to
   * produce a Program (a tree of IRNodes), then feeds the Program into a CodeGenerator to produce
   * compiled output.
   *
   * See the README for information about SkSL.
   */
  class SK_API Compiler {
  public:
      static constexpr const char FRAGCOLOR_NAME[] = "sk_FragColor";
      static constexpr const char RTADJUST_NAME[]  = "sk_RTAdjust";
      static constexpr const char PERVERTEX_NAME[] = "sk_PerVertex";
      static constexpr const char POISON_TAG[]     = "<POISON>";
  
      /**
       * Gets a float4 that adjusts the position from Skia device coords to normalized device coords,
       * used to populate sk_RTAdjust.  Assuming the transformed position, pos, is a homogeneous
       * float4, the vec, v, is applied as such:
       * float4((pos.xy * v.xz) + sk_Position.ww * v.yw, 0, pos.w);
       */
      static std::array<float, 4> GetRTAdjustVector(SkISize rtDims, bool flipY) {
          std::array<float, 4> result;
          result[0] = 2.f/rtDims.width();
          result[2] = 2.f/rtDims.height();
          result[1] = -1.f;
          result[3] = -1.f;
          if (flipY) {
              result[2] = -result[2];
              result[3] = -result[3];
          }
          return result;
      }
  
      /**
       * Uniform values  by the compiler to implement origin-neutral dFdy, sk_Clockwise, and
       * sk_FragCoord.
       */
      static std::array<float, 2> GetRTFlipVector(int rtHeight, bool flipY) {
          std::array<float, 2> result;
          result[0] = flipY ? rtHeight : 0.f;
          result[1] = flipY ?     -1.f : 1.f;
          return result;
      }
  
      struct OptimizationContext {
          // nodes we have already reported errors for and should not error on again
          std::unordered_set<const IRNode*> fSilences;
          // true if we have updated the CFG during this pass
          bool fUpdated = false;
          // true if we need to completely regenerate the CFG
          bool fNeedsRescan = false;
          // Metadata about function and variable usage within the program
          ProgramUsage* fUsage = nullptr;
          // Nodes which we can't throw away until the end of optimization
          StatementArray fOwnedStatements;
      };
  
      Compiler(const ShaderCapsClass* caps);
  
      ~Compiler();
  
      Compiler(const Compiler&) = delete;
      Compiler& operator=(const Compiler&) = delete;
  
      /**
       * Allows optimization settings to be unilaterally overridden. This is meant to allow tools like
       * Viewer or Nanobench to override the compiler's ProgramSettings and ShaderCaps for debugging.
       */
      enum class OverrideFlag {
          kDefault,
          kOff,
          kOn,
      };
      static void EnableOptimizer(OverrideFlag flag) { sOptimizer = flag; }
      static void EnableInliner(OverrideFlag flag) { sInliner = flag; }
  
      /**
       * If fExternalFunctions is supplied in the settings, those values are registered in the symbol
       * table of the Program, but ownership is *not* transferred. It is up to the caller to keep them
       * alive.
       */
      std::unique_ptr<Program> convertProgram(
              ProgramKind kind,
              String text,
              Program::Settings settings);
  
      bool toSPIRV(Program& program, OutputStream& out);
  
      bool toSPIRV(Program& program, String* out);
  
      bool toGLSL(Program& program, OutputStream& out);
  
      bool toGLSL(Program& program, String* out);
  
      bool toHLSL(Program& program, String* out);
  
      bool toMetal(Program& program, OutputStream& out);
  
      bool toMetal(Program& program, String* out);
  
      void handleError(const char* msg, PositionInfo pos);
  
      String errorText(bool showCount = true);
  
      ErrorReporter& errorReporter() { return fContext->errors(); }
  
      int errorCount() const { return fContext->errors().errorCount(); }
  
      void writeErrorCount();
  
      void resetErrors() {
          fErrorText.clear();
          this->errorReporter().resetErrorCount();
      }
  
      Context& context() {
          return *fContext;
      }
  
      // When  SKSL_STANDALONE, fPath is used. (fData, fSize) will be (nullptr, 0)
      // When !SKSL_STANDALONE, fData and fSize are used. fPath will be nullptr.
      struct ModuleData {
          const char*    fPath;
  
          const uint8_t* fData;
          size_t         fSize;
      };
  
      static ModuleData MakeModulePath(const char* path) {
          return ModuleData{path, /*fData=*/nullptr, /*fSize=*/0};
      }
      static ModuleData MakeModuleData(const uint8_t* data, size_t size) {
          return ModuleData{/*fPath=*/nullptr, data, size};
      }
  
      LoadedModule loadModule(ProgramKind kind, ModuleData data, std::shared_ptr<SymbolTable> base,
                              bool dehydrate);
      ParsedModule parseModule(ProgramKind kind, ModuleData data, const ParsedModule& base);
  
      IRGenerator& irGenerator() {
          return *fIRGenerator;
      }
  
      const ParsedModule& moduleForProgramKind(ProgramKind kind);
  
  private:
      class CompilerErrorReporter : public ErrorReporter {
      public:
          CompilerErrorReporter(Compiler* compiler)
              : fCompiler(*compiler) {}
  
          void handleError(const char* msg, PositionInfo pos) override {
              fCompiler.handleError(msg, pos);
          }
  
      private:
          Compiler& fCompiler;
      };
  
      const ParsedModule& loadGPUModule();
      const ParsedModule& loadFragmentModule();
      const ParsedModule& loadVertexModule();
      const ParsedModule& loadGeometryModule();
      const ParsedModule& loadPublicModule();
      const ParsedModule& loadRuntimeColorFilterModule();
      const ParsedModule& loadRuntimeShaderModule();
      const ParsedModule& loadRuntimeBlenderModule();
  
      std::shared_ptr<SymbolTable> makeRootSymbolTable();
      std::shared_ptr<SymbolTable> makePrivateSymbolTable(std::shared_ptr<SymbolTable> parent);
  
      /** Verifies that @if and @switch statements were actually optimized away. */
      void verifyStaticTests(const Program& program);
  
      /** Optimize every function in the program. */
      bool optimize(Program& program);
  
      /** Optimize the module. */
      bool optimize(LoadedModule& module);
  
      /** Eliminates unused functions from a Program, according to the stats in ProgramUsage. */
      bool removeDeadFunctions(Program& program, ProgramUsage* usage);
  
      /** Eliminates unreferenced variables from a Program, according to the stats in ProgramUsage. */
      bool removeDeadGlobalVariables(Program& program, ProgramUsage* usage);
      bool removeDeadLocalVariables(Program& program, ProgramUsage* usage);
  
      /** Eliminates unreachable statements from a Program. */
      void removeUnreachableCode(Program& program, ProgramUsage* usage);
  
      Position position(int offset);
  
      CompilerErrorReporter fErrorReporter;
      std::shared_ptr<Context> fContext;
  
      ParsedModule fRootModule;                // Core types
  
      ParsedModule fPrivateModule;             // [Root] + Internal types
      ParsedModule fGPUModule;                 // [Private] + GPU intrinsics, helper functions
      ParsedModule fVertexModule;              // [GPU] + Vertex stage decls
      ParsedModule fFragmentModule;            // [GPU] + Fragment stage decls
      ParsedModule fGeometryModule;            // [GPU] + Geometry stage decls
  
      ParsedModule fPublicModule;              // [Root] + Public features
      ParsedModule fRuntimeColorFilterModule;  // [Public] + Runtime shader decls
      ParsedModule fRuntimeShaderModule;       // [Public] + Runtime color filter decls
      ParsedModule fRuntimeBlenderModule;      // [Public] + Runtime blender decls
  
      // holds ModifiersPools belonging to the core includes for lifetime purposes
      ModifiersPool fCoreModifiers;
  
      Inliner fInliner;
      std::unique_ptr<IRGenerator> fIRGenerator;
  
      String fErrorText;
  
      static OverrideFlag sOptimizer;
      static OverrideFlag sInliner;
  
      friend class AutoSource;
      friend class ::SkSLCompileBench;
      friend class dsl::DSLCore;
      friend class dsl::DSLWriter;
  };
  
  }  // namespace SkSL
  
  #endif
  