Skip to content

Commit f5dc8ba

Browse files
Merge pull request #2005 from AndreiDiaconu1/ircsharp-unaliased
C# IR: Unaliased SSA
2 parents 0d3edae + 9228cf8 commit f5dc8ba

Some content is hidden

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

45 files changed

+4660
-39
lines changed

csharp/ql/src/semmle/code/csharp/ir/IR.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@
33
* publicly as the "IR".
44
*/
55

6-
import implementation.raw.IR
6+
import implementation.unaliased_ssa.IR

csharp/ql/src/semmle/code/csharp/ir/PrintIR.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@
55
* @kind graph
66
*/
77

8-
import implementation.raw.PrintIR
8+
import implementation.unaliased_ssa.PrintIR
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
import implementation.raw.PrintIR
1+
import implementation.unaliased_ssa.PrintIR
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
import implementation.raw.gvn.ValueNumbering
1+
import implementation.unaliased_ssa.gvn.ValueNumbering

csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedDeclaration.qll

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,4 @@ class TranslatedLocalVariableDeclaration extends TranslatedLocalDeclaration,
7272
// then the simple variable initialization
7373
result = getTranslatedInitialization(var.getInitializer())
7474
}
75-
76-
override predicate isInitializedByElement() { expr.getParent() instanceof IsExpr }
7775
}

csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1792,27 +1792,27 @@ class TranslatedIsExpr extends TranslatedNonConstantExpr {
17921792
this.hasVar() and
17931793
tag = GeneratedBranchTag() and
17941794
(
1795-
tag = GeneratedBranchTag() and
17961795
kind instanceof TrueEdge and
1797-
result = getPatternVarDecl().getFirstInstruction()
1796+
result = this.getInstruction(InitializerStoreTag())
17981797
or
1799-
tag = GeneratedBranchTag() and
18001798
kind instanceof FalseEdge and
18011799
result = this.getParent().getChildSuccessor(this)
18021800
)
18031801
or
18041802
tag = GeneratedConstantTag() and
18051803
kind instanceof GotoEdge and
1806-
result = this.getInstruction(GeneratedNEQTag())
1804+
if this.hasVar()
1805+
then result = this.getPatternVarDecl().getFirstInstruction()
1806+
else result = this.getInstruction(GeneratedNEQTag())
18071807
}
18081808

18091809
override Instruction getChildSuccessor(TranslatedElement child) {
18101810
child = this.getIsExpr() and
18111811
result = this.getInstruction(ConvertTag())
18121812
or
18131813
this.hasVar() and
1814-
child = getPatternVarDecl() and
1815-
result = this.getInstruction(InitializerStoreTag())
1814+
child = this.getPatternVarDecl() and
1815+
result = this.getInstruction(GeneratedNEQTag())
18161816
}
18171817

18181818
override predicate hasInstruction(
@@ -1842,7 +1842,7 @@ class TranslatedIsExpr extends TranslatedNonConstantExpr {
18421842
this.hasVar() and
18431843
tag = GeneratedBranchTag() and
18441844
opcode instanceof Opcode::ConditionalBranch and
1845-
resultType = expr.getType() and
1845+
resultType instanceof VoidType and
18461846
isLValue = false
18471847
}
18481848

csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/common/TranslatedDeclarationBase.qll

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,7 @@ abstract class LocalVariableDeclarationBase extends TranslatedElement {
3939
kind instanceof GotoEdge and
4040
if hasUninitializedInstruction()
4141
then result = getInstruction(InitializerStoreTag())
42-
else
43-
if isInitializedByElement()
44-
then
45-
// initialization is done by an element
46-
result = getParent().getChildSuccessor(this)
47-
else result = getInitialization().getFirstInstruction()
42+
else result = getInitialization().getFirstInstruction()
4843
)
4944
or
5045
hasUninitializedInstruction() and
@@ -75,11 +70,8 @@ abstract class LocalVariableDeclarationBase extends TranslatedElement {
7570
* desugaring process.
7671
*/
7772
predicate hasUninitializedInstruction() {
78-
(
79-
not exists(getInitialization()) or
80-
getInitialization() instanceof TranslatedListInitialization
81-
) and
82-
not isInitializedByElement()
73+
not exists(getInitialization()) or
74+
getInitialization() instanceof TranslatedListInitialization
8375
}
8476

8577
Instruction getVarAddress() { result = getInstruction(InitializerVariableAddressTag()) }
@@ -101,10 +93,4 @@ abstract class LocalVariableDeclarationBase extends TranslatedElement {
10193
* as a different step, but do it during the declaration.
10294
*/
10395
abstract TranslatedElement getInitialization();
104-
105-
/**
106-
* Holds if a declaration is not explicitly initialized,
107-
* but will be implicitly initialized by an element.
108-
*/
109-
abstract predicate isInitializedByElement();
11096
}

csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedDeclaration.qll

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,6 @@ abstract class TranslatedCompilerGeneratedDeclaration extends LocalVariableDecla
7272
// element
7373
override LocalVariable getDeclVar() { none() }
7474

75-
// A compiler generated element always has an explicit
76-
// initialization
77-
override predicate isInitializedByElement() { none() }
78-
7975
override Type getVarType() { result = getIRVariable().getType() }
8076

8177
/**
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) }

0 commit comments

Comments
 (0)