Skip to content

Commit 1e08c11

Browse files
author
Robert Marsh
committed
C++: Share Operand IPA type across IR stages
1 parent 8129d0c commit 1e08c11

File tree

16 files changed

+217
-219
lines changed

16 files changed

+217
-219
lines changed

cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll

Lines changed: 16 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -10,73 +10,10 @@ private import Imports::MemoryAccessKind
1010
private import Imports::IRType
1111
private import Imports::Overlap
1212
private import Imports::OperandTag
13+
private import Imports::TOperand
14+
private import internal.OperandInternal
1315

14-
cached
15-
private newtype TOperand =
16-
TRegisterOperand(Instruction useInstr, RegisterOperandTag tag, Instruction defInstr) {
17-
defInstr = Construction::getRegisterOperandDefinition(useInstr, tag) and
18-
not Construction::isInCycle(useInstr) and
19-
strictcount(Construction::getRegisterOperandDefinition(useInstr, tag)) = 1
20-
} or
21-
TNonPhiMemoryOperand(Instruction useInstr, MemoryOperandTag tag) {
22-
useInstr.getOpcode().hasOperand(tag)
23-
} or
24-
TPhiOperand(
25-
PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap
26-
) {
27-
defInstr = Construction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap)
28-
}
29-
30-
/**
31-
* Base class for all register operands. This is a placeholder for the IPA union type that we will
32-
* eventually use for this purpose.
33-
*/
34-
private class RegisterOperandBase extends TRegisterOperand {
35-
/** Gets a textual representation of this element. */
36-
abstract string toString();
37-
}
38-
39-
/**
40-
* Returns the register operand with the specified parameters.
41-
*/
42-
private RegisterOperandBase registerOperand(
43-
Instruction useInstr, RegisterOperandTag tag, Instruction defInstr
44-
) {
45-
result = TRegisterOperand(useInstr, tag, defInstr)
46-
}
47-
48-
/**
49-
* Base class for all non-Phi memory operands. This is a placeholder for the IPA union type that we
50-
* will eventually use for this purpose.
51-
*/
52-
private class NonPhiMemoryOperandBase extends TNonPhiMemoryOperand {
53-
/** Gets a textual representation of this element. */
54-
abstract string toString();
55-
}
56-
57-
/**
58-
* Returns the non-Phi memory operand with the specified parameters.
59-
*/
60-
private NonPhiMemoryOperandBase nonPhiMemoryOperand(Instruction useInstr, MemoryOperandTag tag) {
61-
result = TNonPhiMemoryOperand(useInstr, tag)
62-
}
63-
64-
/**
65-
* Base class for all Phi operands. This is a placeholder for the IPA union type that we will
66-
* eventually use for this purpose.
67-
*/
68-
private class PhiOperandBase extends TPhiOperand {
69-
abstract string toString();
70-
}
71-
72-
/**
73-
* Returns the Phi operand with the specified parameters.
74-
*/
75-
private PhiOperandBase phiOperand(
76-
Instruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap
77-
) {
78-
result = TPhiOperand(useInstr, defInstr, predecessorBlock, overlap)
79-
}
16+
class TOperand = TRegisterOperand or TNonSSAMemoryOperand or TPhiOperand or TChiOperand;
8017

