Files
revng-revng/lib/HelperArgumentsAnalysis/SlimDownHelpersModule.cpp
T
Giacomo Vercesi 798af62b87 Introduce helpers declarations
Re-organize the variants of `libtcg-helpers-*.bc` as such:
* `libtcg-helpers-full-$ARCH.bc`: unchanged, contains all helper
  function with their bodies and all CSVs.
* `libtcg-helpers-declarations-only-$ARCH.bc`: all helper
  functions have been turned to declarations. All CSVs (except a couple
  of special ones) have been dropped.
* `libtcg-helpers-to-inline-$ARCH.bc`: only functions with the
  `revng_inline` section retain their body. Only CSVs that are used by
  these functions are present.

Lift now loads only the `declarations-only` variant of helpers, as
their body is not required until `inline-helpers`. In `inline-helpers`
the `to-inline` variant is loaded and linked, which then allows the
helpers to be inlined.
2026-02-05 10:20:45 +01:00

113 lines
3.7 KiB
C++

//
// This file is distributed under the MIT License. See LICENSE.md for details.
//
#include "llvm/IR/Constants.h"
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
#include "llvm/Transforms/IPO/AlwaysInliner.h"
#include "llvm/Transforms/IPO/GlobalDCE.h"
#include "revng/Model/FunctionTags.h"
#include "revng/Support/IRHelpers.h"
#include "revng/Support/SimplePassManager.h"
#include "PostProcessingHelpers.h"
using namespace llvm;
class SlimDownHelpersModule : public llvm::ModulePass {
public:
static char ID;
public:
SlimDownHelpersModule() : llvm::ModulePass(ID) {}
bool runOnModule(llvm::Module &M) override {
LLVMContext &Context = M.getContext();
for (Function &F : M) {
if (F.isDeclaration() or F.isIntrinsic())
continue;
// Remove the body of all the functions *not* tagged with `revng_inline`
if (F.getSection() != InlineHelpersSection) {
deleteOnlyBody(F);
} else {
llvm::stripDebugInfo(F);
F.removeFnAttr(Attribute::NoInline);
F.addFnAttr(Attribute::AlwaysInline);
F.setDSOLocal(false);
F.setVisibility(GlobalValue::DefaultVisibility);
}
}
// Now that all of the non-`revng_inline` functions have gone, we want to
// reduce the number of global variables with some help from GlobalDCE.
// We have three type of variables:
// * Special variables (`arch_cpu_type_beacon`, `cpu_loop_exiting`) which
// should not be touched
// * CSVs we want to keep only the ones used by the `revng_inline`
// functions, so we set their linkage temporarily to internal, run
// `globaldce` and then restore them to their original linkage
// * The rest (QEMU globals) do not need their initializer, so it's removed
// and their linkage is set to external. `globaldce` will also remove
// them if they are unused
StringMap<GlobalValue::LinkageTypes> GlobalLinkageBackup;
for (GlobalVariable &GV : M.globals()) {
GV.eraseMetadata(LLVMContext::MD_dbg);
if (GV.isDeclaration() or isSpecialGV(GV))
continue;
if (FunctionTags::CSV.isTagOf(&GV)) {
// Save linkage to be restored after we run globaldce
GlobalLinkageBackup[GV.getName()] = GV.getLinkage();
GV.setLinkage(GlobalValue::InternalLinkage);
} else {
// Blank out initializers for any non-CSV GlobalVariable
GV.setInitializer(nullptr);
GV.setLinkage(GlobalValue::ExternalLinkage);
}
}
// Run always-inline and globaldce.
// It's important to run `always-inline` now so that when the helper
// functions are inlined into the main module it can be done in a single
// pass and not in a fixed-point fashion.
SimplePassManager PM;
PM.addPass(llvm::AlwaysInlinerPass());
PM.addPass(llvm::GlobalDCEPass());
PM.run(M);
// Restore the linkage to CSVs after running globaldce
for (GlobalVariable &GV : M.globals()) {
if (GlobalLinkageBackup.count(GV.getName()) != 0)
GV.setLinkage(GlobalLinkageBackup[GV.getName()]);
}
// Helper functions, down the pipeline, will be given the `NoInline`
// attribute, to avoid the module failing verification remove the
// `AlwaysInline` attribute.
for (llvm::Function &F : M) {
if (F.getSection() == InlineHelpersSection)
F.removeFnAttr(Attribute::AlwaysInline);
}
// Tag all globals
tagQEMUGlobalsAndFunctions(M);
return true;
}
};
char SlimDownHelpersModule::ID = 0;
using Register = RegisterPass<SlimDownHelpersModule>;
static Register X("slim-down-helpers-module",
"Purge non-inline helper functions but keep their "
"declarations alive in a array of pointers.",
true,
true);