Skip to content
This repository was archived by the owner on Apr 4, 2025. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
154 changes: 154 additions & 0 deletions dyninst/cuda/CFGParser.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
#include "CFGParser.hpp"
#include <cctype>
#include <iostream>

namespace CudaParse {

void CFGParser::parse_inst_strings(
const std::string &label,
std::deque<std::string> &inst_strings) {
std::regex e("\\\\l([|]*)");
std::istringstream ss(std::regex_replace(label, e, "\n"));
std::string s;
while (std::getline(ss, s)) {
inst_strings.push_back(s);
}
while (inst_strings.size() > 0) {
if (isdigit(inst_strings.front()[0]) || inst_strings.front()[0] == '<') {
break;
}
inst_strings.pop_front();
}
inst_strings.pop_back();
}


void CFGParser::parse_calls(std::vector<Function *> &functions) {
for (auto *function : functions) {
for (auto *block : function->blocks) {
for (auto *inst : block->insts) {
if (inst->opcode.find("CALL") != std::string::npos || // sm_70
inst->opcode.find("CAL") != std::string::npos) { // sm_60
std::string &operand = inst->operands[0];
Function *callee_function;
for (auto *ff : functions) {
if (ff->name == operand) {
callee_function = ff;
break;
}
}
block->targets.push_back(new Target(inst, callee_function->blocks[0], CALL));
}
}
}
}
}


size_t CFGParser::find_block_parent(size_t node) {
size_t parent = _block_parent[node];
size_t graph_size = _block_parent.size();
if (parent == graph_size) {
return _block_parent[node] = node;
} else if (parent == node) {
return node;
} else {
return _block_parent[node] = find_block_parent(parent);
}
}


void CFGParser::unite_blocks(size_t l, size_t r) {
_block_parent[l] = find_block_parent(r);
}


static bool compare_block_ptr(Block *l, Block *r) {
return *l < *r;
}


static bool compare_target_ptr(Target *l, Target *r) {
return *l < *r;
}


void CFGParser::parse(const Graph &graph, std::vector<Function *> &functions) {
std::unordered_map<size_t, Block *> block_map;
std::vector<Block *> blocks;
size_t graph_size = graph.vertices.size();
_block_parent.resize(graph_size);
for (size_t i = 0; i < graph_size; ++i) {
_block_parent[i] = graph_size;
}

// Parse every vertex to build blocks
for (auto *vertex : graph.vertices) {
Block *block = new Block(vertex->id, vertex->name);

std::deque<std::string> inst_strings;
parse_inst_strings(vertex->label, inst_strings);
for (auto &inst_string : inst_strings) {
block->insts.push_back(new Inst(inst_string));
}

blocks.push_back(block);
block_map[block->id] = block;
}

// Parse every edge to build block relations
for (auto *edge : graph.edges) {
// Find toppest block
unite_blocks(edge->target_id, edge->source_id);
Block *target_block = block_map[edge->target_id];
Block *source_block = block_map[edge->source_id];

TargetType type = DIRECT;
// Link blocks
Inst *target_inst;
for (auto *inst : source_block->insts) {
if (inst->port == edge->source_port[0]) {
if (inst->predicate.find("!@") != std::string::npos) {
type = COND_TAKEN;
} else if (inst->predicate.find("@") != std::string::npos) {
type = COND_NOT_TAKEN;
} else if (inst == source_block->insts.back()) {
type = FALLTHROUGH;
}
source_block->targets.push_back(new Target(inst, target_block, type));
}
}
// Some edge may not have port information
if (source_block->targets.size() == 0) {
Inst *inst = source_block->insts.back();
type = FALLTHROUGH;
source_block->targets.push_back(new Target(inst, target_block, type));
}
}

// Build functions
size_t function_id = 0;
for (auto *block : blocks) {
// Sort block targets according to inst offset
std::sort(block->targets.begin(), block->targets.end(), compare_target_ptr);
if (find_block_parent(block->id) == block->id) {
// Filter out self contained useless loops. A normal function will not start with "."
if (block_map[block->id]->name[0] == '.') {
continue;
}
Function *function = new Function(function_id, block_map[block->id]->name);
++function_id;
for (auto *bb : blocks) {
if (find_block_parent(bb->id) == block->id) {
function->blocks.push_back(bb);
}
}
std::sort(function->blocks.begin(), function->blocks.end(), compare_block_ptr);
functions.push_back(function);
}
}

parse_calls(functions);
}

}
35 changes: 35 additions & 0 deletions dyninst/cuda/CFGParser.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#ifndef _CFG_PARSER_H_
#define _CFG_PARSER_H_

#include <string>
#include <vector>
#include <deque>
#include <unordered_map>
#include "DotCFG.hpp"
#include "Graph.hpp"

namespace CudaParse {

class CFGParser {
public:
CFGParser() : _block_parent(0) {}
void parse(const Graph &graph, std::vector<Function *> &functions);

~CFGParser() {};

private:
void parse_calls(std::vector<Function *> &functions);

void parse_inst_strings(const std::string &label, std::deque<std::string> &inst_strings);

size_t find_block_parent(size_t node);

void unite_blocks(size_t l, size_t r);

private:
std::vector<size_t> _block_parent;
};

}

