brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.6 KiB · 3693980 Raw
241 lines · cpp
1//===- tco.cpp - Tilikum Crossing Opt ---------------------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This is to be like LLVM's opt program, only for FIR.  Such a program is10// required for roundtrip testing, etc.11//12//===----------------------------------------------------------------------===//13 14#include "flang/Optimizer/CodeGen/CodeGen.h"15#include "flang/Optimizer/Dialect/Support/FIRContext.h"16#include "flang/Optimizer/Dialect/Support/KindMapping.h"17#include "flang/Optimizer/Support/DataLayout.h"18#include "flang/Optimizer/Support/InitFIR.h"19#include "flang/Optimizer/Support/InternalNames.h"20#include "flang/Optimizer/Transforms/Passes.h"21#include "flang/Tools/CrossToolHelpers.h"22#include "mlir/IR/AsmState.h"23#include "mlir/IR/BuiltinOps.h"24#include "mlir/IR/MLIRContext.h"25#include "mlir/Parser/Parser.h"26#include "mlir/Pass/Pass.h"27#include "mlir/Pass/PassManager.h"28#include "mlir/Transforms/Passes.h"29#include "llvm/Passes/OptimizationLevel.h"30#include "llvm/Support/CommandLine.h"31#include "llvm/Support/ErrorOr.h"32#include "llvm/Support/FileSystem.h"33#include "llvm/Support/InitLLVM.h"34#include "llvm/Support/MemoryBuffer.h"35#include "llvm/Support/SourceMgr.h"36#include "llvm/Support/TargetSelect.h"37#include "llvm/Support/ToolOutputFile.h"38#include "llvm/Support/raw_ostream.h"39 40using namespace llvm;41 42static cl::opt<std::string>43    inputFilename(cl::Positional, cl::desc("<input file>"), cl::init("-"));44 45static cl::opt<std::string> outputFilename("o",46                                           cl::desc("Specify output filename"),47                                           cl::value_desc("filename"),48                                           cl::init("-"));49 50static cl::opt<bool> emitFir("emit-fir",51                             cl::desc("Parse and pretty-print the input"),52                             cl::init(false));53 54static cl::opt<unsigned>55    OptLevel("O",56             cl::desc("Optimization level. [-O0, -O1, -O2, or -O3] "57                      "(default = '-O2')"),58             cl::Prefix, cl::init(2));59 60static cl::opt<std::string> targetTriple("target",61                                         cl::desc("specify a target triple"),62                                         cl::init("native"));63 64static cl::opt<std::string>65    targetCPU("target-cpu", cl::desc("specify a target CPU"), cl::init(""));66 67static cl::opt<std::string> tuneCPU("tune-cpu", cl::desc("specify a tune CPU"),68                                    cl::init(""));69 70static cl::opt<std::string>71    targetFeatures("target-features", cl::desc("specify the target features"),72                   cl::init(""));73 74static cl::opt<bool> codeGenLLVM(75    "code-gen-llvm",76    cl::desc("Run only CodeGen passes and translate FIR to LLVM IR"),77    cl::init(false));78 79static cl::opt<bool> emitFinalMLIR(80    "emit-final-mlir",81    cl::desc("Only translate FIR to MLIR, do not lower to LLVM IR"),82    cl::init(false));83 84static cl::opt<bool>85    simplifyMLIR("simplify-mlir",86                 cl::desc("Run CSE and canonicalization on MLIR output"),87                 cl::init(false));88 89// Enabled by default to accurately reflect -O290static cl::opt<bool> enableAliasAnalysis("enable-aa",91                                         cl::desc("Enable FIR alias analysis"),92                                         cl::init(true));93 94static cl::opt<bool> testGeneratorMode(95    "test-gen", cl::desc("-emit-final-mlir -simplify-mlir -enable-aa=false"),96    cl::init(false));97 98#include "flang/Optimizer/Passes/CommandLineOpts.h"99#include "flang/Optimizer/Passes/Pipelines.h"100 101static void printModule(mlir::ModuleOp mod, raw_ostream &output) {102  output << mod << '\n';103}104 105static std::optional<llvm::OptimizationLevel>106getOptimizationLevel(unsigned level) {107  switch (level) {108  default:109    return std::nullopt;110  case 0:111    return llvm::OptimizationLevel::O0;112  case 1:113    return llvm::OptimizationLevel::O1;114  case 2:115    return llvm::OptimizationLevel::O2;116  case 3:117    return llvm::OptimizationLevel::O3;118  }119}120 121// compile a .fir file122static llvm::LogicalResult123compileFIR(const mlir::PassPipelineCLParser &passPipeline) {124  // check that there is a file to load125  ErrorOr<std::unique_ptr<MemoryBuffer>> fileOrErr =126      MemoryBuffer::getFileOrSTDIN(inputFilename);127 128  if (std::error_code EC = fileOrErr.getError()) {129    errs() << "Could not open file: " << EC.message() << '\n';130    return mlir::failure();131  }132 133  // load the file into a module134  SourceMgr sourceMgr;135  sourceMgr.AddNewSourceBuffer(std::move(*fileOrErr), SMLoc());136  mlir::DialectRegistry registry;137  fir::support::registerDialects(registry);138  fir::support::addFIRExtensions(registry);139  mlir::MLIRContext context(registry);140  fir::support::loadDialects(context);141  fir::support::registerLLVMTranslation(context);142  auto owningRef = mlir::parseSourceFile<mlir::ModuleOp>(sourceMgr, &context);143 144  if (!owningRef) {145    errs() << "Error can't load file " << inputFilename << '\n';146    return mlir::failure();147  }148  if (mlir::failed(owningRef->verifyInvariants())) {149    errs() << "Error verifying FIR module\n";150    return mlir::failure();151  }152 153  std::error_code ec;154  ToolOutputFile out(outputFilename, ec, sys::fs::OF_None);155 156  // run passes157  fir::KindMapping kindMap{&context};158  fir::setTargetTriple(*owningRef, targetTriple);159  fir::setKindMapping(*owningRef, kindMap);160  fir::setTargetCPU(*owningRef, targetCPU);161  fir::setTuneCPU(*owningRef, tuneCPU);162  fir::setTargetFeatures(*owningRef, targetFeatures);163  // tco is a testing tool, so it will happily use the target independent164  // data layout if none is on the module.165  fir::support::setMLIRDataLayoutFromAttributes(*owningRef,166                                                /*allowDefaultLayout=*/true);167  mlir::PassManager pm((*owningRef)->getName(),168                       mlir::OpPassManager::Nesting::Implicit);169  pm.enableVerifier(/*verifyPasses=*/true);170  (void)mlir::applyPassManagerCLOptions(pm);171  if (emitFir) {172    // parse the input and pretty-print it back out173    // -emit-fir intentionally disables all the passes174  } else if (passPipeline.hasAnyOccurrences()) {175    auto errorHandler = [&](const Twine &msg) {176      mlir::emitError(mlir::UnknownLoc::get(pm.getContext())) << msg;177      return mlir::failure();178    };179    if (mlir::failed(passPipeline.addToPipeline(pm, errorHandler)))180      return mlir::failure();181  } else {182    std::optional<llvm::OptimizationLevel> level =183        getOptimizationLevel(OptLevel);184    if (!level) {185      errs() << "Error invalid optimization level\n";186      return mlir::failure();187    }188    MLIRToLLVMPassPipelineConfig config(*level);189    // TODO: config.StackArrays should be set here?190    config.EnableOpenMP = true;  // assume the input contains OpenMP191    config.AliasAnalysis = enableAliasAnalysis && !testGeneratorMode;192    config.LoopVersioning = OptLevel > 2;193    if (codeGenLLVM) {194      // Run only CodeGen passes.195      fir::createDefaultFIRCodeGenPassPipeline(pm, config);196    } else {197      // Run tco with O2 by default.198      fir::registerDefaultInlinerPass(config);199      fir::createMLIRToLLVMPassPipeline(pm, config);200    }201    if (simplifyMLIR || testGeneratorMode) {202      pm.addPass(mlir::createCanonicalizerPass());203      pm.addPass(mlir::createCSEPass());204    }205    if (!emitFinalMLIR && !testGeneratorMode)206      fir::addLLVMDialectToLLVMPass(pm, out.os());207  }208 209  // run the pass manager210  if (mlir::succeeded(pm.run(*owningRef))) {211    // passes ran successfully, so keep the output212    if ((emitFir || passPipeline.hasAnyOccurrences() || emitFinalMLIR ||213         testGeneratorMode) &&214        !codeGenLLVM)215      printModule(*owningRef, out.os());216    out.keep();217    return mlir::success();218  }219 220  // pass manager failed221  printModule(*owningRef, errs());222  errs() << "\n\nFAILED: " << inputFilename << '\n';223  return mlir::failure();224}225 226int main(int argc, char **argv) {227  // Disable the ExternalNameConversion pass by default until all the tests have228  // been updated to pass with it enabled.229  disableExternalNameConversion = true;230 231  [[maybe_unused]] InitLLVM y(argc, argv);232  fir::support::registerMLIRPassesForFortranTools();233  fir::registerOptCodeGenPasses();234  fir::registerOptTransformPasses();235  mlir::registerMLIRContextCLOptions();236  mlir::registerPassManagerCLOptions();237  mlir::PassPipelineCLParser passPipe("", "Compiler passes to run");238  cl::ParseCommandLineOptions(argc, argv, "Tilikum Crossing Optimizer\n");239  return mlir::failed(compileFIR(passPipe));240}241