Commit Graph

254 Commits

Author SHA1 Message Date
Pavel Yaskevich
24c4fcc10e [DI] Fix check that ignores loads related to assign_or_init and assign_by_wrapper
For cases where init accessor field has a nonmutating set we need
ignore copies and borrows associated with load of "self" because
they are going to be erased together with the setter application
by DI.
2023-09-29 13:18:54 -07:00
Erik Eckstein
5bc036661c SIL optimizer: add the LetPropertyLowering pass
It lowers let property accesses of classes.
Lowering consists of two tasks:

* In class initializers, insert `end_init_let_ref` instructions at places where all let-fields are initialized.
  This strictly separates the life-range of the class into a region where let fields are still written during
  initialization and a region where let fields are truly immutable.

* Add the `[immutable]` flag to all `ref_element_addr` instructions (for let-fields) which are in the "immutable"
  region. This includes the region after an inserted `end_init_let_ref` in an class initializer, but also all
  let-field accesses in other functions than the initializer and the destructor.

This pass should run after DefiniteInitialization but before RawSILInstLowering (because it relies on `mark_uninitialized` still present in the class initializer).
Note that it's not mandatory to run this pass. If it doesn't run, SIL is still correct.

Simplified example (after lowering):

  bb0(%0 : @owned C):                           // = self of the class initializer
    %1 = mark_uninitialized %0
    %2 = ref_element_addr %1, #C.l              // a let-field
    store %init_value to %2
    %3 = end_init_let_ref %1                    // inserted by lowering
    %4 = ref_element_addr [immutable] %3, #C.l  // set to immutable by lowering
    %5 = load %4
2023-09-19 15:10:30 +02:00
Holly Borla
a6d078b820 [Concurrency] Use the 'nonisolated' terminology instead of 'independent'.
This commit is NFC; it's mostly renames.
2023-09-08 13:28:55 -07:00
Michael Gottesman
37d60a08bb [move-only] Rename mark_must_check -> mark_unresolved_non_copyable_value.
I was originally hoping to reuse mark_must_check for multiple types of checkers.
In practice, this is not what happened... so giving it a name specifically to do
with non copyable types makes more sense and makes the code clearer.

Just a pure rename.
2023-08-30 22:29:30 -07:00
Pavel Yaskevich
4ec86f222a [DI] InitAccessor: Ignore a load of "self" introduced by a partial apply of a setter
`nonmutating set` needs to load of "self" but that load could be
ignored safely because it's only viable when self is determined
to be fully initialized by DI. The same applies to `assign_by_wrapper`.
2023-08-25 09:49:31 -07:00
Pavel Yaskevich
2149a4630a [DI] InitAccessors: Ignore unreachable blocks when check property initialization inside of an init accessor 2023-08-21 09:04:34 -07:00
Slava Pestov
9ebb5f2e03 AST: Rename VarDecl::getType() to VarDecl::getTypeInContext()
This is a futile attempt to discourage future use of getType() by
giving it a "scary" name.

We want people to use getInterfaceType() like with the other decl kinds.
2023-08-04 14:19:25 -04:00
Pavel Yaskevich
00729ad958 Merge pull request #67107 from xedin/setterless-init-accessor-properties
[SILGen/DI] Add support for init accessor properties without setters
2023-07-07 00:16:07 -07:00
Pavel Yaskevich
a3e8bb6cce [DI] InitAccessors: Prevent re-initialization of init accessor property with a setter
Init accessor properties without setters behave just like `let` stored properties
and can only be initialized once.
2023-07-04 00:25:24 -07:00
Michael Gottesman
0e383cd918 [move-only] Fix a place in DI where we were not converting an assignable_but_not_consumable -> initable_but_not_consumable.
I fixed this for assign but missed a place where we needed to do the same thing for copy_addr.

rdar://111709236
2023-07-03 15:54:47 -07:00
Evan Wilde
250082df25 [NFC] Reformat all the LLVMs
Reformatting everything now that we have `llvm` namespaces. I've
separated this from the main commit to help manage merge-conflicts and
for making it a bit easier to read the mega-patch.
2023-06-27 09:03:52 -07:00
Evan Wilde
f3ff561c6f [NFC] add llvm namespace to Optional and None
This is phase-1 of switching from llvm::Optional to std::optional in the
next rebranch. llvm::Optional was removed from upstream LLVM, so we need
to migrate off rather soon. On Darwin, std::optional, and llvm::Optional
have the same layout, so we don't need to be as concerned about ABI
beyond the name mangling. `llvm::Optional` is only returned from one
function in
```
getStandardTypeSubst(StringRef TypeName,
                     bool allowConcurrencyManglings);
```
It's the return value, so it should not impact the mangling of the
function, and the layout is the same as `std::optional`, so it should be
mostly okay. This function doesn't appear to have users, and the ABI was
already broken 2 years ago for concurrency and no one seemed to notice
so this should be "okay".

