Skip to content

Commit

Permalink
Merge pull request #753 from smackers/extern-statics
Browse files Browse the repository at this point in the history
Externalize entry points that are marked internal
  • Loading branch information
zvonimir authored Aug 26, 2021
2 parents eae7831 + a603560 commit 7aa5fd7
Show file tree
Hide file tree
Showing 7 changed files with 224 additions and 0 deletions.
17 changes: 17 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,15 @@ add_executable(llvm2bpl
tools/llvm2bpl/llvm2bpl.cpp
)

add_library(externalizePass STATIC
tools/externalizer/ExternalizePass.h
tools/externalizer/ExternalizePass.cpp
)

add_executable(extern-statics
tools/externalizer/extern-statics.cpp
)

# We need to include Boost header files at least for macOS
find_package(Boost 1.55)
if(Boost_FOUND)
Expand Down Expand Up @@ -182,10 +191,18 @@ target_link_libraries(smackTranslator ${LLVM_LIBS} ${LLVM_SYSTEM_LIBS}
${LLVM_LDFLAGS})
target_link_libraries(llvm2bpl smackTranslator utils SeaDsaAnalysis)

target_link_libraries(externalizePass ${LLVM_LIBS} ${LLVM_SYSTEM_LIBS}
${LLVM_LDFLAGS})
target_link_libraries(extern-statics externalizePass)

install(TARGETS llvm2bpl
RUNTIME DESTINATION bin
)

install(TARGETS extern-statics
RUNTIME DESTINATION bin
)

install(FILES
${CMAKE_CURRENT_SOURCE_DIR}/bin/smack
${CMAKE_CURRENT_SOURCE_DIR}/bin/smack-doctor
Expand Down
18 changes: 18 additions & 0 deletions share/smack/frontend.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,23 @@ def smack_lib():
return os.path.join(smack_root(), 'share', 'smack', 'lib')


def extern_entry_points(args, bcs):
new_bcs = []
for bc in bcs:
new_bc = temporary_file(
os.path.splitext(
os.path.basename(bc))[0],
'.bc',
args)
cmd = ['-in', bc, '-out', new_bc]
for ep in args.entry_points:
cmd += ['-entry-points', ep]

try_command(['extern-statics'] + cmd, console=True)
new_bcs.append(new_bc)
return new_bcs


def default_clang_compile_command(args, lib=False):
cmd = [
llvm_exact_bin('clang'),
Expand Down Expand Up @@ -469,6 +486,7 @@ def link_bc_files(bitcodes, libs, args):
for build_lib in libs:
smack_libs += build_lib(args)

bitcodes = extern_entry_points(args, bitcodes)
try_command([llvm_exact_bin('llvm-link'), '-o', args.bc_file] + bitcodes)
try_command([llvm_exact_bin('llvm-link'), '-o', args.linked_bc_file,
args.bc_file] + smack_libs)
Expand Down
14 changes: 14 additions & 0 deletions test/llvm/intern.ll
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)
14 changes: 14 additions & 0 deletions test/llvm/intern_fail.ll
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)
74 changes: 74 additions & 0 deletions tools/externalizer/ExternalizePass.cpp
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
19 changes: 19 additions & 0 deletions tools/externalizer/ExternalizePass.h
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
68 changes: 68 additions & 0 deletions tools/externalizer/extern-statics.cpp
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;
}

0 comments on commit 7aa5fd7

Please sign in to comment.