1
- // ===--- MemoryLifetime .h - --------------------------------------*- C++ -*-===//
1
+ // ===--- MemoryLocations .h --------------------------------------*- C++ -*-===//
2
2
//
3
3
// This source file is part of the Swift.org open source project
4
4
//
5
- // Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors
5
+ // Copyright (c) 2014 - 2021 Apple Inc. and the Swift project authors
6
6
// Licensed under Apache License v2.0 with Runtime Library Exception
7
7
//
8
8
// See https://swift.org/LICENSE.txt for license information
9
9
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10
10
//
11
11
// ===----------------------------------------------------------------------===//
12
12
// /
13
- // / \file Contains utilities for calculating and verifying memory lifetime.
13
+ // / \file Contains the MemoryLocations utility for analyzing memory locations in
14
+ // / a SILFunction.
14
15
// /
15
16
// ===----------------------------------------------------------------------===//
16
17
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
19
20
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"
23
25
24
26
namespace swift {
25
27
28
+ class SILFunction ;
29
+ class SILBasicBlock ;
30
+ class SingleValueInstruction ;
31
+
26
32
void printBitsAsArray (llvm::raw_ostream &OS, const SmallBitVector &bits);
27
33
28
34
inline llvm::raw_ostream &operator <<(llvm::raw_ostream &OS,
@@ -40,10 +46,6 @@ void dumpBits(const SmallBitVector &bits);
40
46
// / Currently only a certain set of address instructions are supported:
41
47
// / Specifically those instructions which are going to be included when SIL
42
48
// / 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.
47
49
class MemoryLocations {
48
50
public:
49
51
@@ -115,10 +117,10 @@ class MemoryLocations {
115
117
// / sub-locations 3 and 4. But bit 0 is set in location 0 (the "self" bit),
116
118
// / because it represents the untracked field ``Outer.z``.
117
119
// /
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`` .
122
124
Bits subLocations;
123
125
124
126
// / The accumulated parent bits, including the "self" bit.
@@ -196,9 +198,13 @@ class MemoryLocations {
196
198
// / init_existential_addr and open_existential_addr.
197
199
bool handleNonTrivialProjections;
198
200
201
+ // / If true, also analyze trivial memory locations.
202
+ bool handleTrivialLocations;
203
+
199
204
public:
200
- MemoryLocations (bool handleNonTrivialProjections) :
201
- handleNonTrivialProjections (handleNonTrivialProjections) {}
205
+ MemoryLocations (bool handleNonTrivialProjections, bool handleTrivialLocations) :
206
+ handleNonTrivialProjections (handleNonTrivialProjections),
207
+ handleTrivialLocations (handleTrivialLocations) {}
202
208
203
209
MemoryLocations (const MemoryLocations &) = delete ;
204
210
MemoryLocations &operator =(const MemoryLocations &) = delete ;
@@ -228,7 +234,7 @@ class MemoryLocations {
228
234
const Location *getRootLocation (unsigned index) const ;
229
235
230
236
// / Registers an address projection instruction for a location.
231
- void registerProjection (SingleValueInstruction * projection, unsigned locIdx) {
237
+ void registerProjection (SILValue projection, unsigned locIdx) {
232
238
addr2LocIdx[projection] = locIdx;
233
239
}
234
240
@@ -285,9 +291,6 @@ class MemoryLocations {
285
291
// / Debug dump the MemoryLifetime internals.
286
292
void dump () const ;
287
293
288
- // / Debug dump a bit set .
289
- static void dumpBits (const Bits &bits);
290
-
291
294
private:
292
295
// / Clears all datastructures, except singleBlockLocations;
293
296
void clear ();
@@ -313,139 +316,6 @@ class MemoryLocations {
313
316
void initFieldsCounter (Location &loc);
314
317
};
315
318
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
-
449
319
} // end swift namespace
450
320
451
321
#endif
0 commit comments