Skip to content

Commit 129e912

Browse files
authored
Merge pull request #2862 from swiftwasm/main
[pull] swiftwasm from main
2 parents 98e1d85 + 5acd5e6 commit 129e912

27 files changed

+972
-822
lines changed

include/swift/SIL/BitDataflow.h

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
//===--- BitDataflow.h ------------------------------------------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2021 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
///
13+
/// \file Contains the BitDataflow utility for performing bit-wise dataflow
14+
/// analysis on a SILFunction.
15+
///
16+
//===----------------------------------------------------------------------===//
17+
18+
#ifndef SWIFT_SIL_BIT_DATAFLOW_H
19+
#define SWIFT_SIL_BIT_DATAFLOW_H
20+
21+
#include "swift/SIL/BasicBlockData.h"
22+
#include "llvm/ADT/SmallBitVector.h"
23+
24+
namespace swift {
25+
26+
class SILFunction;
27+
28+
/// A utility to calculate forward or backward dataflow of bit sets on a
29+
/// SILFunction.
30+
class BitDataflow {
31+
32+
/// What kind of terminators can be reached from a block.
33+
enum class ExitReachability : uint8_t {
34+
/// Worst case: the block is part of a cycle which neither reaches a
35+
/// function-exit nor an unreachable-instruction.
36+
InInfiniteLoop,
37+
38+
/// An unreachable-instruction can be reached from the block, but not a
39+
/// function-exit (like "return" or "throw").
40+
ReachesUnreachable,
41+
42+
/// A function-exit can be reached from the block.
43+
/// This is the case for most basic blocks.
44+
ReachesExit
45+
};
46+
47+
public:
48+
using Bits = llvm::SmallBitVector;
49+
50+
/// Basic-block specific information used for dataflow analysis.
51+
struct BlockState {
52+
/// The bits valid at the entry (i.e. the first instruction) of the block.
53+
Bits entrySet;
54+
55+
/// The bits valid at the exit (i.e. after the terminator) of the block.
56+
Bits exitSet;
57+
58+
/// Generated bits of the block.
59+
Bits genSet;
60+
61+
/// Killed bits of the block.
62+
Bits killSet;
63+
64+
/// True, if this block is reachable from the entry block, i.e. is not an
65+
/// unreachable block.
66+
///
67+
/// This flag is only computed if entryReachabilityAnalysis is called.
68+
bool reachableFromEntry = false;
69+
70+
/// What kind of terminators can be reached from this block.
71+
///
72+
/// This is only computed if exitReachableAnalysis is called.
73+
ExitReachability exitReachability = ExitReachability::InInfiniteLoop;
74+
75+
BlockState(unsigned numLocations) :
76+
entrySet(numLocations), exitSet(numLocations),
77+
genSet(numLocations), killSet(numLocations) {}
78+
79+
bool exitReachable() const {
80+
return exitReachability == ExitReachability::ReachesExit;
81+
}
82+
83+
bool isInInfiniteLoop() const {
84+
return exitReachability == ExitReachability::InInfiniteLoop;
85+
}
86+
};
87+
88+
private:
89+
BasicBlockData<BlockState> blockStates;
90+
91+
public:
92+
93+
using iterator = BasicBlockData<BlockState>::iterator;
94+
95+
/// Sets up the BlockState datastructures and associates all basic blocks with
96+
/// a state.
97+
BitDataflow(SILFunction *function, unsigned numLocations);
98+
99+
BitDataflow(const BitDataflow &) = delete;
100+
BitDataflow &operator=(const BitDataflow &) = delete;
101+
102+
iterator begin() { return blockStates.begin(); }
103+
iterator end() { return blockStates.end(); }
104+
105+
/// Returns the state of a block.
106+
BlockState &operator[] (SILBasicBlock *block) {
107+
return blockStates[block];
108+
}
109+
110+
/// Calculates the BlockState::reachableFromEntry flags.
111+
void entryReachabilityAnalysis();
112+
113+
/// Calculates the BlockState::exitReachable flags.
114+
void exitReachableAnalysis();
115+
116+
using JoinOperation = std::function<void (Bits &dest, const Bits &src)>;
117+
118+
/// Derives the block exit sets from the entry sets by applying the gen and
119+
/// kill sets.
120+
/// At control flow joins, the \p join operation is applied.
121+
void solveForward(JoinOperation join);
122+
123+
/// Calls solveForward() with a bit-intersection as join operation.
124+
void solveForwardWithIntersect();
125+
126+
/// Calls solveForward() with a bit-union as join operation.
127+
void solveForwardWithUnion();
128+
129+
/// Derives the block entry sets from the exit sets by applying the gen and
130+
/// kill sets.
131+
/// At control flow joins, the \p join operation is applied.
132+
void solveBackward(JoinOperation join);
133+
134+
/// Calls solveBackward() with a bit-intersection as join operation.
135+
void solveBackwardWithIntersect();
136+
137+
/// Calls solveBackward() with a bit-union as join operation.
138+
void solveBackwardWithUnion();
139+
140+
/// Debug dump the BitDataflow state.
141+
void dump() const;
142+
};
143+
144+
} // end swift namespace
145+
146+
#endif

