Coverage Report

Created: 2023-10-30 17:15

/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