-
Notifications
You must be signed in to change notification settings - Fork 82
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #753 from smackers/extern-statics
Externalize entry points that are marked internal
- Loading branch information
Showing
7 changed files
with
224 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
; @expect verified | ||
; @flag --entry-points=foo | ||
|
||
source_filename = "llvm-link" | ||
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" | ||
target triple = "x86_64-unknown-linux-gnu" | ||
|
||
; Function Attrs: nounwind uwtable | ||
define internal i32 @foo() { | ||
call void @__VERIFIER_assert(i32 1) | ||
ret i32 0 | ||
} | ||
|
||
declare void @__VERIFIER_assert(i32) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
; @expect error | ||
; @flag --entry-points=foo | ||
|
||
source_filename = "llvm-link" | ||
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" | ||
target triple = "x86_64-unknown-linux-gnu" | ||
|
||
; Function Attrs: nounwind uwtable | ||
define internal i32 @foo() { | ||
call void @__VERIFIER_assert(i32 0) | ||
ret i32 0 | ||
} | ||
|
||
declare void @__VERIFIER_assert(i32) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
#include "ExternalizePass.h" | ||
#include "llvm/IR/GlobalValue.h" | ||
#include "llvm/IR/Instructions.h" | ||
#include "llvm/Support/CommandLine.h" | ||
#include "llvm/Transforms/Utils/Cloning.h" | ||
#include "llvm/Transforms/Utils/ValueMapper.h" | ||
|
||
static llvm::cl::list<std::string> | ||
entryPoints("entry-points", llvm::cl::ZeroOrMore, | ||
llvm::cl::desc("Verification entry points"), | ||
llvm::cl::value_desc("PROCS")); | ||
|
||
using namespace llvm; | ||
|
||
namespace externalize { | ||
// Based on internalizeFunctions | ||
// from https://llvm.org/doxygen/Attributor_8cpp_source.html#l01948 | ||
Function *externalizeFunction(Function *Fn) { | ||
// Generate the externalized version of Fn | ||
Module &M = *Fn->getParent(); | ||
FunctionType *FnTy = Fn->getFunctionType(); | ||
|
||
// Create a copy of the current function | ||
Function *Copied = | ||
Function::Create(FnTy, GlobalValue::LinkageTypes::ExternalLinkage, | ||
Fn->getAddressSpace(), Fn->getName() + ".externalized"); | ||
ValueToValueMapTy VMap; | ||
auto *NewFArgIt = Copied->arg_begin(); | ||
for (auto &Arg : Fn->args()) { | ||
auto ArgName = Arg.getName(); | ||
NewFArgIt->setName(ArgName); | ||
VMap[&Arg] = &(*NewFArgIt++); | ||
} | ||
SmallVector<ReturnInst *, 8> Returns; | ||
|
||
// Copy the body of the original function to the new one | ||
CloneFunctionInto(Copied, Fn, VMap, false, Returns); | ||
|
||
// Copy metadata | ||
SmallVector<std::pair<unsigned, MDNode *>, 1> MDs; | ||
Fn->getAllMetadata(MDs); | ||
for (auto MDIt : MDs) | ||
if (!Copied->hasMetadata()) | ||
Copied->addMetadata(MDIt.first, *MDIt.second); | ||
|
||
M.getFunctionList().insert(Fn->getIterator(), Copied); | ||
Copied->setDSOLocal(true); | ||
|
||
// Replace all uses of the old function with the new externalized function | ||
Fn->replaceAllUsesWith(Copied); | ||
|
||
return Copied; | ||
} | ||
bool ExternalizePass::runOnModule(Module &M) { | ||
bool changed = false; | ||
for (const std::string &e : entryPoints) { | ||
if (Function *f = M.getFunction(e)) { | ||
if (!f->hasExternalLinkage()) { | ||
changed = true; | ||
Function *external = externalizeFunction(f); | ||
f->removeFromParent(); | ||
external->setName(e); | ||
} | ||
} | ||
} | ||
return changed; | ||
} | ||
|
||
char ExternalizePass::ID = 0; | ||
|
||
StringRef ExternalizePass::getPassName() const { | ||
return "Externalize static entry point functions"; | ||
} | ||
} // namespace externalize |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
// | ||
// This file is distributed under the MIT License. See LICENSE for details. | ||
// | ||
#ifndef EXTERNALIZEPASS_H | ||
#define EXTERNALIZEPASS_H | ||
|
||
#include "llvm/IR/Module.h" | ||
#include "llvm/Pass.h" | ||
#include "llvm/Support/raw_ostream.h" | ||
|
||
namespace externalize { | ||
struct ExternalizePass : public llvm::ModulePass { | ||
static char ID; | ||
ExternalizePass() : llvm::ModulePass(ID) {} | ||
virtual llvm::StringRef getPassName() const; | ||
virtual bool runOnModule(llvm::Module &M); | ||
}; | ||
} // namespace externalize | ||
#endif // EXTERNALIZEPASS_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
#include "ExternalizePass.h" | ||
|
||
#include "llvm/Bitcode/BitcodeWriter.h" | ||
#include "llvm/IR/IRPrintingPasses.h" | ||
#include "llvm/IR/LLVMContext.h" | ||
#include "llvm/IR/LegacyPassManager.h" | ||
#include "llvm/IRReader/IRReader.h" | ||
#include "llvm/Support/CommandLine.h" | ||
#include "llvm/Support/Debug.h" | ||
#include "llvm/Support/PrettyStackTrace.h" | ||
#include "llvm/Support/Signals.h" | ||
#include "llvm/Support/ToolOutputFile.h" | ||
|
||
static llvm::cl::opt<std::string> | ||
InputFilename("in", llvm::cl::desc("Input bitcode filename"), | ||
llvm::cl::Required, llvm::cl::value_desc("input filename")); | ||
|
||
static llvm::cl::opt<std::string> | ||
OutputFilename("out", llvm::cl::desc("Output bitcode filename"), | ||
llvm::cl::Required, llvm::cl::value_desc("output filename")); | ||
|
||
int main(int argc, char **argv) { | ||
|
||
llvm::llvm_shutdown_obj shutdown; // calls llvm_shutdown() on exit | ||
llvm::cl::ParseCommandLineOptions( | ||
argc, argv, "extern-statics - Externalize static functions\n"); | ||
|
||
llvm::sys::PrintStackTraceOnErrorSignal(argv[0]); | ||
llvm::PrettyStackTraceProgram PSTP(argc, argv); | ||
llvm::EnableDebugBuffering = true; | ||
|
||
llvm::SMDiagnostic err; | ||
llvm::LLVMContext Context; | ||
|
||
std::unique_ptr<llvm::Module> module = | ||
llvm::parseIRFile(InputFilename, err, Context); | ||
if (!err.getMessage().empty()) { | ||
llvm::errs() << "Problem reading input bitcode/IR: " + | ||
err.getMessage().str() | ||
<< "\n"; | ||
return 1; | ||
} | ||
|
||
/////////////////////////////// | ||
// initialise and run passes // | ||
/////////////////////////////// | ||
|
||
llvm::legacy::PassManager pass_manager; | ||
pass_manager.add(new externalize::ExternalizePass()); | ||
|
||
pass_manager.run(*module.get()); | ||
|
||
std::error_code EC; | ||
auto out = new llvm::ToolOutputFile(OutputFilename.c_str(), EC, | ||
llvm::sys::fs::F_None); | ||
|
||
if (EC) { | ||
llvm::errs() << "Could not create output file: " << EC.message() << "\n"; | ||
return 1; | ||
} | ||
out->keep(); | ||
|
||
WriteBitcodeToFile(*module, out->os()); | ||
|
||
delete out; | ||
|
||
return 0; | ||
} |