include/swift/SIL/MemoryLifetime.h renamed to include/swift/SIL/MemoryLocations.h

Lines changed: 25 additions & 155 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,34 @@
1-
//===--- MemoryLifetime.h ---------------------------------------*- C++ -*-===//
1+
//===--- MemoryLocations.h --------------------------------------*- C++ -*-===//
22
//
33
// This source file is part of the Swift.org open source project
44
//
5-
// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors
5+
// Copyright (c) 2014 - 2021 Apple Inc. and the Swift project authors
66
// Licensed under Apache License v2.0 with Runtime Library Exception
77
//
88
// See https://swift.org/LICENSE.txt for license information
99
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
1010
//
1111
//===----------------------------------------------------------------------===//
1212
///
13-
/// \file Contains utilities for calculating and verifying memory lifetime.
13+
/// \file Contains the MemoryLocations utility for analyzing memory locations in
14+
/// a SILFunction.
1415
///
1516
//===----------------------------------------------------------------------===//
1617

17-
#ifndef SWIFT_SIL_MEMORY_LIFETIME_H
18-
#define SWIFT_SIL_MEMORY_LIFETIME_H
18+
#ifndef SWIFT_SIL_MEMORY_LOCATIONS_H
19+
#define SWIFT_SIL_MEMORY_LOCATIONS_H
1920

20-
#include "swift/SIL/SILBasicBlock.h"
21-
#include "swift/SIL/SILFunction.h"
22-
#include "swift/SIL/BasicBlockData.h"
21+
#include "swift/SIL/SILValue.h"
22+
#include "llvm/ADT/DenseMap.h"
23+
#include "llvm/ADT/SmallBitVector.h"
24+
#include "llvm/Support/raw_ostream.h"
2325

