//===----------------------------------------------------------------------===//
#include "llvm/Transforms/IPO/ElimAvailExtern.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/IR/Constant.h"
+#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalValue.h"
#include "llvm/IR/GlobalVariable.h"
+#include "llvm/IR/MDBuilder.h"
#include "llvm/IR/Module.h"
+#include "llvm/Support/CommandLine.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/Transforms/Utils/GlobalStatus.h"
+#include "llvm/Transforms/Utils/ModuleUtils.h"
using namespace llvm;
#define DEBUG_TYPE "elim-avail-extern"
-STATISTIC(NumFunctions, "Number of functions removed");
+cl::opt<bool> ConvertToLocal(
+ "avail-extern-to-local", cl::Hidden,
+ cl::desc("Convert available_externally into locals, renaming them "
+ "to avoid link-time clashes."));
+
+STATISTIC(NumRemovals, "Number of functions removed");
+STATISTIC(NumConversions, "Number of functions converted");
STATISTIC(NumVariables, "Number of global variables removed");
+void deleteFunction(Function &F) {
+ // This will set the linkage to external
+ F.deleteBody();
+ ++NumRemovals;
+}
+
+/// Create a copy of the thinlto import, mark it local, and redirect direct
+/// calls to the copy. Only direct calls are replaced, so that e.g. indirect
+/// call function pointer tests would use the global identity of the function.
+///
+/// Currently, Value Profiling ("VP") MD_prof data isn't updated to refer to the
+/// clone's GUID (which will be different, because the name and linkage is
+/// different), under the assumption that the last consumer of this data is
+/// upstream the pipeline (e.g. ICP).
+static void convertToLocalCopy(Module &M, Function &F) {
+ assert(F.hasAvailableExternallyLinkage());
+ assert(!F.isDeclaration());
+ // If we can't find a single use that's a call, just delete the function.
+ if (F.uses().end() == llvm::find_if(F.uses(), [&](Use &U) {
+ return isa<CallBase>(U.getUser());
+ }))
+ return deleteFunction(F);
+
+ auto OrigName = F.getName().str();
+ // Build a new name. We still need the old name (see below).
+ // We could just rely on internal linking allowing 2 modules have internal
+ // functions with the same name, but that just creates more trouble than
+ // necessary e.g. distinguishing profiles or debugging. Instead, we append the
+ // module identifier.
+ auto NewName = OrigName + ".__uniq" + getUniqueModuleId(&M);
+ F.setName(NewName);
+ if (auto *SP = F.getSubprogram())
+ SP->replaceLinkageName(MDString::get(F.getParent()->getContext(), NewName));
+
+ F.setLinkage(GlobalValue::InternalLinkage);
+ // Now make a declaration for the old name. We'll use it if there are non-call
+ // uses. For those, it would be incorrect to replace them with the local copy:
+ // for example, one such use could be taking the address of the function and
+ // passing it to an external function, which, in turn, might compare the
+ // function pointer to the original (non-local) function pointer, e.g. as part
+ // of indirect call promotion.
+ auto *Decl =
+ Function::Create(F.getFunctionType(), GlobalValue::ExternalLinkage,
+ F.getAddressSpace(), OrigName, F.getParent());
+ F.replaceUsesWithIf(Decl,
+ [&](Use &U) { return !isa<CallBase>(U.getUser()); });
+ ++NumConversions;
+}
+
static bool eliminateAvailableExternally(Module &M) {
bool Changed = false;
}
GV.removeDeadConstantUsers();
GV.setLinkage(GlobalValue::ExternalLinkage);
- NumVariables++;
+ ++NumVariables;
Changed = true;
}
// Drop the bodies of available externally functions.
- for (Function &F : M) {
- if (!F.hasAvailableExternallyLinkage())
+ for (Function &F : llvm::make_early_inc_range(M)) {
+ if (F.isDeclaration() || !F.hasAvailableExternallyLinkage())
continue;
- if (!F.isDeclaration())
- // This will set the linkage to external
- F.deleteBody();
+
+ if (ConvertToLocal)
+ convertToLocalCopy(M, F);
+ else
+ deleteFunction(F);
+
F.removeDeadConstantUsers();
- NumFunctions++;
Changed = true;
}