forked from revng/revng
-
Notifications
You must be signed in to change notification settings - Fork 0
/
generatedcodebasicinfo.h
187 lines (152 loc) · 5.65 KB
/
generatedcodebasicinfo.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
#ifndef _GENERATEDCODEBASICINFO_H
#define _GENERATEDCODEBASICINFO_H
//
// This file is distributed under the MIT License. See LICENSE.md for details.
//
// Standard includes
#include <cstdint>
#include <map>
#include <utility>
// LLVM includes
#include "llvm/Pass.h"
#include "llvm/Support/Casting.h"
// Local includes
#include "ir-helpers.h"
#include "revamb.h"
// Forward declarations
namespace llvm {
class BasicBlock;
class GlobalVariable;
class Instruction;
class MDNode;
}
static const char *BlockTypeMDName = "revamb.block.type";
/// \brief Pass to collect basic information about the generated code
///
/// This pass provides useful information for other passes by extracting them
/// from the generated IR, and possibly caching them.
///
/// It provides details about the input architecture such as the size of its
/// delay slot, the name of the program counter register and so on. It also
/// provides information about the generated basic blocks, distinguishing
/// between basic blocks generated due to translation and dispatcher-related
/// basic blocks.
class GeneratedCodeBasicInfo : public llvm::FunctionPass {
public:
static char ID;
public:
GeneratedCodeBasicInfo() : llvm::FunctionPass(ID), DelaySlotSize(0),
PC(nullptr), Dispatcher(nullptr),
AnyPC(nullptr), UnexpectedPC(nullptr) { }
void getAnalysisUsage(llvm::AnalysisUsage &AU) const override {
AU.setPreservesAll();
}
bool runOnFunction(llvm::Function &F) override;
/// \brief Return the type of basic block, see BlockType.
BlockType getType(llvm::BasicBlock *BB) const {
return getType(BB->getTerminator());
}
BlockType getType(llvm::TerminatorInst *T) const {
assert(T != nullptr);
llvm::MDNode *MD = T->getMetadata(BlockTypeMDName);
if (MD == nullptr) {
llvm::Instruction *First = &*T->getParent()->begin();
if (auto *Call = llvm::dyn_cast<llvm::CallInst>(First)) {
llvm::Function *Callee = Call->getCalledFunction();
if (Callee != nullptr
&& Callee->getName() == "newpc"
&& getLimitedValue(Call->getArgOperand(2)) == 1) {
return JumpTargetBlock;
}
}
return UntypedBlock;
}
auto *BlockTypeMD = llvm::cast<llvm::MDTuple>(MD);
QuickMetadata QMD(getContext(T));
return BlockType(QMD.extract<uint32_t>(BlockTypeMD, 0));
}
/// \brief Return the size of the delay slot for the input architecture
unsigned delaySlotSize() const { return DelaySlotSize; }
/// \brief Return the CSV representing the program counter
llvm::GlobalVariable *pcReg() const { return PC; }
/// \brief Check if \p GV is the program counter CSV
bool isPCReg(llvm::GlobalVariable *GV) const {
assert(PC != nullptr);
return GV == PC;
}
/// \brief Return the basic block associated to \p PC
///
/// Returns nullptr if the PC doesn't have a basic block (yet)
llvm::BasicBlock *getBlockAt(uint64_t PC) const {
auto It = JumpTargets.find(PC);
if (It == JumpTargets.end())
return nullptr;
return It->second;
}
/// \brief Return true if the basic block is a jump target
bool isJumpTarget(llvm::BasicBlock *BB) const {
return getType(BB->getTerminator()) == JumpTargetBlock;
}
bool isJump(llvm::BasicBlock *BB) const {
return isJump(BB->getTerminator());
}
/// \brief Return true if \p T represents a jump in the input assembly
///
/// Return true if \p T targets include only dispatcher-related basic blocks
/// and jump targets.
bool isJump(llvm::TerminatorInst *T) const {
assert(T != nullptr);
for (llvm::BasicBlock *Successor : T->successors()) {
if (!(Successor == Dispatcher
|| Successor == AnyPC
|| Successor == UnexpectedPC
|| isJumpTarget(Successor)))
return false;
}
return true;
}
/// \brief Return true if \p BB is the result of translating some code
///
/// Return false if \p BB is a dispatcher-related basic block.
bool isTranslated(llvm::BasicBlock *BB) const {
return BB != Dispatcher && BB != AnyPC && BB != UnexpectedPC;
}
/// \brief Find the PC which lead to generated \p TheInstruction
///
/// \return a pair of integers: the first element represents the PC and the
/// second the size of the instruction.
std::pair<uint64_t, uint64_t> getPC(llvm::Instruction *TheInstruction) const;
/// \brief Return the program counter of the next (i.e., fallthrough)
/// instruction of \p TheInstruction
uint64_t getNextPC(llvm::Instruction *TheInstruction) const {
auto Pair = getPC(TheInstruction);
return Pair.first + Pair.second;
}
/// \brief Calls \p Visitor for each instruction preceeding \p I
///
/// See visitPredecessors in ir-helpers.h
void visitPredecessors(llvm::Instruction *I, RVisitorFunction Visitor);
private:
uint32_t DelaySlotSize;
llvm::GlobalVariable *PC;
llvm::BasicBlock *Dispatcher;
llvm::BasicBlock *AnyPC;
llvm::BasicBlock *UnexpectedPC;
std::map<uint64_t, llvm::BasicBlock *> JumpTargets;
};
template<>
struct BlackListTrait<const GeneratedCodeBasicInfo &, llvm::BasicBlock *> :
BlackListTraitBase<const GeneratedCodeBasicInfo &> {
using BlackListTraitBase<const GeneratedCodeBasicInfo &>::BlackListTraitBase;
bool isBlacklisted(llvm::BasicBlock *Value) {
return !this->Obj.isTranslated(Value);
}
};
inline
void GeneratedCodeBasicInfo::visitPredecessors(llvm::Instruction *I,
RVisitorFunction Visitor) {
using BLT = BlackListTrait<const GeneratedCodeBasicInfo &,
llvm::BasicBlock *>;
::visitPredecessors(I, Visitor, BLT(*this));
}
#endif // _GENERATEDCODEBASICINFO_H