2426
namespace swift {
2527

28+
class SILFunction;
29+
class SILBasicBlock;
30+
class SingleValueInstruction;
31+
2632
void printBitsAsArray(llvm::raw_ostream &OS, const SmallBitVector &bits);
2733

2834
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
@@ -40,10 +46,6 @@ void dumpBits(const SmallBitVector &bits);
4046
/// Currently only a certain set of address instructions are supported:
4147
/// Specifically those instructions which are going to be included when SIL
4248
/// supports opaque values.
43-
/// TODO: Support more address instructions, like cast instructions.
44-
///
45-
/// The MemoryLocations works well together with MemoryDataflow, which can be
46-
/// used to calculate global dataflow of location information.
4749
class MemoryLocations {
4850
public:
4951

@@ -115,10 +117,10 @@ class MemoryLocations {
115117
/// sub-locations 3 and 4. But bit 0 is set in location 0 (the "self" bit),
116118
/// because it represents the untracked field ``Outer.z``.
117119
///
118-
/// Single-payload enums are represented by a location with a single sub-
119-
/// location (the projected payload address, i.e. an ``init_enum_data_addr``
120-
/// or an ``unchecked_take_enum_data_addr``.
121-
/// Multi-payload enums are not supported right now.
120+
/// Enums and existentials are represented by a location with a single sub-
121+
/// location (the projected payload/existential address, i.e. an
122+
/// ``init_enum_data_addr``, ``unchecked_take_enum_data_addr`` or
123+
/// ``init_existential_addr``.
122124
Bits subLocations;
123125

124126
/// The accumulated parent bits, including the "self" bit.
@@ -196,9 +198,13 @@ class MemoryLocations {
196198
/// init_existential_addr and open_existential_addr.
197199
bool handleNonTrivialProjections;
198200

201+
/// If true, also analyze trivial memory locations.
202+
bool handleTrivialLocations;
203+
199204
public:
200-
MemoryLocations(bool handleNonTrivialProjections) :
201-
handleNonTrivialProjections(handleNonTrivialProjections) {}
205+
MemoryLocations(bool handleNonTrivialProjections, bool handleTrivialLocations) :
206+
handleNonTrivialProjections(handleNonTrivialProjections),
207+
handleTrivialLocations(handleTrivialLocations) {}
202208

203209
MemoryLocations(const MemoryLocations &) = delete;
204210
MemoryLocations &operator=(const MemoryLocations &) = delete;
@@ -228,7 +234,7 @@ class MemoryLocations {
228234
const Location *getRootLocation(unsigned index) const;
229235

230236
/// Registers an address projection instruction for a location.
231-
void registerProjection(SingleValueInstruction *projection, unsigned locIdx) {
237+
void registerProjection(SILValue projection, unsigned locIdx) {
232238
addr2LocIdx[projection] = locIdx;
233239
}
234240

@@ -285,9 +291,6 @@ class MemoryLocations {
285291
/// Debug dump the MemoryLifetime internals.
286292
void dump() const;
287293

288-
/// Debug dump a bit set .
289-
static void dumpBits(const Bits &bits);
290-
291294
private:
292295
/// Clears all datastructures, except singleBlockLocations;
293296
void clear();
@@ -313,139 +316,6 @@ class MemoryLocations {
313316
void initFieldsCounter(Location &loc);
314317
};
315318

316-
/// The MemoryDataflow utility calculates global dataflow of memory locations.
317-
///
318-
/// The MemoryDataflow works well together with MemoryLocations, which can be
319-
/// used to analyze locations as input to the dataflow.
320-
/// TODO: Actuall this utility can be used for any kind of dataflow, not just
321-
/// for memory locations. Consider renaming it.
322-
class MemoryDataflow {
323-
324-
/// What kind of terminators can be reached from a block.
325-
enum class ExitReachability : uint8_t {
326-
/// Worst case: the block is part of a cycle which neither reaches a
327-
/// function-exit nor an unreachable-instruction.
328-
InInfiniteLoop,
329-
330-
/// An unreachable-instruction can be reached from the block, but not a
331-
/// function-exit (like "return" or "throw").
332-
ReachesUnreachable,
333-
334-
/// A function-exit can be reached from the block.
335-
/// This is the case for most basic blocks.
336-
ReachesExit
337-
};
338-
339-
public:
340-
using Bits = MemoryLocations::Bits;
341-
342-
/// Basic-block specific information used for dataflow analysis.
343-
struct BlockState {
344-
/// The bits valid at the entry (i.e. the first instruction) of the block.
345-
Bits entrySet;
346-
347-
/// The bits valid at the exit (i.e. after the terminator) of the block.
348-
Bits exitSet;
349-
350-
/// Generated bits of the block.
351-
Bits genSet;
352-
353-
/// Killed bits of the block.
354-
Bits killSet;
355-
356-
/// True, if this block is reachable from the entry block, i.e. is not an
357-
/// unreachable block.
358-
///
359-
/// This flag is only computed if entryReachabilityAnalysis is called.
360-
bool reachableFromEntry = false;
361-
362-
/// What kind of terminators can be reached from this block.
363-
///
364-
/// This is only computed if exitReachableAnalysis is called.
365-
ExitReachability exitReachability = ExitReachability::InInfiniteLoop;
366-
367-
BlockState(unsigned numLocations) :
368-
entrySet(numLocations), exitSet(numLocations),
369-
genSet(numLocations), killSet(numLocations) {}
370-
371-
// Utility functions for setting and clearing gen- and kill-bits.
372-
373-
void genBits(SILValue addr, const MemoryLocations &locs) {
374-
locs.genBits(genSet, killSet, addr);
375-
}
376-
377-
void killBits(SILValue addr, const MemoryLocations &locs) {
378-
locs.killBits(genSet, killSet, addr);
379-
}
380-
381-
bool exitReachable() const {
382-
return exitReachability == ExitReachability::ReachesExit;
383-
}
384-
385-
bool isInInfiniteLoop() const {
386-
return exitReachability == ExitReachability::InInfiniteLoop;
387-
}
388-
};
389-
390-
private:
391-
BasicBlockData<BlockState> blockStates;
392-
393-
public:
394-
395-
using iterator = BasicBlockData<BlockState>::iterator;
396-
397-
/// Sets up the BlockState datastructures and associates all basic blocks with
398-
/// a state.
399-
MemoryDataflow(SILFunction *function, unsigned numLocations);
400-
401-
MemoryDataflow(const MemoryDataflow &) = delete;
402-
MemoryDataflow &operator=(const MemoryDataflow &) = delete;
403-
404-
iterator begin() { return blockStates.begin(); }
405-
iterator end() { return blockStates.end(); }
406-
407-
/// Returns the state of a block.
408-
BlockState &operator[] (SILBasicBlock *block) {
409-
return blockStates[block];
410-
}
411-
412-
/// Calculates the BlockState::reachableFromEntry flags.
413-
void entryReachabilityAnalysis();
414-
415-
/// Calculates the BlockState::exitReachable flags.
416-
void exitReachableAnalysis();
417-
418-
using JoinOperation = std::function<void (Bits &dest, const Bits &src)>;
419-
420-
/// Derives the block exit sets from the entry sets by applying the gen and
421-
/// kill sets.
422-
/// At control flow joins, the \p join operation is applied.
423-
void solveForward(JoinOperation join);
424-
425-
/// Calls solveForward() with a bit-intersection as join operation.
426-
void solveForwardWithIntersect();
427-
428-
/// Calls solveForward() with a bit-union as join operation.
429-
void solveForwardWithUnion();
430-
431-
/// Derives the block entry sets from the exit sets by applying the gen and
432-
/// kill sets.
433-
/// At control flow joins, the \p join operation is applied.
434-
void solveBackward(JoinOperation join);
435-
436-
/// Calls solveBackward() with a bit-intersection as join operation.
437-
void solveBackwardWithIntersect();
438-
439-
/// Calls solveBackward() with a bit-union as join operation.
440-
void solveBackwardWithUnion();
441-
442-
/// Debug dump the MemoryLifetime internals.
443-
void dump() const;
444-
};
445-
446-
/// Verifies the lifetime of memory locations in a function.
447-
void verifyMemoryLifetime(SILFunction *function);
448-
449319
} // end swift namespace
450320

451321
#endif

0 commit comments

Comments
 (0)