I'm doing the migration incrementally so that folks working on main can
cherry-pick back to the release/5.9 branch. Once 5.9 is done and locked
away, then we can go through and finish the replacement. Since `None`
and `Optional` show up in contexts where they are not `llvm::None` and
`llvm::Optional`, I'm preparing the work now by going through and
removing the namespace unwrapping and making the `llvm` namespace
explicit. This should make it fairly mechanical to go through and
replace llvm::Optional with std::optional, and llvm::None with
std::nullopt. It's also a change that can be brought onto the
release/5.9 with minimal impact. This should be an NFC change.
2023-06-27 09:03:52 -07:00
Joe Groff
40ad5aaffc DefiniteInitialization: Error when noncopyable types are conditionally initialized.
This leads to unhandled complications in the move-only checker that were causing miscompiles.
We can disallow this for now. rdar://109695770
2023-06-16 17:13:38 -07:00
Pavel Yaskevich
2b8a39724c Merge pull request #66513 from xedin/init-accessor-diagnostics
[Sema/SIL] Improve diagnostics related to init accessors
2023-06-14 09:57:08 -07:00
Erik Eckstein
63808be395 DefinitInitialization: convert begin_access instructions of initializations to a static accesses
In case of `var` initializations, SILGen creates a dynamic begin/end_access pair around the initialization store.
If it's an initialization (and not a re-assign) it's guanranteed that it's an exlusive access and we can convert the access to an `[init] [static]` access.

https://github.com/apple/swift/issues/66496
2023-06-14 07:17:56 +02:00
Pavel Yaskevich
f6fd0bc1a7 [DI] InitAccessors: Enforce that @out parameters are fully initialized before every terminator
This closes a hole where an early return could leave some
properties from `initializes(...)` list uninitialized.

For example:

```swift
init(initialValue) initializes(_a, _b) {
  _a = initialValue.0
  if _a > 0 {
    return
  }

  _b = initialValue.1
}
```

Here `_b` is not initialized when `_a > 0`.
2023-06-13 10:58:50 -07:00
Pavel Yaskevich
c82559e33c [DI/Lowering] InitAccessors: Implement lowering of property assignments
DI marks all of of the previously initialized properties and Raw SIL
lowering emits `destroy_addr` before calling init accessor for such
properties to destroy previously set value.
2023-06-06 18:59:46 -07:00
Pavel Yaskevich
112d0d4f2d [DI] InitAccessors: Start marking initializes(...) properties as "out"
Adjust DI to recognize that "out" location without uses is uninitialized.
2023-06-06 18:59:45 -07:00
Pavel Yaskevich
68866d7ae5 [DI] InitAccessors: Handle assign_or_init without initializations
Introduce a placeholder "init" use anchored on `assign_or_init`
instruction to make sure that `handleStoreUse` gets a called and
sets the kind.
2023-06-06 18:59:13 -07:00
Pavel Yaskevich
fe90ddce74 [DI] InitAccessors: Implement handling of initializes/accesses attributes
- Record all properties listed in `accesses` as loads;
- Record all properties listed in `initialized` as init-or-assign;
- Detect situations when double-init could happen i.e. if one of
  the properties listed in `initializes` attribute is explicitly
  initialized before init accessor call.
2023-06-06 18:59:13 -07:00
Holly Borla
df69020eca [DefiniteInitialization] Lower AssignOrInit instructions to either call the
initializer or the setter closure with the given argument.
2023-06-06 18:59:13 -07:00
Holly Borla
0028bdf91d [DefiniteInitialization] Rename DIUseKind::AssignWrappedValue to DIUseKind::Set. 2023-06-06 18:59:13 -07:00
Holly Borla
684ef9c482 [AST] Add a new accessor kind for init accessors. 2023-06-06 18:57:31 -07:00
Michael Gottesman
d413b24e80 [move-only] Ensure that if we have an allocation that isn't fully initialized (and DI errors on it as such), the move checkers do not run on the allocation.
Previously we would crash.

Since we are relatively late in 5.9, my solution is to just turn off the move
checker on functions whenever DI would emit an error. If we were earlier in the
development cycle, then I would make the error be a per allocation change.

