mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
7f7f9571a8
Add infrastructure to pypeline that allows containers to be notified when they are being used last, this allows two things: * `Pipe`s eagerly clearing those containers once they are done reading their contents * `ScheduledTask`s clearing those out at the end of their execution in case the pipe did not do it This overall should improve memory usage as container no longer take up memory if they are no longer used as part of a `Schedule`.
106 lines
3.0 KiB
C++
106 lines
3.0 KiB
C++
#pragma once
|
|
|
|
//
|
|
// This file is distributed under the MIT License. See LICENSE.md for details.
|
|
//
|
|
|
|
#include "mlir/Bytecode/BytecodeWriter.h"
|
|
#include "mlir/IR/BuiltinOps.h"
|
|
#include "mlir/IR/MLIRContext.h"
|
|
#include "mlir/Parser/Parser.h"
|
|
|
|
#include "revng/Clift/Clift.h"
|
|
#include "revng/Clift/CliftDialect.h"
|
|
#include "revng/PipeboxCommon/Common.h"
|
|
#include "revng/PipeboxCommon/ObjectID.h"
|
|
|
|
namespace revng::pypeline {
|
|
|
|
class CliftFunctionContainer {
|
|
public:
|
|
static constexpr llvm::StringRef Name = "CliftFunctionContainer";
|
|
static constexpr Kind Kind = Kinds::Function;
|
|
static constexpr llvm::StringRef MimeType = "application/x.mlir.bc";
|
|
|
|
private:
|
|
static constexpr auto Threading = mlir::MLIRContext::Threading::DISABLED;
|
|
static inline const mlir::DialectRegistry MLIRDialectRegistry = ([]() {
|
|
mlir::DialectRegistry Registry;
|
|
Registry.insert<mlir::clift::CliftDialect>();
|
|
return Registry;
|
|
})();
|
|
|
|
private:
|
|
bool Disposable = false;
|
|
std::optional<mlir::MLIRContext> Context;
|
|
std::map<ObjectID, mlir::OwningOpRef<mlir::ModuleOp>> Modules;
|
|
|
|
public:
|
|
CliftFunctionContainer() :
|
|
Context(std::in_place_t{}, MLIRDialectRegistry, Threading) {}
|
|
|
|
public:
|
|
std::set<ObjectID> objects() const {
|
|
return std::views::keys(Modules) | revng::to<std::set<ObjectID>>();
|
|
}
|
|
|
|
void
|
|
deserialize(const std::map<const ObjectID *, llvm::ArrayRef<char>> Data) {
|
|
const mlir::ParserConfig Config(&*Context);
|
|
for (auto const &[Object, Buffer] : Data) {
|
|
llvm::StringRef String(Buffer.data(), Buffer.size());
|
|
auto NewModule = mlir::parseSourceString<mlir::ModuleOp>(String, Config);
|
|
revng_assert(NewModule);
|
|
revng_assert(mlir::clift::hasModuleAttr(NewModule.get()));
|
|
Modules[*Object] = std::move(NewModule);
|
|
}
|
|
}
|
|
|
|
std::map<ObjectID, Buffer>
|
|
serialize(const std::vector<const ObjectID *> Objects) const {
|
|
std::map<ObjectID, Buffer> Result;
|
|
for (const ObjectID *Object : Objects) {
|
|
llvm::raw_svector_ostream OS(Result[*Object].data());
|
|
mlir::writeBytecodeToFile(*Modules.at(*Object), OS);
|
|
}
|
|
return Result;
|
|
}
|
|
|
|
bool verify() const {
|
|
bool Result = true;
|
|
for (auto const &[_, Module] : Modules) {
|
|
mlir::LogicalResult ModuleResult = Module.get().verify();
|
|
Result &= ModuleResult.succeeded();
|
|
}
|
|
return Result;
|
|
}
|
|
|
|
void setIsDisposable() { Disposable = true; }
|
|
|
|
void disposeIfPossible() {
|
|
if (not Disposable)
|
|
return;
|
|
|
|
Modules.clear();
|
|
Context.emplace(MLIRDialectRegistry, Threading);
|
|
Disposable = false;
|
|
}
|
|
|
|
public:
|
|
mlir::MLIRContext &getContext() { return *Context; }
|
|
const mlir::MLIRContext &getContext() const { return *Context; }
|
|
|
|
const mlir::ModuleOp getModule(const ObjectID &ID) const {
|
|
return *Modules.at(ID);
|
|
}
|
|
|
|
mlir::ModuleOp getModule(const ObjectID &ID) { return *Modules.at(ID); }
|
|
|
|
void assign(const ObjectID &ID, mlir::ModuleOp NewModule) {
|
|
revng_assert(&*Context == NewModule->getContext());
|
|
Modules[ID] = NewModule;
|
|
}
|
|
};
|
|
|
|
} // namespace revng::pypeline
|