diff --git a/headers/datatypes.h b/headers/datatypes.h index e5b3ae2..68d1c1b 100644 --- a/headers/datatypes.h +++ b/headers/datatypes.h @@ -343,6 +343,7 @@ class ExternalFunction { class Instruction{ public: virtual void pretty_print() {}; + virtual std::string ToString() { return ""; }; InstructionType instrType; }; @@ -393,6 +394,10 @@ class AddrofInstruction : public Instruction{ } } + std::string ToString() { + return lhs->name + " = $addrof " + rhs->name; + } + void pretty_print() { std::cout << "******************* Addrof Instruction *******************" << std::endl; std::cout << "Instruction type: " << instrType << std::endl; @@ -430,6 +435,11 @@ class AllocInstruction : public Instruction{ } } + std::string ToString() { + std::string num_str = (num->var != nullptr) ? num->var->name : std::to_string(num->val); + return lhs->name + " = $alloc " + num_str + " " + "[" + id->name + "]"; + } + void pretty_print() { std::cout << "******************* Alloc Instruction *******************" << std::endl; std::cout << "Instruction type: " << instrType << std::endl; @@ -476,6 +486,21 @@ class ArithInstruction : public Instruction{ } } + std::string ToString() { + std::string op1_str = (op1->var != nullptr) ? op1->var->name : std::to_string(op1->val); + std::string op2_str = (op2->var != nullptr) ? op2->var->name : std::to_string(op2->val); + std::string aop_str = ""; + if (arith_op == "Add") + aop_str = "add"; + else if (arith_op == "Subtract") + aop_str = "sub"; + else if (arith_op == "Multiply") + aop_str = "mul"; + else if (arith_op == "Divide") + aop_str = "div"; + return lhs->name + " = $arith " + aop_str + " " + op1_str + " " + op2_str; + } + void pretty_print() { std::cout << "******************* Arith Instruction *******************" << std::endl; std::cout << "Instruction type: " << instrType << std::endl; @@ -523,6 +548,25 @@ class CmpInstruction : public Instruction{ } } + std::string ToString() { + std::string op1_str = (op1->var != nullptr) ? op1->var->name : std::to_string(op1->val); + std::string op2_str = (op2->var != nullptr) ? op2->var->name : std::to_string(op2->val); + std::string rop_str = ""; + if (cmp_op == "Eq") + rop_str = "eq"; + else if (cmp_op == "Neq") + rop_str = "neq"; + else if (cmp_op == "Less") + rop_str = "lt"; + else if (cmp_op == "LessEq") + rop_str = "lte"; + else if (cmp_op == "Greater") + rop_str = "gt"; + else if (cmp_op == "GreaterEq") + rop_str = "gte"; + return lhs->name + " = $cmp " + rop_str + " " + op1_str + " " + op2_str; + } + void pretty_print() { std::cout << "******************* Cmp Instruction *******************" << std::endl; std::cout << "Instruction type: " << instrType << std::endl; @@ -562,6 +606,11 @@ class CopyInstruction : public Instruction{ } } + std::string ToString() { + std::string op_str = (op->var != nullptr) ? op->var->name : std::to_string(op->val); + return lhs->name + " = $copy " + op_str; + } + void pretty_print() { std::cout << "******************* Copy Instruction *******************" << std::endl; std::cout << "Instruction type: " << instrType << std::endl; @@ -599,6 +648,11 @@ class GepInstruction : public Instruction{ } } + std::string ToString() { + std::string idx_str = (idx->var != nullptr) ? idx->var->name : std::to_string(idx->val); + return lhs->name + " = $gep " + src->name + " " + idx_str; + } + void pretty_print() { std::cout << "******************* Gep Instruction *******************" << std::endl; std::cout << "Instruction type: " << instrType << std::endl; @@ -635,6 +689,11 @@ class GfpInstruction : public Instruction{ } } + std::string ToString() + { + return lhs->name + " = $gfp " + src->name + " " + field->name; + } + void pretty_print() { std::cout << "******************* Gfp Instruction *******************" << std::endl; std::cout << "Instruction type: " << instrType << std::endl; @@ -668,6 +727,11 @@ class LoadInstruction : public Instruction{ } } + std::string ToString() + { + return lhs->name + " = $load " + src->name; + } + void pretty_print() { std::cout << "******************* Load Instruction *******************" << std::endl; std::cout << "Instruction type: " << instrType << std::endl; @@ -701,6 +765,12 @@ class StoreInstruction : public Instruction { } } + std::string ToString() + { + std::string op_str = (op->var != nullptr) ? op->var->name : std::to_string(op->val); + return "$store " + dst->name + " " + op_str; + } + void pretty_print() { std::cout << "******************* Store Instruction *******************" << std::endl; std::cout << "Instruction type: " << instrType << std::endl; @@ -731,7 +801,7 @@ class CallExtInstruction : public Instruction{ lhs = new Variable(inst_val["lhs"]["name"], new Type(inst_val["lhs"]["typ"])); } if (inst_val["ext_callee"] != nullptr) { - extFuncName = inst_val["ext_callee"].dump(); + extFuncName = inst_val["ext_callee"]; } if (inst_val["args"] != nullptr) { for (auto &[arg_key, arg_val] : inst_val["args"].items()) { @@ -743,6 +813,19 @@ class CallExtInstruction : public Instruction{ } } + std::string ToString() { + std::string args_str = ""; + int i = 0; + for (auto arg : args) { + args_str += (arg->var != nullptr) ? arg->var->name : std::to_string(arg->val); + if (i != args.size() - 1) + args_str += ", "; + i += 1; + } + std::string lhs_str = (lhs != nullptr) ? lhs->name + " = " : ""; + return lhs_str + "$call_ext " + extFuncName + "(" + args_str + ")"; + } + void pretty_print() { std::cout << "******************* CallExt Instruction *******************" << std::endl; std::cout << "Instruction type: " << instrType << std::endl; @@ -791,6 +874,12 @@ class BranchInstruction : public Instruction{ } }; + std::string ToString() + { + std::string cond_str = (condition->var != nullptr) ? condition->var->name : std::to_string(condition->val); + return "$branch " + cond_str + " " + tt + " " + ff; + } + void pretty_print() { std::cout << "******************* Branch Instruction *******************" << std::endl; std::cout << "Instruction type: " << instrType << std::endl; @@ -816,6 +905,10 @@ class JumpInstruction : public Instruction{ // std::cout << inst_val << std::endl; }; + std::string ToString() { + return "$jump " + label; + } + void pretty_print() { std::cout << "******************* Jump Instruction *******************" << std::endl; std::cout << "Instruction type: " << instrType << std::endl; @@ -848,6 +941,14 @@ class RetInstruction : public Instruction{ op = new Operand(inst_val["CInt"]); } + std::string ToString() + { + if (op == nullptr) + return "$ret"; + else + return "$ret " + ((op->var != nullptr) ? op->var->name : std::to_string(op->val)); + } + void pretty_print() { std::cout << "******************* Ret Instruction *******************" << std::endl; std::cout << "Instruction type: " << instrType << std::endl; @@ -892,6 +993,20 @@ class CallDirInstruction : public Instruction{ } } + std::string ToString() + { + std::string args_str = ""; + int i = 0; + for (auto arg : args) { + args_str += (arg->var != nullptr) ? arg->var->name : std::to_string(arg->val); + if (i != args.size() - 1) + args_str += ", "; + i += 1; + } + std::string lhs_str = (lhs != nullptr) ? lhs->name + " = " : ""; + return lhs_str + "$call_dir " + callee + "(" + args_str + ") then " + next_bb; + } + void pretty_print() { std::cout << "******************* CallDir Instruction *******************" << std::endl; std::cout << "Instruction type: " << instrType << std::endl; @@ -946,6 +1061,20 @@ class CallIdrInstruction : public Instruction{ } } + std::string ToString() + { + std::string args_str = ""; + int i = 0; + for (auto arg : args) { + args_str += (arg->var != nullptr) ? arg->var->name : std::to_string(arg->val); + if (i != args.size() - 1) + args_str += ", "; + i += 1; + } + std::string lhs_str = (lhs != nullptr) ? lhs->name + " = " : ""; + return lhs_str + "$call_idr " + fp->name + "(" + args_str + ") then " + next_bb; + } + void pretty_print() { std::cout << "******************* CallIdr Instruction *******************" << std::endl; std::cout << "Instruction type: " << instrType << std::endl; diff --git a/program-dependence-graph/pdg-tests/points-to-files/emptyfile b/program-dependence-graph/pdg-tests/points-to-files/emptyfile new file mode 100644 index 0000000..e69de29 diff --git a/program-dependence-graph/pdg-tests/test.3.lir b/program-dependence-graph/pdg-tests/test.3.lir new file mode 100644 index 0000000..42b7033 --- /dev/null +++ b/program-dependence-graph/pdg-tests/test.3.lir @@ -0,0 +1,30 @@ +extern input:(int,&int) -> int + +g1:int +g2:&int + +fn main() -> int { + let i:int, j:int, x:int, y:int, z:int, tmp:int, a:&int + + entry: + x = $call_ext input(tmp,a) + y = $copy 0 + z = $copy 1 + i = $copy 0 + j = $copy 1 + $jump loop_hdr + + loop_hdr: + tmp = $cmp lt i x + $branch tmp loop_body exit + + loop_body: + y = $arith add y 2 + z = $arith mul z j + i = $arith add i 1 + j = $arith add j 2 + $jump loop_hdr + + exit: + $ret y +} \ No newline at end of file diff --git a/program-dependence-graph/pdg-tests/test.3.lir.json b/program-dependence-graph/pdg-tests/test.3.lir.json new file mode 100644 index 0000000..c9d2eab --- /dev/null +++ b/program-dependence-graph/pdg-tests/test.3.lir.json @@ -0,0 +1 @@ +{"structs":{},"globals":[{"name":"g1","typ":"Int","scope":null},{"name":"g2","typ":{"Pointer":"Int"},"scope":null}],"functions":{"main":{"id":"main","ret_ty":"Int","params":[],"locals":[{"name":"a","typ":{"Pointer":"Int"},"scope":"main"},{"name":"i","typ":"Int","scope":"main"},{"name":"j","typ":"Int","scope":"main"},{"name":"tmp","typ":"Int","scope":"main"},{"name":"x","typ":"Int","scope":"main"},{"name":"y","typ":"Int","scope":"main"},{"name":"z","typ":"Int","scope":"main"}],"body":{"entry":{"id":"entry","insts":[{"CallExt":{"lhs":{"name":"x","typ":"Int","scope":"main"},"ext_callee":"input","args":[{"Var":{"name":"tmp","typ":"Int","scope":"main"}},{"Var":{"name":"a","typ":{"Pointer":"Int"},"scope":"main"}}]}},{"Copy":{"lhs":{"name":"y","typ":"Int","scope":"main"},"op":{"CInt":0}}},{"Copy":{"lhs":{"name":"z","typ":"Int","scope":"main"},"op":{"CInt":1}}},{"Copy":{"lhs":{"name":"i","typ":"Int","scope":"main"},"op":{"CInt":0}}},{"Copy":{"lhs":{"name":"j","typ":"Int","scope":"main"},"op":{"CInt":1}}}],"term":{"Jump":"loop_hdr"}},"exit":{"id":"exit","insts":[],"term":{"Ret":{"Var":{"name":"y","typ":"Int","scope":"main"}}}},"loop_body":{"id":"loop_body","insts":[{"Arith":{"lhs":{"name":"y","typ":"Int","scope":"main"},"aop":"Add","op1":{"Var":{"name":"y","typ":"Int","scope":"main"}},"op2":{"CInt":2}}},{"Arith":{"lhs":{"name":"z","typ":"Int","scope":"main"},"aop":"Multiply","op1":{"Var":{"name":"z","typ":"Int","scope":"main"}},"op2":{"Var":{"name":"j","typ":"Int","scope":"main"}}}},{"Arith":{"lhs":{"name":"i","typ":"Int","scope":"main"},"aop":"Add","op1":{"Var":{"name":"i","typ":"Int","scope":"main"}},"op2":{"CInt":1}}},{"Arith":{"lhs":{"name":"j","typ":"Int","scope":"main"},"aop":"Add","op1":{"Var":{"name":"j","typ":"Int","scope":"main"}},"op2":{"CInt":2}}}],"term":{"Jump":"loop_hdr"}},"loop_hdr":{"id":"loop_hdr","insts":[{"Cmp":{"lhs":{"name":"tmp","typ":"Int","scope":"main"},"rop":"Less","op1":{"Var":{"name":"i","typ":"Int","scope":"main"}},"op2":{"Var":{"name":"x","typ":"Int","scope":"main"}}}}],"term":{"Branch":{"cond":{"Var":{"name":"tmp","typ":"Int","scope":"main"}},"tt":"loop_body","ff":"exit"}}}}}},"externs":{"input":{"Function":{"ret_ty":"Int","param_ty":["Int",{"Pointer":"Int"}]}}}} \ No newline at end of file diff --git a/program-dependence-graph/program_slicing.cpp b/program-dependence-graph/program_slicing.cpp index 74042f1..cd85c2f 100644 --- a/program-dependence-graph/program_slicing.cpp +++ b/program-dependence-graph/program_slicing.cpp @@ -33,9 +33,9 @@ class PDG { static std::string GetPP(std::string function, BasicBlock *bb, int idx) { if (idx == bb->instructions.size()) { - return function + ":" + bb->label + ":term"; + return function + "#" + bb->label + "#term"; } - return function + ":" + bb->label + ":" + std::to_string(idx); + return function + "#" + bb->label + "#" + std::to_string(idx); } static void ProcessControlDependencies(Function *func, std::map> control_dependencies) { @@ -80,14 +80,16 @@ class PDG { static void ProcessDataDependencies(Function *func, std::map> data_dependencies) { for(const auto& [use, definitions]: data_dependencies) { - std::string use_pp = func->name + ":" + use; + std::string use_pp = func->name + "#" + use; + std::replace(use_pp.begin(), use_pp.end(), '.', '#'); if(!pdg.count(use_pp)) { pdg[use_pp] = new PDGNode(use_pp); } for(const auto& definition: definitions) { - std::string definition_pp = func->name + ":" + definition; + std::string definition_pp = func->name + "#" + definition; + std::replace(definition_pp.begin(), definition_pp.end(), '.', '#'); if(!pdg.count(definition_pp)) { pdg[definition_pp] = new PDGNode(definition_pp); @@ -99,6 +101,38 @@ class PDG { } } + /* + * Print PDG + */ + static void PrintPDG() { + for(const auto& [pp, node]: pdg) { + std::cout << "PP: " << pp << std::endl; + std::cout << "DD Pred: "; + for(const auto& pred: node->dd_pred) { + std::cout << pred << " "; + } + std::cout << std::endl; + + std::cout << "DD Succ: "; + for(const auto& succ: node->dd_succ) { + std::cout << succ << " "; + } + std::cout << std::endl; + + std::cout << "CD Pred: "; + for(const auto& pred: node->cd_pred) { + std::cout << pred << " "; + } + std::cout << std::endl; + + std::cout << "CD Succ: "; + for(const auto& succ: node->cd_succ) { + std::cout << succ << " "; + } + std::cout << std::endl; + } + } + }; std::vector SplitPP(std::string pp) { @@ -119,7 +153,7 @@ string PadPP(string pp) { while(cmp[2].size() < 4) { cmp[2].insert(0, "0"); } - string new_pp = cmp[0] + ":" + cmp[1] + ":" + cmp[2]; + string new_pp = cmp[0] + "#" + cmp[1] + "#" + cmp[2]; return new_pp; } @@ -147,56 +181,58 @@ struct order { }; std::set GetSlice(string slice_pp) { - std::set slice = {}; - slice.insert(PadPP(slice_pp)); - - std::queue to_visit; - to_visit.push(slice_pp); - - while(!to_visit.empty()) { - string pp = to_visit.front(); - to_visit.pop(); - - if(pdg.find(pp) != pdg.end()) { - for(const auto& pred: pdg[pp]->dd_pred) { - std::string tmp = PadPP(pred); - if(!slice.count(tmp)) { - to_visit.push(pred); - slice.insert(tmp); + std::cout << "Get Slice for " << slice_pp << std::endl; + std::set slice = {}; + slice.insert(PadPP(slice_pp)); + + std::queue to_visit; + to_visit.push(slice_pp); + + while(!to_visit.empty()) { + string pp = to_visit.front(); + to_visit.pop(); + + std::cout << "Finding pp in pdg: " << pp << std::endl; + if(pdg.find(pp) != pdg.end()) { + for(const auto& pred: pdg[pp]->dd_pred) { + std::string tmp = PadPP(pred); + if(!slice.count(tmp)) { + to_visit.push(pred); + slice.insert(tmp); + } } - } - for(const auto& pred: pdg[pp]->cd_pred) { - std::string tmp = PadPP(pred); - if(!slice.count(tmp)) { - to_visit.push(pred); - slice.insert(tmp); + for(const auto& pred: pdg[pp]->cd_pred) { + std::string tmp = PadPP(pred); + if(!slice.count(tmp)) { + to_visit.push(pred); + slice.insert(tmp); + } + } } - } } - } - return slice; + return slice; } int main(int argc, char const *argv[]) { - if (argc != 4) { - std::cerr << "Usage: program_slicing " << std::endl; + if (argc != 5) { + std::cerr << "Usage: program_slicing " << std::endl; return EXIT_FAILURE; } - std::ifstream f(argv[1]); + std::ifstream f(argv[2]); json lir_json = json::parse(f); - std::string slice_pp = argv[2]; + std::string slice_pp = argv[3]; std::vector pp = SplitPP(slice_pp); std::string func_name = pp[0]; std::string bb_name = pp[1]; std::string idx = pp[2]; std::cout << "Function: " << func_name << " BB: " << bb_name << " Index: " << idx << std::endl; - std::string pointsToFile = argv[3]; + std::string pointsToFile = argv[4]; std::ifstream in(pointsToFile); std::string input_str(std::istreambuf_iterator{in}, {}); @@ -242,14 +278,30 @@ int main(int argc, char const *argv[]) PDG::ProcessDataDependencies(program.funcs[func_name], data_dependencies); + PDG::PrintPDG(); + // Get slice for given program point std::set slice = GetSlice(slice_pp); - std::cout << "Slice: {" << std::endl; + std::cout << "Slice for pp: " << slice_pp << std::endl; + + string curr_bb = ""; for(const auto& pp: slice) { - std::cout << pp << std::endl; + std::vector cmp = SplitPP(pp); + if(cmp[1] != curr_bb) { + if(curr_bb != "") { + std::cout << std::endl; + } + curr_bb = cmp[1]; + std::cout << curr_bb << ":" << std::endl; + } + BasicBlock *bb_ptr = program.funcs[cmp[0]]->bbs[curr_bb]; + if (cmp[2] == "term") { + std::cout << bb_ptr->terminal->ToString() << std::endl; + } else { + std::cout << bb_ptr->instructions[std::stoi(cmp[2])]->ToString() << std::endl; + } } - std::cout << "}" << std::endl; std::cout << std::endl; return 0; diff --git a/run-slice.sh b/run-slice.sh index 2523d61..42803e8 100644 --- a/run-slice.sh +++ b/run-slice.sh @@ -1,3 +1,3 @@ #!/bin/bash -./program-slicing "$1" "$2" "$3" "$4" \ No newline at end of file +./program-slicing "$1" "$2" "$3" "$4" "$5" \ No newline at end of file