rdar://108993297
2023-05-08 13:32:06 -07:00
Doug Gregor
593c2364e8 [Macros] "Subsume" the initializer when an accessor macros adds non-observers
When an accessor macro adds a non-observing accessor to a property, it
subsumes the initializer. We had previously modeled this as removing
the initializer, but doing so means that the initializer could not be
used for type inference and was lost in the AST.

Explicitly mark the initializer as "subsumed" here, and be more
careful when querying the initializer to distinguish between "the
initializer that was written" and "the initializer that will execute"
in more places. This distinction already existed at the
pattern-binding level, but not at the variable-declaration level.

This is the proper fix for the circular reference issue described in
rdar://108565923 (test case in the prior commit).
2023-04-28 09:50:00 -07:00
Joe Groff
8e21bfcc47 MoveOnlyAddressChecker: Confine analysis to current formal access.
Code can only locally interact with a mutable memory location within a
formal access, and is only responsible for maintaining its invariants
during that access, so the move-only address checker does not need to,
and should not, observe operations that occur outside of the access
marked with the `mark_must_check` instruction. And for immutable
memory locations, although there are no explicit formal accesses, that's
because every access must be read-only, so although individual
accesses are not delimited, they are all compatible as far as
move-only checking is concerned. So we can back out the changes to SILGen
to re-project a memory location from its origin on every access, a
change which breaks invariants assumed by other SIL passes.
2023-04-02 16:33:57 -07:00
Michael Gottesman
43d8ab24f4 [move-only] Add a new type of mark_must_check initable_but_not_consumable.
This is used to teach the checker that the thing being checked is supposed to be
uninitialized at the mark_must_check point so that we don't put a destroy_addr
there.

The way this is implemented is that we always initially add
assignable_but_not_consumable but in DI once we discover that the assign we are
guarding is an init, we convert the assignable to its initable variant.

rdar://106525988
2023-03-31 17:32:58 -07:00
Pavel Yaskevich
e0bf2ff854 [SIL/DI] NFC: Remove TypeWrappers feature functionality 2023-02-08 10:14:29 -08:00
John McCall
d25a8aec8b Add explicit lowering for value packs and pack expansions.
- SILPackType carries whether the elements are stored directly
  in the pack, which we're not currently using in the lowering,
  but it's probably something we'll want in the final ABI.
  Having this also makes it clear that we're doing the right
  thing with substitution and element lowering.  I also toyed
  with making this a scalar type, which made it necessary in
  various places, although eventually I pulled back to the
  design where we always use packs as addresses.

- Pack boundaries are a core ABI concept, so the lowering has
  to wrap parameter pack expansions up as packs.  There are huge
  unimplemented holes here where the abstraction pattern will
  need to tell us how many elements to gather into the pack,
  but a naive approach is good enough to get things off the
  ground.

- Pack conventions are related to the existing parameter and
  result conventions, but they're different on enough grounds
  that they deserve to be separated.
