[flang] Fix some memory leaks (#121050)

This commit fixes some but not all memory leaks in Flang. There are
still 91 tests that fail with ASAN.

- Use `mlir::OwningOpRef` instead of `std::unique_ptr`. The latter does
not free allocations of nested blocks.
- Pass `ModuleOp` as value instead of reference.
- Add few missing deallocations in test cases and other places.
This commit is contained in:
Matthias Springer 2024-12-25 09:42:03 +01:00 committed by GitHub
parent c29536b033
commit c870632ef6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 85 additions and 67 deletions

View File

@ -19,6 +19,7 @@
#include "flang/Semantics/semantics.h"
#include "mlir/IR/BuiltinOps.h"
#include "mlir/IR/OwningOpRef.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/IR/Module.h"
#include <memory>
@ -215,8 +216,8 @@ protected:
CodeGenAction(BackendActionTy act) : action{act} {};
/// @name MLIR
/// {
std::unique_ptr<mlir::ModuleOp> mlirModule;
std::unique_ptr<mlir::MLIRContext> mlirCtx;
mlir::OwningOpRef<mlir::ModuleOp> mlirModule;
/// }
/// @name LLVM IR

View File

@ -62,7 +62,7 @@ struct SymbolBox;
namespace pft {
struct Variable;
struct FunctionLikeUnit;
}
} // namespace pft
using SomeExpr = Fortran::evaluate::Expr<Fortran::evaluate::SomeType>;
using SymbolRef = Fortran::common::Reference<const Fortran::semantics::Symbol>;
@ -295,7 +295,7 @@ public:
/// Get the OpBuilder
virtual fir::FirOpBuilder &getFirOpBuilder() = 0;
/// Get the ModuleOp
virtual mlir::ModuleOp &getModuleOp() = 0;
virtual mlir::ModuleOp getModuleOp() = 0;
/// Get the MLIRContext
virtual mlir::MLIRContext &getMLIRContext() = 0;
/// Unique a symbol (add a containing scope specific prefix)

View File

