/builds/2mk6rsew/0/parcoach/parcoach/src/aSSA/Instrumentation.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | #include "Instrumentation.h" |
2 | | |
3 | | #include "parcoach/CollListFunctionAnalysis.h" |
4 | | #include "parcoach/Collectives.h" |
5 | | #include "parcoach/Passes.h" |
6 | | |
7 | | #include "llvm/IR/DebugInfo.h" |
8 | | #include "llvm/IR/IRBuilder.h" |
9 | | #include "llvm/IR/InstIterator.h" |
10 | | |
11 | | #define DEBUG_TYPE "instrumentation" |
12 | | |
13 | | namespace parcoach { |
14 | | |
15 | | using namespace llvm; |
16 | | |
17 | | namespace { |
18 | | |
19 | 17 | std::string getCheckFunctionName(Collective const *C) { |
20 | 17 | if (C == nullptr) { |
21 | 4 | return "check_collective_return"; |
22 | 4 | } |
23 | 13 | if (isa<MPICollective>(C)) { |
24 | 12 | return "check_collective_MPI"; |
25 | 12 | #ifdef PARCOACH_ENABLE_OPENMP |
26 | 12 | } |
27 | 1 | if (isa<OMPCollective>(C)) { |
28 | 1 | return "check_collective_OMP"; |
29 | 1 | #endif |
30 | | #ifdef PARCOACH_ENABLE_UPC |
31 | | } else if (isa<UPCCollective>(C)) { |
32 | | return "check_collective_UPC"; |
33 | | #endif |
34 | 1 | } |
35 | 1 | llvm_unreachable("unhandled collective type"); |
36 | 1 | } |
37 | | |
38 | | // Check Collective function before a collective |
39 | | // + Check Collective function before return statements |
40 | | // --> check_collective_MPI(int OP_color, const char* OP_name, int OP_line, |
41 | | // char* OP_warnings, char *FILE_name) |
42 | | // --> void check_collective_UPC(int OP_color, const char* OP_name, |
43 | | // int OP_line, char* warnings, char *FILE_name) |
44 | | void insertCC(Instruction *I, Collective const *C, Function const &F, |
45 | 17 | int OpLine, llvm::StringRef WarningMsg, llvm::StringRef File) { |
46 | 17 | Module &M = *I->getModule(); |
47 | 17 | IRBuilder<> Builder(I); |
48 | 17 | IntegerType *I32Ty = Builder.getInt32Ty(); |
49 | 17 | PointerType *I8PtrTy = Builder.getInt8PtrTy(); |
50 | | // Arguments of the new function |
51 | 17 | unsigned constexpr NParams = 5; |
52 | 17 | std::array<Type *, NParams> Params{ |
53 | 17 | I32Ty, // OP_color |
54 | 17 | I8PtrTy, // OP_name |
55 | 17 | I32Ty, // OP_line |
56 | 17 | I8PtrTy, // OP_warnings |
57 | 17 | I8PtrTy, // FILE_name |
58 | 17 | }; |
59 | 17 | Value *StrPtrName = Builder.CreateGlobalStringPtr(F.getName()); |
60 | 17 | Value *StrPtrWarnings = Builder.CreateGlobalStringPtr(WarningMsg); |
61 | 17 | Value *StrPtrFilename = Builder.CreateGlobalStringPtr(File); |
62 | | // Set new function name, type and arguments |
63 | 17 | FunctionType *FTy = FunctionType::get(Builder.getVoidTy(), Params, false); |
64 | 17 | int OpColor = C != nullptr ? (int)C->K : (int)Collective::Kind::C_Last; |
65 | 17 | std::array<Value *, NParams> CallArgs = { |
66 | 17 | ConstantInt::get(I32Ty, OpColor), StrPtrName, |
67 | 17 | ConstantInt::get(I32Ty, OpLine), StrPtrWarnings, StrPtrFilename}; |
68 | 17 | std::string FunctionName = getCheckFunctionName(C); |
69 | | |
70 | 17 | FunctionCallee CCFunction = M.getOrInsertFunction(FunctionName, FTy); |
71 | | |
72 | | // Create new function |
73 | 17 | CallInst::Create(CCFunction, CallArgs, "", I); |
74 | 17 | LLVM_DEBUG(dbgs() << "=> Insertion of " << FunctionName << " (" << OpColor |
75 | 17 | << ", " << F.getName() << ", " << OpLine << ", " |
76 | 17 | << WarningMsg << ", " << File << ")\n"); |
77 | 17 | } |
78 | | } // namespace |
79 | | |
80 | | CollectiveInstrumentation::CollectiveInstrumentation( |
81 | | WarningCollection const &Warnings) |
82 | 5 | : Warnings(Warnings) {} |
83 | | |
84 | 53 | bool CollectiveInstrumentation::run(Function &F) { |
85 | 53 | TimeTraceScope TTS("CollectiveInstrumentation", F.getName()); |
86 | 53 | bool Changed = false; |
87 | 275 | auto IsaDirectCall = [](Instruction const &I) { |
88 | 275 | if (CallInst const *CI = dyn_cast<CallInst>(&I)) { |
89 | 119 | Function const *F = CI->getCalledFunction(); |
90 | 119 | return (bool)F; |
91 | 119 | } |
92 | 156 | return false; |
93 | 275 | }; |
94 | 53 | auto Candidates = make_filter_range(instructions(F), IsaDirectCall); |
95 | 119 | for (Instruction &I : Candidates) { |
96 | 119 | CallInst &CI = cast<CallInst>(I); |
97 | 119 | std::string WarningStr = " "; |
98 | 119 | auto It = Warnings.find(&CI); |
99 | 119 | if (It != Warnings.end()) { |
100 | 8 | WarningStr = It->second.toString(); |
101 | 8 | } |
102 | | |
103 | | // Debug info (line in the source code, file) |
104 | 119 | DebugLoc DLoc = CI.getDebugLoc(); |
105 | 119 | std::string File = "o"; |
106 | 119 | int OpLine = -1; |
107 | 119 | if (DLoc) { |
108 | 119 | OpLine = DLoc.getLine(); |
109 | 119 | File = DLoc->getFilename().str(); |
110 | 119 | } |
111 | | // call instruction |
112 | 119 | Function *Callee = CI.getCalledFunction(); |
113 | 119 | assert(Callee && "Callee expected to be not null"); |
114 | 119 | auto const *Coll = Collective::find(*Callee); |
115 | 119 | StringRef CalleeName = Callee->getName(); |
116 | | |
117 | | // Before finalize or exit/abort |
118 | 119 | if (CalleeName == "MPI_Finalize" || CalleeName == "MPI_Abort" || |
119 | 119 | CalleeName == "abort") { |
120 | 4 | LLVM_DEBUG(dbgs() << "-> insert check before " << CalleeName << " line " |
121 | 4 | << OpLine << "\n"); |
122 | 4 | insertCC(&CI, nullptr, *Callee, OpLine, WarningStr, File); |
123 | 4 | Changed = true; |
124 | 4 | continue; |
125 | 4 | } |
126 | 115 | if (Coll != nullptr) { |
127 | | // Before a collective |
128 | 13 | LLVM_DEBUG(dbgs() << "-> insert check before " << CalleeName << " line " |
129 | 13 | << OpLine << "\n"); |
130 | 13 | insertCC(&CI, Coll, *Callee, OpLine, WarningStr, File); |
131 | 13 | Changed = true; |
132 | 13 | } |
133 | 115 | } // END FOR |
134 | 53 | return Changed; |
135 | 53 | } |
136 | | |
137 | | PreservedAnalyses |
138 | | ParcoachInstrumentationPass::run(llvm::Module &M, |
139 | 5 | llvm::ModuleAnalysisManager &AM) { |
140 | 5 | TimeTraceScope TTS("CollectiveInstrumentation"); |
141 | 5 | auto const &Warnings = AM.getResult<CollectiveAnalysis>(M); |
142 | 5 | if (Warnings->empty()) { |
143 | 0 | LLVM_DEBUG(dbgs() << "Skipping instrumentation: no warnings detected."); |
144 | 0 | return PreservedAnalyses::all(); |
145 | 0 | } |
146 | 5 | parcoach::CollectiveInstrumentation Instrum(*Warnings); |
147 | 5 | LLVM_DEBUG( |
148 | 5 | dbgs() |
149 | 5 | << "\033[0;35m=> Static instrumentation of the code ...\033[0;0m\n"); |
150 | 53 | for (Function &F : M) { |
151 | 53 | Instrum.run(F); |
152 | 53 | } |
153 | 5 | return PreservedAnalyses::all(); |
154 | 5 | } |
155 | | |
156 | | } // namespace parcoach |