Commit Graph

682 Commits

Author SHA1 Message Date
Erik Eckstein
3522ba1521 SILOptimizer: rename LibswiftPassInvocation -> SwiftPassInvocation
And a few other small related changes:
* remove libswiftPassInvocation from SILInstructionWorklist (because it's not needed)
* replace start/finishPassRun with start/finishFunction/InstructionPassRun

NFC
2022-01-05 10:15:56 +01:00
Erik Eckstein
3540c01125 rename initializeLibSwift -> InitializeSwiftModules
and some updates in comments.
2021-12-22 11:31:52 +01:00
Nate Chandler
59ae5180ba [NFC] Used SILOption field for copy propagation.
Replaced the quad-state (of state which one was illegal) of two booleans
(EnableCopyPropagation and DisableCopyPropagation) with an enum.
2021-12-13 17:44:28 -08:00
Erik Eckstein
3cb63c0646 SILCombine: fix a crash when optimizing stack allocations of existentials
The deinit_existential_addr instruction needs to be handled.

rdar://86069731
2021-12-06 12:31:55 +01:00
Andrew Trick
4180acf1a6 Add dynamic alignment optimization for 32-bit SIL. 2021-12-01 11:42:32 -08:00
Andrew Trick
c47fe03241 Optimize Builtin.assumeAlignment -> pointer_to_address
Case #1. Literal zero = natural alignment
   %1 = integer_literal $Builtin.Int64, 0
   %2 = builtin "uncheckedAssertAlignment"
	(%0 : $Builtin.RawPointer, %1 : $Builtin.Int64) : $Builtin.RawPointer
   %3 = pointer_to_address %2 : $Builtin.RawPointer to [align=1] $*Int

   Erases the `pointer_to_address` `[align=]` attribute:

Case #2. Literal nonzero = forced alignment.

   %1 = integer_literal $Builtin.Int64, 16
   %2 = builtin "uncheckedAssertAlignment"
	(%0 : $Builtin.RawPointer, %1 : $Builtin.Int64) : $Builtin.RawPointer
   %3 = pointer_to_address %2 : $Builtin.RawPointer to [align=1] $*Int

   Promotes the `pointer_to_address` `[align=]` attribute to a higher value.

Case #3. Folded dynamic alignment

   %1 = builtin "alignof"<T>(%0 : $@thin T.Type) : $Builtin.Word
   %2 = builtin "uncheckedAssertAlignment"
	(%0 : $Builtin.RawPointer, %1 : $Builtin.Int64) : $Builtin.RawPointer
   %3 = pointer_to_address %2 : $Builtin.RawPointer to [align=1] $*T

   Erases the `pointer_to_address` `[align=]` attribute.
2021-11-30 12:23:46 -08:00
Saleem Abdulrasool
349af3707d Merge pull request #40305 from compnerd/semitruck
gardening: make c++98-compat-extra-semi an error
2021-11-30 08:18:36 -08:00
Erik Eckstein
b89f58de6d SILCombine: replace Array.capacity with 0 if it's the empty array singleton
We already do that for Array.count. Now add Array.capacity.
2021-11-29 09:41:05 +01:00
Saleem Abdulrasool
910fbee14e gardening: make c++98-compat-extra-semi an error
This cleans up 90 instances of this warning and reduces the build spew
when building on Linux.  This helps identify actual issues when
building which can get lost in the stream of warning messages.  It also
helps restore the ability to build the compiler with gcc.
2021-11-27 11:40:17 -08:00
Erik Eckstein
49351c4759 SILOptimizer: extract the peephole optimization for Builtin.canBeClass into a separate utility. 2021-10-28 18:43:14 +02:00
Andrew Trick
8db4bb523d Fix SILCombine to use OSSA RAUW prepareReplacement
These SILCombine patterns produce new instructions that use the the
original value after it is updated for OSSA. The RAUW utility needs to
copy/borrow the original value before SILCombine can generate the new
replacement. Then SILCombine can pass that replacement back to RAUW to
perform the final replaceAllUsesWith.

1. PointerToAddress and RawPointerToRef

Fixes bugs where RAUW inserts borrows in the wrong place.

2. UncheckedBitwiseCast

The OSSA RAUW helper is incorrect here for producing a new
UncheckedRefCast. Simply don't use it. Since a bitwise cast is an
"Unowned" pointer escape, simply convert the unchecked_bitwise_cast
opcode to unchecked_ref_cast with Unowned forwarding ownership.

3. ConvertFunction

Make sure RAUW is never called with a replacement value that has
different ownership than the original.
2021-10-18 09:01:15 -07:00
Andrew Trick
0e696e1d67 SILCombine - Fix worklist logic for OSSA canonicalization
Required before fixing/re-enabling OSSA RAUW utilities.

Make sure the SILCombine worklist canonicalizes all the copies and
guarantees termination.

Run canonicalization on every existing copy_value once
and once for every new copy_value added during SILCombine.

Only add copies and their uses back to the worklist if
canonicalization deleted an instruction.

Add tracing for sinking forwaring instructions.
2021-10-15 14:48:41 -07:00
Meghana Gupta
cefc92588c Temporarily disable SILCombine keypath optimization in OSSA (#39364)
KeyPathProjector is not fully ported. Disable until OSSA support
in KeyPathProjector is implemented.
2021-09-19 08:58:47 -07:00
Andrew Trick
a5b1b5c3f8 SILOptimizer OSSA support for switch_enum & checked_cast_br
To create OSSA terminator results, use:
- OwnershipForwardingTermInst::createResult(SILType ValueOwnershipKind)
- SwitchEnumInst::createDefaultResult()

Add support for passing trivial values to nontrivial forwarding
ownership. This effectively converts None to Guaranteed ownership.

This is essential for handling ".none" enums as trivial values while
extracting a nontrivial payload with switch_enum. This converts None
to Guaranteed ownership. Generates a copy if needed to convert back to
Owned ownership.
2021-09-07 22:50:46 -07:00
Min-Yih Hsu
343d842394 [SIL][DebugInfo] PATCH 3/3: Deprecate debug_value_addr SIL instruciton
This patch removes all references to DebugValueAddrInst class and
debug_value_addr instruction in textual SIL files.
2021-08-31 12:01:04 -07:00
Min-Yih Hsu
e1023bc323 [DebugInfo] PATCH 2/3: Duplicate logics regarding debug_value_addr
This patch replace all in-memory objects of DebugValueAddrInst with
DebugValueInst + op_deref, and duplicates logics that handles
DebugValueAddrInst with the latter. All related check in the tests
have been updated as well.

Note that this patch neither remove the DebugValueAddrInst class nor
remove `debug_value_addr` syntax in the test inputs.
2021-08-31 11:57:56 -07:00
Erik Eckstein
8be0ca07c2 SIL optimizer: remove unbalanced retains/releases from immortal objects
ARC operations don't have an effect on immortal objects, like the empty array singleton or statically allocated arrays.
Therefore we can freely remove and retain/release instructions on such objects, even if there is no paired balanced ARC operation.

This optimization can only be done with a minimum deployment target of Swift 5.1, because in that version we added immortal ref count bits.

The optimization is implemented in libswift. Additionally, the remaining logic of simplifying strong_retain and strong_release is also ported to libswift.

rdar://81482156
2021-08-23 10:23:59 +02:00
Erik Eckstein
90c71ad002 libswift: improve and simplify pass invocation
* unify FunctionPassContext and InstructionPassContext
* add a modification API: PassContext.setOperand
* automatic invalidation notifications when the SIL is modified
2021-08-23 10:21:12 +02:00
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
290093ea90 Simplify lifetime canonicalization in SILCombine
And fix the way it handles of borrow scopes so we can enable borrow
scope rewiting. Make sure SILCombine only does canonicalization that
operates on a self-contained single-value-lifetime. It's important to
limit SILCombine to transformations where each individual step
converges quickly to a more canonical form. Rewriting borrow scopes
requires the copy propagation pass to coordinate all the individual
transformations.

Make canonicalizeLifetimes a SILCombine utility. This moves complexity
out of the main loop. SILCombine knows which values it wants to
canonicalize and can directly call either canonicalizeValueLifetime or
canonicalizeFunctionArgument for each one.

Respect the -enable/disable-copy-propagation options.
2021-07-01 21:46:29 -07:00
Erik Eckstein
e8d408d036 libswift: implement SILCombine's global_value optimization as instruction pass in libswift.
But keeping the old visit function as legacy
2021-06-09 11:33:41 +02:00
Erik Eckstein
1010f1e2ae libswift: infrastructure to define "instruction" passes.
Instruction passes are basically visit functions in SILCombine for a specific instruction type.
With the macro SWIFT_INSTRUCTION_PASS such a pass can be declared in Passes.def.
SILCombine then calls the run function of the pass in libswift.
2021-06-09 11:33:41 +02:00
Andrew Trick
0407a4e34a Add UpdatingInstructionIterator.
Track in-use iterators and update them both when instructions are
deleted and when they are added.

Safe iteration in the presence of arbitrary changes now looks like
this:

    for (SILInstruction *inst : deleter.updatingRange(&bb)) {
      modify(inst);
    }
2021-06-02 07:38:27 -07:00
Andrew Trick
0f88e0f3cc Rewrite instruction deletion logic in many passes
Fix innumerable latent bugs with iterator invalidation and callback invocation.

Removes dead code earlier and chips away at all the redundant copies the compiler generates.
2021-06-02 07:38:27 -07:00
Erik Eckstein
4977850092 SIL: remove the notifyDeleteHandlers mechanism
It's not needed anymore with delayed instruction deletion.
It was used for two purposes:
1. For analysis, which cache instructions, to avoid dangling instruction pointers
2. For passes, which maintain worklists of instructions, to remove a deleted instructions from the worklist. This is now done by checking SILInstruction::isDeleted().
2021-05-26 21:57:54 +02:00
Erik Eckstein
d2fc6eb3b5 AliasAnalysis: make AliasAnalysis a function analysis and simplify the cache keys
Instead of caching alias results globally for the module, make AliasAnalysis a FunctionAnalysisBase which caches the alias results per function.
Why?
* So far the result caches could only grow. They were reset when they reached a certain size. This was not ideal. Now, they are invalidated whenever the function changes.
* It was not possible to actually invalidate an alias analysis result. This is required, for example in TempRValueOpt and TempLValueOpt (so far it was done manually with invalidateInstruction).
* Type based alias analysis results were also cached for the whole module, while it is actually dependent on the function, because it depends on the function's resilience expansion. This was a potential bug.

I also added a new PassManager API to directly get a function-base analysis:
    getAnalysis(SILFunction *f)

The second change of this commit is the removal of the instruction-index indirection for the cache keys. Now the cache keys directly work on instruction pointers instead of instruction indices. This reduces the number of hash table lookups for a cache lookup from 3 to 1.
This indirection was needed to avoid dangling instruction pointers in the cache keys. But this is not needed anymore, because of the new delayed instruction deletion mechanism.
2021-05-26 21:57:54 +02:00
Michael Gottesman
e670d2b4de [sil-combine] Canonicalize copies using canonicalizeOSSALifetimes when moving newly created instructions into the worklist.
To be more explicit, canonicalizeOSSALifetimes is a utility that
re-canonicalizes all at once a set of defs that the caller found by applying
CanonicalizeOSSALifetime::getCanonicalCopiedDef(copy)). The reason why I am
doing this is that when we RAUW in OSSA, we sometimes insert additional copies
to make the problem easier for a utility to handle. This lets us canonicalize
away any copies before we even leave the pass.
2021-05-01 16:02:21 -07:00
Michael Gottesman
b6bfea1f39 [sil-optimizer] Get rid of the InstModCallback constructors in favor of onDelete/onCreatedNewInst/etc.
Without this when constructing an InstModCallback it is hard to distinguish
which closure is meant for which operation when passed to the constructor of
InstModCallback (if this was in Swift, we could use argument labels, but we do
not have such things in c++).

This new value type sort of formulation makes it unambiguous which callback is
used for what when constructing one of these.
2021-04-26 23:33:33 -07: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
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
Erik Eckstein
b3a7792d1d Reinstate "SIL: add a StackList data structure with zero cost operations."
... with a fix for a non-assert build crash: I used the wrong ilist type for SlabList. This does not explain the crash, though. What I think happened here is that llvm miscompiled and put the llvm_unreachable from the Slab's deleteNode function unconditionally into the SILModule destructor.
Now by using simple_ilist, there is no need for a deleteNode at all.
2021-04-13 13:49:45 +02:00
Arnold Schwaighofer
ddfdf4779d Revert "SIL: add a StackList data structure with zero cost operations." 2021-04-12 12:48:16 -07:00
Erik Eckstein
0456d95cb0 SIL: Use StackList in BasicBlockWorklist and BasicBlockSetVector
plus: I moved both data structures into a separate header file.
2021-04-11 14:07:26 +02:00
Erik Eckstein
ea8f43a8ba SILCombine: remove unneeded reference counting instructions from global_value
Delete all reference count instructions on a global_value if the only other uses are projections (ref_element_addr and ref_tail_addr).
2021-03-15 11:54:23 +01:00
Erik Eckstein
78a7887244 SILCombine: optimize mark_dependence of a string literal.
This pattern can occur after StringOptimization when a utf8CString of a literal is replace by the string_literal itself.
2021-03-08 08:34:53 +01:00
Slava Pestov
7ccc41a7b7 SIL: Preliminary support for 'apply [noasync]' calls
Refactor SILGen's ApplyOptions into an OptionSet, add a
DoesNotAwait flag to go with DoesNotThrow, and sink it
all down into SILInstruction.h.

Then, replace the isNonThrowing() flag in ApplyInst and
BeginApplyInst with getApplyOptions(), and plumb it
through to TryApplyInst as well.

Set the flag when SILGen emits a sync call to a reasync
function.

When set, this disables the SIL verifier check against
calling async functions from sync functions.

Finally, this allows us to add end-to-end tests for
rdar://problem/71098795.
2021-03-04 22:41:46 -05:00
Andrew Trick
7e19c4af03 Add a -sil-combine-canonicalize=false option for testing.
So I can test interesting ownership RAUW cases.
2021-02-24 21:27:42 -08:00
Michael Gottesman
428ab472ac [sil-combine] Turn off try_apply convert_function elimination on both ossa/non-ossa SIL.
In SILCombine, we do not want to add or delete edges. We are ok with swapping
edges or replacing edges when the CFG structure is preserved. This becomes an
issue since by performing this optimization, we are going to get rid of the
error parameter but leave a try_apply, breaking SIL invariants. So to do perform
this optimization, we would need to convert to an apply and eliminate the error
edge, breaking the aforementioned SILCombine invariant. So, just do not perform
this for now and leave it to other passes like SimplifyCFG.
2021-02-12 23:18:29 -08:00
Erik Eckstein
214b7a9929 Use the new BasicBlockWorklist utility in various places in the compiler.
It's a refactoring which simplifies the code.
NFC.
2021-02-12 11:15:55 +01:00
Erik Eckstein
fe10f98cf0 SIL: rename the SILBitfield.h header file to BasicBlockBits.h
NFC
2021-02-12 11:15:55 +01:00
eeckstein
a2996b7703 Merge pull request #35780 from eeckstein/static-function-arrays
SILOptimizer: allow function pointers in static globals and static global arrays.
2021-02-10 09:02:44 +01:00
Erik Eckstein
65b03f9815 SILOptimizer: prevent illegal load forwarding of function references in global variables.
We cannot replace a load from a global let-variable with a function_ref, if the referenced function would violate the resilience rules.
That means if a non-public function_ref would be inlined into a function which is serialized.
2021-02-09 19:56:43 +01:00
Erik Eckstein
542a378436 SIL: add FunctionRefInst::getReferencedFunction()
If we know that we have a FunctionRefInst (and not another variant of FunctionRefBaseInst), we know that getting the referenced function will not be null (in contrast to FunctionRefBaseInst::getReferencedFunctionOrNull).

NFC
2021-02-09 19:56:43 +01:00
Michael Gottesman
421addacce [ownership] Change store_borrow to be an interior pointer and update interior pointer formalism to use it.
For those who are unaware, a store_borrow is an instruction that is needed so
that we can without adding ARC traffic materialize a guaranteed object value
into memory so we can pass it as an in_guaranteed argument. It has not had its
model completely implemented due to time. I am going to add some information
about it in this commit message for others.

From a model semantic perspective, a store_borrow is meant to allow for a
guaranteed value to be materialized into memory safely for a scoped region of
time and be able to guarantee that:

1. The guaranteed value that was stored is always live.
2. The memory is never written to within that region.

The natural way to model this type of guaranteeing behavior from an object to an
address is via a safe interior pointer formulation and thus with that in mind I
made it so that store_borrow returned an address that was an interior pointer of
the guaranteed value. Sadly, we have not changed the compiler yet to use this
effectively since we in store_borrow code paths generally just use the input
address. That being said, in this PR I begin to move us toward this world by
making store_borrow's src operand an InteriorPointerOperand. This means that we
will require the borrowed value to be alive at all use points of the
store_borrow result. That will not have a large effect today but I am going to
loop back around and extend that.

There is additional work here that I wish to accomplish in the future is that I
would like to define an end_store_borrow instruction to explicitly end the scope
in which there is a condition on the borrow. Then we would require that the
memory we are using to for sure never be written to in that region and maybe
additionally try to give some sort of guarantee around exclusivity (consider if
we made it so that we could only store_borrow into an alloc_stack with certain
conditions). Not sure about the last one yet. But philosophically since we are
using this to just handle reabstraction suggests we can do something more
constrained.
2021-02-08 10:53:56 -08:00
Michael Gottesman
d1e462cdd1 [sil-combine] Leave the new load at the old load site when promoting unchecked_take_enum_data_addr + load -> load + unchecked_enum_data.
We must make sure the new load is inserted where the old load was instead of
inserting it at the unchecked_take_enum_data_addr, since the
unchecked_take_enum_data_addr may be in a different block from old load /and/
old load may not post-dominate that point. This was just a thinko.
2021-02-05 17:56:15 -08:00
Michael Gottesman
6475178189 [sil-combine] When promoting an unchecked_take_enum_data_addr + load -> load + unchecked_enum_data, make sure to handle the non-trivialness of the operand and the trivialness of the result correctly. 2021-02-05 12:31:16 -08:00
Michael Gottesman
729c089244 Merge pull request #35769 from gottesmm/pr-24641c31dd4cd867a16902b73ef96df6882ffd1c
[sil-combine] When folding (unchecked_trivial_bit_cast (unchecked_ref_cast)), make sure to move the unchecked_trivial_bit_cast to before the unchecked_ref_cast.
2021-02-05 08:06:11 -08:00
Michael Gottesman
c4945866c0 Merge pull request #35771 from gottesmm/pr-7a86804ccb656c83ca0ea919f73e6321c84ec937
[ownership] Distinguish on any forwarding insts in between the ownership kind that is "forwarded" and the ownership kind of its result to allow for trivial results to be modeled correctly
2021-02-05 08:05:46 -08:00
Erik Eckstein
5dd322ffaf SILCombine: remove release_value of a trivial enum
Even if the enum type is not trivial (because it has not trivial payloads for some cases), a release of such an enum can be removed if the enum is constructed with a trivial case.
2021-02-05 08:53:03 +01:00
Michael Gottesman
73745163cb [sil-combine] When folding (unchecked_trivial_bit_cast (unchecked_ref_cast)), make sure to move the unchecked_trivial_bit_cast to before the unchecked_ref_cast.
The reason that this needs to be done is that if the unchecked_ref_cast is an
owned value, it will end the lifetime of its operand meaning that we can't just
use it for a later unchecked_trivial_bit_cast.
2021-02-04 20:36:22 -08:00