8118
/**
8219
* An operand of an `Instruction`. The operand represents a use of the result of one instruction
@@ -239,8 +176,9 @@ class Operand extends TOperand {
239176
*/
240177
class MemoryOperand extends Operand {
241178
MemoryOperand() {
242-
this instanceof NonPhiMemoryOperandBase or
243-
this instanceof PhiOperandBase
179+
this instanceof TNonSSAMemoryOperand or
180+
this instanceof TPhiOperand or
181+
this instanceof TChiOperand
244182
}
245183

246184
/**
@@ -278,7 +216,8 @@ class NonPhiOperand extends Operand {
278216

279217
NonPhiOperand() {
280218
this = registerOperand(useInstr, tag, _) or
281-
this = nonPhiMemoryOperand(useInstr, tag)
219+
this = nonSSAMemoryOperand(useInstr, tag) or
220+
this = chiOperand(useInstr, tag)
282221
}
283222

284223
final override Instruction getUse() { result = useInstr }
@@ -298,7 +237,7 @@ class NonPhiOperand extends Operand {
298237
/**
299238
* An operand that consumes a register (non-memory) result.
300239
*/
301-
class RegisterOperand extends NonPhiOperand, RegisterOperandBase {
240+
class RegisterOperand extends NonPhiOperand, TRegisterOperand {
302241
override RegisterOperandTag tag;
303242
Instruction defInstr;
304243

@@ -317,10 +256,14 @@ class RegisterOperand extends NonPhiOperand, RegisterOperandBase {
317256
/**
318257
* A memory operand other than the operand of a `Phi` instruction.
319258
*/
320-
class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOperandBase {
259+
class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand {
321260
override MemoryOperandTag tag;
322261

323-
NonPhiMemoryOperand() { this = nonPhiMemoryOperand(useInstr, tag) }
262+
NonPhiMemoryOperand() {
263+
this = nonSSAMemoryOperand(useInstr, tag)
264+
or
265+
this = chiOperand(useInstr, tag)
266+
}
324267

325268
final override string toString() { result = tag.toString() }
326269

@@ -462,7 +405,7 @@ class SideEffectOperand extends TypedOperand {
462405
/**
463406
* An operand of a `PhiInstruction`.
464407
*/
465-
class PhiInputOperand extends MemoryOperand, PhiOperandBase {
408+
class PhiInputOperand extends MemoryOperand, TPhiOperand {
466409
PhiInstruction useInstr;
467410
Instruction defInstr;
468411
IRBlock predecessorBlock;

cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/OperandImports.qll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ import semmle.code.cpp.ir.implementation.MemoryAccessKind as MemoryAccessKind
22
import semmle.code.cpp.ir.implementation.IRType as IRType
33
import semmle.code.cpp.ir.internal.Overlap as Overlap
44
import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag
5+
import semmle.code.cpp.ir.implementation.internal.TOperand as TOperand
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
private import semmle.code.cpp.ir.implementation.internal.TOperand
2+
import AliasedSSAOperands

cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ private import Imports::Overlap
66
private import Imports::TInstruction
77
private import Imports::RawIR as RawIR
88
private import SSAInstructions
9+
private import SSAOperands
910
private import NewIR
1011

1112
private class OldBlock = Reachability::ReachableBlock;
@@ -42,6 +43,9 @@ private module Cached {
4243
class TStageInstruction =
4344
TRawInstruction or TPhiInstruction or TChiInstruction or TUnreachedInstruction;
4445

46+
class TStageOperand =
47+
TRegisterOperand or TNonSSAMemoryOperand or TPhiOperand or TChiOperand;
48+
4549
cached
4650
predicate hasInstruction(TStageInstruction instr) {
4751
instr instanceof TRawInstruction and instr instanceof OldInstruction

cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstructionImports.qll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag
33
import semmle.code.cpp.ir.internal.Overlap as Overlap
44
import semmle.code.cpp.ir.implementation.internal.TInstruction as TInstruction
55
import semmle.code.cpp.ir.implementation.raw.IR as RawIR
6+
import semmle.code.cpp.ir.implementation.internal.TOperand as TOperand

cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstructionInternal.qll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ import semmle.code.cpp.ir.implementation.aliased_ssa.IR as NewIR
55
import semmle.code.cpp.ir.implementation.internal.TInstruction::AliasedSSAInstructions as SSAInstructions
66
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
77
import AliasedSSA as Alias
8+
import semmle.code.cpp.ir.implementation.internal.TOperand::UnliasedSSAOperands as SSAOperands
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
private import TInstruction
2+
private import OperandTag
3+
private import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as RawConstruction
4+
private import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.SSAConstruction as UnaliasedConstruction
5+
private import semmle.code.cpp.ir.implementation.aliased_ssa.internal.SSAConstruction as AliasedConstruction
6+
private import semmle.code.cpp.ir.implementation.raw.IR as Raw
7+
private import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as Unaliased
8+
private import semmle.code.cpp.ir.implementation.aliased_ssa.IR as Aliased
9+
private import semmle.code.cpp.ir.internal.Overlap
10+
11+
private module Internal {
12+
cached
13+
newtype TOperand =
14+
// RAW
15+
TRegisterOperand(TRawInstruction useInstr, RegisterOperandTag tag, TRawInstruction defInstr) {
16+
defInstr = RawConstruction::getRegisterOperandDefinition(useInstr, tag) and
17+
not RawConstruction::isInCycle(useInstr) and
18+
strictcount(RawConstruction::getRegisterOperandDefinition(useInstr, tag)) = 1
19+
} or
20+
// Placeholder for Phi and Chi operands in stages that don't have the corresponding instructions
21+
TNoOperand() { none() } or
22+
// Can be "removed" later when there's unreachable code
23+
// These operands can be reused across all three stages. They just get different defs.
24+
TNonSSAMemoryOperand(Raw::Instruction useInstr, MemoryOperandTag tag) {
25+
// Has no definition in raw but will get definitions later
26+
useInstr.getOpcode().hasOperand(tag)
27+
} or
28+
TUnaliasedPhiOperand(
29+
Unaliased::PhiInstruction useInstr, Unaliased::Instruction defInstr,
30+
Unaliased::IRBlock predecessorBlock, Overlap overlap
31+
) {
32+
defInstr = UnaliasedConstruction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap)
33+
} or
34+
//// ALIASED
35+
////
36+
// If we share SSA, these will be all the phis there are. Otherwise these
37+
// will add to the ones that are already there.
38+
// If we share SSA, be careful with the case where we remove all possible
39+
// indirect writes to a variable because they're dead code. In that case it's
40+
// important that we use the same definition of "is variable aliased" across
41+
// the phases.
42+
TAliasedPhiOperand(
43+
TAliasedSSAPhiInstruction useInstr, Aliased::Instruction defInstr,
44+
Aliased::IRBlock predecessorBlock, Overlap overlap
45+
) {
46+
defInstr = AliasedConstruction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap)
47+
} or
48+
TAliasedChiOperand(TAliasedSSAChiInstruction useInstr, ChiOperandTag tag) {
49+
// TODO: any further restrictions here?
50+
any()
51+
}
52+
}
53+
54+
private module Shared {
55+
class TRegisterOperand = Internal::TRegisterOperand;
56+
57+
/**
58+
* Returns the register operand with the specified parameters.
59+
*/
60+
TRegisterOperand registerOperand(
61+
TRawInstruction useInstr, RegisterOperandTag tag, TRawInstruction defInstr
62+
) {
63+
result = Internal::TRegisterOperand(useInstr, tag, defInstr)
64+
}
65+
66+
class TNonSSAMemoryOperand = Internal::TNonSSAMemoryOperand;
67+
68+
/**
69+
* Returns the non-Phi memory operand with the specified parameters.
70+
*/
71+
TNonSSAMemoryOperand nonSSAMemoryOperand(TRawInstruction useInstr, MemoryOperandTag tag) {
72+
result = Internal::TNonSSAMemoryOperand(useInstr, tag)
73+
}
74+
}
75+
76+
module RawOperands {
77+
import Shared
78+
79+
class TPhiOperand = Internal::TNoOperand;
80+
81+
class TChiOperand = Internal::TNoOperand;
82+
83+
/**
84+
* Returns the Phi operand with the specified parameters.
85+
*/
86+
TPhiOperand phiOperand(
87+
Raw::PhiInstruction useInstr, Raw::Instruction defInstr, Raw::IRBlock predecessorBlock,
88+
Overlap overlap
89+
) {
90+
none()
91+
}
92+
93+
/**
94+
* Returns the Chi operand with the specified parameters.
95+
*/
96+
TChiOperand chiOperand(Raw::Instruction useInstr, ChiOperandTag tag) { none() }
97+
}
98+
99+
// TODO: can we get everything into either here or Operand.qll?
100+
// TODO: can we put `TStageOperand` in Construction? Might break something about the module caching setup, `Operand` is currently after everything in SSAConstruction
101+
// TODO: share empty ChiOperand?
102+
module UnliasedSSAOperands {
103+
import Shared
104+
105+
class TPhiOperand = Internal::TUnaliasedPhiOperand;
106+
107+
class TChiOperand = Internal::TNoOperand;
108+
109+
/**
110+
* Returns the Phi operand with the specified parameters.
111+
*/
112+
TPhiOperand phiOperand(
113+
Unaliased::PhiInstruction useInstr, Unaliased::Instruction defInstr,
114+
Unaliased::IRBlock predecessorBlock, Overlap overlap
115+
) {
116+
result = Internal::TUnaliasedPhiOperand(useInstr, defInstr, predecessorBlock, overlap)
117+
}
118+
119+
/**
120+
* Returns the Chi operand with the specified parameters.
121+
*/
122+
TChiOperand chiOperand(Unaliased::Instruction useInstr, ChiOperandTag tag) { none() }
123+
}
124+
125+
module AliasedSSAOperands {
126+
import Shared
127+
128+
class TPhiOperand = Internal::TAliasedPhiOperand;
129+
130+
class TChiOperand = Internal::TAliasedChiOperand;
131+
132+
/**
133+
* Returns the Phi operand with the specified parameters.
134+
*/
135+
TPhiOperand phiOperand(
136+
TAliasedSSAPhiInstruction useInstr, Aliased::Instruction defInstr,
137+
Aliased::IRBlock predecessorBlock, Overlap overlap
138+
) {
139+
result = Internal::TAliasedPhiOperand(useInstr, defInstr, predecessorBlock, overlap)
140+
}
141+
142+
/**
143+
* Returns the Chi operand with the specified parameters.
144+
*/
145+
TChiOperand chiOperand(TAliasedSSAChiInstruction useInstr, ChiOperandTag tag) {
146+
result = Internal::TAliasedChiOperand(useInstr, tag)
147+
}
148+
}

0 commit comments

Comments
 (0)