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
2426namespace swift {
2527
28+ class SILFunction ;
29+ class SILBasicBlock ;
30+ class SingleValueInstruction ;
31+
2632void printBitsAsArray (llvm::raw_ostream &OS, const SmallBitVector &bits);
2733
2834inline 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.
4749class MemoryLocations {
4850public:
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+
199204public:
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-
291294private:
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