text: /*
   * Copyright 2020-2021 Hewlett Packard Enterprise Development LP
   * Copyright 2004-2019 Cray Inc.
   * Other additional copyright holders may be indicated within.
   *
   * The entirety of this work is licensed under the Apache License,
   * Version 2.0 (the "License"); you may not use this file except
   * in compliance with the License.
   *
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  #include "runpasses.h"
  
  #include "checks.h"
  #include "driver.h"
  #include "log.h"
  #include "parser.h"
  #include "passes.h"
  #include "PhaseTracker.h"
  
  #include <cstdio>
  #include <sys/time.h>
  
  int   currentPassNo   = 1;
  
  struct PassInfo {
    void (*passFunction) ();      // The function which implements the pass.
    void (*checkFunction)();      // per-pass check function
    const char* name;
    char        logTag;
  };
  
  // These entries should be kept in the same order as the entries in passlist.h.
  #define LOG_parse                              'p'
  #define LOG_checkParsed                        LOG_NEVER
  #define LOG_docs                               LOG_NEVER
  #define LOG_readExternC                        LOG_NO_SHORT
  #define LOG_cleanup                            LOG_NO_SHORT
  #define LOG_scopeResolve                       's'
  #define LOG_flattenClasses                     LOG_NO_SHORT
  #define LOG_normalize                          'n'
  #define LOG_checkNormalized                    LOG_NEVER
  #define LOG_buildDefaultFunctions              LOG_NO_SHORT
  #define LOG_createTaskFunctions                LOG_NO_SHORT
  #define LOG_expandExternArrayCalls             LOG_NO_SHORT
  #define LOG_resolve                            'r'
  #define LOG_resolveIntents                     LOG_NO_SHORT
  #define LOG_checkResolved                      LOG_NEVER
  #define LOG_replaceArrayAccessesWithRefTemps   LOG_NO_SHORT
  #define LOG_flattenFunctions                   LOG_NO_SHORT
  #define LOG_cullOverReferences                 LOG_NO_SHORT
  #define LOG_lowerErrorHandling                 LOG_NO_SHORT
  #define LOG_callDestructors                    LOG_NO_SHORT
  #define LOG_lowerIterators                     LOG_NO_SHORT
  #define LOG_parallel                           LOG_NO_SHORT
  #define LOG_prune                              LOG_NO_SHORT
  #define LOG_bulkCopyRecords                    LOG_NO_SHORT
  #define LOG_removeUnnecessaryAutoCopyCalls     LOG_NO_SHORT
  #define LOG_inlineFunctions                    LOG_NO_SHORT
  #define LOG_scalarReplace                      LOG_NO_SHORT
  #define LOG_refPropagation                     LOG_NO_SHORT
  #define LOG_copyPropagation                    LOG_NO_SHORT
  #define LOG_deadCodeElimination                LOG_NO_SHORT
  #define LOG_removeEmptyRecords                 LOG_NO_SHORT
  #define LOG_localizeGlobals                    LOG_NO_SHORT
  #define LOG_loopInvariantCodeMotion            LOG_NO_SHORT
  #define LOG_prune2                             LOG_NO_SHORT
  #define LOG_returnStarTuplesByRefArgs          LOG_NO_SHORT
  #define LOG_insertWideReferences               LOG_NO_SHORT
  #define LOG_optimizeOnClauses                  LOG_NO_SHORT
  #define LOG_addInitCalls                       LOG_NO_SHORT
  #define LOG_insertLineNumbers                  LOG_NO_SHORT
  #define LOG_denormalize                        LOG_NO_SHORT
  #define LOG_codegen                            'c'
  #define LOG_makeBinary                         LOG_NEVER
  
  #define RUN(x) { x, check_ ## x, #x, LOG_ ## x }
  
  //
  // passlist: contains passes in the order that they are called
  //
  static PassInfo sPassList[] = {
    // Chapel to AST
    RUN(parse),                   // parse files and create AST
    RUN(checkParsed),             // checks semantics of parsed AST
    RUN(docs),                    // if fDocs is set, this will generate docs.
                                  // if the executable is named "chpldoc" then
                                  // the application will stop after this phase
  
    // Read in runtime and included C header file types/prototypes
    RUN(readExternC),
  
    // create wrapper functions to allow arrays to be passed to extern routines
    RUN(expandExternArrayCalls),
  
    // Scope resolution and normalization
    RUN(cleanup),                 // post parsing transformations
    RUN(scopeResolve),            // resolve symbols by scope
    RUN(flattenClasses),          // denest nested classes
  
    RUN(normalize),               // normalization transformations
    RUN(checkNormalized),         // check semantics of normalized AST
  
    RUN(buildDefaultFunctions),   // build default functions
    RUN(createTaskFunctions),     // convert 'begin' et al. to functions
  
    // Function resolution and shallow type inference
    RUN(resolve),                 // resolves function calls and types
    RUN(resolveIntents),          // resolve argument intents
    RUN(checkResolved),           // checks semantics of resolved AST
  
    RUN(replaceArrayAccessesWithRefTemps), // replace multiple array access calls with reference temps
  
    // Post-resolution cleanup
    RUN(flattenFunctions),        // denest nested functions
    RUN(cullOverReferences),      // remove excess references
    RUN(lowerErrorHandling),      // lower error handling constructs
    RUN(callDestructors),
    RUN(lowerIterators),          // lowers iterators into functions/classes
    RUN(parallel),                // parallel transforms
    RUN(prune),                   // prune AST of dead functions and types
  
    // Optimizations
    RUN(bulkCopyRecords),         // replace simple assignments with PRIM_ASSIGN.
    RUN(removeUnnecessaryAutoCopyCalls),
    RUN(inlineFunctions),         // function inlining
    RUN(scalarReplace),           // scalar replace all tuples
    RUN(refPropagation),          // reference propagation
    RUN(copyPropagation),         // copy propagation
    RUN(deadCodeElimination),     // eliminate dead code
    RUN(removeEmptyRecords),      // remove empty records
    RUN(localizeGlobals),         // pull out global constants from loop runs
    RUN(loopInvariantCodeMotion), // move loop invariant code above loop runs
    RUN(prune2),                  // prune AST of dead functions and types again
  
    RUN(returnStarTuplesByRefArgs),
  
    RUN(insertWideReferences),    // inserts wide references for on clauses
    RUN(optimizeOnClauses),       // Optimize on clauses
    RUN(addInitCalls),            // Add module init calls and guards.
  
    // AST to C or LLVM
    RUN(insertLineNumbers),       // insert line numbers for error messages
    RUN(denormalize),             // denormalize -- remove local temps
    RUN(codegen),                 // generate C code
    RUN(makeBinary)               // invoke underlying C compiler
  };
  
  static void runPass(PhaseTracker& tracker, size_t passIndex, bool isChpldoc);
  
  void runPasses(PhaseTracker& tracker, bool isChpldoc) {
    size_t passListSize = sizeof(sPassList) / sizeof(sPassList[0]);
  
    setupLogfiles();
  
    if (printPasses == true || printPassesFile != 0) {
      tracker.ReportPass();
    }
  
    for (size_t i = 0; i < passListSize; i++) {
      runPass(tracker, i, isChpldoc);
  
      USR_STOP(); // quit if fatal errors were encountered in pass
  
      currentPassNo++;
  
      // Break early if this is a parse-only run
      if (fParseOnly ==  true && strcmp(sPassList[i].name, "checkParsed") == 0) {
        break;
      }
  
      // Breaks early if the user specified to stop after this pass
      if (stopAfterPass[0] != '\0' && strcmp(sPassList[i].name, stopAfterPass) == 0) {
        break;
      }
  
      // Break early if this is a chpl doc run
      if (isChpldoc == true && strcmp(sPassList[i].name, "docs") == 0) {
        break;
      }
    }
  
    destroyAst();
    teardownLogfiles();
  }
  
  static void runPass(PhaseTracker& tracker, size_t passIndex, bool isChpldoc) {
    PassInfo* info = &sPassList[passIndex];
  
    //
    // The primary work for this pass
    //
  
    tracker.StartPhase(info->name, PhaseTracker::kPrimary);
  
    if (fPrintStatistics[0] != '\0' && passIndex > 0)
      printStatistics("clean");
  
    (*(info->passFunction))();
  
    //
    // Statistics and logging
    //
  
    if (fPrintStatistics[0] != '\0')
      printStatistics(info->name);
  
    logWriteLog(info->name, currentPassNo, info->logTag);
  
    considerExitingEndOfPass();
  
    //
    // An optional verify pass
    //
    tracker.StartPhase(info->name, PhaseTracker::kVerify);
    (*(info->checkFunction))(); // Run per-pass check function.
  
    //
    // Clean up the global pointers to AST.  If we're running chpldoc,
    // there's no real reason to run this step (and at the time of this
    // writing, it didn't work if we hadn't parsed all the 'use'd
    // modules.
    //
    if (!isChpldoc) {
      tracker.StartPhase(info->name, PhaseTracker::kCleanAst);
      cleanAst();
    }
  
    if (printPasses == true || printPassesFile != 0) {
      tracker.ReportPass();
    }
  }
  
  //
  // The logging machinery wants to know a "name" for every pass that it can
  // match to command line arguments but does not, currently, want to know
  // about the pass list itself.
  //
  //  This function provides a vector of the pass list names
  //
  // This routine also verifies that each non-NUL flag is unique.
  
  void initPassesForLogging() {
    size_t passListSize = sizeof(sPassList) / sizeof(sPassList[0]);
  
    for (size_t i = 0; i < passListSize; i++) {
      PassInfo* pass = &sPassList[i];
  
      logMakePassAvailable(pass->name, pass->logTag);
    }
  }
  