Skip to content

Commit 42e23f1

Browse files
committed
Merged in openmp (pull request #20)
Initial implementation of Openmp-based parallelization and analysis server. Approved-by: Nikita <[email protected]>
2 parents 6c7be07 + ae0f9ed commit 42e23f1

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+3060
-133
lines changed

include/tsar/ADT/Bimap.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -453,10 +453,10 @@ class Bimap {
453453
/// \return Iterator following the removed element.
454454
iterator erase(iterator I) {
455455
assert(I != end() && "Iterator must refer element in the container!");
456-
auto Node = const_cast<pointer>(*I);
456+
auto *Node = const_cast<BimapNode *>(&*I.mCurItr);
457457
mFirstToSecond.erase(Node);
458458
mSecondToFirst.erase(Node);
459-
return mColl.erase(Node);
459+
return InternalItrC(mColl.erase(Node));
460460
}
461461

462462
/// \brief Removes the elements in the range [I; EI), which must be

include/tsar/APC/APCContext.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
#ifndef TSAR_APC_CONTEXT_H
2727
#define TSAR_APC_CONTEXT_H
2828

29-
#include "tsar/Analysis/AnalysisWrapperPass.h"
29+
#include "tsar/Support/AnalysisWrapperPass.h"
3030
#include "tsar/Support/Tags.h"
3131
#include <apc/apc-config.h>
3232
#include <bcl/utility.h>
Lines changed: 349 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,349 @@
1+
//===--- AnalysisServer.h ------ Analysis Server ----------------*- C++ -*-===//
2+
//
3+
// Traits Static Analyzer (SAPFOR)
4+
//
5+
// Copyright 2019 DVM System Group
6+
//
7+
// Licensed under the Apache License, Version 2.0 (the "License");
8+
// you may not use this file except in compliance with the License.
9+
// You may obtain a copy of the License at
10+
//
11+
// http://www.apache.org/licenses/LICENSE-2.0
12+
//
13+
// Unless required by applicable law or agreed to in writing, software
14+
// distributed under the License is distributed on an "AS IS" BASIS,
15+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
// See the License for the specific language governing permissions and
17+
// limitations under the License.
18+
//
19+
//===----------------------------------------------------------------------===//
20+
//
21+
// This file implements base representation of analysis server and a server pass
22+
// which could be used to send response.
23+
//
24+
// There are following steps to create and run server.
25+
// (1) Inherit AnalysisServer class and override virtual methods. The last pass
26+
// executed on the server notifies the client that connection can be closed.
27+
// So, before this pass all shared data should be freed, for example all
28+
// handles should be destroyed to avoid undefined behavior.
29+
// (2) On client:
30+
// (a) create socket (createAnalysisSocketImmutableStorage()),
31+
// (b) create server pass inherited from AnalysisServer to run server,
32+
// (c) wait notification from server (createAnalysisWaitServerPass()),
33+
// (d) after notification server is initialized and client may change
34+
// original module,
35+
// (e) use socket (getAnalysis<AnalsysisSocketImmutableWrapper>) to access
36+
// results of analysis in server (Socket->getAnalysis<...>(...)).
37+
// It is possible to use provider on server at this moment:
38+
// - use Socket->getAnalysis<...>() to get necessary passes to
39+
// initialize provider,
40+
// - initialize provider (in general way),
41+
// - use Socket->getAnalysis<...>(F) to access passes from provider.
42+
// This function looks up for an appropriate provider which contains
43+
// all required passes and returns related analysis results. It is
44+
// also possible to access provider explicitly
45+
// Socket->getAnalysis<...>(F).
46+
// (f) notify server that all analysis requests have been received
47+
// (createAnalysisReleaseServerPass()),
48+
// (g) close connection (createAnalysisCloseConnectionPass()). Client will
49+
// be blocked until server confirms that connection can be closed.
50+
//
51+
//===----------------------------------------------------------------------===//
52+
53+
#ifndef TSAR_ANALYSIS_SERVER_H
54+
#define TSAR_ANALYSIS_SERVER_H
55+
56+
#include "tsar/Analysis/AnalysisSocket.h"
57+
#include "tsar/Analysis/Passes.h"
58+
#include "tsar/Support/AnalysisWrapperPass.h"
59+
#include "tsar/Support/PassProvider.h"
60+
#include <bcl/IntrusiveConnection.h>
61+
#include <bcl/cell.h>
62+
#include <bcl/utility.h>
63+
#include <llvm/ADT/SmallVector.h>
64+
#include <llvm/ADT/STLExtras.h>
65+
#include <llvm/IR/LegacyPassManager.h>
66+
#include <llvm/Pass.h>
67+
#include <llvm/Transforms/Utils/Cloning.h>
68+
#include <type_traits>
69+
70+
namespace llvm {
71+
/// Initialize a wrapper pass to access mapping from a client module to
72+
/// a server module.
73+
void initializeAnalysisClientServerMatcherWrapperPass(PassRegistry &Registry);
74+
75+
/// Create a wrapper pass to access mapping from a client module to
76+
/// a server module.
77+
ImmutablePass *
78+
createAnalysisClientServerMatcherWrapper(ValueToValueMapTy &OriginalToClone);
79+
80+
/// Wrapper pass to access mapping from a client module to a server module.
81+
using AnalysisClientServerMatcherWrapper =
82+
AnalysisWrapperPass<ValueToValueMapTy>;
83+
84+
/// Abstract class which implement analysis server base.
85+
///
86+
/// Note, that server analyzes a copy of the original module.
87+
/// This pass run analysis server and prepares to clone module
88+
/// (prepareToClone()), then this pass performs server initialization
89+
/// (initializeServer()), then server passes are invoked (addServerPasses()).
90+
/// After initialization the server notifies client (AnalysisNotifyClientPass),
91+
/// so client should wait for this notification (AnalysisWaitServerPass) before
92+
/// further analysis of the original module.
93+
class AnalysisServer : public ModulePass, private bcl::Uncopyable {
94+
public:
95+
explicit AnalysisServer(char &ID) : ModulePass(ID) {}
96+
97+
/// Run server.
98+
bool runOnModule(Module &M) override {
99+
auto &Socket = getAnalysis<AnalysisSocketImmutableWrapper>().get();
100+
bcl::IntrusiveConnection::connect(
101+
&Socket, tsar::AnalysisSocket::Delimiter,
102+
[this, &M](bcl::IntrusiveConnection C) {
103+
ValueToValueMapTy CloneMap;
104+
prepareToClone(M, CloneMap);
105+
auto CloneM = CloneModule(M, CloneMap);
106+
legacy::PassManager PM;
107+
PM.add(createAnalysisConnectionImmutableWrapper(C));
108+
PM.add(createAnalysisClientServerMatcherWrapper(CloneMap));
109+
initializeServer(M, *CloneM, CloneMap, PM);
110+
PM.add(createAnalysisNotifyClientPass());
111+
addServerPasses(*CloneM, PM);
112+
prepareToClose(PM);
113+
PM.add(createAnalysisNotifyClientPass());
114+
PM.run(*CloneM);
115+
});
116+
return false;
117+
}
118+
119+
/// Override this function if additional passes required to initialize server
120+
/// (see initializeServer()).
121+
void getAnalysisUsage(AnalysisUsage &AU) const override {
122+
AU.addRequired<AnalysisSocketImmutableWrapper>();
123+
AU.setPreservesAll();
124+
}
125+
126+
/// Prepare to clone a specified module.
127+
///
128+
/// For example, manual mapping of metadata could be inserted to
129+
/// `ClientToServer` map (by default global metadata variables and some of
130+
/// local variables are not cloned). This leads to implicit references to
131+
/// the original module. For example, traverse of MetadataAsValue for the
132+
/// mentioned variables visits DbgInfo intrinsics in both modules (clone and
133+
/// origin).
134+
virtual void prepareToClone(Module &ClientM,
135+
ValueToValueMapTy &ClientToServer) = 0;
136+
137+
/// Initialize server.
138+
///
139+
/// The server processes a copy `ServerM` of original module `ClientM`.
140+
/// Correspondence between values of these modules is established in
141+
/// `ClientToServer` map. If some initialization passes must be run on server,
142+
/// add these passes to the server pass manager `PM`.
143+
virtual void initializeServer(Module &ClientM, Module &ServerM,
144+
ValueToValueMapTy &ClientToServer,
145+
legacy::PassManager &PM) = 0;
146+
147+
/// Add passes to execute on server and to process requests from client.
148+
///
149+
/// Note, AnalysisResponsePass<...> template could be used to process
150+
/// requests in simple cases.
151+
virtual void addServerPasses(Module &ServerM, legacy::PassManager &PM) = 0;
152+
153+
/// Add passes to execute until connection is not closed, for example
154+
/// shared data are freed.
155+
virtual void prepareToClose(legacy::PassManager & PM) = 0;
156+
};
157+
158+
/// This pass waits for requests from client and send responses from server.
159+
///
160+
/// This pass should be run on server (use AnalysisServer::addServerPasses).
161+
/// List of types ResponseT... specifies passes which may be interested for
162+
/// a client.
163+
template <class... ResponseT>
164+
class AnalysisResponsePass : public ModulePass, private bcl::Uncopyable {
165+
166+
struct AddRequiredFunctor {
167+
AddRequiredFunctor(llvm::AnalysisUsage &AU) : mAU(AU) {}
168+
template <class AnalysisType> void operator()() {
169+
mAU.addRequired<typename std::remove_pointer<AnalysisType>::type>();
170+
}
171+
172+
private:
173+
llvm::AnalysisUsage &mAU;
174+
};
175+
176+
/// Look up for analysis with a specified ID in a list of analysis.
177+
///
178+
/// Set `Exists` to true if analysis is found.
179+
struct FindAnalysis {
180+
template <class T> void operator()() { Exist |= (ID == &T::ID); }
181+
AnalysisID ID;
182+
bool &Exist;
183+
};
184+
185+
/// List of analysis results (ID to Analysis).
186+
using AnalysisCache =
187+
llvm::SmallVector<std::pair<llvm::AnalysisID, void *>, 8>;
188+
189+
/// Get all available analysis from a specified provider and store their
190+
/// into a specified cache.
191+
template <class ProviderT> struct GetAllFromProvider {
192+
template <class T> void operator()() {
193+
auto &P = Provider.template get<T>();
194+
Cache.emplace_back(&T::ID, static_cast<void *>(&P));
195+
}
196+
ProviderT &Provider;
197+
AnalysisCache &Cache;
198+
};
199+
200+
/// This functor looks up for a provider which allows to access required
201+
/// analysis mentioned in AnalysisRequest.
202+
///
203+
/// If provider is found results of required analysis will be stored in
204+
/// analysis response.
205+
struct FindProvider {
206+
/// Perform search while response is empty.
207+
template <class T> void operator()() {
208+
if (Response[tsar::AnalysisResponse::Analysis].empty())
209+
processAsProvider<T>(tsar::is_pass_provider<T>());
210+
}
211+
212+
/// Process `T` as a provider.
213+
template <class T> void processAsProvider(std::true_type) {
214+
bool ExistInProvider = true;
215+
for (auto &ID : Request[tsar::AnalysisRequest::AnalysisIDs]) {
216+
bool E = false;
217+
tsar::pass_provider_analysis<T>::for_each_type(FindAnalysis{ID, E});
218+
ExistInProvider &= E;
219+
}
220+
if (ExistInProvider) {
221+
auto &Provider = This->getAnalysis<T>(CloneF);
222+
for (auto &ID : Request[tsar::AnalysisRequest::AnalysisIDs]) {
223+
Response[tsar::AnalysisResponse::Analysis].push_back(
224+
Provider.getWithID(ID));
225+
}
226+
tsar::pass_provider_analysis<T>::for_each_type(
227+
GetAllFromProvider<T>{Provider, Cache});
228+
}
229+
}
230+
231+
/// Do not process `T` as a provider.
232+
template <class T> void processAsProvider(std::false_type) {}
233+
234+
AnalysisResponsePass<ResponseT...> *This;
235+
Function &CloneF;
236+
tsar::AnalysisRequest &Request;
237+
tsar::AnalysisResponse &Response;
238+
AnalysisCache &Cache;
239+
};
240+
241+
public:
242+
static char ID;
243+
244+
AnalysisResponsePass() : ModulePass(ID) {}
245+
246+
/// Wait for requests in infinite loop. Stop waiting after incorrect request.
247+
bool runOnModule(Module &M) {
248+
auto &C = getAnalysis<AnalysisConnectionImmutableWrapper>();
249+
auto &OriginalToClone =
250+
getAnalysis<AnalysisClientServerMatcherWrapper>().get();
251+
bool WaitForRequest = true;
252+
llvm::Function *ActiveFunc = nullptr;
253+
AnalysisCache ActiveIDs;
254+
while (WaitForRequest && C->answer([this, &OriginalToClone, &ActiveFunc,
255+
&ActiveIDs,
256+
&WaitForRequest](std::string &Request)
257+
-> std::string {
258+
if (Request == tsar::AnalysisSocket::Release) {
259+
WaitForRequest = false;
260+
return { tsar::AnalysisSocket::Notify };
261+
}
262+
json::Parser<tsar::AnalysisRequest> Parser(Request);
263+
tsar::AnalysisRequest R;
264+
if (!Parser.parse(R)) {
265+
llvm_unreachable("Unknown request: listen for analysis request!");
266+
return { tsar::AnalysisSocket::Invalid };
267+
}
268+
tsar::AnalysisResponse Response;
269+
if (auto *F = R[tsar::AnalysisRequest::Function]) {
270+
auto &CloneF = OriginalToClone[F];
271+
if (!CloneF)
272+
return { tsar::AnalysisSocket::Analysis };
273+
// Check whether we already have required analysis.
274+
if (ActiveFunc == &*CloneF) {
275+
for (auto ID : R[tsar::AnalysisRequest::AnalysisIDs]) {
276+
auto Itr =
277+
llvm::find_if(ActiveIDs, [ID](AnalysisCache::value_type &V) {
278+
return V.first == ID;
279+
});
280+
if (Itr == ActiveIDs.end()) {
281+
Response[tsar::AnalysisResponse::Analysis].clear();
282+
ActiveIDs.clear();
283+
break;
284+
}
285+
Response[tsar::AnalysisResponse::Analysis].push_back(Itr->second);
286+
}
287+
} else {
288+
ActiveFunc = cast<Function>(CloneF);
289+
}
290+
if (Response[tsar::AnalysisResponse::Analysis].empty()) {
291+
// If only one function-level analysis is required, then try to find
292+
// it in the list of available responses (ResponseT...). Otherwise,
293+
// try to find in the list of providers which provides
294+
// access to required analysis results.
295+
if (R[tsar::AnalysisRequest::AnalysisIDs].size() == 1) {
296+
auto ID = R[tsar::AnalysisRequest::AnalysisIDs].front();
297+
bool E = false;
298+
bcl::TypeList<ResponseT...>::for_each_type(FindAnalysis{ID, E});
299+
if (E) {
300+
auto ResultPass = getResolver()->findImplPass(
301+
this, ID, *cast<Function>(CloneF));
302+
assert(ResultPass && "getAnalysis*() called on an analysis that "
303+
"was not 'required' by pass!");
304+
Response[tsar::AnalysisResponse::Analysis].push_back(
305+
ResultPass->getAdjustedAnalysisPointer(ID));
306+
ActiveIDs.emplace_back(
307+
ID, Response[tsar::AnalysisResponse::Analysis].back());
308+
}
309+
}
310+
if (Response[tsar::AnalysisResponse::Analysis].empty()) {
311+
FindProvider FindImpl{this, *cast<Function>(CloneF), R, Response,
312+
ActiveIDs};
313+
bcl::TypeList<ResponseT...>::for_each_type(FindImpl);
314+
if (Response[tsar::AnalysisResponse::Analysis].empty())
315+
return {tsar::AnalysisSocket::Analysis};
316+
}
317+
}
318+
} else {
319+
// Use implementation of getAnalysisID() from
320+
// llvm/PassAnalysisSupport.h. Pass::getAnalysisID() is a template,
321+
// however it does not know a type of required pass. So, copy body of
322+
// getAnalysisID() without type cast.
323+
assert(getResolver() &&
324+
"Pass has not been inserted into a PassManager object!");
325+
for (auto &ID : R[tsar::AnalysisRequest::AnalysisIDs]) {
326+
auto ResultPass = getResolver()->findImplPass(ID);
327+
assert(ResultPass && "getAnalysis*() called on an analysis that was "
328+
"not 'required' by pass!");
329+
Response[tsar::AnalysisResponse::Analysis].push_back(
330+
ResultPass->getAdjustedAnalysisPointer(ID));
331+
}
332+
}
333+
return tsar::AnalysisSocket::Analysis +
334+
json::Parser<tsar::AnalysisResponse>::unparseAsObject(Response);
335+
}))
336+
;
337+
return false;
338+
}
339+
340+
void getAnalysisUsage(AnalysisUsage &AU) const override {
341+
AU.addRequired<AnalysisConnectionImmutableWrapper>();
342+
AU.addRequired<AnalysisClientServerMatcherWrapper>();
343+
AddRequiredFunctor AddRequired(AU);
344+
bcl::TypeList<ResponseT...>::for_each_type(AddRequired);
345+
AU.setPreservesAll();
346+
}
347+
};
348+
} // namespace llvm
349+
#endif // TSAR_ANALYSIS_SERVER_H

0 commit comments

Comments
 (0)