#endif
22 changes: 22 additions & 0 deletions dyninst/cuda/CudaBlock.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#include "CudaBlock.hpp"


namespace Dyninst {
namespace ParseAPI {

CudaBlock::CudaBlock(CodeObject * o, CodeRegion * r,
Address start, std::vector<Offset> &offsets) : Block(o, r, start) {
for (auto offset : offsets) {
_inst_offsets.push_back(offset);
}
}

void CudaBlock::getInsns(Insns &insns) const {
for (auto offset : _inst_offsets) {
insns.insert(std::pair<long unsigned int,
boost::shared_ptr<Dyninst::InstructionAPI::Instruction>>(offset, NULL));
}
}

}
}
24 changes: 24 additions & 0 deletions dyninst/cuda/CudaBlock.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#ifndef _CUDA_BLOCK_H_
#define _CUDA_BLOCK_H_

#include <CFG.h>

namespace Dyninst {
namespace ParseAPI {

class PARSER_EXPORT CudaBlock : public Block {
public:
CudaBlock(CodeObject * o, CodeRegion * r, Address start, std::vector<Offset> &offsets);

virtual ~CudaBlock() {}

virtual void getInsns(Insns &insns) const;

private:
std::vector<Offset> _inst_offsets;
};

}
}

#endif
75 changes: 75 additions & 0 deletions dyninst/cuda/CudaCFGFactory.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#include "CudaCFGFactory.hpp"
#include "CudaFunction.hpp"
#include <iostream>

namespace Dyninst {
namespace ParseAPI {

Function *CudaCFGFactory::mkfunc(Address addr, FuncSource src,
std::string name, CodeObject * obj, CodeRegion * region,
Dyninst::InstructionSource * isrc) {
// find function by name
for (auto *function : _functions) {
if (function->name == name) {
CudaFunction *ret_func = new CudaFunction(addr, name, obj, region, isrc);

bool first_entry = true;
for (auto *block : function->blocks) {
CudaBlock *ret_block = NULL;
if (_block_filter.find(block->id) == _block_filter.end()) {
std::vector<Offset> inst_offsets;
for (auto *inst : block->insts) {
inst_offsets.push_back(inst->offset);
}
ret_block = new CudaBlock(obj, region, block->insts[0]->offset, inst_offsets);
_block_filter[block->id] = ret_block;
blocks_.add(*ret_block);
ret_func->add_block(ret_block);
} else {
ret_block = _block_filter[block->id];
}

if (first_entry) {
ret_func->setEntry(ret_block);
first_entry = false;
}

for (auto *target : block->targets) {
CudaBlock *ret_target_block = NULL;
if (_block_filter.find(target->block->id) == _block_filter.end()) {
std::vector<Offset> inst_offsets;
for (auto *inst : target->block->insts) {
inst_offsets.push_back(inst->offset);
}
ret_target_block = new CudaBlock(obj, region, target->block->insts[0]->offset, inst_offsets);
_block_filter[target->block->id] = ret_target_block;
blocks_.add(*ret_target_block);
ret_func->add_block(ret_target_block);
} else {
ret_target_block = _block_filter[target->block->id];
}

Edge *ret_edge = NULL;
if (target->type == CudaParse::CALL) {
ret_edge = new Edge(ret_block, ret_target_block, CALL);
} else if (target->type = CudaParse::FALLTHROUGH) {
ret_edge = new Edge(ret_block, ret_target_block, FALLTHROUGH);
} else { // TODO(Keren): Add more edge types
ret_edge = new Edge(ret_block, ret_target_block, DIRECT);
}
ret_edge->install();
edges_.add(*ret_edge);
}
}
return ret_func;
}
}
return NULL;
// iterate blocks
// add blocks
// iterate targets
// add edges
}

}
}
31 changes: 31 additions & 0 deletions dyninst/cuda/CudaCFGFactory.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#ifndef _CUDA_CFG_FACTORY_H_
#define _CUDA_CFG_FACTORY_H_

#include <CFGFactory.h>
#include <unordered_map>

#include "CudaBlock.hpp"
#include "DotCFG.hpp"

namespace Dyninst {
namespace ParseAPI {

class PARSER_EXPORT CudaCFGFactory : public CFGFactory {
public:
CudaCFGFactory(std::vector<CudaParse::Function *> &functions) : _functions(functions) {};
virtual ~CudaCFGFactory() {};

protected:
virtual Function * mkfunc(Address addr, FuncSource src,
std::string name, CodeObject * obj, CodeRegion * region,
Dyninst::InstructionSource * isrc);

private:
std::vector<CudaParse::Function *> &_functions;
std::unordered_map<size_t, CudaBlock *> _block_filter;
};

}
}

#endif
14 changes: 14 additions & 0 deletions dyninst/cuda/CudaCodeSource.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#include "CudaCodeSource.hpp"

namespace Dyninst {
namespace ParseAPI {

CudaCodeSource::CudaCodeSource(std::vector<CudaParse::Function *> &functions) {
for (auto *function : functions) {
int offset = function->blocks[0]->insts[0]->offset;
_hints.push_back(Hint(offset, 0, 0, function->name));
}
}

}
}
Loading