@ -23,6 +23,7 @@
#include "flang/Optimizer/Builder/FIRBuilder.h"
#include "flang/Optimizer/Dialect/Support/KindMapping.h"
#include "mlir/IR/BuiltinOps.h"
#include "mlir/IR/OwningOpRef.h"
#include <set>
namespace llvm {
@ -83,7 +84,8 @@ public:
mlir::MLIRContext &getMLIRContext() { return context; }
/// Get the ModuleOp. It can never be null, which is asserted in the ctor.
mlir::ModuleOp &getModule() { return *module.get(); }
mlir::ModuleOp getModule() { return *module; }
mlir::ModuleOp getModuleAndRelease() { return module.release(); }
const Fortran::common::IntrinsicTypeDefaultKinds &getDefaultKinds() const {
return defaultKinds;
@ -166,7 +168,7 @@ private:
const Fortran::evaluate::TargetCharacteristics &targetCharacteristics;
const Fortran::parser::AllCookedSources *cooked;
mlir::MLIRContext &context;
std::unique_ptr<mlir::ModuleOp> module;
mlir::OwningOpRef<mlir::ModuleOp> module;
fir::KindMapping &kindMap;
const Fortran::lower::LoweringOptions &loweringOptions;
const std::vector<Fortran::lower::EnvironmentDefault> &envDefaults;

View File

@ -19,7 +19,7 @@ namespace llvm {
template <typename T, unsigned N>
class SmallVector;
class StringRef;
}
} // namespace llvm
namespace mlir {
class Location;
@ -44,7 +44,7 @@ struct OpenACCRoutineConstruct;
namespace semantics {
class SemanticsContext;
class Symbol;
}
} // namespace semantics
namespace lower {
@ -78,11 +78,11 @@ void genOpenACCDeclarativeConstruct(AbstractConverter &,
AccRoutineInfoMappingList &);
void genOpenACCRoutineConstruct(AbstractConverter &,
Fortran::semantics::SemanticsContext &,
mlir::ModuleOp &,
mlir::ModuleOp,
const parser::OpenACCRoutineConstruct &,
AccRoutineInfoMappingList &);
void finalizeOpenACCRoutineAttachment(mlir::ModuleOp &,
void finalizeOpenACCRoutineAttachment(mlir::ModuleOp,
AccRoutineInfoMappingList &);
/// Get a acc.private.recipe op for the given type or create it if it does not

View File

@ -174,7 +174,7 @@ struct OffloadModuleOpts {
// Shares assinging of the OpenMP OffloadModuleInterface and its assorted
// attributes accross Flang tools (bbc/flang)
[[maybe_unused]] static void setOffloadModuleInterfaceAttributes(
mlir::ModuleOp &module, OffloadModuleOpts Opts) {
mlir::ModuleOp module, OffloadModuleOpts Opts) {
// Should be registered by the OpenMPDialect
if (auto offloadMod = llvm::dyn_cast<mlir::omp::OffloadModuleInterface>(
module.getOperation())) {
@ -198,7 +198,7 @@ struct OffloadModuleOpts {
}
[[maybe_unused]] static void setOpenMPVersionAttribute(
mlir::ModuleOp &module, int64_t version) {
mlir::ModuleOp module, int64_t version) {
module.getOperation()->setAttr(
mlir::StringAttr::get(module.getContext(), llvm::Twine{"omp.version"}),
mlir::omp::VersionAttr::get(module.getContext(), version));

View File

@ -149,7 +149,7 @@ bool PrescanAndSemaDebugAction::beginSourceFileAction() {
(runSemanticChecks() || true) && (generateRtTypeTables() || true);
}
static void addDependentLibs(mlir::ModuleOp &mlirModule, CompilerInstance &ci) {
static void addDependentLibs(mlir::ModuleOp mlirModule, CompilerInstance &ci) {
const std::vector<std::string> &libs =
ci.getInvocation().getCodeGenOpts().DependentLibs;
if (libs.empty()) {
@ -171,7 +171,7 @@ static void addDependentLibs(mlir::ModuleOp &mlirModule, CompilerInstance &ci) {
// Add to MLIR code target specific items which are dependent on target
// configuration specified by the user.
// Clang equivalent function: AMDGPUTargetCodeGenInfo::emitTargetGlobals
static void addAMDGPUSpecificMLIRItems(mlir::ModuleOp &mlirModule,
static void addAMDGPUSpecificMLIRItems(mlir::ModuleOp mlirModule,
CompilerInstance &ci) {
const TargetOptions &targetOpts = ci.getInvocation().getTargetOpts();
const llvm::Triple triple(targetOpts.triple);
@ -269,7 +269,7 @@ bool CodeGenAction::beginSourceFileAction() {
return false;
}
mlirModule = std::make_unique<mlir::ModuleOp>(module.release());
mlirModule = std::move(module);
const llvm::DataLayout &dl = targetMachine.createDataLayout();
fir::support::setMLIRDataLayout(*mlirModule, dl);
return true;
@ -303,14 +303,11 @@ bool CodeGenAction::beginSourceFileAction() {
ci.getInvocation().getFrontendOpts().features, targetMachine,
ci.getInvocation().getTargetOpts(), ci.getInvocation().getCodeGenOpts());
// Fetch module from lb, so we can set
mlirModule = std::make_unique<mlir::ModuleOp>(lb.getModule());
if (ci.getInvocation().getFrontendOpts().features.IsEnabled(
Fortran::common::LanguageFeature::OpenMP)) {
setOffloadModuleInterfaceAttributes(*mlirModule,
setOffloadModuleInterfaceAttributes(lb.getModule(),
ci.getInvocation().getLangOpts());
setOpenMPVersionAttribute(*mlirModule,
setOpenMPVersionAttribute(lb.getModule(),
ci.getInvocation().getLangOpts().OpenMPVersion);
}
@ -318,6 +315,9 @@ bool CodeGenAction::beginSourceFileAction() {
Fortran::parser::Program &parseTree{*ci.getParsing().parseTree()};
lb.lower(parseTree, ci.getSemanticsContext());
// Fetch module from lb, so we can set
mlirModule = lb.getModuleAndRelease();
// Add target specific items like dependent libraries, target specific
// constants etc.
addDependentLibs(*mlirModule, ci);
@ -961,6 +961,9 @@ static void generateMachineCodeOrAssemblyImpl(clang::DiagnosticsEngine &diags,
// Run the passes
codeGenPasses.run(llvmModule);
// Cleanup
delete tlii;
}
void CodeGenAction::runOptimizationPipeline(llvm::raw_pwrite_stream &os) {
@ -1043,6 +1046,9 @@ void CodeGenAction::runOptimizationPipeline(llvm::raw_pwrite_stream &os) {
// Run the passes.
mpm.run(*llvmModule, mam);
// Cleanup
delete tlii;
}
// This class handles optimization remark messages requested if

View File

@ -1028,7 +1028,7 @@ public:
fir::FirOpBuilder &getFirOpBuilder() override final { return *builder; }
mlir::ModuleOp &getModuleOp() override final { return bridge.getModule(); }
mlir::ModuleOp getModuleOp() override final { return bridge.getModule(); }
mlir::MLIRContext &getMLIRContext() override final {
return bridge.getMLIRContext();
@ -6137,10 +6137,7 @@ void Fortran::lower::LoweringBridge::lower(
}
void Fortran::lower::LoweringBridge::parseSourceFile(llvm::SourceMgr &srcMgr) {
mlir::OwningOpRef<mlir::ModuleOp> owningRef =
mlir::parseSourceFile<mlir::ModuleOp>(srcMgr, &context);
module.reset(new mlir::ModuleOp(owningRef.get().getOperation()));
owningRef.release();
module = mlir::parseSourceFile<mlir::ModuleOp>(srcMgr, &context);
}
Fortran::lower::LoweringBridge::LoweringBridge(
@ -6207,19 +6204,18 @@ Fortran::lower::LoweringBridge::LoweringBridge(
};
// Create the module and attach the attributes.
module = std::make_unique<mlir::ModuleOp>(
module = mlir::OwningOpRef<mlir::ModuleOp>(
mlir::ModuleOp::create(getPathLocation()));
assert(module.get() && "module was not created");
fir::setTargetTriple(*module.get(), triple);
fir::setKindMapping(*module.get(), kindMap);
fir::setTargetCPU(*module.get(), targetMachine.getTargetCPU());
fir::setTuneCPU(*module.get(), targetOpts.cpuToTuneFor);
fir::setTargetFeatures(*module.get(), targetMachine.getTargetFeatureString());
fir::support::setMLIRDataLayout(*module.get(),
targetMachine.createDataLayout());
fir::setIdent(*module.get(), Fortran::common::getFlangFullVersion());
assert(*module && "module was not created");
fir::setTargetTriple(*module, triple);
fir::setKindMapping(*module, kindMap);
fir::setTargetCPU(*module, targetMachine.getTargetCPU());
fir::setTuneCPU(*module, targetOpts.cpuToTuneFor);
fir::setTargetFeatures(*module, targetMachine.getTargetFeatureString());
fir::support::setMLIRDataLayout(*module, targetMachine.createDataLayout());
fir::setIdent(*module, Fortran::common::getFlangFullVersion());
if (cgOpts.RecordCommandLine)
fir::setCommandline(*module.get(), *cgOpts.RecordCommandLine);
fir::setCommandline(*module, *cgOpts.RecordCommandLine);
}
void Fortran::lower::genCleanUpInRegionIfAny(

View File

@ -2670,11 +2670,13 @@ static void genACCDataOp(Fortran::lower::AbstractConverter &converter,
asyncOnlyDeviceTypes);
attachEntryOperands.append(dataClauseOperands.begin() + crtDataStart,
dataClauseOperands.end());
} else if(const auto *defaultClause =
std::get_if<Fortran::parser::AccClause::Default>(&clause.u)) {
} else if (const auto *defaultClause =
std::get_if<Fortran::parser::AccClause::Default>(
&clause.u)) {
if ((defaultClause->v).v == llvm::acc::DefaultValue::ACC_Default_none)
hasDefaultNone = true;
else if ((defaultClause->v).v == llvm::acc::DefaultValue::ACC_Default_present)
else if ((defaultClause->v).v ==
llvm::acc::DefaultValue::ACC_Default_present)
hasDefaultPresent = true;
}
}
@ -3830,7 +3832,7 @@ genDeclareInFunction(Fortran::lower::AbstractConverter &converter,
static void
genDeclareInModule(Fortran::lower::AbstractConverter &converter,
mlir::ModuleOp &moduleOp,
mlir::ModuleOp moduleOp,
const Fortran::parser::AccClauseList &accClauseList) {
mlir::OpBuilder modBuilder(moduleOp.getBodyRegion());
for (const Fortran::parser::AccClause &clause : accClauseList.v) {
@ -3981,7 +3983,7 @@ static void attachRoutineInfo(mlir::func::FuncOp func,
void Fortran::lower::genOpenACCRoutineConstruct(
Fortran::lower::AbstractConverter &converter,
Fortran::semantics::SemanticsContext &semanticsContext, mlir::ModuleOp &mod,
Fortran::semantics::SemanticsContext &semanticsContext, mlir::ModuleOp mod,
const Fortran::parser::OpenACCRoutineConstruct &routineConstruct,
Fortran::lower::AccRoutineInfoMappingList &accRoutineInfos) {
fir::FirOpBuilder &builder = converter.getFirOpBuilder();
@ -4139,7 +4141,7 @@ void Fortran::lower::genOpenACCRoutineConstruct(
}
void Fortran::lower::finalizeOpenACCRoutineAttachment(
mlir::ModuleOp &mod,
mlir::ModuleOp mod,
Fortran::lower::AccRoutineInfoMappingList &accRoutineInfos) {
for (auto &mapping : accRoutineInfos) {
mlir::func::FuncOp funcOp =

View File

@ -3087,7 +3087,7 @@ struct GlobalOpConversion : public fir::FIROpConversion<fir::GlobalOp> {
private:
static void addComdat(mlir::LLVM::GlobalOp &global,
mlir::ConversionPatternRewriter &rewriter,
mlir::ModuleOp &module) {
mlir::ModuleOp module) {
const char *comdatName = "__llvm_comdat";
mlir::LLVM::ComdatOp comdatOp =
module.lookupSymbol<mlir::LLVM::ComdatOp>(comdatName);

View File

@ -72,8 +72,7 @@ public:
mlirCtx->loadDialect<test::DummyDialect>();
mlir::Location loc(mlir::UnknownLoc::get(mlirCtx.get()));
mlirModule =
std::make_unique<mlir::ModuleOp>(mlir::ModuleOp::create(loc, "mod"));
mlirModule = mlir::ModuleOp::create(loc, "mod");
mlir::OpBuilder builder(mlirCtx.get());
builder.setInsertionPointToStart(&mlirModule->getRegion().front());

View File

@ -26,19 +26,20 @@ public:
// Set up a Module with a dummy function operation inside.
// Set the insertion point in the function entry block.
mlir::ModuleOp mod = builder.create<mlir::ModuleOp>(loc);
mlir::func::FuncOp func = mlir::func::FuncOp::create(
moduleOp = builder.create<mlir::ModuleOp>(loc);
builder.setInsertionPointToStart(moduleOp->getBody());
mlir::func::FuncOp func = builder.create<mlir::func::FuncOp>(
loc, "func1", builder.getFunctionType(std::nullopt, std::nullopt));
auto *entryBlock = func.addEntryBlock();
mod.push_back(mod);
builder.setInsertionPointToStart(entryBlock);
firBuilder = std::make_unique<fir::FirOpBuilder>(mod, *kindMap);
firBuilder = std::make_unique<fir::FirOpBuilder>(builder, *kindMap);
}
fir::FirOpBuilder &getBuilder() { return *firBuilder; }
mlir::MLIRContext context;
mlir::OwningOpRef<mlir::ModuleOp> moduleOp;
std::unique_ptr<fir::KindMapping> kindMap;
std::unique_ptr<fir::FirOpBuilder> firBuilder;
};

View File

@ -22,15 +22,15 @@ public:
// Set up a Module with a dummy function operation inside.
// Set the insertion point in the function entry block.
mlir::ModuleOp mod = builder.create<mlir::ModuleOp>(loc);
mlir::func::FuncOp func = mlir::func::FuncOp::create(
moduleOp = builder.create<mlir::ModuleOp>(loc);
builder.setInsertionPointToStart(moduleOp->getBody());
mlir::func::FuncOp func = builder.create<mlir::func::FuncOp>(
loc, "func1", builder.getFunctionType(std::nullopt, std::nullopt));
auto *entryBlock = func.addEntryBlock();
mod.push_back(mod);
builder.setInsertionPointToStart(entryBlock);
kindMap = std::make_unique<fir::KindMapping>(&context);
firBuilder = std::make_unique<fir::FirOpBuilder>(mod, *kindMap);
firBuilder = std::make_unique<fir::FirOpBuilder>(builder, *kindMap);
helper = std::make_unique<fir::factory::Complex>(*firBuilder, loc);
// Init commonly used types
@ -46,6 +46,7 @@ public:
}
mlir::MLIRContext context;
mlir::OwningOpRef<mlir::ModuleOp> moduleOp;
std::unique_ptr<fir::KindMapping> kindMap;
std::unique_ptr<fir::FirOpBuilder> firBuilder;
std::unique_ptr<fir::factory::Complex> helper;

View File

@ -26,19 +26,20 @@ public:
// Set up a Module with a dummy function operation inside.
// Set the insertion point in the function entry block.
mlir::ModuleOp mod = builder.create<mlir::ModuleOp>(loc);
mlir::func::FuncOp func = mlir::func::FuncOp::create(
moduleOp = builder.create<mlir::ModuleOp>(loc);
builder.setInsertionPointToStart(moduleOp->getBody());
mlir::func::FuncOp func = builder.create<mlir::func::FuncOp>(
loc, "func1", builder.getFunctionType(std::nullopt, std::nullopt));
auto *entryBlock = func.addEntryBlock();
mod.push_back(mod);
builder.setInsertionPointToStart(entryBlock);
firBuilder = std::make_unique<fir::FirOpBuilder>(mod, kindMap);
firBuilder = std::make_unique<fir::FirOpBuilder>(builder, kindMap);
}
fir::FirOpBuilder &getBuilder() { return *firBuilder; }
mlir::MLIRContext context;
mlir::OwningOpRef<mlir::ModuleOp> moduleOp;
std::unique_ptr<fir::FirOpBuilder> firBuilder;
};

View File

@ -25,14 +25,14 @@ public:
// Set up a Module with a dummy function operation inside.
// Set the insertion point in the function entry block.
mlir::ModuleOp mod = builder.create<mlir::ModuleOp>(loc);
mlir::func::FuncOp func = mlir::func::FuncOp::create(
moduleOp = builder.create<mlir::ModuleOp>(loc);
builder.setInsertionPointToStart(moduleOp->getBody());
mlir::func::FuncOp func = builder.create<mlir::func::FuncOp>(
loc, "func1", builder.getFunctionType(std::nullopt, std::nullopt));
auto *entryBlock = func.addEntryBlock();
mod.push_back(mod);
builder.setInsertionPointToStart(entryBlock);
firBuilder = std::make_unique<fir::FirOpBuilder>(mod, kindMap);
firBuilder = std::make_unique<fir::FirOpBuilder>(builder, kindMap);
}
mlir::Value createDeclare(fir::ExtendedValue exv) {
@ -52,6 +52,7 @@ public:
int varCounter = 0;
mlir::MLIRContext context;
mlir::OwningOpRef<mlir::ModuleOp> moduleOp;
std::unique_ptr<fir::FirOpBuilder> firBuilder;
};

View File

@ -24,16 +24,16 @@ public:
// Set up a Module with a dummy function operation inside.
// Set the insertion point in the function entry block.
mlir::ModuleOp mod = builder.create<mlir::ModuleOp>(loc);
moduleOp = builder.create<mlir::ModuleOp>(loc);
builder.setInsertionPointToStart(moduleOp->getBody());
mlir::func::FuncOp func =
mlir::func::FuncOp::create(loc, "runtime_unit_tests_func",
builder.create<mlir::func::FuncOp>(loc, "runtime_unit_tests_func",
builder.getFunctionType(std::nullopt, std::nullopt));
auto *entryBlock = func.addEntryBlock();
mod.push_back(mod);
builder.setInsertionPointToStart(entryBlock);
kindMap = std::make_unique<fir::KindMapping>(&context);
firBuilder = std::make_unique<fir::FirOpBuilder>(mod, *kindMap);
firBuilder = std::make_unique<fir::FirOpBuilder>(builder, *kindMap);
i1Ty = firBuilder->getI1Type();
i8Ty = firBuilder->getI8Type();
@ -66,6 +66,7 @@ public:
}
mlir::MLIRContext context;
mlir::OwningOpRef<mlir::ModuleOp> moduleOp;
std::unique_ptr<fir::KindMapping> kindMap;
std::unique_ptr<fir::FirOpBuilder> firBuilder;

View File

@ -19,12 +19,12 @@ public:
// Set up a Module with a dummy function operation inside.
// Set the insertion point in the function entry block.
mlir::ModuleOp mod = builder->create<mlir::ModuleOp>(loc);
moduleOp = builder->create<mlir::ModuleOp>(loc);
builder->setInsertionPointToStart(moduleOp->getBody());
mlir::func::FuncOp func =
mlir::func::FuncOp::create(loc, "fortran_variable_tests",
builder->create<mlir::func::FuncOp>(loc, "fortran_variable_tests",
builder->getFunctionType(std::nullopt, std::nullopt));
auto *entryBlock = func.addEntryBlock();
mod.push_back(mod);
builder->setInsertionPointToStart(entryBlock);
}
@ -40,6 +40,7 @@ public:
}
mlir::MLIRContext context;
std::unique_ptr<mlir::OpBuilder> builder;
mlir::OwningOpRef<mlir::ModuleOp> moduleOp;
};
TEST_F(FortranVariableTest, SimpleScalar) {

View File

@ -127,6 +127,9 @@ TEST(ArrayConstructor, Character) {
0);
result.Deallocate();
cookieAllocator.deallocate(acVector, 1);
x->Deallocate();
y->Deallocate();
c->Deallocate();
}
TEST(ArrayConstructor, CharacterRuntimeCheck) {

View File

@ -259,6 +259,9 @@ void RunExtremumTests(const char *which,
t.expect[i], t.expect[i] + std::strlen(t.expect[i])};
EXPECT_EQ(expect, got) << "inputs: '" << t.x[i] << "','" << t.y[i] << "'";
}
x->Deallocate();
y->Deallocate();
}
}