blob: 128f5d5f3d0d64558f29b20f84f7e18773eb2b92 [file] [log] [blame]
// Copyright 2020 The IREE Authors
//
// Licensed 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
#include "iree/compiler/Dialect/HAL/Target/LLVM/LLVMIRPasses.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/PassManager.h"
#include "llvm/IR/Verifier.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/Passes/StandardInstrumentations.h"
#include "llvm/Support/CodeGen.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Instrumentation/AddressSanitizer.h"
namespace mlir {
namespace iree_compiler {
namespace IREE {
namespace HAL {
static llvm::CodeGenOpt::Level passBuilderOptLevelToCodeGenOptLevel(
const llvm::OptimizationLevel &level) {
switch (level.getSpeedupLevel()) {
case 0:
return llvm::CodeGenOpt::None;
case 1:
return llvm::CodeGenOpt::Less;
case 2:
default:
return llvm::CodeGenOpt::Default;
case 3:
return llvm::CodeGenOpt::Aggressive;
}
}
std::unique_ptr<llvm::TargetMachine> createTargetMachine(
const LLVMTargetOptions &targetOptions) {
std::string errorMessage;
auto target = llvm::TargetRegistry::lookupTarget(targetOptions.targetTriple,
errorMessage);
if (!target) return nullptr;
std::unique_ptr<llvm::TargetMachine> machine(target->createTargetMachine(
targetOptions.targetTriple, targetOptions.targetCPU /* cpu e.g k8*/,
targetOptions.targetCPUFeatures /* cpu features e.g avx512fma*/,
targetOptions.options, llvm::Reloc::Model::PIC_, {},
passBuilderOptLevelToCodeGenOptLevel(targetOptions.optLevel),
/*JIT=*/false));
return machine;
}
LogicalResult runLLVMIRPasses(const LLVMTargetOptions &options,
llvm::TargetMachine *machine,
llvm::Module *module) {
llvm::LoopAnalysisManager loopAnalysisManager;
llvm::FunctionAnalysisManager functionAnalysisManager;
llvm::CGSCCAnalysisManager cGSCCAnalysisManager;
llvm::ModuleAnalysisManager moduleAnalysisManager;
llvm::PassInstrumentationCallbacks passInstrumentationCallbacks;
llvm::StandardInstrumentations standardInstrumentations(
/*DebugLogging=*/false);
standardInstrumentations.registerCallbacks(passInstrumentationCallbacks);
llvm::PassBuilder passBuilder(machine, options.pipelineTuningOptions, {},
&passInstrumentationCallbacks);
llvm::AAManager aa = passBuilder.buildDefaultAAPipeline();
functionAnalysisManager.registerPass([&] { return std::move(aa); });
passBuilder.registerModuleAnalyses(moduleAnalysisManager);
passBuilder.registerCGSCCAnalyses(cGSCCAnalysisManager);
passBuilder.registerFunctionAnalyses(functionAnalysisManager);
passBuilder.registerLoopAnalyses(loopAnalysisManager);
passBuilder.crossRegisterProxies(loopAnalysisManager, functionAnalysisManager,
cGSCCAnalysisManager, moduleAnalysisManager);
switch (options.sanitizerKind) {
case SanitizerKind::kNone:
break;
case SanitizerKind::kAddress: {
passBuilder.registerOptimizerLastEPCallback(
[](llvm::ModulePassManager &modulePassManager,
llvm::OptimizationLevel Level) {
bool compileKernel = false;
bool recover = false;
bool useAfterScope = true;
bool moduleUseAfterScope = false;
bool useOdrIndicator = false;
modulePassManager.addPass(
llvm::RequireAnalysisPass<llvm::ASanGlobalsMetadataAnalysis,
llvm::Module>());
modulePassManager.addPass(llvm::ModuleAddressSanitizerPass(
compileKernel, recover, moduleUseAfterScope, useOdrIndicator));
modulePassManager.addPass(
createModuleToFunctionPassAdaptor(llvm::AddressSanitizerPass(
compileKernel, recover, useAfterScope)));
});
} break;
}
if (options.optLevel != llvm::OptimizationLevel::O0) {
llvm::ModulePassManager modulePassManager;
modulePassManager =
passBuilder.buildPerModuleDefaultPipeline(options.optLevel);
modulePassManager.run(*module, moduleAnalysisManager);
}
if (llvm::verifyModule(*module)) return failure();
return success();
}
LogicalResult runEmitObjFilePasses(llvm::TargetMachine *machine,
llvm::Module *module, std::string *objData) {
llvm::SmallVector<char, 0> stream_buffer;
{
// TODO(ataei): Use non legacy pass mamanger for this.
llvm::legacy::PassManager passManager;
passManager.add(
new llvm::TargetLibraryInfoWrapperPass(machine->getTargetTriple()));
llvm::raw_svector_ostream ostream(stream_buffer);
if (machine->addPassesToEmitFile(passManager, ostream,
/*DwoOut=*/nullptr,
llvm::CGFT_ObjectFile)) {
return failure();
}
passManager.run(*module);
}
// TODO(ataei): This is a work around stream truncation when directly write to
// string.
*objData = std::string(stream_buffer.begin(), stream_buffer.end());
return success();
}
} // namespace HAL
} // namespace IREE
} // namespace iree_compiler
} // namespace mlir