Commit Graph

1065 Commits

Author SHA1 Message Date
Andrew Trick
88df7833af Add InteriorPointer::ProjectBox.
InteriorPointer needs to handle all access base kinds that may be borrowed.
2021-08-07 15:26:47 -07:00
Andrew Trick
9984b81de7 MemAccessUtils cleanup: rename hasIdenticalBase
to hasIdenticalStorage.

Be precise in preparation for unifying and clarifying the access base model.
2021-08-07 15:26:46 -07:00
swift-ci
34ff88a273 Merge remote-tracking branch 'origin/main' into rebranch 2021-08-06 18:53:41 -07:00
Meghana Gupta
64095a6d6b Fix use of MemAcessUtils in LICM (#38784)
AccessPathWithBase::compute can return a valid access path with unidentified base.
In such cases, we cannot LICM stores, because there is no base address to check if it is invariant
2021-08-06 18:34:55 -07:00
Arnold Schwaighofer
5a83172a55 Merge remote-tracking branch 'upstream/main' into rebranch 2021-08-05 12:04:56 -07:00
Andrew Trick
c323c6298b Fix an assert in collectUses when handling unknown index offsets.
AccessPathDefUseTraversal accumulates the offsets that it has seen on
the def-use walk while visiting index_addr and casts.

This is quite tricky because either the AccessPath being matched or
the def-use chain could contain unknown offsets. We need to correctly
classify all cases as either an exact, inner, or overlapping match.

For SIL like this

 %91 = integer_literal $Builtin.Int64, 0
 %113 = builtin "truncOrBitCast_Int64_Word"(%91 : $Builtin.Int64) : $Builtin.Word
 %115 = index_addr %114 : $*MyStruct, %113 : $Builtin.Word
 %119 = struct_element_addr %115 : $*MyStruct, #MyStruct.klass

We have Path: (@Unknown,#0)

There are two issues

(1) When AccessPathDefUseTraversal::checkAndUpdateOffset visits the
struct_element_addr, it fails to pop the unknown offset from the
expected path but continues trying to handle the struct_element_addr
and hits an assert. This PR fixes this.

(2) If the builtin "truncOrBitCast_Int64_Word" comes from a literal,
we should not treat it as an unknown offset (given that the literal is
within the size of a word). Added a test for this case, we should be able
to identify the access path accurately in this.
2021-08-04 17:38:51 -07:00
swift-ci
f1dbc19673 Merge remote-tracking branch 'origin/main' into rebranch 2021-07-23 07:53:50 -07:00
Joe Groff
fc67ba57f2 Merge pull request #37938 from jckarter/async-let-multi-suspend
Handle multiple awaits and suspend-on-exit for async let tasks.
2021-07-23 07:36:54 -07:00
swift-ci
fd87ebc401 Merge remote-tracking branch 'origin/main' into rebranch 2021-07-23 07:13:34 -07:00
Robert Widmann
1329f3cfbd [NFC] Lift getGenericEnvironment() into GenericSignature 2021-07-22 23:33:02 -07:00
Joe Groff
439edbce1f Handle multiple awaits and suspend-on-exit for async let tasks.
Change the code generation patterns for `async let` bindings to use an ABI based on the following
functions:

- `swift_asyncLet_begin`, which starts an `async let` child task, but which additionally
  now associates the `async let` with a caller-owned buffer to receive the result of the task.
  This is intended to allow the task to emplace its result in caller-owned memory, allowing the
  child task to be deallocated after completion without invalidating the result buffer.
- `swift_asyncLet_get[_throwing]`, which replaces `swift_asyncLet_wait[_throwing]`. Instead of
  returning a copy of the value, this entry point concerns itself with populating the local buffer.
  If the buffer hasn't been populated, then it awaits completion of the task and emplaces the
  result in the buffer; otherwise, it simply returns. The caller can then read the result out of
  its owned memory. These entry points are intended to be used before every read from the
  `async let` binding, after which point the local buffer is guaranteed to contain an initialized
  value.
- `swift_asyncLet_finish`, which replaces `swift_asyncLet_end`. Unlike `_end`, this variant
  is async and will suspend the parent task after cancelling the child to ensure it finishes
  before cleaning up. The local buffer will also be deinitialized if necessary. This is intended
  to be used on exit from an `async let` scope, to handle cleaning up the local buffer if necessary
  as well as cancelling, awaiting, and deallocating the child task.
- `swift_asyncLet_consume[_throwing]`, which combines `get` and `finish`. This will await completion
  of the task, leaving the result value in the result buffer (or propagating the error, if it
  throws), while destroying and deallocating the child task. This is intended as an optimization
  for reading `async let` variables that are read exactly once by their parent task.

To avoid an epoch break with existing swiftinterfaces and ABI clients, the old builtins and entry
points are kept intact for now, but SILGen now only generates code using the new interface.

This new interface fixes several issues with the old async let codegen, including use-after-free
crashes if the `async let` was never awaited, and the inability to read from an `async let` variable
more than once.

rdar://77855176
2021-07-22 10:19:31 -07:00
swift-ci
7d22e5ce38 Merge remote-tracking branch 'origin/main' into rebranch 2021-07-21 10:35:07 -07:00
Becca Royal-Gordon
04775d41ea Merge pull request #38419 from beccadax/the-generic-bound-is-cheaper
[IRGen] Fix crashes involving ObjC generic params
2021-07-21 10:15:23 -07:00
Becca Royal-Gordon
9da193ec8f [NFC] Unify helpers for checking for ObjC generics
There were two differently-named and slightly differently-implemented checks on nominal type decls. Clean this up a bit.
2021-07-19 19:59:26 -07:00
swift-ci
aa831950b4 Merge remote-tracking branch 'origin/main' into rebranch 2021-07-19 07:36:06 -07:00
Andrew Trick
8e4c27daaa BasicBlockCloner: support for updating DeadEndBlocks.
DeadEndBlocks is used by low-level OSSA utilities. It needs to be
valid whenever OSSA transformations is being done.
2021-07-17 18:31:25 -07:00
Andrew Trick
9d5b0d5455 OSSA: Allow BasicBlockUtils getEdgeArgs to create guaranteed phis
For switch_enum and dynamic_method_br
2021-07-17 18:31:25 -07:00
swift-ci
9fbe65dfd9 Merge remote-tracking branch 'origin/main' into rebranch 2021-07-08 20:33:22 -07:00
Michael Gottesman
79211d4869 [assembly-vision] If a nominal type is marked with @_assemblyVision emit AssemblyVisionRemarks for all of the nominal type's methods.
This is implemented by checking if a function has a self parameter and if the
self parameter is a nominal type, checking for the relevant attribute.
2021-07-08 15:08:38 -07:00
swift-ci
e0e2634b84 Merge remote-tracking branch 'origin/main' into rebranch 2021-07-06 09:35:07 -07:00
Michael Gottesman
37be1f2f85 Merge pull request #38217 from gottesmm/pr-4acf599c8ec4a79b006ea0873129b68adb749de1
[assembly-vision] Change release to do backwards then forwards when inferring source locs.
2021-07-02 22:10:34 -07:00
Michael Gottesman
804bcac1e6 [assembly-vision] Change release to do backwards then forwards when inferring source locs.
TLDR: I fixed a whole in the assembly-vision opt-remark pass where we were not
emitting a remark for end of scope instructions at the beginning of blocks. Now
all of these instructions (strong_release, end_access) should always reliably
have a remark emitted for them.

----

I think that this is a pragmatic first solution to the problem of
strong_release, release_value being the first instruction of a block. For those
who are unaware, this issue is that for a long time we have searched backwards
first for "end of scope" like instructions. This then allows us to identify the
"end of scope" instruction as happening at the end of the previous statement
which is where the developer thinks it should be:

```
var global: Klass
func bar() -> @owned Klass { global }
func foo() {
   // We want the remark for the
   bar()                          // expected-remark {{retain}}
}
```

This makes sense since we want to show end of scope instructions as being
applied to the earlier code whose scope it is ending. We can be clear that it is
at the end of the statement by placing the carrot on the end of statement
SourceLoc so there isn't any confusion upon whether or not

That generally has delivered nice looking results, but what if our release is
the first instruction in the block? In that case, we do not have any instruction
that we can immediately use, so traditionally we just gave up and didn't emit
anything. This is not an acceptable solution! We should be able to emit
something for every retain/release in the program if we want users to be able to
rely upon this! Thus we need to be able to get source location information from
somewhere around

First before we begin, my approach here is informed by my seeing over time that
the optimizer does a pretty good job of not breaking SourceLoc info for
terminators.

With that in mind, there are two possible approaches here: using the terminator
from the previous block and searching forward at worst taking the SourceLoc of
the current block's terminator (or earlier if we find a good SourceLoc). I
wasn't sure what the correct thing to do was at the time so I didn't fix the
issue. After some thought, I realized that the correct solution is to if we fail
a backwards search, search forwards. The reason why is that since our remarks
runs late in the optimization pipeline, there is a very high likelihood that if
we aren't folded into our previous block that there is a true need in the
program for conditional control flow here. We want to avoid placing the release
out of such pieces of code since it is misleading to the user:

```

In this example there is a release inside the case for .x but none for .y. In
that case it is possible that we get a release for .f since payload is passed in
at +1 at SILGen time. In such a case, using the terminator of the previous block
would mean that we would have the release be marked as on payload instead of
inside the case of .x. By using the terminator of the releases block, we can

switch payload {
case let .x(f):
  ...
case let .y:
  ...
}
```

So using the terminator from the previous block would be
  misleading to the user. Instead it is better to pick a location after the release that way
  we know at least the instruction we are inferring from must in some sense be

With this fix, we should not emit locations for all retains, releases. We may
not identify a good source loc for all of them, but we will identify them.

optimization pipeline, if our block was not folded into the previous block there
is a very high liklihood that there is some sort of conditional control flow
that is truly necessary in the program. If we

this
generally implies that there is a real side effect in the program that is
requiring conditional code execution (since the optimizer would have folded it).

The reason why is that we are at least going to hit a terminator or a
side-effect having instruction that generally have debug info preserved by the
optimizer.
2021-07-02 11:51:09 -07:00
Erik Eckstein
b175436d07 libswift: add instructions, support block predecessors/successors
Add many new instruction classes in libswift, including all terminator instructions.
This allows to support BasicBlock predecessors and successors.
2021-07-01 16:15:44 +02:00
Erik Eckstein
46c3a17e3d libswift: add Type.isAddress and Type.isObject 2021-07-01 15:23:08 +02:00
Erik Eckstein
891f53d1e3 libswift: bridge the MemoryBehavior enum instead of all the mayRead/Write instruction functions 2021-07-01 15:17:51 +02:00
swift_jenkins
1bd446a6cb Merge remote-tracking branch 'origin/main' into next 2021-06-24 16:21:41 -07:00
Doug Gregor
e7e922ea77 Introduce a createAsyncTaskInGroup SIL builtin.
Rather than using group task options constructed from the Swift parts
of the _Concurrency library and passed through `createAsyncTask`'s
options, introduce a separate builtin that always takes a group. Move
the responsibility for creating the options structure into IRGen, so
we don't need to expose the TaskGroupTaskOptionRecord type in Swift.
2021-06-24 07:53:18 -07:00
Doug Gregor
76959b1d4f Remove CreateAsyncTaskGroupFuture and swift_task_create_group_future.
We've moved everything over to `CreateAsyncTask` now.
2021-06-24 07:53:18 -07:00
Doug Gregor
a61adace85 Remove CreateAsyncTaskFuture and swift_task_create_future.
We no longer need these entry points.
2021-06-24 07:53:18 -07:00
Doug Gregor
c7edfa3ba9 Centralize non-group task creation on swift_task_create[_f].
Introduce a builtin `createAsyncTask` that maps to `swift_task_create`,
and use that for the non-group task creation operations based on the
task-creation flags. `swift_task_create` and the thin function version
`swift_task_create_f` go through the dynamically-replaceable
`swift_task_create_common`, where all of the task creation logic is
present.

While here, move copying of task locals and the initial scheduling of
the task into `swift_task_create_common`, enabling by separate flags.
2021-06-24 07:53:17 -07:00
Evan Wilde
0aafd09835 F_None was renamed OF_None
This patch updates usages of F_None to OF_None, as LLVM changed that in
commit 3302af9d4c39642bebe64dd60a3aa162fefc44b2.
2021-06-23 10:36:39 -07:00
Erik Eckstein
d49108da07 libswift: add the SIL Builder
And two example instruction building functions.
2021-06-09 11:31:06 +02:00
Erik Eckstein
8080465e77 libswift: basic SIL and SIL bridging
This is the initial version of a buildable SIL definition in libswift.
It defines an initial set of SIL classes, like Function, BasicBlock, Instruction, Argument, and a few instruction classes.
The interface between C++ and SIL is a bridging layer, implemented in C.
It contains all the required bridging data structures used to access various SIL data structures.
2021-06-09 11:28:57 +02:00
Saleem Abdulrasool
25f437e17d mark some switches as covered (NFCI)
Unfortunately, MSVC does not detect covered switches as clang.  Mark
some of the switches as covered to avoid an unnecessary warning from
MSVC.
2021-06-05 15:30:25 -07:00
Erik Eckstein
24799e1526 SIL: defer instruction deletion to the end of a pass run.
When an instruction is "deleted" from the SIL, it is put into the SILModule::scheduledForDeletion list.
The instructions in this list are eventually deleted for real in SILModule::flushDeletedInsts(), which is called by the pass manager after each pass run.
In other words: instruction deletion is deferred to the end of a pass.

This avoids dangling instruction pointers within the run of a pass and in analysis caches.
Note that the analysis invalidation mechanism ensures that analysis caches are invalidated before flushDeletedInsts().
2021-05-26 21:57:54 +02:00
Erik Eckstein
4affa11604 OwnershipUtils: let visitTransitiveEndBorrows work with a BorrowedValue.
... and not only with a begin_borrow
2021-05-18 08:56:22 +02:00
Alejandro Alonso
444c35cf8d Merge pull request #36953 from Azoy/isType-isDeclType
[NFC] Introduce isDecl and getDeclType
2021-04-20 15:33:00 -04:00
Azoy
9ed732f0ab Introduce isDecl and getDeclType
fix enum logic issue

fix tests

guard against null types
2021-04-20 02:22:16 -04:00
Konrad `ktoso` Malawski
d3c5ebc9b7 [AsyncLet] reimplemented with new ABI and builtins 2021-04-19 10:06:23 +09:00
Konrad `ktoso` Malawski
ba615029c7 [Concurrency] Store child record when async let child task spawned 2021-04-19 10:06:23 +09:00
Erik Eckstein
6ec788ff09 SIL: remove the SILOpenedArchetypesTracker
Instead, put the archetype->instrution map into SIlModule.

SILOpenedArchetypesTracker tried to maintain and reconstruct the mapping locally, e.g. during a use of SILBuilder.
Having a "global" map in SILModule makes the whole logic _much_ simpler.

I'm wondering why we didn't do this in the first place.

This requires that opened archetypes must be unique in a module - which makes sense. This was the case anyway, except for keypath accessors (which I fixed in the previous commit) and in some sil test files.
2021-04-14 08:36:10 +02:00
Doug Gregor
e77a27e8ed [Concurrency] Introduce runtime detection of data races.
Through various means, it is possible for a synchronous actor-isolated
function to escape to another concurrency domain and be called from
outside the actor. The problem existed previously, but has become far
easier to trigger now that `@escaping` closures and local functions
can be actor-isolated.

Introduce runtime detection of such data races, where a synchronous
actor-isolated function ends up being called from the wrong executor.
Do this by emitting an executor check in actor-isolated synchronous
functions, where we query the executor in thread-local storage and
ensure that it is what we expect. If it isn't, the runtime complains.
The runtime's complaints can be controlled with the environment
variable `SWIFT_UNEXPECTED_EXECUTOR_LOG_LEVEL`:

  0 - disable checking
  1 - warn when a data race is detected
  2 - error and abort when a data race is detected

At an implementation level, this introduces a new concurrency runtime
entry point `_checkExpectedExecutor` that checks the given executor
(on which the function should always have been called) against the
executor on which is called (which is in thread-local storage). There
is a special carve-out here for `@MainActor` code, where we check
against the OS's notion of "main thread" as well, so that `@MainActor`
code can be called via (e.g.) the Dispatch library's
`DispatchQueue.main.async`.

The new SIL instruction `extract_executor` performs the lowering of an
actor down to its executor, which is implicit in the `hop_to_executor`
instruction. Extend the LowerHopToExecutor pass to perform said
lowering.
2021-04-12 15:19:51 -07:00
Erik Eckstein
09755659a1 SIL: remove the sub-classes of MultipleValueInstructionResult
They are not really needed, because they don't contain any stored properties and for isa-checks we can check the parent instruction.
2021-04-11 19:14:34 +02:00
John McCall
efeb818161 Clean up the TaskGroup ABI:
- stop storing the parent task in the TaskGroup at the .swift level
- make sure that swift_taskGroup_isCancelled is implied by the parent
  task being cancelled
- make the TaskGroup structs frozen
- make the withTaskGroup functions inlinable
- remove swift_taskGroup_create
- teach IRGen to allocate memory for the task group
- don't deallocate the task group in swift_taskGroup_destroy

To achieve the allocation change, introduce paired create/destroy builtins.

Furthermore, remove the _swiftRetain and _swiftRelease functions and
several calls to them.  Replace them with uses of the appropriate builtins.
I should probably change the builtins to return retained, since they're
working with a managed type, but I'll do that in a separate commit.
2021-04-09 03:06:31 -04:00
John McCall
57c0c787db Make Builtin.getCurrentExecutor conservatively not readnone.
Fixes a miscompile where the hop_to_executor optimizer would
remove hop_to_executor before a getCurrentExecutor.
2021-04-08 12:57:11 -04:00
Michael Gottesman
059421e26c [mem-access-utils] Allow for getStackInitAllocStackUse to recognize an always take from a unconditional_checked_cast_addr as a destroy_addr 2021-03-29 12:14:14 -07:00
Michael Gottesman
6bb92533f6 [mem-access-utils] Allow for getStackInitAllocStackUse to recognize an always take from a checked_cast_addr_br as a destroy_addr.
Since it is an always take, we know that the original value will always be
invalidated by the checked_cast_addr_br.

This also lets me use this to recognize simple cases of checked casts in
opt-remark-gen.
2021-03-29 12:10:37 -07:00
Michael Gottesman
f6e71d4433 [mem-access-utils] Refactor isSingleInitAllocStack into getSingleInitAllocStackUse and rewrite the former in terms of the first.
This enabled me to expand this API to return the underlying single init use. I
want this information in OptRemarkGen.
2021-03-29 12:10:37 -07:00
Michael Gottesman
360e32bfbd Merge pull request #36622 from gottesmm/pr-f547a5b1d52f9b19efd84b124f089c7df498f07f
[opt-remark-gen] Teach OptRemarkGen how to emit diagnostics about exclusivity.
2021-03-28 18:20:00 -07:00
Michael Gottesman
1227693d29 [opt-remark-gen] Teach OptRemarkGen how to emit diagnostics about exclusivity.
For example, now we get the following diagnostic on globals:

 public func getGlobal() -> Klass {
     return global // expected-remark @:5 {{retain of type 'Klass'}}
                   // expected-note @-5:12 {{of 'global'}}
+                  // expected-remark @-2:12 {{begin exclusive access to value of type 'Klass'}}
+                  // expected-note @-7:12 {{of 'global'}}
+                  // expected-remark @-4 {{end exclusive access to value of type 'Klass'}}
+                  // expected-note @-9:12 {{of 'global'}}
+
 }

and for classes when we can't eliminate the access:

+func simpleInOut() -> Klass {
+    let x = Klass() // expected-remark @:13 {{heap allocated ref of type 'Klass'}}
+                    // expected-note @-1:9 {{of 'x'}}
+    simpleInOutUser(&x.next) // expected-remark @:5 {{begin exclusive access to value of type 'Optional<Klass>'}}
+                             // expected-note @-3:9 {{of 'x.next'}}
+                             // expected-remark @-2:28 {{end exclusive access to value of type 'Optional<Klass>'}}
+                             // expected-note @-5:9 {{of 'x.next'}}
+    return x
+}
2021-03-28 13:39:13 -07:00