Coverage Report

Created: 2023-10-30 17:15

/builds/2mk6rsew/0/parcoach/parcoach/src/aSSA/CollListFunctionAnalysis.cpp
Line
Count
Source
1
#include "parcoach/CollListFunctionAnalysis.h"
2
3
#include "parcoach/CollectiveList.h"
4
#include "parcoach/DepGraphDCF.h"
5
#include "parcoach/MPICommAnalysis.h"
6
#include "parcoach/Options.h"
7
8
#include "PTACallGraph.h"
9
#include "Utils.h"
10
11
#include "llvm/ADT/SCCIterator.h"
12
#include "llvm/IR/InstIterator.h"
13
14
#define DEBUG_TYPE "coll-list-func"
15
16
using namespace llvm;
17
18
namespace parcoach {
19
namespace {
20
21
struct CollListCFGVisitor : CFGVisitor<CollListCFGVisitor> {
22
  using CFGVisitor::CFGVisitor;
23
  CollListCFGVisitor(ModuleAnalysisManager &AM, PTACallGraph const &CG,
24
                     SmallPtrSetImpl<Value *> const &Comms)
25
1.76k
      : CFGVisitor(AM), PTACG(CG), Communicators(Comms){};
26
  PTACallGraph const &PTACG;
27
  SmallPtrSetImpl<Value *> const &Communicators;
28
  CollectiveList::CommToBBToCollListMap CollListsPerComm;
29
30
  template <typename SuccessorsRange>
31
  CollectiveList compute(CollectiveList::BBToCollListMap &Lists,
32
                         SuccessorsRange Successors, BasicBlock *BB,
33
14.6k
                         bool IsLoopHeader, Value *Comm) {
34
14.6k
    bool IsNAVS = CollectiveList::NeighborsAreNAVS(
35
14.6k
        Lists, BB, Successors.begin(), Successors.end());
36
14.6k
    LLVM_DEBUG(dbgs() << "NAVS computed from succ: " << IsNAVS << "\n");
37
14.6k
    CollectiveList Current{};
38
39
14.6k
    if (IsLoopHeader) {
40
459
      if (IsNAVS) {
41
2
        Current.extendWith<NavsElement>();
42
457
      } else {
43
        // Push the original loop coll set
44
457
        Current.extendWith(Lists[BB]);
45
457
      }
46
14.2k
    } else {
47
14.2k
      Current = CollectiveList::CreateFromBB(Lists, PTACG, IsNAVS, *BB, Comm);
48
14.2k
    }
49
50
14.6k
    LLVM_DEBUG(dbgs() << "Current CollectiveList: " << Current.toString()
51
14.6k
                      << "\n");
52
53
14.6k
    if (!IsNAVS) {
54
      // If we're looking at the exit node it doesn't have any successor.
55
13.9k
      if (!empty(Successors)) {
56
11.9k
        assert(Lists.count(*Successors.begin()) &&
57
11.9k
               "Successor should have been computed already.");
58
11.9k
        CollectiveList const &SuccSet = Lists[*Successors.begin()];
59
11.9k
        Current.extendWith(SuccSet);
60
11.9k
      }
61
13.9k
    }
62
14.6k
    return Current;
63
14.6k
  }
CollListFunctionAnalysis.cpp:_ZN8parcoach12_GLOBAL__N_118CollListCFGVisitor7computeIN4llvm14iterator_rangeIPKPNS3_10BasicBlockEEEEENS_14CollectiveListERNS3_8DenseMapIS6_SA_NS3_12DenseMapInfoIS6_vEENS3_6detail12DenseMapPairIS6_SA_EEEET_S6_bPNS3_5ValueE
Line
Count
Source
33
459
                         bool IsLoopHeader, Value *Comm) {
34
459
    bool IsNAVS = CollectiveList::NeighborsAreNAVS(
35
459
        Lists, BB, Successors.begin(), Successors.end());
36
459
    LLVM_DEBUG(dbgs() << "NAVS computed from succ: " << IsNAVS << "\n");
37
459
    CollectiveList Current{};
38
39
459
    if (IsLoopHeader) {
40
459
      if (IsNAVS) {
41
2
        Current.extendWith<NavsElement>();
42
457
      } else {
43
        // Push the original loop coll set
44
457
        Current.extendWith(Lists[BB]);
45
457
      }
46
459
    } else {
47
0
      Current = CollectiveList::CreateFromBB(Lists, PTACG, IsNAVS, *BB, Comm);
48
0
    }
49
50
459
    LLVM_DEBUG(dbgs() << "Current CollectiveList: " << Current.toString()
51
459
                      << "\n");
52
53
459
    if (!IsNAVS) {
54
      // If we're looking at the exit node it doesn't have any successor.
55
457
      if (!empty(Successors)) {
56
457
        assert(Lists.count(*Successors.begin()) &&
57
457
               "Successor should have been computed already.");
58
457
        CollectiveList const &SuccSet = Lists[*Successors.begin()];
59
457
        Current.extendWith(SuccSet);
60
457
      }
61
457
    }
62
459
    return Current;
63
459
  }
CollListFunctionAnalysis.cpp:_ZN8parcoach12_GLOBAL__N_118CollListCFGVisitor7computeIN4llvm14iterator_rangeINS3_12SuccIteratorINS3_11InstructionENS3_10BasicBlockEEEEEEENS_14CollectiveListERNS3_8DenseMapIPS7_SA_NS3_12DenseMapInfoISC_vEENS3_6detail12DenseMapPairISC_SA_EEEET_SC_bPNS3_5ValueE
Line
Count
Source
33
14.2k
                         bool IsLoopHeader, Value *Comm) {
34
14.2k
    bool IsNAVS = CollectiveList::NeighborsAreNAVS(
35
14.2k
        Lists, BB, Successors.begin(), Successors.end());
36
14.2k
    LLVM_DEBUG(dbgs() << "NAVS computed from succ: " << IsNAVS << "\n");
37
14.2k
    CollectiveList Current{};
38
39
14.2k
    if (IsLoopHeader) {
40
0
      if (IsNAVS) {
41
0
        Current.extendWith<NavsElement>();
42
0
      } else {
43
        // Push the original loop coll set
44
0
        Current.extendWith(Lists[BB]);
45
0
      }
46
14.2k
    } else {
47
14.2k
      Current = CollectiveList::CreateFromBB(Lists, PTACG, IsNAVS, *BB, Comm);
48
14.2k
    }
49
50
14.2k
    LLVM_DEBUG(dbgs() << "Current CollectiveList: " << Current.toString()
51
14.2k
                      << "\n");
52
53
14.2k
    if (!IsNAVS) {
54
      // If we're looking at the exit node it doesn't have any successor.
55
13.4k
      if (!empty(Successors)) {
56
11.5k
        assert(Lists.count(*Successors.begin()) &&
57
11.5k
               "Successor should have been computed already.");
58
11.5k
        CollectiveList const &SuccSet = Lists[*Successors.begin()];
59
11.5k
        Current.extendWith(SuccSet);
60
11.5k
      }
61
13.4k
    }
62
14.2k
    return Current;
63
14.2k
  }
64
65
  void visitBB(BasicBlock *BB,
66
14.1k
               LoopAggretationInfo const *LoopAnalysisResult = nullptr) {
67
14.1k
    LLVM_DEBUG({
68
14.1k
      dbgs() << "CFGVisitor::visitBB::";
69
14.1k
      if (LoopAnalysisResult) {
70
14.1k
        dbgs() << "header::";
71
14.1k
      }
72
14.1k
      BB->printAsOperand(dbgs());
73
14.1k
      dbgs() << "\n";
74
14.1k
    });
75
14.6k
    for (Value *Comm : Communicators) {
76
14.6k
      auto &Lists = CollListsPerComm[Comm];
77
14.6k
      CollectiveList Current;
78
14.6k
      if (LoopAnalysisResult) {
79
459
        assert(Lists[BB].getLoopHeader() &&
80
459
               "Visiting header which is not a loop?!");
81
459
        auto const &Successors =
82
459
            LoopAnalysisResult->LoopHeaderToSuccessors.find(BB)->second;
83
459
        Lists[BB] =
84
459
            compute(Lists, make_range(Successors.begin(), Successors.end()), BB,
85
459
                    true, Comm);
86
14.2k
      } else {
87
14.2k
        Lists[BB] = compute(Lists, successors(BB), BB, false, Comm);
88
14.2k
      }
89
14.6k
    }
90
14.1k
  }
91
92
1.82k
  void Visit(Function &F, LoopCFGInfo const &LoopAnalysisResult) {
93
1.82k
    for (auto const &[Comm, Lists] : LoopAnalysisResult.CommToBBToCollList) {
94
1.43k
      for (auto const &[BB, Colls] : Lists) {
95
1.43k
        CollListsPerComm[Comm].insert({BB, Colls});
96
1.43k
      }
97
427
    }
98
1.82k
    CFGVisitor::Visit(F, LoopAnalysisResult.LAI);
99
1.82k
    LLVM_DEBUG({
100
1.82k
      dbgs() << "CollLists per communicator at end of function:\n";
101
1.82k
      for (auto const &[Comm, Lists] : CollListsPerComm) {
102
1.82k
        dbgs() << "comm:";
103
1.82k
        Comm->print(dbgs());
104
1.82k
        dbgs() << "\n";
105
1.82k
        for (auto const &[BB, Set] : Lists) {
106
1.82k
          BB->printAsOperand(dbgs());
107
1.82k
          dbgs() << ": " << Set.toString() << "\n";
108
1.82k
        }
109
1.82k
        dbgs() << "-----\n";
110
1.82k
      }
111
1.82k
    });
112
1.82k
  }
113
};
114
115
void checkWarnings(
116
    Function &F, CollectiveList::CommToBBToCollListMap const &CollListsPerComm,
117
    DepGraphDCF const &DG, WarningCollection &Warnings,
118
1.82k
    FunctionAnalysisManager &FAM, bool EmitDotDG) {
119
1.82k
  llvm::LoopInfo &LI = FAM.getResult<llvm::LoopAnalysis>(F);
120
188k
  auto IsaDirectCallToCollective = [](Instruction const &I) {
121
188k
    if (CallInst const *CI = dyn_cast<CallInst>(&I)) {
122
53.8k
      Function const *F = CI->getCalledFunction();
123
53.8k
      if (F) {
124
53.8k
        return Collective::isCollective(*F);
125
53.8k
      }
126
53.8k
    }
127
134k
    return false;
128
188k
  };
129
1.82k
  auto Candidates =
130
1.82k
      make_filter_range(instructions(F), IsaDirectCallToCollective);
131
6.87k
  for (Instruction &I : Candidates) {
132
6.87k
    CallInst &CI = cast<CallInst>(I);
133
6.87k
    Function &F = *CI.getCalledFunction();
134
6.87k
    Collective const *Coll = Collective::find(F);
135
6.87k
    assert(Coll && "Coll expected to be not null because of filter");
136
    // Get conditionals from the callsite
137
6.87k
    std::set<BasicBlock const *> CallIpdf;
138
6.87k
    DG.getCallInterIPDF(&CI, CallIpdf);
139
6.87k
    LLVM_DEBUG(dbgs() << "Call to " << Coll->Name << "\n");
140
6.87k
    LLVM_DEBUG(dbgs() << "callIPDF size: " << CallIpdf.size() << "\n");
141
6.87k
    Value *CommForCollective{};
142
143
6.87k
    if (auto const *MPIColl = dyn_cast<MPICollective>(Coll)) {
144
6.85k
      CommForCollective = MPIColl->getCommunicator(CI);
145
6.85k
    }
146
147
6.87k
    Warning::ConditionalsContainerTy Conditionals;
148
6.87k
    for (BasicBlock const *BB : CallIpdf) {
149
4.95k
      LLVM_DEBUG({
150
4.95k
        BB->printAsOperand(dbgs());
151
4.95k
        dbgs() << " is on path\n";
152
4.95k
      });
153
4.95k
      Loop const *L = LI[BB];
154
      // Is this node detected as potentially dangerous by parcoach?
155
4.95k
      bool HasNAVS = false;
156
4.95k
      for (auto const &[Comm, Lists] : CollListsPerComm) {
157
        // At this point:
158
        //   - we have a non-null comm, we'll use it for colllists
159
        //   - we have a null comm: either it's for non-mpi collectives, or
160
        //   it's a mpi finalize, in both cases we want to check colllists for
161
        //   all communicators.
162
4.95k
        if (!CommForCollective || Comm == CommForCollective) {
163
4.95k
          CollectiveList const &CL =
164
4.95k
              L ? Lists.find(L->getHeader())->second : Lists.find(BB)->second;
165
4.95k
          LLVM_DEBUG(dbgs() << "CL for BB on IPDF: " << CL.toString() << "\n");
166
4.95k
          HasNAVS |= CL.navs();
167
4.95k
        }
168
4.95k
      }
169
170
4.95k
      if (!HasNAVS) {
171
2.37k
        continue;
172
2.37k
      }
173
174
      // Is this condition tainted?
175
2.57k
      Value const *Cond = getBasicBlockCond(BB);
176
177
2.57k
      if (!Cond || !DG.isTaintedValue(Cond)) {
178
96
        LLVM_DEBUG(dbgs() << "Not tainted\n");
179
96
        continue;
180
96
      }
181
182
2.47k
      DebugLoc BDLoc = (BB->getTerminator())->getDebugLoc();
183
2.47k
      Instruction const *Inst = BB->getTerminator();
184
2.47k
      DebugLoc Loc = Inst->getDebugLoc();
185
2.47k
      Conditionals.push_back(Loc);
186
187
2.47k
      if (EmitDotDG) {
188
1
        std::string Dotfilename("taintedpath-");
189
1
        std::string Filename = Loc->getFilename().str();
190
1
        size_t LastposSlash = Filename.find_last_of('/');
191
1
        if (LastposSlash != std::string::npos) {
192
1
          Filename = Filename.substr(LastposSlash + 1, Filename.size());
193
1
        }
194
1
        Dotfilename.append(Filename).append("-");
195
1
        Dotfilename.append(std::to_string(Loc.getLine())).append(".dot");
196
1
        DG.dotTaintPath(Cond, Dotfilename, &CI);
197
1
      }
198
2.47k
    } // END FOR
199
200
6.87k
    if (Conditionals.empty()) {
201
4.45k
      continue;
202
4.45k
    }
203
2.41k
    Warnings.insert(
204
2.41k
        {&CI, Warning(F, CI.getDebugLoc(), std::move(Conditionals))});
205
2.41k
  }
206
1.82k
}
207
} // namespace
208
209
llvm::AnalysisKey CollListFunctionAnalysis::Key;
210
llvm::AnalysisKey CollectiveAnalysis::Key;
211
212
CollectiveAnalysis::Result
213
CollectiveAnalysis::run(llvm::Module &M,
214
1.76k
                        llvm::ModuleAnalysisManager &AM) const {
215
1.76k
  TimeTraceScope TTS("ParcoachCollectiveAnalysis");
216
1.76k
  PTACallGraph const &PTACG = *AM.getResult<PTACallGraphAnalysis>(M);
217
1.76k
  auto &DG = AM.getResult<DepGraphDCFAnalysis>(M);
218
1.76k
  auto &BBToCollList = AM.getResult<CollListFunctionAnalysis>(M);
219
1.76k
  auto &FAM = AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
220
1.76k
  WarningCollection Result;
221
1.76k
  scc_iterator<PTACallGraph const *> CgSccIter = scc_begin(&PTACG);
222
25.1k
  while (!CgSccIter.isAtEnd()) {
223
23.3k
    auto const &NodeVec = *CgSccIter;
224
23.3k
    for (PTACallGraphNode const *Node : NodeVec) {
225
23.3k
      Function *F = Node->getFunction();
226
23.3k
      if (!F || F->isDeclaration() || !PTACG.isReachableFromEntry(*F)) {
227
21.5k
        continue;
228
21.5k
      }
229
1.82k
      checkWarnings(*F, *BBToCollList, *DG, Result, FAM, EmitDotDG_);
230
1.82k
    }
231
23.3k
    ++CgSccIter;
232
23.3k
  }
233
1.76k
  return std::make_unique<WarningCollection>(std::move(Result));
234
1.76k
}
235
236
CollListFunctionAnalysis::Result
237
CollListFunctionAnalysis::run(llvm::Module &M,
238
1.76k
                              llvm::ModuleAnalysisManager &AM) {
239
1.76k
  TimeTraceScope TTS("CollListFunctionAnalysis");
240
1.76k
  auto const &Res = AM.getResult<PTACallGraphAnalysis>(M);
241
1.76k
  PTACallGraph const &PTACG = *Res;
242
1.76k
  auto &FAM = AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
243
1.76k
  scc_iterator<PTACallGraph const *> CgSccIter = scc_begin(&PTACG);
244
1.76k
  auto Comms = AM.getResult<MPICommAnalysis>(M);
245
1.76k
  if (Comms.empty()) {
246
    // We're likely checking collectives other than MPI, insert a null comm.
247
246
    Comms.insert(nullptr);
248
246
  }
249
1.76k
  CollListCFGVisitor Visitor(AM, PTACG, Comms);
250
  // This loop "analysis" actually uses the PTACG to build collective list
251
  // for indirect calls!
252
1.76k
  CollListLoopAnalysis LoopAnalysis(PTACG, Comms);
253
25.1k
  while (!CgSccIter.isAtEnd()) {
254
23.3k
    auto const &NodeVec = *CgSccIter;
255
23.3k
    for (PTACallGraphNode const *Node : NodeVec) {
256
23.3k
      Function *F = Node->getFunction();
257
23.3k
      if (!F || F->isDeclaration() || !PTACG.isReachableFromEntry(*F)) {
258
21.5k
        continue;
259
21.5k
      }
260
      // FIXME: we should definitely share the visitor's BBToCollList with the
261
      // loop analysis!
262
1.82k
      LoopCFGInfo Info = LoopAnalysis.run(*F, FAM);
263
1.82k
      LLVM_DEBUG({
264
1.82k
        dbgs() << "LoopCFGInfo for " << F->getName() << ":\n";
265
1.82k
        Info.dump();
266
1.82k
      });
267
1.82k
      Visitor.Visit(*F, Info);
268
1.82k
    }
269
23.3k
    ++CgSccIter;
270
23.3k
  }
271
1.76k
  return std::make_unique<CollectiveList::CommToBBToCollListMap>(
272
1.76k
      std::move(Visitor.CollListsPerComm));
273
1.76k
}
274
} // namespace parcoach