Skip to content

Commit d8292f6

Browse files
authored
Merge pull request #9 from jbaileyhandle/amd-feature/hip-performance-analysis
Drano integrated w/ AMD llvm, basic functionality working.
2 parents 539532f + 67d280d commit d8292f6

17 files changed

+1601
-0
lines changed

llvm/lib/Transforms/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@ add_subdirectory(ObjCARC)
1010
add_subdirectory(Coroutines)
1111
add_subdirectory(CFGuard)
1212
add_subdirectory(HC)
13+
add_subdirectory(UncoalescedAnalysis)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
#ifndef ABSTRACT_EXECUTION_ENGINE_H
2+
#define ABSTRACT_EXECUTION_ENGINE_H
3+
4+
#include "AbstractState.h"
5+
#include "AbstractValue.h"
6+
7+
#include "llvm/ADT/SmallVector.h"
8+
#include "llvm/IR/BasicBlock.h"
9+
#include "llvm/IR/Instruction.h"
10+
#include "llvm/Support/Debug.h"
11+
#include "llvm/Support/raw_ostream.h"
12+
#include <list>
13+
#include <map>
14+
#include <string>
15+
#include <utility>
16+
17+
#ifndef DEBUG_TYPE
18+
#define DEBUG_TYPE "abstract-execution"
19+
#endif
20+
21+
#define NUM_RECENT_BLOCKS 16
22+
23+
using namespace llvm;
24+
25+
// This class defines an abstract execution engine. An abstract execution engine
26+
// takes in a program and executes the program abstractly using semantics
27+
// defined for an abstract value.
28+
// T is the type of abstract value used for abstract execution. It must implement
29+
// AbstractValue<T>.
30+
// U is the type of abstract value used for abstract execution. It must implement
31+
// AbstractState<T>.
32+
template<typename T, typename U>
33+
class AbstractExecutionEngine {
34+
static_assert(
35+
std::is_base_of<AbstractValue<T>, T>::value,
36+
"T must be a descendant of AbstractValue<T>"
37+
);
38+
static_assert(
39+
std::is_base_of<AbstractState<T, U>, U>::value,
40+
"U must be a descendant of AbstractState<T, U>"
41+
);
42+
public:
43+
AbstractExecutionEngine()
44+
: entryBlock_(nullptr) {}
45+
AbstractExecutionEngine(const BasicBlock* entryBlock, U initialState)
46+
: entryBlock_(entryBlock), initialState_(initialState) {}
47+
48+
virtual ~AbstractExecutionEngine() = 0;
49+
50+
// Queries the state before an instruction.
51+
const U& getStateBeforeInstruction(const Instruction* inst){
52+
return StateBeforeInstructionMap_[inst];
53+
}
54+
55+
// Adds a block to execute next and the state in which the block must be
56+
// executed.
57+
void AddBlockToExecute(const BasicBlock* b, U st);
58+
59+
// Executes program (can be overriden).
60+
virtual void Execute();
61+
62+
// Executes the instruction on a state and returns the state after execution.
63+
virtual U ExecuteInstruction(const Instruction* inst,
64+
U st) = 0;
65+
66+
protected:
67+
// Entry block where the abstract execution begins.
68+
const BasicBlock* entryBlock_;
69+
70+
// Initial state before execution of the program.
71+
U initialState_;
72+
73+
private:
74+
// Returns the next unit to execute.
75+
std::pair<const BasicBlock*, U> getNextExecutionUnit(
76+
std::list<std::pair<const BasicBlock*, U>>& worklist);
77+
78+
// Add block to recently executed blocks.
79+
void AddRecentBlock(const BasicBlock* block);
80+
81+
// Stores some recent blocks executed by the engine.
82+
SmallVector<const BasicBlock*, NUM_RECENT_BLOCKS> recentBlocks_;
83+
84+
// Records abstract state before an instruction is executed.
85+
std::map<const Instruction*, U> StateBeforeInstructionMap_;
86+
87+
// Buffer to store the set of blocks that must be executed after this block
88+
// completes execution.
89+
std::list<std::pair<const BasicBlock*, U>> BlocksToExecuteBuffer_;
90+
};
91+
92+
template<typename T, typename U>
93+
AbstractExecutionEngine<T, U>::~AbstractExecutionEngine() {}
94+
95+
template<typename T, typename U>
96+
void AbstractExecutionEngine<T, U>::AddBlockToExecute(const BasicBlock* b, U st) {
97+
BlocksToExecuteBuffer_.push_back(std::pair<const BasicBlock*, U>(b, st));
98+
}
99+
100+
// Returns a block in recentBlocks_ if found. Otherwise returns the
101+
// first block in worklist. This optimization is useful for execution
102+
// of loops. All blocks within the loop are given priority over blocks
103+
// after the loop. This ensures that the blocks after the loop are
104+
// executed only after the loop reaches a fixed point.
105+
template<typename T, typename U>
106+
std::pair<const BasicBlock*, U>
107+
AbstractExecutionEngine<T, U>::getNextExecutionUnit(
108+
std::list<std::pair<const BasicBlock*, U>>& worklist) {
109+
for (const BasicBlock* block : recentBlocks_) {
110+
auto listIt = find_if(worklist.begin(), worklist.end(),
111+
[block](const std::pair<const BasicBlock*, U>& item){
112+
if (item.first == block) return true;
113+
else return false;
114+
});
115+
if (listIt != worklist.end()) {
116+
// Block found.
117+
auto unit = *listIt;
118+
worklist.erase(listIt);
119+
AddRecentBlock(unit.first);
120+
return unit;
121+
}
122+
}
123+
auto unit = worklist.front();
124+
worklist.pop_front();
125+
AddRecentBlock(unit.first);
126+
return unit;
127+
}
128+
129+
// Adds block to the set of recent blocks.
130+
template<typename T, typename U>
131+
void AbstractExecutionEngine<T, U>::AddRecentBlock(const BasicBlock* block) {
132+
auto pos = recentBlocks_.begin();
133+
while (*pos != block && pos != recentBlocks_.end()) ++pos;
134+
if (pos != recentBlocks_.end()) { recentBlocks_.erase(pos); }
135+
if (recentBlocks_.size() >= NUM_RECENT_BLOCKS) {
136+
recentBlocks_.pop_back();
137+
}
138+
recentBlocks_.insert(recentBlocks_.begin(), block);
139+
}
140+
141+
template<typename T, typename U>
142+
void AbstractExecutionEngine<T, U>::Execute() {
143+
// Worklist to execute basic blocks.
144+
// Each worklist item consists of a basicblock and an abstract state to be
145+
// propagated through the block.
146+
std::list<std::pair<const BasicBlock*, U>> worklist;
147+
worklist.push_back(std::pair<const BasicBlock*, U>(entryBlock_, initialState_));
148+
149+
// Execute work items in worklist.
150+
StateBeforeInstructionMap_.clear();
151+
while (!worklist.empty()) {
152+
auto unit = getNextExecutionUnit(worklist);
153+
const BasicBlock *b = unit.first; // next block to be executed.
154+
U st = unit.second; // state before next block.
155+
LLVM_DEBUG(errs() << "BasicBlock: " << b->getName() << "\n");
156+
157+
// Clear buffer.
158+
BlocksToExecuteBuffer_.clear();
159+
// Execute instructions within the block.
160+
for (BasicBlock::const_iterator it = b->begin(), ite = b->end();
161+
it != ite; ++it) {
162+
const Instruction* I = &*it;
163+
// If I is the first statement in the block, merge I's pre-state
164+
// with incoming state.
165+
if (it == b->begin()) {
166+
if(StateBeforeInstructionMap_.find(I) !=
167+
StateBeforeInstructionMap_.end()) {
168+
U oldState = StateBeforeInstructionMap_[I];
169+
U newState = oldState.mergeState(st);
170+
// State before block unchanged; no need to execute block.
171+
if (oldState == newState) break;
172+
173+
StateBeforeInstructionMap_[I] = newState;
174+
} else {
175+
StateBeforeInstructionMap_[I] = st;
176+
}
177+
} else {
178+
StateBeforeInstructionMap_[I] = st;
179+
}
180+
181+
LLVM_DEBUG(errs() << " " << *I << ", " << st.printInstructionState(I) << "\n");
182+
st = ExecuteInstruction(I, st);
183+
}
184+
// Add subsequent blocks to be executed. Note that these were added to
185+
// the buffer during the execution of instructions in the current block.
186+
for (auto bufferIt = BlocksToExecuteBuffer_.begin(),
187+
bufferIte = BlocksToExecuteBuffer_.end(); bufferIt != bufferIte;
188+
++bufferIt) {
189+
// Check if the key already exists in worklist, if so, merge the two
190+
// work items. This is an optimization that helps scale the execution,
191+
// at the cost of being slightly imprecise.
192+
const BasicBlock* block = bufferIt->first;
193+
auto listIt = find_if(worklist.begin(), worklist.end(),
194+
[block](const std::pair<const BasicBlock*, U>& item){
195+
if (item.first == block) return true;
196+
else return false;
197+
});
198+
if (listIt != worklist.end()) {
199+
listIt->second = listIt->second.mergeState(bufferIt->second);
200+
} else {
201+
worklist.push_back(std::pair<const BasicBlock*, U>(bufferIt->first,
202+
bufferIt->second));
203+
}
204+
}
205+
}
206+
}
207+
208+
#undef DEBUG_TYPE
209+
210+
#endif /* AbstractExecutionEngine.h */
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
#ifndef ABSTRACT_STATE_H
2+
#define ABSTRACT_STATE_H
3+
4+
#include "AbstractValue.h"
5+
6+
#include "llvm/IR/BasicBlock.h"
7+
#include "llvm/IR/Value.h"
8+
#include <map>
9+
#include <string>
10+
11+
using namespace llvm;
12+
13+
// Defines an abstract state used by the abstract execution engine to store
14+
// the current state of the abstract execution.
15+
template <typename T, typename U>
16+
class AbstractState {
17+
static_assert(
18+
std::is_base_of<AbstractValue<T>, T>::value,
19+
"T must be a descendant of AbstractValue<T>"
20+
);
21+
public:
22+
AbstractState() {}
23+
24+
virtual ~AbstractState() = 0;
25+
26+
void clear() { valueMap_.clear(); }
27+
28+
bool operator==(const AbstractState& st) const {
29+
return (valueMap_ == st.valueMap_);
30+
}
31+
32+
void operator=(const AbstractState& st) {
33+
valueMap_ = st.valueMap_;
34+
}
35+
36+
bool hasValue(const Value* in) const {
37+
return (valueMap_.find(in) != valueMap_.end());
38+
}
39+
40+
virtual T getValue(const Value* in) const {
41+
return valueMap_.at(in);
42+
}
43+
44+
virtual void setValue(const Value* in, T v) { valueMap_[in] = v; }
45+
46+
virtual U mergeState(const U& st) const;
47+
48+
// Pretty printing
49+
virtual std::string getString() const;
50+
virtual std::string printInstructionState(const Instruction* I) const;
51+
52+
private:
53+
// Map from variables to their abstract values.
54+
std::map<const Value*, T> valueMap_;
55+
};
56+
57+
template<typename T, typename U>
58+
AbstractState<T, U>::~AbstractState() {}
59+
60+
template<typename T, typename U>
61+
U AbstractState<T, U>::mergeState(const U& st) const {
62+
U result = st;
63+
for (auto it = this->valueMap_.begin(), ite = this->valueMap_.end();
64+
it != ite; ++it) {
65+
const Value* in = it->first;
66+
T v = it->second;
67+
if (st.hasValue(in)) {
68+
result.setValue(in, v.join(st.valueMap_.at(in)));
69+
} else {
70+
result.setValue(in, v);
71+
}
72+
}
73+
return result;
74+
}
75+
76+
template<typename T, typename U>
77+
std::string AbstractState<T, U>::getString() const {
78+
std::string s;
79+
s.append("[");
80+
for (auto it = valueMap_.begin(), ite = valueMap_.end(); it != ite; ++it) {
81+
const Value* in = it->first;
82+
T v = it->second;
83+
s.append(in->getName().str()).append(":").append(v.getString()).append(", ");
84+
}
85+
s.append("]");
86+
return s;
87+
}
88+
89+
template<typename T, typename U>
90+
std::string AbstractState<T, U>::printInstructionState(
91+
const Instruction* I) const {
92+
std::string s;
93+
s.append("[");
94+
for (unsigned i = 0; i < I->getNumOperands(); i++) {
95+
T v = this->getValue(I->getOperand(i));
96+
s.append(I->getOperand(i)->getName().str()).append(":").append(v.getString()).append(",");
97+
}
98+
s.append("]");
99+
return s;
100+
}
101+
102+
#endif /* AbstractState.h */
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#ifndef ABSTRACT_VALUE_H
2+
#define ABSTRACT_VALUE_H
3+
4+
#include <string>
5+
6+
// This class defines an abstract value and semantics for the various
7+
// operations performed during the abstract execution of the program.
8+
template<typename T>
9+
class AbstractValue {
10+
public:
11+
AbstractValue() {}
12+
13+
virtual ~AbstractValue() = 0;
14+
15+
virtual std::string getString() const = 0;
16+
17+
// Returns a merge of this value with value v.
18+
virtual T join(const T& v) const = 0;
19+
};
20+
21+
template<typename T>
22+
AbstractValue<T>::~AbstractValue() {}
23+
24+
#endif /* AbstractValue.h */
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# If we don't need RTTI or EH, there's no reason to export anything
2+
# from the hello plugin.
3+
# if( NOT LLVM_REQUIRES_RTTI )
4+
# if( NOT LLVM_REQUIRES_EH )
5+
# set(LLVM_EXPORTED_SYMBOL_FILE ${CMAKE_CURRENT_SOURCE_DIR}/Hello.exports
6+
# endif()
7+
# endif()
8+
9+
if(WIN32 OR CYGWIN)
10+
set(LLVM_LINK_COMPONENTS Core Support)
11+
endif()
12+
13+
#set(CMAKE_BUILD_TYPE "Debug")
14+
set(LLVM_ENABLE_PLUGINS ON)
15+
set(LLVM_LINK_COMPONENTS
16+
Demangle
17+
)
18+
19+
add_llvm_library(LLVMUncoalescedAnalysis MODULE
20+
InterprocUncoalescedAnalysisPass.cpp
21+
UncoalescedAnalysisPass.cpp
22+
GPUState.cpp
23+
MultiplierValue.cpp
24+
UncoalescedAnalysis.cpp
25+
26+
DEPENDS
27+
intrinsics_gen
28+
PLUGIN_TOOL
29+
opt
30+
)

0 commit comments

Comments
 (0)