Skip to content

Commit 1dab4e0

Browse files
author
AndreiDiaconu1
committed
Initial commit, C++ files
1 parent 7f76947 commit 1dab4e0

34 files changed

+4632
-0
lines changed
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import IRFunction
2+
import Instruction
3+
import IRBlock
4+
import IRVariable
5+
import Operand
6+
private import internal.IRImports as Imports
7+
import Imports::EdgeKind
8+
import Imports::MemoryAccessKind
9+
10+
private newtype TIRPropertyProvider = MkIRPropertyProvider()
11+
12+
/**
13+
* Class that provides additional properties to be dumped for IR instructions and blocks when using
14+
* the PrintIR module. Libraries that compute additional facts about IR elements can extend the
15+
* single instance of this class to specify the additional properties computed by the library.
16+
*/
17+
class IRPropertyProvider extends TIRPropertyProvider {
18+
string toString() { result = "IRPropertyProvider" }
19+
20+
/**
21+
* Gets the value of the property named `key` for the specified instruction.
22+
*/
23+
string getInstructionProperty(Instruction instruction, string key) { none() }
24+
25+
/**
26+
* Gets the value of the property named `key` for the specified block.
27+
*/
28+
string getBlockProperty(IRBlock block, string key) { none() }
29+
}
Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
private import internal.IRInternal
2+
import Instruction
3+
private import internal.IRBlockImports as Imports
4+
import Imports::EdgeKind
5+
private import Cached
6+
7+
/**
8+
* A basic block in the IR. A basic block consists of a sequence of `Instructions` with the only
9+
* incoming edges at the beginning of the sequence and the only outgoing edges at the end of the
10+
* sequence.
11+
*
12+
* This class does not contain any members that query the predecessor or successor edges of the
13+
* block. This allows different classes that extend `IRBlockBase` to expose different subsets of
14+
* edges (e.g. ignoring unreachable edges).
15+
*
16+
* Most consumers should use the class `IRBlock`.
17+
*/
18+
class IRBlockBase extends TIRBlock {
19+
final string toString() { result = getFirstInstruction(this).toString() }
20+
21+
final Language::Location getLocation() { result = getFirstInstruction().getLocation() }
22+
23+
final string getUniqueId() { result = getFirstInstruction(this).getUniqueId() }
24+
25+
/**
26+
* Gets the zero-based index of the block within its function. This is used
27+
* by debugging and printing code only.
28+
*/
29+
int getDisplayIndex() {
30+
this = rank[result + 1](IRBlock funcBlock |
31+
funcBlock.getEnclosingFunction() = getEnclosingFunction()
32+
|
33+
funcBlock order by funcBlock.getUniqueId()
34+
)
35+
}
36+
37+
final Instruction getInstruction(int index) { result = getInstruction(this, index) }
38+
39+
final PhiInstruction getAPhiInstruction() {
40+
Construction::getPhiInstructionBlockStart(result) = getFirstInstruction()
41+
}
42+
43+
final Instruction getAnInstruction() {
44+
result = getInstruction(_) or
45+
result = getAPhiInstruction()
46+
}
47+
48+
final Instruction getFirstInstruction() { result = getFirstInstruction(this) }
49+
50+
final Instruction getLastInstruction() { result = getInstruction(getInstructionCount() - 1) }
51+
52+
final int getInstructionCount() { result = getInstructionCount(this) }
53+
54+
final IRFunction getEnclosingIRFunction() {
55+
result = getFirstInstruction(this).getEnclosingIRFunction()
56+
}
57+
58+
final Language::Function getEnclosingFunction() {
59+
result = getFirstInstruction(this).getEnclosingFunction()
60+
}
61+
}
62+
63+
/**
64+
* A basic block with additional information about its predecessor and successor edges. Each edge
65+
* corresponds to the control flow between the last instruction of one block and the first
66+
* instruction of another block.
67+
*/
68+
class IRBlock extends IRBlockBase {
69+
final IRBlock getASuccessor() { blockSuccessor(this, result) }
70+
71+
final IRBlock getAPredecessor() { blockSuccessor(result, this) }
72+
73+
final IRBlock getSuccessor(EdgeKind kind) { blockSuccessor(this, result, kind) }
74+
75+
final IRBlock getBackEdgeSuccessor(EdgeKind kind) { backEdgeSuccessor(this, result, kind) }
76+
77+
final predicate immediatelyDominates(IRBlock block) { blockImmediatelyDominates(this, block) }
78+
79+
final predicate strictlyDominates(IRBlock block) { blockImmediatelyDominates+(this, block) }
80+
81+
final predicate dominates(IRBlock block) { strictlyDominates(block) or this = block }
82+
83+
pragma[noinline]
84+
final IRBlock dominanceFrontier() {
85+
dominates(result.getAPredecessor()) and
86+
not strictlyDominates(result)
87+
}
88+
89+
/**
90+
* Holds if this block is reachable from the entry point of its function
91+
*/
92+
final predicate isReachableFromFunctionEntry() {
93+
this = getEnclosingIRFunction().getEntryBlock() or
94+
getAPredecessor().isReachableFromFunctionEntry()
95+
}
96+
}
97+
98+
private predicate startsBasicBlock(Instruction instr) {
99+
not instr instanceof PhiInstruction and
100+
(
101+
count(Instruction predecessor | instr = predecessor.getASuccessor()) != 1 // Multiple predecessors or no predecessor
102+
or
103+
exists(Instruction predecessor |
104+
instr = predecessor.getASuccessor() and
105+
strictcount(Instruction other | other = predecessor.getASuccessor()) > 1
106+
) // Predecessor has multiple successors
107+
or
108+
exists(Instruction predecessor, EdgeKind kind |
109+
instr = predecessor.getSuccessor(kind) and
110+
not kind instanceof GotoEdge
111+
) // Incoming edge is not a GotoEdge
112+
or
113+
exists(Instruction predecessor |
114+
instr = Construction::getInstructionBackEdgeSuccessor(predecessor, _)
115+
) // A back edge enters this instruction
116+
)
117+
}
118+
119+
private predicate isEntryBlock(TIRBlock block) {
120+
block = MkIRBlock(any(EnterFunctionInstruction enter))
121+
}
122+
123+
cached
124+
private module Cached {
125+
cached
126+
newtype TIRBlock = MkIRBlock(Instruction firstInstr) { startsBasicBlock(firstInstr) }
127+
128+
/** Holds if `i2` follows `i1` in a `IRBlock`. */
129+
private predicate adjacentInBlock(Instruction i1, Instruction i2) {
130+
exists(GotoEdge edgeKind | i2 = i1.getSuccessor(edgeKind)) and
131+
not startsBasicBlock(i2)
132+
}
133+
134+
/** Holds if `i` is the `index`th instruction the block starting with `first`. */
135+
private Instruction getInstructionFromFirst(Instruction first, int index) =
136+
shortestDistances(startsBasicBlock/1, adjacentInBlock/2)(first, result, index)
137+
138+
/** Holds if `i` is the `index`th instruction in `block`. */
139+
cached
140+
Instruction getInstruction(TIRBlock block, int index) {
141+
result = getInstructionFromFirst(getFirstInstruction(block), index)
142+
}
143+
144+
cached
145+
int getInstructionCount(TIRBlock block) { result = strictcount(getInstruction(block, _)) }
146+
147+
cached
148+
predicate blockSuccessor(TIRBlock pred, TIRBlock succ, EdgeKind kind) {
149+
exists(Instruction predLast, Instruction succFirst |
150+
predLast = getInstruction(pred, getInstructionCount(pred) - 1) and
151+
succFirst = predLast.getSuccessor(kind) and
152+
succ = MkIRBlock(succFirst)
153+
)
154+
}
155+
156+
pragma[noinline]
157+
private predicate blockIdentity(TIRBlock b1, TIRBlock b2) { b1 = b2 }
158+
159+
pragma[noopt]
160+
cached
161+
predicate backEdgeSuccessor(TIRBlock pred, TIRBlock succ, EdgeKind kind) {
162+
backEdgeSuccessorRaw(pred, succ, kind)
163+
or
164+
// See the QLDoc on `backEdgeSuccessorRaw`.
165+
exists(TIRBlock pred2 |
166+
// Joining with `blockIdentity` is a performance trick to get
167+
// `forwardEdgeRaw` on the RHS of a join, where it's fast.
168+
blockIdentity(pred, pred2) and
169+
forwardEdgeRaw+(pred, pred2)
170+
) and
171+
blockSuccessor(pred, succ, kind)
172+
}
173+
174+
/**
175+
* Holds if there is an edge from `pred` to `succ` that is not a back edge.
176+
*/
177+
private predicate forwardEdgeRaw(TIRBlock pred, TIRBlock succ) {
178+
exists(EdgeKind kind |
179+
blockSuccessor(pred, succ, kind) and
180+
not backEdgeSuccessorRaw(pred, succ, kind)
181+
)
182+
}
183+
184+
/**
185+
* Holds if the `kind`-edge from `pred` to `succ` is a back edge according to
186+
* `Construction`.
187+
*
188+
* There could be loops of non-back-edges if there is a flaw in the IR
189+
* construction or back-edge detection, and this could cause non-termination
190+
* of subsequent analysis. To prevent that, a subsequent predicate further
191+
* classifies all edges as back edges if they are involved in a loop of
192+
* non-back-edges.
193+
*/
194+
private predicate backEdgeSuccessorRaw(TIRBlock pred, TIRBlock succ, EdgeKind kind) {
195+
exists(Instruction predLast, Instruction succFirst |
196+
predLast = getInstruction(pred, getInstructionCount(pred) - 1) and
197+
succFirst = Construction::getInstructionBackEdgeSuccessor(predLast, kind) and
198+
succ = MkIRBlock(succFirst)
199+
)
200+
}
201+
202+
cached
203+
predicate blockSuccessor(TIRBlock pred, TIRBlock succ) { blockSuccessor(pred, succ, _) }
204+
205+
cached
206+
predicate blockImmediatelyDominates(TIRBlock dominator, TIRBlock block) =
207+
idominance(isEntryBlock/1, blockSuccessor/2)(_, dominator, block)
208+
}
209+
210+
Instruction getFirstInstruction(TIRBlock block) { block = MkIRBlock(result) }
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
private import internal.IRInternal
2+
import Instruction
3+
4+
private newtype TIRFunction =
5+
MkIRFunction(Language::Function func) { Construction::functionHasIR(func) }
6+
7+
/**
8+
* Represents the IR for a function.
9+
*/
10+
class IRFunction extends TIRFunction {
11+
Language::Function func;
12+
13+
IRFunction() { this = MkIRFunction(func) }
14+
15+
final string toString() { result = "IR: " + func.toString() }
16+
17+
/**
18+
* Gets the function whose IR is represented.
19+
*/
20+
final Language::Function getFunction() { result = func }
21+
22+
/**
23+
* Gets the location of the function.
24+
*/
25+
final Language::Location getLocation() { result = func.getLocation() }
26+
27+
/**
28+
* Gets the entry point for this function.
29+
*/
30+
pragma[noinline]
31+
final EnterFunctionInstruction getEnterFunctionInstruction() {
32+
result.getEnclosingIRFunction() = this
33+
}
34+
35+
/**
36+
* Gets the exit point for this function.
37+
*/
38+
pragma[noinline]
39+
final ExitFunctionInstruction getExitFunctionInstruction() {
40+
result.getEnclosingIRFunction() = this
41+
}
42+
43+
pragma[noinline]
44+
final UnmodeledDefinitionInstruction getUnmodeledDefinitionInstruction() {
45+
result.getEnclosingIRFunction() = this
46+
}
47+
48+
pragma[noinline]
49+
final UnmodeledUseInstruction getUnmodeledUseInstruction() {
50+
result.getEnclosingIRFunction() = this
51+
}
52+
53+
/**
54+
* Gets the single return instruction for this function.
55+
*/
56+
pragma[noinline]
57+
final ReturnInstruction getReturnInstruction() { result.getEnclosingIRFunction() = this }
58+
59+
/**
60+
* Gets the variable used to hold the return value of this function. If this
61+
* function does not return a value, this predicate does not hold.
62+
*/
63+
pragma[noinline]
64+
final IRReturnVariable getReturnVariable() { result.getEnclosingIRFunction() = this }
65+
66+
/**
67+
* Gets the block containing the entry point of this function.
68+
*/
69+
pragma[noinline]
70+
final IRBlock getEntryBlock() { result.getFirstInstruction() = getEnterFunctionInstruction() }
71+
72+
/**
73+
* Gets all instructions in this function.
74+
*/
75+
final Instruction getAnInstruction() { result.getEnclosingIRFunction() = this }
76+
77+
/**
78+
* Gets all blocks in this function.
79+
*/
80+
final IRBlock getABlock() { result.getEnclosingIRFunction() = this }
81+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/**
2+
* @name SSA IR Sanity Check
3+
* @description Performs sanity checks on the Intermediate Representation. This query should have no results.
4+
* @kind table
5+
* @id cpp/ssa-ir-sanity-check
6+
*/
7+
8+
import IRSanity
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
private import IR
2+
import InstructionSanity

0 commit comments

Comments
 (0)