Skip to content

Commit

Permalink
consolidated injection of exit and extraction
Browse files Browse the repository at this point in the history
  • Loading branch information
examon committed Nov 21, 2018
1 parent ad64141 commit c1dd802
Show file tree
Hide file tree
Showing 7 changed files with 148 additions and 96 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ doc:
doxygen Doxyfile

clean:
rm -rf apex.out
rm -rf apex/build
rm -rf apex/cmake-build-debug
rm -rf build
Expand Down
182 changes: 101 additions & 81 deletions apex/apex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,10 @@ bool APEXPass::runOnModule(Module &M) {
logPrintUnderline("Constructing function dependency blocks.");
apexDgComputeFunctionDependencyBlocks(M, apex_dg, function_dependency_blocks);

if (VERBOSE_DEBUG) {
logPrintUnderline("Printing calculated function dependency blocks.");
apexDgPrintFunctionDependencyBlocks(function_dependency_blocks);
}
// if (VERBOSE_DEBUG) {
logPrintUnderline("Printing calculated function dependency blocks.");
apexDgPrintFunctionDependencyBlocks(function_dependency_blocks);
// }

logPrintUnderline("Constructing dependency blocks to functions callgraph.");
apexDgConstructBlocksFunctionsCallgraph(function_dependency_blocks,
Expand All @@ -96,48 +96,8 @@ bool APEXPass::runOnModule(Module &M) {
removeUnneededStuff(M, path, blocks_functions_callgraph,
function_dependency_blocks);

logPrintUnderline("Inserting exit call after target instructions.");
moduleInsertExit(M, target_function_id);

logPrintUnderline("Extracting data.");
// TODO: extract operand from target instruction and pass it as arg to dump.
{
Instruction *insertion_point =
const_cast<Instruction *>(target_instructions_.back());
std::vector<Type *> params_tmp = {Type::getInt32Ty(M.getContext())};
ArrayRef<Type *> params = makeArrayRef(params_tmp);
FunctionType *fType =
FunctionType::get(Type::getVoidTy(M.getContext()), params, false);
Constant *temp = M.getOrInsertFunction("lib_dump_int", fType);
Function *dump_fcn = cast<Function>(temp);

insertion_point->dump();
for (unsigned i = 0; i < insertion_point->getNumOperands(); ++i) {
logPrint("- op");
Value *op = insertion_point->getOperand(i);
op->dump();
}

Value *dump_arg_val =
ConstantInt::get(Type::getInt32Ty(M.getContext()), 123456);
dump_arg_val->dump();

ArrayRef<Value *> dump_params =
makeArrayRef(dump_arg_val);
CallInst *dump_call_inst = CallInst::Create(dump_fcn, dump_params, "");

if (insertion_point->isTerminator()) {
logPrintFlat("- @insertion_point is terminator, inserting " +
dump_fcn->getGlobalIdentifier() + " before: ");
insertion_point->dump();
dump_call_inst->insertBefore(insertion_point);
} else {
logPrintFlat("- @insertion_point is NOT terminator, inserting " +
dump_fcn->getGlobalIdentifier() + " after: ");
insertion_point->dump();
dump_call_inst->insertAfter(insertion_point);
}
}
logPrintUnderline("Injecting exit and extract calls.");
moduleInjectExitExtract(M, target_function_id);

logPrintUnderline("Stripping debug symbols from every function in module.");
stripAllDebugSymbols(M);
Expand Down Expand Up @@ -707,7 +667,7 @@ void APEXPass::apexDgPrintFunctionDependencyBlocks(
std::string fcn_id = function_blocks.first->getGlobalIdentifier();
logPrint("FUNCTION: " + fcn_id);
for (auto &block : function_blocks.second) {
logPrint("- BLOCK:");
logPrint("- COMPONENT:");
for (auto &node : block) {
logPrintFlat(" ");
node->getValue()->dump();
Expand Down Expand Up @@ -751,7 +711,8 @@ void APEXPass::apexDgPrintBlocksFunctionsCallgraph(
for (const auto &block_functions : blocks_functions_callgraph) {
const Instruction *node_inst =
cast<Instruction>(block_functions.first.front()->getValue());
logPrint("BLOCK: in " + node_inst->getFunction()->getGlobalIdentifier());
logPrint("COMPONENT: in " +
node_inst->getFunction()->getGlobalIdentifier());
for (const auto &node : block_functions.first) {
node->getValue()->dump();
}
Expand Down Expand Up @@ -810,10 +771,10 @@ void APEXPass::moduleFindTargetInstructionsOrDie(Module &M,
}
}

/// Inserts lib_exit() call at the end of the @target_instructions_.
// TODO: Rename this method.
void APEXPass::moduleInsertExit(Module &M,
const std::string &target_function_id) {
/// Injects _apex_exit() call at the end of the @target_instructions_.
/// Injects lib_dump_int() call before lib_exit().
void APEXPass::moduleInjectExitExtract(Module &M,
const std::string &target_function_id) {

logPrint("Supplied target instructions from: " +
target_instructions_.back()->getFunction()->getGlobalIdentifier());
Expand All @@ -824,13 +785,13 @@ void APEXPass::moduleInsertExit(Module &M,
target_instruction->dump();
}

logPrint("\nSetting insertion point:");
Instruction *insertion_point =
logPrint("\nSetting injection point:");
Instruction *injection_point =
const_cast<Instruction *>(target_instructions_.back());
logPrintFlat("-");
insertion_point->dump();
injection_point->dump();

logPrint("\nInserting instruction lib_exit():");
logPrint("\nInjecting call instruction to _apex_exit():");
{
// Create vector of types and put one integer into this vector.
std::vector<Type *> params_tmp = {Type::getInt32Ty(M.getContext())};
Expand All @@ -839,51 +800,110 @@ void APEXPass::moduleInsertExit(Module &M,

// Create function that returns void and has parameters that are
// specified in the @params (that is, one Int32).
FunctionType *fType =
FunctionType *fcn_type =
FunctionType::get(Type::getVoidTy(M.getContext()), params, false);

// Load exit function into variable.
Constant *temp = M.getOrInsertFunction("lib_exit", fType);
Constant *temp = M.getOrInsertFunction("_apex_exit", fcn_type);
if (nullptr == temp) {
logPrint("ERROR: lib_exit function is not in symbol table.");
exit(-1);
}
Function *exit_fcn = cast<Function>(temp);
logPrint("- loaded function: " + exit_fcn->getGlobalIdentifier());
Function *_apex_exit_fcn = cast<Function>(temp);
logPrint("- loaded function: " + _apex_exit_fcn->getGlobalIdentifier());

// Create exit call instruction.
Value *exit_arg_val =
Value *_apex_exit_fcn_arg_val =
ConstantInt::get(Type::getInt32Ty(M.getContext()), APEX_DONE);
ArrayRef<Value *> exit_params = makeArrayRef(exit_arg_val);
ArrayRef<Value *> _apex_exit_fcn_params =
makeArrayRef(_apex_exit_fcn_arg_val);
// CallInst::Create build call instruction to @exit_fcn that has
// @exit_params. Empty string "" means that the @exit_call_inst will not
// have return variable.
CallInst *exit_call_inst = CallInst::Create(exit_fcn, exit_params, "");
// @_apex_exit_fcn_params. Empty string "" means that the
// @_apex_exit_call_inst will not have return variable.
CallInst *_apex_exit_call_inst =
CallInst::Create(_apex_exit_fcn, _apex_exit_fcn_params, "");

// If the @insertion point is terminator, insert @exit_call_inst before it.
// Otherwise, basic blocks will not end with terminator.
// If the @insertion point is terminator, insert @_apex_exit_call_inst
// before it. Otherwise, basic blocks will not end with terminator.
// TODO: Will this inconsistency cause problems?
if (insertion_point->isTerminator()) {
logPrintFlat("- @insertion_point is terminator, inserting " +
exit_fcn->getGlobalIdentifier() + " before: ");
insertion_point->dump();
exit_call_inst->insertBefore(insertion_point);
if (injection_point->isTerminator()) {
logPrintFlat("- @injection_point is terminator, inserting " +
_apex_exit_fcn->getGlobalIdentifier() + " before: ");
injection_point->dump();
_apex_exit_call_inst->insertBefore(injection_point);
} else {
logPrintFlat("- @insertion_point is NOT terminator, inserting " +
exit_fcn->getGlobalIdentifier() + " after: ");
insertion_point->dump();
exit_call_inst->insertAfter(insertion_point);
logPrintFlat("- @injection_point is NOT terminator, inserting " +
_apex_exit_fcn->getGlobalIdentifier() + " after: ");
injection_point->dump();
_apex_exit_call_inst->insertAfter(injection_point);
}

// Final check.
if (nullptr == exit_call_inst) {
logPrint("ERROR: could not create " + exit_fcn->getGlobalIdentifier() +
" call instruction.");
if (nullptr == _apex_exit_call_inst) {
logPrint("ERROR: could not create " +
_apex_exit_fcn->getGlobalIdentifier() + " call instruction.");
exit(-1);
}
logPrintFlat("- " + exit_fcn->getGlobalIdentifier() +
logPrintFlat("- " + _apex_exit_fcn->getGlobalIdentifier() +
" call instruction created: ");
_apex_exit_call_inst->dump();

// Set insertion point to the exit call we just inserted.
// All new instructions are going to be inserted before exit call.
injection_point = _apex_exit_call_inst;
}

logPrint("\nInjecting call instruction to _apex_extract_int():");
{
// Load _apex_extract_int() from lib.c and save it.
Instruction *last_target =
const_cast<Instruction *>(target_instructions_.back());
std::vector<Type *> params_tmp = {PointerType::getInt32Ty(M.getContext())};
ArrayRef<Type *> params = makeArrayRef(params_tmp);
FunctionType *fcn_type =
FunctionType::get(Type::getVoidTy(M.getContext()), params, false);
Constant *temp = M.getOrInsertFunction("_apex_extract_int", fcn_type);
Function *_apex_extract_int_fcn = cast<Function>(temp);
logPrint("- loaded function: " +
_apex_extract_int_fcn->getGlobalIdentifier());

logPrintFlat("- last of the target functions: ");
last_target->dump();

if (false == isa<StoreInst>(last_target)) {
logPrint("ERROR: Invalid target instruction! It has to be StoreInst!");
exit(FATAL_ERROR);
}

if (2 != last_target->getNumOperands()) {
logPrint("ERROR: Invalid target instruction! It has to have 2 operands!");
exit(FATAL_ERROR);
}

// Example of instruction: store i32 %call, i32* %f, allign 4
// @_apex_extract_int_arg would be second operand: i32* %f
Value *_apex_extract_int_arg =
last_target->getOperand(last_target->getNumOperands() - 1);
logPrintFlat("- last of the target instructions, second op: ");
_apex_extract_int_arg->dump();

// Now we need to load that pointer to i32 into classic i32.
// Because @lib_extract_int takes i32 instead of i32*.
LoadInst *_apex_extract_int_arg_loadinst = new LoadInst(
_apex_extract_int_arg, "_apex_extract_int_arg", injection_point);
logPrintFlat("- created load instruction: ");
_apex_extract_int_arg_loadinst->dump();

// Now make callinst to _apex_extract_int with the correct argument
// (that is i32 and not i32*).
std::vector<Value *> dump_params = {_apex_extract_int_arg_loadinst};
CallInst *lib_extract_int_fcn_callinst =
CallInst::Create(_apex_extract_int_fcn, dump_params, "");

logPrintFlat("- " + _apex_extract_int_fcn->getGlobalIdentifier() +
" call instruction created: ");
exit_call_inst->dump();
lib_extract_int_fcn_callinst->dump();
lib_extract_int_fcn_callinst->insertBefore(injection_point);
}
}

Expand Down
31 changes: 23 additions & 8 deletions apex/apex.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,28 @@ using DependencyBlock = std::vector<LLVMNode *>;

/// Protected functions IDs. These will not be removed by APEXPass.
std::vector<std::string> PROTECTED_FCNS = {
// These belong to the lib_exit()
"lib_exit", "exit",
// These belong to the lib_dump_int()
"lib_dump_int", "abs", "log10", "floor", "fopen", "fputs", "fclose", "exit",
// These belong to the _apex_exit function.
"_apex_exit",
"exit",

// These belong to the _apex_extract_int function.
"_apex_extract_int",
"abs",
"log10",
"floor",
"fopen",
"fputs",
"fclose",
"exit",
"sprintf",
"printf", // Maybe remove prints?
"llvm.dbg.declare", "llvm.stackrestore",
"llvm.stacksave", // Introduced with debug symbols.

// Keep printf calls.
"printf",

// Introduced with debug symbols.
"llvm.dbg.declare",
"llvm.stackrestore",
"llvm.stacksave",
};

/// Command line arguments for opt.
Expand Down Expand Up @@ -149,7 +163,8 @@ class APEXPass : public ModulePass {
void moduleParseCmdLineArgsOrDie(void);
void moduleFindTargetInstructionsOrDie(Module &M, const std::string &file,
const std::string &line);
void moduleInsertExit(Module &M, const std::string &target_function_id);
void moduleInjectExitExtract(Module &M,
const std::string &target_function_id);

void findPath(Module &M,
std::map<DependencyBlock, std::vector<const Function *>>
Expand Down
6 changes: 4 additions & 2 deletions build_and_run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@
INPUT_LIB="c-code/lib.c"
INPUT_SOURCE="c-code/test_dependencies_minimal.c"
FILE="c-code/test_dependencies_minimal.c"
LINE=43

LINE=27
#INPUT_SOURCE="c-code/callgraph.c"
#FILE="c-code/callgraph.c"
#LINE=11

# Generated bytecodes during all stages of processing.
BYTECODE_FROM_INPUT="bytecode_from_input.bc" # No optimizations.
Expand Down
13 changes: 13 additions & 0 deletions c-code/callgraph.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
int y(void) {
return 2;
}

int x(void) {
return 1;
}

int main(void) {
int x_ret = x();
int y_ret = y();
return 0;
}
9 changes: 5 additions & 4 deletions c-code/lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@
#include <stdlib.h>
#include <math.h>

/// Function used for getting out of the program, usually after calling @lib_dump_int().
void lib_exit(int exit_code) {
#define APEX_OUTPUT "apex.out"

/// Function used for getting out of the program, usually after calling @_apex_extract_int().
void _apex_exit(int exit_code) {
exit(exit_code);
}

/// Function used for dumping value @i to file @APEX_OUTPUT.
void lib_dump_int(int i) {
#define APEX_OUTPUT "apex.out"
void _apex_extract_int(int i) {
// Figure out number of digits @i has.
// So we can allocate big enough buffer.
int i_digits = 0;
Expand Down
2 changes: 1 addition & 1 deletion c-code/test_dependencies_minimal.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ int n(void) {

int flag(void) {
printf("flag: in\n");
return 0;
return 100;
}

int main(int argc, char **argv) {
Expand Down

0 comments on commit c1dd802

Please sign in to comment.