2023-01-29 03:29:06 -05:00
Max Desiatov
0812484a4a SILOptimizer: remove unused variables and fields (#63018)
Exact warning text:
```
swift/lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp:3239:12: warning: variable 'NumMemoryElements' set but not used [-Wunused-but-set-variable]
  unsigned NumMemoryElements = TheMemory.getNumElements();
           ^
1 warning generated.
```
2023-01-16 12:53:07 +00:00
Pavel Yaskevich
01b5a9d182 [DI] TypeWrappers: Support conformance requirements on Wrapper/Storage parameters 2022-12-19 14:17:38 -08:00
Pavel Yaskevich
2ce48e0b7d [AST/Sema] TypeWrappers: Augment GetTypeWrapper request to produce more info
The request is updated to return attribute, wrapper declaration,
the declaration its attached to and whether or not it has been
inferred (opposite to being declared directly).
2022-12-14 17:50:22 -08:00
Nate Chandler
8d8577e5b0 [SIL] Removed Indirect_In_Constant convention.
It is no different from @in.

Continue parse @in_constant in textual and serialized SIL, but just as
an alias for @in.
2022-12-09 21:54:00 -08:00
Adrian Prantl
c4695d5861 Use SILBuilderWithScope in the DefiniteInitialization pass
DefiniteInitialization used a running SILBuilder to insert all instructions and
didn't consistently set the scope to a meaningful value. This patch replaces all
uses of the running Builder with ad-hoc instances of SILBuilderWithScope which
should capture the intention of the code better.

rdar://102296138
2022-11-29 13:19:16 -08:00
Erik Eckstein
ab1b343dad use new llvm::Optional API
`getValue` -> `value`
`getValueOr` -> `value_or`
`hasValue` -> `has_value`
`map` -> `transform`

The old API will be deprecated in the rebranch.
To avoid merge conflicts, use the new API already in the main branch.

rdar://102362022
2022-11-21 19:44:24 +01:00
Pavel Yaskevich
db4b6a5c0f [AST/Sema] TypeWrappers: Implement type wrappers on protocols
Adding a type wrapper attribute on a protocol does two things:

- Synthesizes `associatedtype $Storage` declaration with `internal` access
- Synthesizes `var $storage: <#Wrapper#><Self, Self.$Storage>` value requirement
2022-11-07 14:55:05 -08:00
Pavel Yaskevich
b769f9f2e4 [Sema] TypeWrappers: Adjust synthesized type wrapper init calls to pass the wrapped type 2022-10-21 20:04:01 +01:00
Pavel Yaskevich
0f48f5c152 [AST/Sema] TypeWrappers/NFC: Rename type wrapper init parameter to storage: 2022-10-21 20:04:00 +01:00
Pavel Yaskevich
40d1146eac Merge pull request #61427 from xedin/type-wrappers-add-support-for-let-properties
[Sema/DI] TypeWrappers: Add support for `let` properties
2022-10-04 21:17:20 -07:00
Allan Shortlidge
c7ce7b75e0 Merge pull request #42514 from jsoref/spelling-siloptimizer
Spelling siloptimizer
2022-10-03 22:50:19 -07:00
Pavel Yaskevich
644a7f8ef1 [DI] Fail if _storage checking fails
If `_storage` checking fails, let's stop because otherwise
DI would end up emitting extraneous errors about uninitialized
`self.$_storage` which are consequence of `_storage` failures.
2022-10-03 16:58:50 -07:00
Josh Soref
730b16c569 Spelling siloptimizer
* access
* accessed
* accesses
* accessor
* acquiring
* across
* activated
* additive
* address
* addresses'
* aggregated
* analysis
* and
* appropriately
* archetype
* argument
* associated
* availability
* barriers
* because
* been
* beginning
* belongs
* beneficial
* blocks
* borrow
* builtin
* cannot
* canonical
* canonicalize
* clazz
* cleanup
* coalesceable
* coalesced
* comparisons
* completely
* component
* computed
* concrete
* conjunction
* conservatively
* constituent
* construct
* consuming
* containing
* covered
* creates
* critical
* dataflow
* declaration
* defined
* defining
* definition
* deinitialization
* deliberately
* dependencies
* dependent
* deserialized
* destroy
* deterministic
* deterministically
* devirtualizes
* diagnostic
* diagnostics
* differentiation
* disable
* discipline
* dominate
* dominates
* don't
* element
* eliminate
* eliminating
* elimination
* embedded
* encounter
* epilogue
* epsilon
* escape
* escaping
* essential
* evaluating
* evaluation
* evaluator
* executing
* existential
* existentials
* explicit
* expression
* extended
* extension
* extract
* for
* from
* function
* generic
* guarantee
* guaranteed
* happened
* heuristic
* however
* identifiable
* immediately
* implementation
* improper
* include
* infinite
* initialize
* initialized
* initializer
* inside
* instruction
* interference
* interferes
* interleaved
* internal
* intersection
* intractable
* intrinsic
* invalidates
* irreducible
* irrelevant
* language
* lifetime
* literal
* looks
* materialize
* meaning
* mergeable
* might
* mimics
* modification
* modifies
* multiple
* mutating
* necessarily
* necessary
* needsmultiplecopies
* nonetheless
* nothing
* occurred
* occurs
* optimization
* optimizing
* original
* outside
* overflow
* overlapping
* overridden
* owned
* ownership
* parallel
* parameter
* paths
* patterns
* pipeline
* plottable
* possible
* potentially
* practically
* preamble
* precede
* preceding
* predecessor
* preferable
* preparation
* probably
* projection
* properties
* property
* protocol
* reabstraction
* reachable
* recognized
* recursive
* recursively
* redundant
* reentrancy
* referenced
* registry
* reinitialization
* reload
* represent
* requires
* response
* responsible
* retrieving
* returned
* returning
* returns
* rewriting
* rewritten
* sample
* scenarios
* scope
* should
* sideeffects
* similar
* simplify
* simplifycfg
* somewhat
* spaghetti
* specialization
* specializations
* specialized
* specially
* statistically
* substitute
* substitution
* succeeds
* successful
* successfully
* successor
* superfluous
* surprisingly
* suspension
* swift
* targeted
* that
* that our
* the
* therefore
* this
* those
* threshold
* through
* transform
* transformation
* truncated
* ultimate
* unchecked
* uninitialized
* unlikely
* unmanaged
* unoptimized key
* updataflow
* usefulness
* utilities
* villain
* whenever
* writes

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>
2022-10-03 18:31:33 -04:00
Pavel Yaskevich
a9251423f5 [DI] Leave a comment about origins of _storage variable 2022-09-30 00:15:55 -07:00
Pavel Yaskevich
113c4fba87 [DI] NFC: Add a TODO comment about possible refactoring 2022-09-29 20:50:38 -07:00
Pavel Yaskevich
746457f346 [SILOptimizer] TypeWrappers: Implement self.$storage initialization injection
Inject a call to $Storage.init(...) which is then used to initialize
type wrapper property `$storage` via `self.$storage = <TypeWrapper>(memberwise: <storage>)`
call at each point where `_storage` becomes fully initialized.
2022-09-29 20:50:37 -07:00
Pavel Yaskevich
d5844e5300 [DI] Process type wrapper _storage before any other initialization
`_storage` is special because it emits assignments to compiler
synthesized stored property `$storage`, without that `self`
cannot be fully initialized.
2022-09-29 20:50:37 -07:00
Kavon Farvardin
77195823f2 [DI] sink injectActorHops() after processing destroys
While trying to reuse the liveness-points analysis originally in DI for
injecting actor hops for more general purposes, Pavel and I discovered
that the point at which we are injecting the hops might not have
fully-computed the liveness information.

That appears to be the case because we were computing the fully-initialized
points before having processed destroy/releases of TheMemory. While this
most likely had no influence on the actor hop injection, it does affect
what the outgoing AvailabilitySet contains for a block. In particular, for
this example:

```swift
struct X {
  init(cond: Bool) {
    var _storage: (name: String, age: Int)
    _storage.name = ""
    if cond {
      _storage.age = 30
    } else {
      _storage.age = 40
    }
  }
}
```

But because we are determine the full initialization points before processing
the destroy, the liveness analysis doesn't iterate to correctly determine the
out-availability of block 1 and 3 (corresponding to the then and else blocks
in the example above). Here's the debug output showing that issue:

```
*** Definite Init looking at:   %5 = mark_uninitialized [var] %4 : $*(name: String, age: Int) // users: %37, %12, %22, %32

Get liveness 0, #1 at   assign %11 to %13 : $*String                    // id: %14
Get liveness 1, #1 at   assign %21 to %23 : $*Int                       // id: %24
  Get liveness for block 1
    Iteration 0
    Result: (yn)
Get liveness 1, #1 at   assign %31 to %33 : $*Int                       // id: %34
  Get liveness for block 3
    add block 2 to worklist
    Iteration 0
      Block 2 out: (yn)
    Iteration 1
      Block 2 out: (yn)
    Result: (yn)
full-init-finder: rejecting bb0 b/c non-Yes OUT avail
full-init-finder: rejecting bb1 b/c non-Yes OUT avail
full-init-finder: rejecting bb2 b/c no non-load uses.
full-init-finder: rejecting bb3 b/c non-Yes OUT avail
full-init-finder: rejecting bb4 b/c no non-load uses.
Get liveness 0, #2 at   destroy_addr %5 : $*(name: String, age: Int)    // id: %37
  Get liveness for block 4
    add block 3 to worklist
    add block 1 to worklist
    Iteration 0
      Block 1 out: (yy)
      Block 3 out: (yy)
    Iteration 1
      Block 1 out: (yy)
      Block 3 out: (yy)
    Result: (yy)
```

So, this patch basically just sinks the computation so it happens after, so that
we force the incremental liveness analysis to also consider the liveness at the
point of the destroy, but before having done any other transformations or modifications
to the CFG to handle a destroy of something partially initialized.
2022-09-22 17:34:10 -07:00
Pavel Yaskevich
11a94478a1 [DI] Add a way to determine full initialization points
Logic that used to determine where `self` is completely
initialized to inject actor hops has been generalized
and is now available via `findFullInitializationPoints` method.
2022-09-19 15:55:04 -07:00
Meghana Gupta
34cc511af5 Fix store_borrow pattern in DefiniteInitialization 2022-08-16 15:08:22 -07:00
Kavon Farvardin
a4a5d32668 suppress notes from DI about @_compilerInitialized when reasonable
Since the only user of `@_compilerInitialized` is distributed
actors, I decided to make DI's diagnostics saying that such a
var was not initialized a second-tier note. If there is some other
var associated with the same Memory that is _not_ compiler initialized
AND is also _not_ initialized, then we suppress the suggestion to initialize
the @_compilerInitialized thing, because something else is problematic. Only
when there are @_compilerInitialized things that are still not initialized,
do we emit a note talking about that.
2022-03-24 16:20:06 -07:00