Skip to content

Commit 367dc1a

Browse files
committed
SwiftCompilerSources: add OperandSet and OperandWorklist
Implemented by bridging the C++ OperandSet, similar to BasicBlockSet and NodeSet
1 parent 7afa419 commit 367dc1a

File tree

7 files changed

+130
-1
lines changed

7 files changed

+130
-1
lines changed

SwiftCompilerSources/Sources/Optimizer/DataStructures/Set.swift

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,3 +176,55 @@ struct InstructionSet : IntrusiveSet {
176176
context.freeNodeSet(bridged)
177177
}
178178
}
179+
180+
/// A set of operands.
181+
///
182+
/// This is an extremely efficient implementation which does not need memory
183+
/// allocations or hash lookups.
184+
///
185+
/// This type should be a move-only type, but unfortunately we don't have move-only
186+
/// types yet. Therefore it's needed to call `deinitialize()` explicitly to
187+
/// destruct this data structure, e.g. in a `defer {}` block.
188+
struct OperandSet : IntrusiveSet {
189+
190+
private let context: BridgedPassContext
191+
private let bridged: BridgedOperandSet
192+
193+
init(_ context: some Context) {
194+
self.context = context._bridged
195+
self.bridged = self.context.allocOperandSet()
196+
}
197+
198+
func contains(_ operand: Operand) -> Bool {
199+
bridged.contains(operand.bridged)
200+
}
201+
202+
/// Returns true if `inst` was not contained in the set before inserting.
203+
@discardableResult
204+
mutating func insert(_ operand: Operand) -> Bool {
205+
bridged.insert(operand.bridged)
206+
}
207+
208+
mutating func erase(_ operand: Operand) {
209+
bridged.erase(operand.bridged)
210+
}
211+
212+
var description: String {
213+
let function = bridged.getFunction().function
214+
var d = "{\n"
215+
for inst in function.instructions {
216+
for op in inst.operands {
217+
if contains(op) {
218+
d += op.description
219+
}
220+
}
221+
}
222+
d += "}\n"
223+
return d
224+
}
225+
226+
/// TODO: once we have move-only types, make this a real deinit.
227+
mutating func deinitialize() {
228+
context.freeOperandSet(bridged)
229+
}
230+
}

SwiftCompilerSources/Sources/Optimizer/DataStructures/Worklist.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,3 +75,4 @@ struct Worklist<Set: IntrusiveSet> : CustomStringConvertible, NoReflectionChildr
7575
typealias BasicBlockWorklist = Worklist<BasicBlockSet>
7676
typealias InstructionWorklist = Worklist<InstructionSet>
7777
typealias ValueWorklist = Worklist<ValueSet>
78+
typealias OperandWorklist = Worklist<OperandSet>

SwiftCompilerSources/Sources/SIL/Operand.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import SILBridging
1414

