Files
clang-p2996/flang/tools/tco/tco.cpp
Tarun Prabhu c3201ddaea [flang][NFC] Refactor to remove .inc file containing shared code (#109874)
Remove flang/include/flang/Tools/CLOptions.inc - which was included as
is in - several places. Move the code in it to header and source files
which are used used in the "standard" way. Some minor cleanup such as
removing trailing whitespace and excessive newlines and reordering
entries alphabetically for files that were modified along the way.
Update the documentation that referenced CLOptions.inc.
2024-09-25 14:04:38 -06:00

184 lines
6.8 KiB
C++

//===- tco.cpp - Tilikum Crossing Opt ---------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This is to be like LLVM's opt program, only for FIR. Such a program is
// required for roundtrip testing, etc.
//
//===----------------------------------------------------------------------===//
#include "flang/Optimizer/CodeGen/CodeGen.h"
#include "flang/Optimizer/Dialect/Support/FIRContext.h"
#include "flang/Optimizer/Dialect/Support/KindMapping.h"
#include "flang/Optimizer/Support/DataLayout.h"
#include "flang/Optimizer/Support/InitFIR.h"
#include "flang/Optimizer/Support/InternalNames.h"
#include "flang/Optimizer/Transforms/Passes.h"
#include "flang/Tools/CrossToolHelpers.h"
#include "mlir/IR/AsmState.h"
#include "mlir/IR/BuiltinOps.h"
#include "mlir/IR/MLIRContext.h"
#include "mlir/Parser/Parser.h"
#include "mlir/Pass/Pass.h"
#include "mlir/Pass/PassManager.h"
#include "mlir/Transforms/Passes.h"
#include "llvm/Passes/OptimizationLevel.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/ToolOutputFile.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
static cl::opt<std::string>
inputFilename(cl::Positional, cl::desc("<input file>"), cl::init("-"));
static cl::opt<std::string> outputFilename("o",
cl::desc("Specify output filename"),
cl::value_desc("filename"),
cl::init("-"));
static cl::opt<bool> emitFir("emit-fir",
cl::desc("Parse and pretty-print the input"),
cl::init(false));
static cl::opt<std::string> targetTriple("target",
cl::desc("specify a target triple"),
cl::init("native"));
static cl::opt<std::string>
targetCPU("target-cpu", cl::desc("specify a target CPU"), cl::init(""));
static cl::opt<std::string> tuneCPU("tune-cpu", cl::desc("specify a tune CPU"),
cl::init(""));
static cl::opt<std::string>
targetFeatures("target-features", cl::desc("specify the target features"),
cl::init(""));
static cl::opt<bool> codeGenLLVM(
"code-gen-llvm",
cl::desc("Run only CodeGen passes and translate FIR to LLVM IR"),
cl::init(false));
#include "flang/Optimizer/Passes/CommandLineOpts.h"
#include "flang/Optimizer/Passes/Pipelines.h"
static void printModule(mlir::ModuleOp mod, raw_ostream &output) {
output << mod << '\n';
}
// compile a .fir file
static llvm::LogicalResult
compileFIR(const mlir::PassPipelineCLParser &passPipeline) {
// check that there is a file to load
ErrorOr<std::unique_ptr<MemoryBuffer>> fileOrErr =
MemoryBuffer::getFileOrSTDIN(inputFilename);
if (std::error_code EC = fileOrErr.getError()) {
errs() << "Could not open file: " << EC.message() << '\n';
return mlir::failure();
}
// load the file into a module
SourceMgr sourceMgr;
sourceMgr.AddNewSourceBuffer(std::move(*fileOrErr), SMLoc());
mlir::DialectRegistry registry;
fir::support::registerDialects(registry);
fir::support::addFIRExtensions(registry);
mlir::MLIRContext context(registry);
fir::support::loadDialects(context);
fir::support::registerLLVMTranslation(context);
auto owningRef = mlir::parseSourceFile<mlir::ModuleOp>(sourceMgr, &context);
if (!owningRef) {
errs() << "Error can't load file " << inputFilename << '\n';
return mlir::failure();
}
if (mlir::failed(owningRef->verifyInvariants())) {
errs() << "Error verifying FIR module\n";
return mlir::failure();
}
std::error_code ec;
ToolOutputFile out(outputFilename, ec, sys::fs::OF_None);
// run passes
fir::KindMapping kindMap{&context};
fir::setTargetTriple(*owningRef, targetTriple);
fir::setKindMapping(*owningRef, kindMap);
fir::setTargetCPU(*owningRef, targetCPU);
fir::setTuneCPU(*owningRef, tuneCPU);
fir::setTargetFeatures(*owningRef, targetFeatures);
// tco is a testing tool, so it will happily use the target independent
// data layout if none is on the module.
fir::support::setMLIRDataLayoutFromAttributes(*owningRef,
/*allowDefaultLayout=*/true);
mlir::PassManager pm((*owningRef)->getName(),
mlir::OpPassManager::Nesting::Implicit);
pm.enableVerifier(/*verifyPasses=*/true);
(void)mlir::applyPassManagerCLOptions(pm);
if (emitFir) {
// parse the input and pretty-print it back out
// -emit-fir intentionally disables all the passes
} else if (passPipeline.hasAnyOccurrences()) {
auto errorHandler = [&](const Twine &msg) {
mlir::emitError(mlir::UnknownLoc::get(pm.getContext())) << msg;
return mlir::failure();
};
if (mlir::failed(passPipeline.addToPipeline(pm, errorHandler)))
return mlir::failure();
} else {
MLIRToLLVMPassPipelineConfig config(llvm::OptimizationLevel::O2);
config.AliasAnalysis = true; // enabled when optimizing for speed
if (codeGenLLVM) {
// Run only CodeGen passes.
fir::createDefaultFIRCodeGenPassPipeline(pm, config);
} else {
// Run tco with O2 by default.
fir::registerDefaultInlinerPass(config);
fir::createMLIRToLLVMPassPipeline(pm, config);
}
fir::addLLVMDialectToLLVMPass(pm, out.os());
}
// run the pass manager
if (mlir::succeeded(pm.run(*owningRef))) {
// passes ran successfully, so keep the output
if ((emitFir || passPipeline.hasAnyOccurrences()) && !codeGenLLVM)
printModule(*owningRef, out.os());
out.keep();
return mlir::success();
}
// pass manager failed
printModule(*owningRef, errs());
errs() << "\n\nFAILED: " << inputFilename << '\n';
return mlir::failure();
}
int main(int argc, char **argv) {
// Disable the ExternalNameConversion pass by default until all the tests have
// been updated to pass with it enabled.
disableExternalNameConversion = true;
[[maybe_unused]] InitLLVM y(argc, argv);
fir::support::registerMLIRPassesForFortranTools();
fir::registerOptCodeGenPasses();
fir::registerOptTransformPasses();
mlir::registerMLIRContextCLOptions();
mlir::registerPassManagerCLOptions();
mlir::PassPipelineCLParser passPipe("", "Compiler passes to run");
cl::ParseCommandLineOptions(argc, argv, "Tilikum Crossing Optimizer\n");
return mlir::failed(compileFIR(passPipe));
}