Skip to content

Commit 96e9130

Browse files
author
Robert Marsh
committed
C#: share IR Operand IPA type between stages
1 parent 89a59d5 commit 96e9130

File tree

9 files changed

+173
-144
lines changed

9 files changed

+173
-144
lines changed
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
private import TInstruction
2+
private import OperandTag
3+
private import experimental.ir.implementation.raw.internal.IRConstruction as RawConstruction
4+
private import experimental.ir.implementation.unaliased_ssa.internal.SSAConstruction as UnaliasedConstruction
5+
private import experimental.ir.implementation.raw.IR as Raw
6+
private import experimental.ir.implementation.unaliased_ssa.IR as Unaliased
7+
private import experimental.ir.internal.Overlap
8+
9+
/**
10+
* Provides the newtype used to represent operands across all phases of the IR.
11+
*/
12+
private module Internal {
13+
14+
/**
15+
* An IR operand. `TOperand` is shared across all phases of the IR. There are branches of this
16+
* type for operands created directly from the AST (`TRegisterOperand` and `TNonSSAMemoryOperand`),
17+
* for operands computed by each stage of SSA construction (`T*PhiOperand` and
18+
* `TAliasedChiOperand`), and a placehold branch for operands that do not exist in a given
19+
* stage of IR construction (`TNoOperand`).
20+
*/
21+
cached
22+
newtype TOperand =
23+
// RAW
24+
TRegisterOperand(TRawInstruction useInstr, RegisterOperandTag tag, TRawInstruction defInstr) {
25+
defInstr = RawConstruction::getRegisterOperandDefinition(useInstr, tag) and
26+
not RawConstruction::isInCycle(useInstr) and
27+
strictcount(RawConstruction::getRegisterOperandDefinition(useInstr, tag)) = 1
28+
} or
29+
// Placeholder for Phi and Chi operands in stages that don't have the corresponding instructions
30+
TNoOperand() { none() } or
31+
// Can be "removed" later when there's unreachable code
32+
// These operands can be reused across all three stages. They just get different defs.
33+
TNonSSAMemoryOperand(Raw::Instruction useInstr, MemoryOperandTag tag) {
34+
// Has no definition in raw but will get definitions later
35+
useInstr.getOpcode().hasOperand(tag)
36+
} or
37+
TUnaliasedPhiOperand(
38+
Unaliased::PhiInstruction useInstr, Unaliased::Instruction defInstr,
39+
Unaliased::IRBlock predecessorBlock, Overlap overlap
40+
) {
41+
defInstr = UnaliasedConstruction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap)
42+
}
43+
}
44+
45+
/**
46+
* Reexports some branches from `TOperand` so they can be used in stage modules without importing
47+
* `TOperand` itself.
48+
*/
49+
private module Shared {
50+
class TRegisterOperand = Internal::TRegisterOperand;
51+
52+
/**
53+
* Returns the register operand with the specified parameters.
54+
*/
55+
TRegisterOperand registerOperand(
56+
TRawInstruction useInstr, RegisterOperandTag tag, TRawInstruction defInstr
57+
) {
58+
result = Internal::TRegisterOperand(useInstr, tag, defInstr)
59+
}
60+
61+
class TNonSSAMemoryOperand = Internal::TNonSSAMemoryOperand;
62+
63+
/**
64+
* Returns the non-Phi memory operand with the specified parameters.
65+
*/
66+
TNonSSAMemoryOperand nonSSAMemoryOperand(TRawInstruction useInstr, MemoryOperandTag tag) {
67+
result = Internal::TNonSSAMemoryOperand(useInstr, tag)
68+
}
69+
}
70+
71+
/**
72+
* Provides wrappers for the constructors of each branch of `TOperand` that is used by the
73+
* raw IR stage.
74+
* These wrappers are not parameterized because it is not possible to invoke an IPA constructor via
75+
* a class alias.
76+
*/
77+
module RawOperands {
78+
import Shared
79+
80+
class TPhiOperand = Internal::TNoOperand;
81+
82+
class TChiOperand = Internal::TNoOperand;
83+
84+
/**
85+
* Returns the Phi operand with the specified parameters.
86+
*/
87+
TPhiOperand phiOperand(
88+
Raw::PhiInstruction useInstr, Raw::Instruction defInstr, Raw::IRBlock predecessorBlock,
89+
Overlap overlap
90+
) {
91+
none()
92+
}
93+
94+
/**
95+
* Returns the Chi operand with the specified parameters.
96+
*/
97+
TChiOperand chiOperand(Raw::Instruction useInstr, ChiOperandTag tag) { none() }
98+
}
99+
100+
/**
101+
* Provides wrappers for the constructors of each branch of `TOperand` that is used by the
102+
* unaliased SSA stage.
103+
* These wrappers are not parameterized because it is not possible to invoke an IPA constructor via
104+
* a class alias.
105+
*/
106+
module UnaliasedSSAOperands {
107+
import Shared
108+
109+
class TPhiOperand = Internal::TUnaliasedPhiOperand;
110+
111+
class TChiOperand = Internal::TNoOperand;
112+
113+
/**
114+
* Returns the Phi operand with the specified parameters.
115+
*/
116+
TPhiOperand phiOperand(
117+
Unaliased::PhiInstruction useInstr, Unaliased::Instruction defInstr,
118+
Unaliased::IRBlock predecessorBlock, Overlap overlap
119+
) {
120+
result = Internal::TUnaliasedPhiOperand(useInstr, defInstr, predecessorBlock, overlap)
121+
}
122+
123+
/**
124+
* Returns the Chi operand with the specified parameters.
125+
*/
126+
TChiOperand chiOperand(Unaliased::Instruction useInstr, ChiOperandTag tag) { none() }
127+
}