1515
/// An operand of an instruction.
1616
public struct Operand : CustomStringConvertible, NoReflectionChildren {
17-
fileprivate let bridged: BridgedOperand
17+
public let bridged: BridgedOperand
1818

1919
public init(bridged: BridgedOperand) {
2020
self.bridged = bridged

include/swift/SILOptimizer/OptimizerBridging.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ class DominanceInfo;
5050
class PostDominanceInfo;
5151
class BasicBlockSet;
5252
class NodeSet;
53+
class OperandSet;
5354
class ClonerWithFixedLocation;
5455
class SwiftPassInvocation;
5556
class FixedSizeSlabPayload;
@@ -155,6 +156,15 @@ struct BridgedNodeSet {
155156
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedFunction getFunction() const;
156157
};
157158

159+
struct BridgedOperandSet {
160+
swift::OperandSet * _Nonnull set;
161+
162+
BRIDGED_INLINE bool contains(BridgedOperand operand) const;
163+
BRIDGED_INLINE bool insert(BridgedOperand operand) const;
164+
BRIDGED_INLINE void erase(BridgedOperand operand) const;
165+
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedFunction getFunction() const;
166+
};
167+
158168
struct BridgedCloner {
159169
swift::ClonerWithFixedLocation * _Nonnull cloner;
160170

@@ -244,6 +254,8 @@ struct BridgedPassContext {
244254
BRIDGED_INLINE void freeBasicBlockSet(BridgedBasicBlockSet set) const;
245255
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedNodeSet allocNodeSet() const;
246256
BRIDGED_INLINE void freeNodeSet(BridgedNodeSet set) const;
257+
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedOperandSet allocOperandSet() const;
258+
BRIDGED_INLINE void freeOperandSet(BridgedOperandSet set) const;
247259

248260
// Stack nesting
249261

include/swift/SILOptimizer/OptimizerBridgingImpl.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,26 @@ BridgedFunction BridgedNodeSet::getFunction() const {
129129
return {set->getFunction()};
130130
}
131131

132+
//===----------------------------------------------------------------------===//
133+
// BridgedOperandSet
134+
//===----------------------------------------------------------------------===//
135+
136+
bool BridgedOperandSet::contains(BridgedOperand operand) const {
137+
return set->contains(operand.op);
138+
}
139+
140+
bool BridgedOperandSet::insert(BridgedOperand operand) const {
141+
return set->insert(operand.op);
142+
}
143+
144+
void BridgedOperandSet::erase(BridgedOperand operand) const {
145+
set->erase(operand.op);
146+
}
147+
148+
BridgedFunction BridgedOperandSet::getFunction() const {
149+
return {set->getFunction()};
150+
}
151+
132152
//===----------------------------------------------------------------------===//
133153
// BridgedPassContext
134154
//===----------------------------------------------------------------------===//
@@ -256,6 +276,14 @@ void BridgedPassContext::freeNodeSet(BridgedNodeSet set) const {
256276
invocation->freeNodeSet(set.set);
257277
}
258278

279+
BridgedOperandSet BridgedPassContext::allocOperandSet() const {
280+
return {invocation->allocOperandSet()};
281+
}
282+
283+
void BridgedPassContext::freeOperandSet(BridgedOperandSet set) const {
284+
invocation->freeOperandSet(set.set);
285+
}
286+
259287
void BridgedPassContext::notifyInvalidatedStackNesting() const {
260288
invocation->setNeedFixStackNesting(true);
261289
}

include/swift/SILOptimizer/PassManager/PassManager.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,11 @@ class SwiftPassInvocation {
8484
bool aliveNodeSets[NodeSetCapacity];
8585
int numNodeSetsAllocated = 0;
8686

87+
static constexpr int OperandSetCapacity = Operand::numCustomBits;
88+
char operandSetStorage[sizeof(OperandSet) * OperandSetCapacity];
89+
bool aliveOperandSets[OperandSetCapacity];
90+
int numOperandSetsAllocated = 0;
91+
8792
int numClonersAllocated = 0;
8893

8994
bool needFixStackNesting = false;
@@ -124,6 +129,10 @@ class SwiftPassInvocation {
124129

125130
void freeNodeSet(NodeSet *set);
126131

132+
OperandSet *allocOperandSet();
133+
134+
void freeOperandSet(OperandSet *set);
135+
127136
/// The top-level API to erase an instruction, called from the Swift pass.
128137
void eraseInstruction(SILInstruction *inst);
129138

lib/SILOptimizer/PassManager/PassManager.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1449,6 +1449,30 @@ void SwiftPassInvocation::freeNodeSet(NodeSet *set) {
14491449
}
14501450
}
14511451

1452+
OperandSet *SwiftPassInvocation::allocOperandSet() {
1453+
require(numOperandSetsAllocated < OperandSetCapacity,
1454+
"too many OperandSets allocated");
1455+
1456+
auto *storage = (OperandSet *)operandSetStorage + numOperandSetsAllocated;
1457+
OperandSet *set = new (storage) OperandSet(function);
1458+
aliveOperandSets[numOperandSetsAllocated] = true;
1459+
++numOperandSetsAllocated;
1460+
return set;
1461+
}
1462+
1463+
void SwiftPassInvocation::freeOperandSet(OperandSet *set) {
1464+
int idx = set - (OperandSet *)operandSetStorage;
1465+
assert(idx >= 0 && idx < numOperandSetsAllocated);
1466+
assert(aliveOperandSets[idx] && "double free of OperandSet");
1467+
aliveOperandSets[idx] = false;
1468+
1469+
while (numOperandSetsAllocated > 0 && !aliveOperandSets[numOperandSetsAllocated - 1]) {
1470+
auto *set = (OperandSet *)operandSetStorage + numOperandSetsAllocated - 1;
1471+
set->~OperandSet();
1472+
--numOperandSetsAllocated;
1473+
}
1474+
}
1475+
14521476
void SwiftPassInvocation::startModulePassRun(SILModuleTransform *transform) {
14531477
assert(!this->function && !this->transform && "a pass is already running");
14541478
this->function = nullptr;
@@ -1493,6 +1517,7 @@ void SwiftPassInvocation::endPass() {
14931517
assert(allocatedSlabs.empty() && "StackList is leaking slabs");
14941518
assert(numBlockSetsAllocated == 0 && "Not all BasicBlockSets deallocated");
14951519
assert(numNodeSetsAllocated == 0 && "Not all NodeSets deallocated");
1520+
assert(numOperandSetsAllocated == 0 && "Not all OperandSets deallocated");
14961521
assert(numClonersAllocated == 0 && "Not all cloners deallocated");
14971522
assert(!needFixStackNesting && "Stack nesting not fixed");
14981523
if (ssaUpdater) {
@@ -1517,6 +1542,7 @@ void SwiftPassInvocation::endTransformFunction() {
15171542
function = nullptr;
15181543
assert(numBlockSetsAllocated == 0 && "Not all BasicBlockSets deallocated");
15191544
assert(numNodeSetsAllocated == 0 && "Not all NodeSets deallocated");
1545+
assert(numOperandSetsAllocated == 0 && "Not all OperandSets deallocated");
15201546
}
15211547

15221548
void SwiftPassInvocation::beginVerifyFunction(SILFunction *function) {
@@ -1535,6 +1561,7 @@ void SwiftPassInvocation::endVerifyFunction() {
15351561
"verifyication must not change the SIL of a function");
15361562
assert(numBlockSetsAllocated == 0 && "Not all BasicBlockSets deallocated");
15371563
assert(numNodeSetsAllocated == 0 && "Not all NodeSets deallocated");
1564+
assert(numOperandSetsAllocated == 0 && "Not all OperandSets deallocated");
15381565
function = nullptr;
15391566
}
15401567
}

0 commit comments

Comments
 (0)