csharp/ql/src/experimental/ir/implementation/raw/Operand.qll

Lines changed: 19 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -10,79 +10,20 @@ private import Imports::MemoryAccessKind
1010
private import Imports::IRType
1111
private import Imports::Overlap
1212
private import Imports::OperandTag
13-
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-
}
13+
private import Imports::TOperand
14+
private import internal.OperandInternal
6315

6416
/**
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.
17+
* An operand of an `Instruction` in this stage of the IR. Implemented as a union of the branches
18+
* of `TOperand` that are used in this stage.
6719
*/
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-
}
20+
private class TStageOperand = TRegisterOperand or TNonSSAMemoryOperand or TPhiOperand or TChiOperand;
8021

8122
/**
8223
* An operand of an `Instruction`. The operand represents a use of the result of one instruction
8324
* (the defining instruction) in another instruction (the use instruction)
8425
*/
85-
class Operand extends TOperand {
26+
class Operand extends TStageOperand {
8627
/** Gets a textual representation of this element. */
8728
string toString() { result = "Operand" }
8829

@@ -239,8 +180,9 @@ class Operand extends TOperand {
239180
*/
240181
class MemoryOperand extends Operand {
241182
MemoryOperand() {
242-
this instanceof NonPhiMemoryOperandBase or
243-
this instanceof PhiOperandBase
183+
this instanceof TNonSSAMemoryOperand or
184+
this instanceof TPhiOperand or
185+
this instanceof TChiOperand
244186
}
245187

246188
/**
@@ -278,7 +220,8 @@ class NonPhiOperand extends Operand {
278220

279221
NonPhiOperand() {
280222
this = registerOperand(useInstr, tag, _) or
281-
this = nonPhiMemoryOperand(useInstr, tag)
223+
this = nonSSAMemoryOperand(useInstr, tag) or
224+
this = chiOperand(useInstr, tag)
282225
}
283226

284227
final override Instruction getUse() { result = useInstr }
@@ -298,7 +241,7 @@ class NonPhiOperand extends Operand {
298241
/**
299242
* An operand that consumes a register (non-memory) result.
300243
*/
301-
class RegisterOperand extends NonPhiOperand, RegisterOperandBase {
244+
class RegisterOperand extends NonPhiOperand, TRegisterOperand {
302245
override RegisterOperandTag tag;
303246
Instruction defInstr;
304247

@@ -317,10 +260,14 @@ class RegisterOperand extends NonPhiOperand, RegisterOperandBase {
317260
/**
318261
* A memory operand other than the operand of a `Phi` instruction.
319262
*/
320-
class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOperandBase {
263+
class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand {
321264
override MemoryOperandTag tag;
322265

323-
NonPhiMemoryOperand() { this = nonPhiMemoryOperand(useInstr, tag) }
266+
NonPhiMemoryOperand() {
267+
this = nonSSAMemoryOperand(useInstr, tag)
268+
or
269+
this = chiOperand(useInstr, tag)
270+
}
324271

325272
final override string toString() { result = tag.toString() }
326273

@@ -462,7 +409,7 @@ class SideEffectOperand extends TypedOperand {
462409
/**
463410
* An operand of a `PhiInstruction`.
464411
*/
465-
class PhiInputOperand extends MemoryOperand, PhiOperandBase {
412+
class PhiInputOperand extends MemoryOperand, TPhiOperand {
466413
PhiInstruction useInstr;
467414
Instruction defInstr;
468415
IRBlock predecessorBlock;

csharp/ql/src/experimental/ir/implementation/raw/internal/OperandImports.qll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ import experimental.ir.implementation.MemoryAccessKind as MemoryAccessKind
22
import experimental.ir.implementation.IRType as IRType
33
import experimental.ir.internal.Overlap as Overlap
44
import experimental.ir.implementation.internal.OperandTag as OperandTag
5+
import experimental.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 experimental.ir.implementation.internal.TOperand
2+
import RawOperands

0 commit comments

Comments
 (0)